Example #1
0
        hasattr(expr, 't1') and setattr(expr, 't1', time)
        hasattr(expr, 't2') and setattr(expr, 't2', time+fluid_parameters['dt'])

    # Solve fluid problem
    uf_, pf_ = solve_fluid(Wf, f=Constant((0, 0)), u_n=uf_n, p_n=pf_n,  bdries=fluid_bdries, bcs=bcs_fluid,
                           parameters=fluid_parameters)

    # Update current solution
    uf_n.assign(uf_)
    pf_n.assign(pf_)
    
    # Solve ALE
    # compute the displacement
    #ale_u_bottom=Expression((UALE_vessel,'0'), t1 = time, t2=time+dt, degree=2) 

    eta_f = solve_ale(Va, f=Constant((0, 0)), bdries=fluid_bdries, bcs=bcs_ale,
                      parameters=ale_parameters)
    
    # Move domains
    ALE.move(mesh_f, eta_f)

    # Save output
    if(timestep % int(Toutput/fluid_parameters['dt']) == 0):

        eta_f.rename("eta_f", "tmp")

        etaf_out << (eta_f, time)
 
        uf_.rename("uf", "tmp")
        pf_.rename("pf", "tmp")

        uf_out << (uf_, time)
Example #2
0
def PVS_simulation(args):
    """ Solve the flow and tracer transport in the PVS :
    Outputs :
    - a logfile with information about the simulation
    - .pvd files with the u, p and c field at specified args.toutput time period
    
    Return : u, p, c 1D array of the u, p, c fields on the middle line """



    # output folder name
    outputfolder=args.output_folder+'/'+args.job_name+'/'

    if not os.path.exists(outputfolder):
        os.makedirs(outputfolder)


    if not os.path.exists(outputfolder+'/profiles'):
        os.makedirs(outputfolder+'/profiles')

    if not os.path.exists(outputfolder+'/fields'):
        os.makedirs(outputfolder+'/fields')

    # Create output files

    #txt files
    csv_p=open(outputfolder+'profiles'+'/pressure.txt', 'w')
    csv_u=open(outputfolder+'profiles'+'/velocity.txt', 'w')
    csv_c=open(outputfolder+'profiles'+'/concentration.txt', 'w')
    csv_rv=open(outputfolder+'profiles'+'/radius.txt', 'w')

    #pvd files
    uf_out, pf_out= File(outputfolder+'fields'+'/uf.pvd'), File(outputfolder+'fields'+'/pf.pvd')
    c_out= File(outputfolder+'fields'+'/c.pvd')
    facets_out=File(outputfolder+'fields'+'/facets.pvd')

    # Create logger
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    # log to a file
    now = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = os.path.join(outputfolder+'/', 'PVS_info.log')
    file_handler = logging.FileHandler(filename,mode='w')
    file_handler.setLevel(logging.INFO)
    #formatter = logging.Formatter("%(asctime)s %(filename)s, %(lineno)d, %(funcName)s: %(message)s")
    #file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    # log to the console
    console_handler = logging.StreamHandler()
    level = logging.INFO
    console_handler.setLevel(level)
    logger.addHandler(console_handler)

    

    # initialise logging

    logging.info(title1("Simulation of the PVS flow and tracer transport using non steady solver and diffusion-advection solvers"))

    logging.info("Date and time:"+datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))

    logging.info('Job name : '+args.job_name)

    logging.debug('logging initialized')


    # Set parameters

    logging.info(title1("Parameters"))

    # Geometry params
    logging.info('\n * Geometry')
    Rv = args.radius_vessel # centimeters
    Rpvs =args.radius_pvs # centimeters
    L = args.length # centimeters

    logging.info('Vessel radius : %e cm'%Rv)
    logging.info('PVS radius : %e cm'%Rpvs)
    logging.info('PVS length : %e cm'%L)

    #Mesh
    logging.info('\n * Mesh')
    #number of cells in the radial direction
    Nr=args.N_radial
    DR=(Rpvs-Rv)/Nr
    #number of cells in the axial direction
    if args.N_axial :
        Nl=args.N_axial
    else :
        Nl=round(L/DR)

    DY=L/Nl
    
    logging.info('N axial : %i'%Nl)
    logging.info('N radial : %e'%Nr)

    

    #time parameters
    logging.info('\n * Time')
    toutput=args.toutput
    tfinal=args.tend
    dt=args.time_step

    logging.info('final time: %e s'%tfinal)
    logging.info('output period : %e s'%toutput)
    logging.info('time step : %e s'%dt)

    # approximate CFL for fluid solver : need to compute max velocity depending on the wall displacement... 
    # maybe just add a warning in computation with actual velocity
    #Uapprox=500e-4 #upper limit for extected max velocity
    #CFL_dt=0.25*DY/Uapprox
    #if  CFL_dt < dt :
    #    logging.warning('The specified time step of %.2e s does not fullfil the fluid CFL condition. New fluid time step : %.2e s'%(dt, CFL_dt))
    #dt_fluid=min(dt,CFL_dt)
    dt_fluid=dt

    # approximate CFL for tracer solver
    dt_advdiff=dt


    # material parameters
    logging.info('\n * Fluid properties')
    mu=args.viscosity
    rho=args.density

    logging.info('density: %e g/cm3'%rho)
    logging.info('dynamic viscosity : %e dyn s/cm2'%mu)

    logging.info('\n* Tracer properties')
    D=args.diffusion_coef
    sigma_gauss=args.sigma
    logging.info('Free diffusion coef: %e cm2/s'%D)
    logging.info('STD of initial gaussian profile: %e '%sigma_gauss)
    xi_gauss=args.initial_pos
    logging.info('Initial position: %e cm2'%xi_gauss)



    logging.info('\n * ALE')
    kappa=args.ale_parameter
    logging.info('ALE parameter: %e '%kappa)

    logging.info('\n * Lateral BC')
    resistance=args.resistance
    logging.info('inner resistance: %e '%resistance)
    if resistance == 0 :
        lateral_bc='free'
        logging.info('right BC will be set to the free assumption')
    elif resistance < 0 :
        lateral_bc='noflow'
        logging.info('right BC will be set to the no flow assumption')
    else :
        lateral_bc='resistance'
        logging.info('right BC will be set to the resistance assumption')

    fluid_parameters = {'mu': mu, 'rho': rho, 'dt':dt_fluid}
    tracer_parameters={'kappa': D, 'dt':dt_advdiff}
    ale_parameters = {'kappa': kappa}


    # Mesh
    logging.info(title1('Meshing'))

    logging.info('cell size : %e cm'%(np.sqrt(DR**2+DY**2)))
    logging.info('nb cells: %i'%(Nl*Nr*2))

    mesh_f= RectangleMesh(Point(0, Rv), Point(L, Rpvs), Nl, Nr)

    fluid_bdries = MeshFunction("size_t", mesh_f, mesh_f.topology().dim()-1,0)

    # Label facets
    xy = mesh_f.coordinates().copy()              
    x, y = xy.T

    xmin=x.min()
    xmax=x.max()
    ymin=y.min()
    ymax=y.max()


    tol=min(DR,DY)/2 #cm

    class Boundary_left(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[0],xmin,tol) #left


    class Boundary_right(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[0],xmax,tol)# right


    class Boundary_bottom(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[1], ymin,tol) #bottom
        
    class Boundary_top(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[1], ymax,tol) #top



    btop= Boundary_top()
    bbottom = Boundary_bottom()
    bleft = Boundary_left()
    bright = Boundary_right()


    bbottom.mark(fluid_bdries,  2) 
    btop.mark(fluid_bdries,  4)  
    bleft.mark(fluid_bdries, 1) 
    bright.mark(fluid_bdries,  3) 

    

    facet_lookup = {'x_min': 1 ,'y_min': 2, 'x_max': 3, 'y_max': 4}

    facets_out << fluid_bdries


    #FEM space

    logging.info(title1("Set FEM spaces"))

    logging.info('\n * Fluid')
    Vf_elm = VectorElement('Lagrange', triangle, 2)
    Qf_elm = FiniteElement('Lagrange', triangle, 1)
    Wf_elm = MixedElement([Vf_elm, Qf_elm])
    Wf = FunctionSpace(mesh_f, Wf_elm)
    logging.info('Velocity : "Lagrange", triangle, 2')
    logging.info('Pressure : "Lagrange", triangle, 1')

    logging.info('\n * Tracer')
    Ct_elm = FiniteElement('Lagrange', triangle, 1)
    Ct = FunctionSpace(mesh_f, Ct_elm)
    logging.info('Concentration : "Lagrange", triangle, 1')


    logging.info('\n * ALE')
    Va_elm = VectorElement('Lagrange', triangle, 1)
    Va = FunctionSpace(mesh_f, Va_elm)
    logging.info('ALE displacement: "Lagrange", triangle, 1')
    


    # Setup of boundary conditions
    logging.info(title1("Boundary conditions"))

    import sympy
    tn = sympy.symbols("tn")
    tnp1 = sympy.symbols("tnp1")
    sin = sympy.sin
    sqrt = sympy.sqrt

    logging.info('\n * Cross section area parameters')
    ai=args.ai
    fi=args.fi
    phii=args.phii
    logging.info('ai (dimensionless): '+'%e '*len(ai)%tuple(ai))
    logging.info('fi (Hz) : '+'%e '*len(fi)%tuple(fi))
    logging.info('phii (rad) : '+'%e '*len(phii)%tuple(phii))



    functionR = Rpvs-(Rpvs-Rv)*(1+sum([a*sin(2*pi*f*tn+phi) for a,f,phi in zip(ai,fi,phii)])) # displacement
    R_vessel = sympy.printing.ccode(functionR)

    functionV = sympy.diff(functionR,tn) # velocity
    V_vessel = sympy.printing.ccode(functionV)

    #Delta U for ALE. I dont really like this
    functionUALE=-(Rpvs-Rv)*(1+sum([a*sin(2*pi*f*tnp1+phi) for a,f,phi in zip(ai,fi,phii)]))+(Rpvs-Rv)*(1+sum([a*sin(2*pi*f*tn+phi) for a,f,phi in zip(ai,fi,phii)]))
    UALE_vessel = sympy.printing.ccode(functionUALE)   

    vf_bottom = Expression(('0',V_vessel ), tn = 0, degree=2)   # no slip no gap condition at vessel wall 
    uale_bottom = Expression(('0',UALE_vessel ), tn = 0, tnp1=1, degree=2) # displacement for ALE at vessel wall 

    logging.info('\n * Lateral assumption')
    logging.info(lateral_bc)

    logging.info('\n * Fluid')
    logging.info('Left : zero pressure')

    if lateral_bc=='free' :
        logging.info('Right : zero pressure')
    elif lateral_bc=='resistance' :
        logging.info('Right : resistance')
    else :
        logging.info('Right : no flow')

    logging.info('Top : no slip no gap fixed wall')
    logging.info('Bottom : no slip no gap moving wall')

    logging.info('\n * Tracer concentration')
    logging.info('Left : zero concentration')

    if lateral_bc=='free' :
        logging.info('Right : zero concentration')
    else :
        logging.info('Right : no flux')


    logging.info('Top : no flux')
    logging.info('Bottom : no flux')

    logging.info('\n * ALE')
    logging.info('Left : no flux')
    logging.info('Right : no flux')
    logging.info('Top : no displacement')
    logging.info('Bottom : vessel displacement')

    # Now we wire up

    if lateral_bc=='free' :
        bcs_fluid = {'velocity': [(facet_lookup['y_min'],vf_bottom),
                                (facet_lookup['y_max'], Constant((0,0)))],
                    'traction': [],  
                    'pressure': [(facet_lookup['x_min'], Constant(0)),
                                (facet_lookup['x_max'], Constant(0))]}

    elif lateral_bc=='resistance' :

        Rpressure=Expression('R*Q+p0', R = resistance, Q=0, p0=0, degree=1) #
  
        # Compute pressure to impose according to the flow at previous time step and resistance.

        bcs_fluid = {'velocity': [(facet_lookup['y_min'],vf_bottom),
                                (facet_lookup['y_max'], Constant((0,0)))],
                    'traction': [],  
                    'pressure': [(facet_lookup['x_min'], Constant(0)),
                                 (facet_lookup['x_max'], Rpressure)]}
    else :
        bcs_fluid = {'velocity': [(facet_lookup['y_min'],vf_bottom),
                                (facet_lookup['y_max'], Constant((0,0))),
                                (facet_lookup['x_max'], Constant((0,0)))], # I would like only normal flow to be zero 
                    'traction': [],  
                    'pressure': [(facet_lookup['x_min'], Constant(0))]}     


    if lateral_bc=='free' :
        bcs_tracer = {'concentration': [(facet_lookup['x_max'], Constant(0)),
                                        (facet_lookup['x_min'], Constant(0))],
                    'flux': [(facet_lookup['y_max'], Constant(0)),
                            (facet_lookup['y_min'], Constant(0))]}
    else :
        bcs_tracer = {'concentration': [(facet_lookup['x_min'], Constant(0))],
                    'flux': [(facet_lookup['x_max'], Constant(0)),
                            (facet_lookup['y_max'], Constant(0)),
                            (facet_lookup['y_min'], Constant(0))]}


    bcs_ale = {'dirichlet': [(facet_lookup['y_min'], uale_bottom),
                            (facet_lookup['y_max'], Constant((0, 0)))],
               'neumann': [(facet_lookup['x_min'], Constant((0, 0))),
                        (facet_lookup['x_max'], Constant((0, 0)))]}




    # We collect the time dependent BC for update
    driving_expressions = (uale_bottom,vf_bottom)

    # Initialisation : 
    logging.info(title1("Initialisation"))
    logging.info("\n * Fluid")
    logging.info("Velocity : zero field")
    logging.info("Pressure : zero field")
    uf_n = project(Constant((0, 0)), Wf.sub(0).collapse())
    pf_n =  project(Constant(0), Wf.sub(1).collapse())

    logging.info("\n * Tracer")
    logging.info("Concentration : Gaussian profile")
    logging.info("                Centered at mid length")
    logging.info("                STD parameter = %e"%sigma_gauss)


    c_0 = Expression('exp(-a*pow(x[0]-b, 2)) ', degree=1, a=1/2/sigma_gauss**2, b=xi_gauss)
    c_n =  project(c_0,Ct)

    # Save initial state
    uf_n.rename("uf", "tmp")
    pf_n.rename("pf", "tmp")
    c_n.rename("c", "tmp")
    uf_out << (uf_n, 0)
    pf_out << (pf_n, 0)
    c_out << (c_n, 0)

    files=[csv_p,csv_u,csv_c]
    fields=[pf_n,uf_n.sub(0),c_n]
    
    slice_line = line([0,(Rpvs+Rv)/2],[L,(Rpvs+Rv)/2], 100)

    for csv_file,field in zip(files,fields) :
        #print the x scale
        values=np.linspace(0,L,100)
        row=[0]+list(values)
        csv_file.write(('%e'+', %e'*len(values)+'\n')%tuple(row))
        #print the initial 1D slice
        values = line_sample(slice_line, field) 
        row=[0]+list(values)
        csv_file.write(('%e'+', %e'*len(values)+'\n')%tuple(row))



    ############# RUN ############3

    logging.info(title1("Run"))

    # Time loop
    time = 0.
    timestep=0

    


    # Here I dont know if there will be several dt for advdiff and fluid solver
    while time < tfinal:

        # Update boundary conditions
        for expr in driving_expressions:
            hasattr(expr, 'tn') and setattr(expr, 'tn', time)
            hasattr(expr, 'tnp1') and setattr(expr, 'tnp1', time+dt)

        if lateral_bc=='resistance' :
            z, r = SpatialCoordinate(mesh_f)
            ds = Measure('ds', domain=mesh_f, subdomain_data=fluid_bdries)
            n = FacetNormal(mesh_f)
            Flow=assemble(2*pi*r*dot(uf_n, n)*ds(facet_lookup['x_max']))

            print('Right outflow : %e \n'%Flow)
            setattr(Rpressure, 'Q', Flow)

        #Solve ALE and move mesh 
        eta_f = solve_ale(Va, f=Constant((0, 0)), bdries=fluid_bdries, bcs=bcs_ale,
                      parameters=ale_parameters)
        ALE.move(mesh_f, eta_f)
        mesh_f.bounding_box_tree().build(mesh_f)



        # Solve fluid problem
        uf_, pf_ = solve_fluid(Wf, u_0=uf_n,  f=Constant((0, 0)), bdries=fluid_bdries, bcs=bcs_fluid,
                            parameters=fluid_parameters)


        tracer_parameters["T0"]=time
        tracer_parameters["nsteps"]=1
        tracer_parameters["dt"]=dt

        # Solve tracer problem
        c_, T0= solve_adv_diff(Ct, velocity=uf_-eta_f/Constant(dt), phi=Constant(1), f=Constant(0), c_0=c_n, phi_0=Constant(1),
                                  bdries=fluid_bdries, bcs=bcs_tracer, parameters=tracer_parameters)


        # Update current solution
        uf_n.assign(uf_)
        pf_n.assign(pf_)
        c_n.assign(c_)

        #Update time
        time += dt
        timestep+=1

        # Save output
        if(timestep % int(toutput/dt) == 0):

            

            logging.info("\n*** save output time %e s"%time)
            logging.info("number of time steps %i"%timestep)

            # may report Courant number or other important values that indicate how is doing the run

            uf_.rename("uf", "tmp")
            pf_.rename("pf", "tmp")
            c_.rename("c", "tmp")
            uf_out << (uf_, time)
            pf_out << (pf_, time)
            c_out << (c_, time)


            # Get the 1 D profiles at umax (to be changed in cyl coordinate)
            mesh_points=mesh_f.coordinates()                                                      
            x=mesh_points[:,0]
            y=mesh_points[:,1]
            xmin=min(x)
            xmax=max(x)
            ymin=min(y)
            ymax=max(y)
                        
            #slice_line = line([xmin,(ymin+ymax)/2],[xmax,(ymin+ymax)/2], 100)

            logging.info('Rpvs : %e'%ymax)
            logging.info('Rvn : %e'%ymin)

            files=[csv_p,csv_u,csv_c]
            fields=[pf_n,uf_n.sub(0),c_n]
            field_names=['pressure (dyn/cm2)','axial velocity (cm/s)','concentration']

            for csv_file,field,name in zip(files,fields,field_names) :
                #values = line_sample(slice_line, field)
                values =profile(field,xmin,xmax,ymin,ymax)
                logging.info('Max '+name+' : %.2e'%max(abs(values)))
                #logging.info('Norm '+name+' : %.2e'%field.vector().norm('linf'))
                row=[time]+list(values)
                csv_file.write(('%e'+', %e'*len(values)+'\n')%tuple(row))

            csv_rv.write('%e, %e\n'%(time,ymin))
Example #3
0
def PVS_simulation(args):
    """ Solve the flow and tracer transport in the PVS, assumption flat plates :
    Outputs :
    - a logfile with information about the simulation
    - .pvd files with the u, p and c field at specified args.toutput time period
    
    Return : u, p, c 1D array of the u, p, c fields on the middle line """

    # output folder name
    outputfolder = args.output_folder + '/' + args.job_name + '/'

    if not os.path.exists(outputfolder):
        os.makedirs(outputfolder)

    if not os.path.exists(outputfolder + '/profiles'):
        os.makedirs(outputfolder + '/profiles')

    if not os.path.exists(outputfolder + '/fields'):
        os.makedirs(outputfolder + '/fields')

    # Create output files

    #txt files
    csv_p = open(outputfolder + 'profiles' + '/pressure.txt', 'w')
    csv_u = open(outputfolder + 'profiles' + '/velocity.txt', 'w')
    csv_c = open(outputfolder + 'profiles' + '/concentration.txt', 'w')
    csv_rv = open(outputfolder + 'profiles' + '/radius.txt', 'w')

    #pvd files
    uf_out, pf_out = File(outputfolder + 'fields' +
                          '/uf.pvd'), File(outputfolder + 'fields' + '/pf.pvd')
    c_out = File(outputfolder + 'fields' + '/c.pvd')
    facets_out = File(outputfolder + 'fields' + '/facets.pvd')

    # Create logger
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    # log to a file
    now = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = os.path.join(outputfolder + '/', 'PVS_info.log')
    file_handler = logging.FileHandler(filename, mode='w')
    file_handler.setLevel(logging.INFO)
    #formatter = logging.Formatter("%(asctime)s %(filename)s, %(lineno)d, %(funcName)s: %(message)s")
    #file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    # log to the console
    console_handler = logging.StreamHandler()
    level = logging.INFO
    console_handler.setLevel(level)
    logger.addHandler(console_handler)

    # initialise logging

    logging.info(
        ' ______     ______        _                 _       _   _             \n'
    )
    logging.info(
        '|  _ \ \   / / ___|   ___(_)_ __ ___  _   _| | __ _| |_(_) ___  _ __  \n'
    )
    logging.info(
        "| |_) \ \ / /\___ \  / __| | '_ ` _ \| | | | |/ _` | __| |/ _ \| '_ \ \n"
    )
    logging.info(
        '|  __/ \ V /  ___) | \__ \ | | | | | | |_| | | (_| | |_| | (_) | | | |\n'
    )
    logging.info(
        '|_|     \_/  |____/  |___/_|_| |_| |_|\__,_|_|\__,_|\__|_|\___/|_| |_|\n\n'
    )

    logging.info(
        title1(
            "Simulation of the PVS flow and tracer transport using steady stokes solver and diffusion-advection solver. Flat plates geometry"
        ))

    logging.info("Date and time:" +
                 datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))

    logging.info('Job name : ' + args.job_name)

    logging.debug('logging initialized')

    # Set parameters

    logging.info(title1("Parameters"))

    # Geometry params
    logging.info('\n * Geometry')
    Rv = args.radius_vessel  # centimeters
    Rpvs = args.radius_pvs  # centimeters
    L = args.length  # centimeters

    Rsas = args.radius_sas + Rv
    Lsas = args.length_sas

    logging.info('Vessel radius : %e cm' % Rv)
    logging.info('PVS radius : %e cm' % Rpvs)
    logging.info('PVS length : %e cm' % L)
    logging.info('SAS length : %e cm' % Lsas)
    logging.info('SAS radius : %e cm' % Rsas)

    logging.info('\n * Cross section area deformation parameters')
    ai = args.ai
    fi = args.fi
    phii = args.phii
    logging.info('ai (dimensionless): ' + '%e ' * len(ai) % tuple(ai))
    logging.info('fi (Hz) : ' + '%e ' * len(fi) % tuple(fi))
    logging.info('phii (rad) : ' + '%e ' * len(phii) % tuple(phii))

    #Mesh
    logging.info('\n * Mesh')
    #number of cells in the radial direction
    Nr = args.N_radial
    DR = (Rpvs - Rv) / Nr

    logging.info('N radial : %e' % Nr)

    #time parameters
    logging.info('\n * Time')
    toutput = args.toutput
    tfinal = args.tend
    dt = args.time_step

    logging.info('final time: %e s' % tfinal)
    logging.info('output period : %e s' % toutput)
    logging.info('time step : %e s' % dt)

    # approximate CFL for fluid solver : need to compute max velocity depending on the wall displacement...
    # maybe just add a warning in computation with actual velocity
    #Uapprox=500e-4 #upper limit for extected max velocity
    #CFL_dt=0.25*DY/Uapprox
    #if  CFL_dt < dt :
    #    logging.warning('The specified time step of %.2e s does not fullfil the fluid CFL condition. New fluid time step : %.2e s'%(dt, CFL_dt))
    #dt_fluid=min(dt,CFL_dt)
    dt_fluid = dt

    # approximate CFL for tracer solver
    dt_advdiff = dt

    # material parameters
    logging.info('\n * Fluid properties')
    mu = args.viscosity
    rho = args.density

    logging.info('density: %e g/cm3' % rho)
    logging.info('dynamic viscosity : %e dyn s/cm2' % mu)

    logging.info('\n* Tracer properties')
    D = args.diffusion_coef
    sigma_gauss = args.sigma
    logging.info('Free diffusion coef: %e cm2/s' % D)
    logging.info('STD of initial gaussian profile: %e ' % sigma_gauss)
    xi_gauss = args.initial_pos
    logging.info('Initial position: %e cm2' % xi_gauss)

    logging.info('\n * ALE')
    kappa = args.ale_parameter
    logging.info('ALE parameter: %e ' % kappa)

    logging.info('\n * Lateral BC')
    resistance = args.resistance
    logging.info('inner resistance: %e ' % resistance)
    if resistance == 0:
        lateral_bc = 'free'
        logging.info('right BC will be set to the free assumption')
    elif resistance < 0:
        lateral_bc = 'noflow'
        logging.info('right BC will be set to the no flow assumption')
    else:
        lateral_bc = 'resistance'
        logging.info('right BC will be set to the resistance assumption')

    fluid_parameters = {'mu': mu, 'rho': rho, 'dt': dt_fluid}
    tracer_parameters = {'kappa': D, 'dt': dt_advdiff}
    ale_parameters = {'kappa': kappa}

    # Mesh
    logging.info(title1('Meshing'))

    logging.info('cell size : %e cm' % (DR))

    from sleep.mesh import mesh_model2d, load_mesh2d, set_mesh_size
    import sys

    gmsh.initialize(['', '-format', 'msh2'])

    model = gmsh.model

    import math
    Apvs0 = math.pi * Rpvs**2
    Av0 = math.pi * Rv**2
    A0 = Apvs0 - Av0

    # progressive mesh
    factory = model.occ
    a = factory.addPoint(-Lsas, Rv, 0)
    b = factory.addPoint(L, Rv, 0)
    c = factory.addPoint(L, Rpvs, 0)
    d = factory.addPoint(0, Rpvs, 0)
    e = factory.addPoint(0, Rsas, 0)
    f = factory.addPoint(-Lsas, Rsas, 0)

    fluid_lines = [
        factory.addLine(*p)
        for p in ((a, b), (b, c), (c, d), (d, e), (e, f), (f, a))
    ]
    named_lines = dict(
        zip(('bottom', 'pvs_right', 'pvs_top', 'brain_surf', 'sas_top',
             'sas_left'), fluid_lines))

    fluid_loop = factory.addCurveLoop(fluid_lines)
    fluid = factory.addPlaneSurface([fluid_loop])

    factory.synchronize()

    model.addPhysicalGroup(2, [fluid], 1)

    for name in named_lines:
        tag = named_lines[name]
        model.addPhysicalGroup(1, [tag], tag)

    # boxes for mesh refinement
    cell_size = DR * (Rpvs - Rv) / (Rpvs - Rv)
    boxes = []
    # add box on the PVS for mesh
    field = model.mesh.field
    fid = 1
    field.add('Box', fid)
    field.setNumber(fid, 'XMin', 0)
    field.setNumber(fid, 'XMax', L)
    field.setNumber(fid, 'YMin', Rv)
    field.setNumber(fid, 'YMax', Rpvs)
    field.setNumber(fid, 'VIn', cell_size)
    field.setNumber(fid, 'VOut', DR * 50)
    field.setNumber(fid, 'Thickness', Rsas)

    boxes.append(fid)

    # Combine
    field.add('Min', 2)
    field.setNumbers(2, 'FieldsList', boxes)
    field.setAsBackgroundMesh(2)

    model.occ.synchronize()

    h5_filename = outputfolder + '/mesh.h5'
    tags = {'cell': {'F': 1}, 'facet': {}}
    mesh_model2d(model, tags, h5_filename)

    mesh_f, markers, lookup = load_mesh2d(h5_filename)

    gmsh.finalize()

    # todo : how to know nb of cells ?
    #logging.info('nb cells: %i'%(Nl*Nr*2))

    fluid_bdries = MeshFunction("size_t", mesh_f,
                                mesh_f.topology().dim() - 1, 0)

    # Label facets
    xy = mesh_f.coordinates().copy()
    x, y = xy.T

    xmin = x.min()
    xmax = x.max()
    ymin = y.min()
    ymax = y.max()

    tol = cell_size / 2  #cm

    class Boundary_sas_left(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[0], -Lsas, tol)

    # downstream
    class Boundary_pvs_right(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[0], L, tol)

    class Boundary_sas_top(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[1], Rsas, tol) and (x[0] < tol)

    class Boundary_pvs_top(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[1], Rpvs, tol) and (x[0] > -tol)

    # brain
    class Boundary_brainsurf(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[0], 0, tol) and (x[1] > Rpvs - tol)

    class Boundary_bottom(SubDomain):
        def inside(self, x, on_boundary):
            return on_boundary and near(x[1], ymin, tol)

    btop_sas = Boundary_sas_top()
    btop_pvs = Boundary_pvs_top()
    bbottom = Boundary_bottom()

    bvert_left = Boundary_sas_left()
    bvert_brain = Boundary_brainsurf()
    bvert_right = Boundary_pvs_right()

    btop_sas.mark(fluid_bdries, 1)
    btop_pvs.mark(fluid_bdries, 2)
    bbottom.mark(fluid_bdries, 3)

    bvert_left.mark(fluid_bdries, 4)
    bvert_brain.mark(fluid_bdries, 5)
    bvert_right.mark(fluid_bdries, 6)

    facet_lookup = {
        'sas_top': 1,
        'pvs_top': 2,
        'vessel': 3,
        'sas_left': 4,
        'brain_surf': 5,
        'pvs_right': 6
    }

    facets_out << fluid_bdries

    #FEM space

    logging.info(title1("Set FEM spaces"))

    logging.info('\n * Fluid')
    Vf_elm = VectorElement('Lagrange', triangle, 2)
    Qf_elm = FiniteElement('Lagrange', triangle, 1)
    Wf_elm = MixedElement([Vf_elm, Qf_elm])
    Wf = FunctionSpace(mesh_f, Wf_elm)
    logging.info('Velocity : "Lagrange", triangle, 2')
    logging.info('Pressure : "Lagrange", triangle, 1')

    logging.info('\n * Tracer')
    Ct_elm = FiniteElement('Lagrange', triangle, 1)
    Ct = FunctionSpace(mesh_f, Ct_elm)
    logging.info('Concentration : "Lagrange", triangle, 1')

    logging.info('\n * ALE')
    Va_elm = VectorElement('Lagrange', triangle, 1)
    Va = FunctionSpace(mesh_f, Va_elm)
    logging.info('ALE displacement: "Lagrange", triangle, 1')

    # Setup of boundary conditions
    logging.info(title1("Boundary conditions"))

    import sympy
    tn = sympy.symbols("tn")
    tnp1 = sympy.symbols("tnp1")
    sin = sympy.sin
    sqrt = sympy.sqrt

    functionR = Rpvs - (Rpvs - Rv) * (1 + sum(
        [a * sin(2 * pi * f * tn + phi)
         for a, f, phi in zip(ai, fi, phii)]))  # displacement bottom plate
    R_vessel = sympy.printing.ccode(functionR)

    functionV = sympy.diff(functionR, tn)  # velocity
    V_vessel = sympy.printing.ccode(functionV)

    #Delta U for ALE. I dont really like this
    functionUALE = -(Rpvs - Rv) * (1 + sum([
        a * sin(2 * pi * f * tnp1 + phi) for a, f, phi in zip(ai, fi, phii)
    ])) + (Rpvs - Rv) * (1 + sum(
        [a * sin(2 * pi * f * tn + phi) for a, f, phi in zip(ai, fi, phii)]))
    UALE_vessel = sympy.printing.ccode(functionUALE)

    vf_bottom = Expression(('0', V_vessel), tn=0,
                           degree=2)  # no slip no gap condition at vessel wall
    uale_bottom = Expression(('0', UALE_vessel), tn=0, tnp1=1,
                             degree=2)  # displacement for ALE at vessel wall

    logging.info('\n * Lateral assumption')
    logging.info(lateral_bc)

    logging.info('\n * Fluid')
    logging.info('Left : zero pressure')

    if lateral_bc == 'free':
        logging.info('Right : zero pressure')
    elif lateral_bc == 'resistance':
        logging.info('Right : resistance')
    else:
        logging.info('Right : no flow')

    logging.info('Top : no slip no gap fixed wall')
    logging.info('Bottom : no slip no gap moving wall')

    logging.info('\n * Tracer concentration')
    logging.info('Left : zero concentration')

    if lateral_bc == 'free':
        logging.info('Right : zero concentration')
    else:
        logging.info('Right : no flux')

    logging.info('Top : no flux')
    logging.info('Bottom : no flux')

    logging.info('\n * ALE')
    logging.info('Left : no flux')
    logging.info('Right : no flux')
    logging.info('Top : no displacement')
    logging.info('Bottom : vessel displacement')

    # Now we wire up
    if lateral_bc == 'free':
        bcs_fluid = {
            'velocity': [(facet_lookup['vessel'], vf_bottom),
                         (facet_lookup['sas_left'], Constant((0, 0))),
                         (facet_lookup['brain_surf'], Constant((0, 0))),
                         (facet_lookup['pvs_top'], Constant((0, 0)))],
            'traction': [],
            'pressure': [(facet_lookup['sas_top'], Constant(0)),
                         (facet_lookup['pvs_right'], Constant(0))]
        }

    elif lateral_bc == 'resistance':

        Rpressure = Expression('R*Q+p0', R=resistance, Q=0, p0=0, degree=1)  #

        # Compute pressure to impose according to the flow at previous time step and resistance.

        bcs_fluid = {
            'velocity': [(facet_lookup['vessel'], vf_bottom),
                         (facet_lookup['sas_left'], Constant((0, 0))),
                         (facet_lookup['brain_surf'], Constant((0, 0))),
                         (facet_lookup['pvs_top'], Constant((0, 0)))],
            'traction': [],
            'pressure': [(facet_lookup['sas_top'], Constant(0)),
                         (facet_lookup['pvs_right'], Rpressure)]
        }
    else:
        bcs_fluid = {
            'velocity':
            [(facet_lookup['vessel'], vf_bottom),
             (facet_lookup['sas_left'], Constant((0, 0))),
             (facet_lookup['brain_surf'], Constant((0, 0))),
             (facet_lookup['pvs_top'], Constant((0, 0))),
             (facet_lookup['pvs_right'], Constant(
                 (0, 0)))],  # would be more correct to impose only on u x
            'traction': [],
            'pressure': [(facet_lookup['sas_top'], Constant(0))]
        }

    if lateral_bc == 'free':
        bcs_tracer = {
            'concentration': [(facet_lookup['sas_top'], Constant(0)),
                              (facet_lookup['pvs_right'], Constant(0))],
            'flux': [(facet_lookup['vessel'], Constant(0)),
                     (facet_lookup['sas_left'], Constant(0)),
                     (facet_lookup['brain_surf'], Constant(0)),
                     (facet_lookup['pvs_top'], Constant(0))]
        }
    else:
        bcs_tracer = {
            'concentration': [(facet_lookup['sas_top'], Constant(0))],
            'flux': [(facet_lookup['vessel'], Constant(0)),
                     (facet_lookup['sas_left'], Constant(0)),
                     (facet_lookup['brain_surf'], Constant(0)),
                     (facet_lookup['pvs_top'], Constant(0)),
                     (facet_lookup['pvs_right'], Constant(0))]
        }

    bcs_ale = {
        'dirichlet': [(facet_lookup['vessel'], uale_bottom),
                      (facet_lookup['sas_top'], Constant((0, 0))),
                      (facet_lookup['pvs_top'], Constant((0, 0))),
                      (facet_lookup['brain_surf'], Constant((0, 0)))],
        'neumann': [(facet_lookup['sas_left'], Constant((0, 0))),
                    (facet_lookup['pvs_right'], Constant((0, 0)))]
    }

    # We collect the time dependent BC for update
    driving_expressions = (uale_bottom, vf_bottom)

    # Initialisation :
    logging.info(title1("Initialisation"))

    # We start at a time shift
    tshift = -1 / 4 / fi[0]  ##todo : modify to be compatible with phii

    # Update boundary conditions
    for expr in driving_expressions:
        hasattr(expr, 'tn') and setattr(expr, 'tn', 0)
        hasattr(expr, 'tnp1') and setattr(expr, 'tnp1', tshift)

    #Solve ALE and move mesh
    eta_f = solve_ale(Va,
                      f=Constant((0, 0)),
                      bdries=fluid_bdries,
                      bcs=bcs_ale,
                      parameters=ale_parameters)
    ALE.move(mesh_f, eta_f)
    mesh_f.bounding_box_tree().build(mesh_f)

    logging.info("\n * Fluid")
    logging.info("Velocity : zero field")
    logging.info("Pressure : zero field")
    uf_n = project(Constant((0, 0)), Wf.sub(0).collapse())
    pf_n = project(Constant(0), Wf.sub(1).collapse())

    logging.info("\n * Tracer")
    logging.info("Concentration : Gaussian profile")
    logging.info("                Centered at mid length")
    logging.info("                STD parameter = %e" % sigma_gauss)

    c_0 = Expression('exp(-a*pow(x[0]-b, 2)) ',
                     degree=1,
                     a=1 / 2 / sigma_gauss**2,
                     b=xi_gauss)
    c_n = project(c_0, Ct)

    # Save initial state

    uf_n.rename("uf", "tmp")
    pf_n.rename("pf", "tmp")
    c_n.rename("c", "tmp")
    uf_out << (uf_n, 0)
    pf_out << (pf_n, 0)
    c_out << (c_n, 0)

    # Get the 1 D profiles at umax (to be changed in cyl coordinate)
    mesh_points = mesh_f.coordinates()
    x = mesh_points[:, 0]
    y = mesh_points[:, 1]
    xmin = 0
    xmax = L
    ymin = min(y)
    ymax = Rpvs

    files = [csv_p, csv_u, csv_c]
    fields = [pf_n, uf_n.sub(0), c_n]
    field_names = [
        'pressure (dyn/cm2)', 'axial velocity (cm/s)', 'concentration'
    ]

    for csv_file, field, name in zip(files, fields, field_names):
        #values = line_sample(slice_line, field)
        values = profile(field, xmin, xmax, ymin, ymax)
        logging.info('Max ' + name + ' : %.2e' % max(abs(values)))
        #logging.info('Norm '+name+' : %.2e'%field.vector().norm('linf'))
        row = [0] + list(values)
        csv_file.write(('%e' + ', %e' * len(values) + '\n') % tuple(row))

    csv_rv.write('%e, %e' % (0, ymin))

    ############# RUN ############3

    logging.info(title1("Run"))

    # Time loop
    ### We start at the quarter of the period so that velocity=0
    print('tini = ', tshift)
    time = tshift
    timestep = 0

    # Here I dont know if there will be several dt for advdiff and fluid solver
    while time < tfinal + tshift:

        # Update boundary conditions
        for expr in driving_expressions:
            hasattr(expr, 'tn') and setattr(expr, 'tn', time)
            hasattr(expr, 'tnp1') and setattr(expr, 'tnp1', time + dt)

        if lateral_bc == 'resistance':
            z, r = SpatialCoordinate(mesh_f)
            ds = Measure('ds', domain=mesh_f, subdomain_data=fluid_bdries)
            n = FacetNormal(mesh_f)
            Flow = assemble(2 * pi * r * dot(uf_n, n) *
                            ds(facet_lookup['x_max']))

            print('Right outflow : %e \n' % Flow)
            setattr(Rpressure, 'Q', Flow)

        #Solve ALE and move mesh
        eta_f = solve_ale(Va,
                          f=Constant((0, 0)),
                          bdries=fluid_bdries,
                          bcs=bcs_ale,
                          parameters=ale_parameters)
        ALE.move(mesh_f, eta_f)
        mesh_f.bounding_box_tree().build(mesh_f)

        # Solve fluid problem
        uf_, pf_ = solve_fluid(Wf,
                               u_0=uf_n,
                               f=Constant((0, 0)),
                               bdries=fluid_bdries,
                               bcs=bcs_fluid,
                               parameters=fluid_parameters)

        tracer_parameters["T0"] = time
        tracer_parameters["nsteps"] = 1
        tracer_parameters["dt"] = dt

        # Solve tracer problem
        c_, T0 = solve_adv_diff(Ct,
                                velocity=uf_ - eta_f / Constant(dt),
                                phi=Constant(1),
                                f=Constant(0),
                                c_0=c_n,
                                phi_0=Constant(1),
                                bdries=fluid_bdries,
                                bcs=bcs_tracer,
                                parameters=tracer_parameters)

        # Update current solution
        uf_n.assign(uf_)
        pf_n.assign(pf_)
        c_n.assign(c_)

        #Update time
        time += dt
        timestep += 1

        # Save output
        if (timestep % int(toutput / dt) == 0):

            logging.info("\n*** save output time %e s" % (time - tshift))
            logging.info("number of time steps %i" % timestep)

            # may report Courant number or other important values that indicate how is doing the run

            uf_.rename("uf", "tmp")
            pf_.rename("pf", "tmp")
            c_.rename("c", "tmp")
            uf_out << (uf_, time - tshift)
            pf_out << (pf_, time - tshift)
            c_out << (c_, time - tshift)

            # Get the 1 D profiles at umax (to be changed in cyl coordinate)
            mesh_points = mesh_f.coordinates()
            x = mesh_points[:, 0]
            y = mesh_points[:, 1]
            xmin = 0
            xmax = L
            ymin = min(y)
            ymax = Rpvs

            #slice_line = line([xmin,(ymin+ymax)/2],[xmax,(ymin+ymax)/2], 100)

            logging.info('Rpvs : %e' % ymax)
            logging.info('Rvn : %e' % ymin)

            files = [csv_p, csv_u, csv_c]
            fields = [pf_n, uf_n.sub(0), c_n]
            field_names = [
                'pressure (dyn/cm2)', 'axial velocity (cm/s)', 'concentration'
            ]

            for csv_file, field, name in zip(files, fields, field_names):
                #values = line_sample(slice_line, field)
                values = profile(field, xmin, xmax, ymin, ymax)
                logging.info('Max ' + name + ' : %.2e' % max(abs(values)))
                #logging.info('Norm '+name+' : %.2e'%field.vector().norm('linf'))
                row = [time - tshift] + list(values)
                csv_file.write(
                    ('%e' + ', %e' * len(values) + '\n') % tuple(row))

            csv_rv.write('%e, %e' % (time - tshift, ymin))