Exemplo n.º 1
0
                    degree=2)  # no slip condition at the top

# Now we wire up
bcs_fluid = {
    'velocity': [(facet_lookup['F_bottom'], uf_bottom),
                 ((facet_lookup['I_bottom'], uf_top))],
    'traction': [],
    'pressure': [(facet_lookup['F_left'], pf_in),
                 (facet_lookup['F_right'], pf_out)]
}

# Get the initial conditions ------------------------------------- FIXME

# Solve fluid steady state

uf_out, pf_out = File('./output/poisseuille/uf.pvd'), File(
    './output/poisseuille/pf.pvd')

# Solve fluid problem
u_f, p_f = solve_fluid(Wf,
                       f=Constant((0, 0)),
                       bdries=fluid_bdries,
                       bcs=bcs_fluid,
                       parameters=fluid_parameters)

u_f.rename("uf", "tmp")
p_f.rename("pf", "tmp")

uf_out << (u_f)
pf_out << (p_f)
Exemplo n.º 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))
Exemplo n.º 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))
Exemplo n.º 4
0
def SAS_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_inner  # centimeters
    Rpvs = args.radius_outer  # centimeters
    L = args.length  # centimeters

    logging.info('Inner radius : %e cm' % Rv)
    logging.info('Outer radius : %e cm' % Rpvs)
    logging.info('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 * Lateral BC')
    compliance = args.compliance
    logging.info('outer compliance: %e ' % compliance)
    if compliance <= 0:
        lateral_bc = 'free'
        logging.info('right BC will be set to the free assumption')
    else:
        lateral_bc = 'compliance'
        logging.info('right BC will be set to the compliance assumption')

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

    # 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')

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

    import sympy
    tn = sympy.symbols("tn")

    sin = sympy.sin
    cos = sympy.cos
    sqrt = sympy.sqrt

    logging.info('\n * inner face flow 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))

    #Brain outflow due to vessel contraction/dilation
    #blood_vol=12.5e-3#*1.5  #cm3 total cerebral blood volume
    brainvolume = pi * Rv**2 * L
    brainsurface = 2 * pi * Rv * L
    blood_vol = 0.035 * brainvolume
    pc_arterioles = 0.01  #pc of total blood volume in arterioles
    V0_arterioles = pc_arterioles * blood_vol
    Asas = pi * (Rpvs**2) - pi * Rv**2

    #CSF production
    Qprod = 6e-6  #cm3/s
    #Steady velocity due to production
    Uprod = Qprod / Asas

    #Concentration in the brain
    cbrain = Expression('c0*(1-tn)', c0=1, tn=0, degree=2)

    logging.info('brain volume: %e cm3 ' % brainvolume)
    logging.info('brain surface: %e cm2 ' % brainsurface)
    logging.info('blood volume: %e cm3 ' % blood_vol)
    logging.info('pourcentage of arterioles: %e pc ' % (pc_arterioles * 100))

    functionV = V0_arterioles * (1 + sum(
        [a * sin(2 * pi * f * tn + phi)
         for a, f, phi in zip(ai, fi, phii)]))  # blood volume
    functionU = sympy.diff(functionV, tn) / brainsurface  # velocity
    #functionU=V0_arterioles*(sum([a*2*pi*f*cos(2*pi*f*tn+phi) for a,f,phi in zip(ai,fi,phii)]))/brainsurface
    ubottom = sympy.printing.ccode(functionU)

    vf_bottom = Expression(('0', ubottom), tn=0,
                           degree=2)  # no slip no gap condition 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')
    else:
        logging.info('Right : compliance')

    logging.info('Top : no slip no gap fixed wall')
    logging.info('Bottom : no slip and brain inflow')

    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')

    # Now we wire up

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

    else:

        E = 100
        P0 = 5330
        Pn = 5330
        Pout = Expression('Pn', Pn=Pn, degree=0)  #

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

        bcs_fluid = {
            'velocity': [(facet_lookup['y_min'], vf_bottom),
                         (facet_lookup['y_max'], Constant((0, 0))),
                         (facet_lookup['x_max'], Constant((-Uprod, 0)))],
            'traction': [],
            'pressure': [(facet_lookup['x_min'], Pout)]
        }

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

    # We collect the time dependent BC for update
    driving_expressions = (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(Constant(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

    intQout = 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)

        vf_bottom.tn = time

        if lateral_bc == 'compliance':
            # Compliance law dP/dt=dP/dV.dV/dt=dP/dV.qout=E*P*qout

            #qout=2 pi int_Rv^Rpvs u r dr
            z, r = SpatialCoordinate(mesh_f)
            ds = Measure('ds', domain=mesh_f, subdomain_data=fluid_bdries)
            n = FacetNormal(mesh_f)
            Qout = assemble(2 * pi * r * dot(uf_n, n) *
                            ds(facet_lookup['x_max']))
            #Pn+1=pn+dt*(E*P*qoutn)
            #Pout.Pn=Pn+dt*E*Pn*Qout
            # dP/dt=dP/dV.dV/dt=dP/dV.qout=E*P*qout
            # ln(p)-ln(p0)=E int_0^t Qout
            #p=p0exp(E int_0^t Qout)
            intQout += Qout * dt
            Pout.Pn = P0 * exp(E * intQout)

            print('Right pressure : %e mmHg \n' % (Pout.Pn / 1333))

        # 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_,
                                mesh_displacement=Constant((0, 0)),
                                f=Constant(0),
                                phi_0=c_n,
                                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_cyl(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' % (time, ymin))
Exemplo n.º 5
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(args.output_folder + '/' + args.job_name + '_pressure.txt',
                 'w')
    csv_u = open(args.output_folder + '/' + args.job_name + '_velocity.txt',
                 'w')
    csv_c = open(
        args.output_folder + '/' + args.job_name + '_concentration.txt', 'w')
    csv_rv = open(args.output_folder + '/' + args.job_name + '_radius.txt',
                  'w')

    csv_mass = open(args.output_folder + '/' + args.job_name + '_mass.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 = args.output_folder + '/' + args.job_name + '_PVSinfo.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

    # initialise logging

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

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

    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)

    # test presence of the SAS compartment on the mesh
    isSAS = args.SAS

    if isSAS:
        logging.info('Add a SAS compartment on the left')
        Rsas = args.radius_sas + Rv
        Lsas = args.length_sas
        logging.info('SAS length : %e cm' % Lsas)
        logging.info('SAS radius : %e cm' % Rsas)

    #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}

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

    logging.info('\n * Cross section area parameters')

    if args.cycle:
        logging.info('frequency and amplitude data from cycle ' + args.cycle)
        timedependentfa = True
    else:
        timedependentfa = False
        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))

    if timedependentfa:

        ##
        logging.info('creation of cycle')

        cycleObj = ReadCycle('../stages/cycles.yml', args.cycle)
        totalcycletime = np.sum(cycleObj.durations)
        spantime, listspana, listspanf, spanRv, spanh0, spanRpvs = cycleObj.generatedata(
            int(tfinal / totalcycletime) + 1)

        logging.info('*** Simulation of %s cycle ' % cycleObj.name)

        # adjust last time in order to be able to interpolate
        #spantime[-1]=max(tfinal+2*dt,spantime[-1])

        from scipy.interpolate import interp1d
        varflist = {}
        varalist = {}

        for freq in listspanf:
            varflist[freq] = interp1d(spantime, listspanf[freq])
            varalist[freq] = interp1d(spantime, listspana[freq])

        varh0 = interp1d(spantime, spanh0)
        varRpvs = interp1d(spantime, spanRpvs)

        #varda=interp1d(spantime,dadt,kind="previous")

        fs = 1 / dt  # test if same result if multiplying by 10 ?

        time = 0 + np.arange(
            int((tfinal + 2 * dt) * fs)
        ) / fs  # longer than the simulation time because we need tn+1 for the U ALE computation

        modulation = {}
        for freq in listspanf:
            modulation[freq] = varalist[freq](time) * np.sin(
                2 * np.pi * np.cumsum(varflist[freq](time)) / fs)

        OuterRadius = varRpvs(time)
        InnerRadius = varRpvs(time) - varh0(time) * (
            1 + modulation['cardiac'] + modulation['resp'] + modulation['LF'] +
            modulation['VLF'])

        # define the thickness interpolation function
        interph0 = interp1d(
            time,
            varh0(time) * (1 + modulation['cardiac'] + modulation['resp'] +
                           modulation['LF'] + modulation['VLF']))

        ## More easy here to take the numerical derivative of the radius
        ##dadt= np.array(list(np.diff(vara(time))/np.diff(time))+[0.0])
        ##dRadiusdt= -(Rpvs-Rv)*(dadt*np.sin(2*np.pi*np.cumsum(varf(time))/fs)+vara(time)*np.cos((2*np.pi*np.cumsum(varf(time))/fs))*(2*np.pi*varf(time)))
        douterRadiusdt = np.array(
            list(np.diff(OuterRadius) / np.diff(time)) + [0.0])
        dinnerRadiusdt = np.array(
            list(np.diff(InnerRadius) / np.diff(time)) + [0.0])

        # define an expression for the radius and the derivative

        class Interp(UserExpression):
            def __init__(self, x, y, **kwargs):
                super().__init__(self, **kwargs)
                self.interp = interp1d(x, y)
                self.tn = 0

            def eval(self, values, x):
                values[0] = 0
                values[1] = self.interp(self.tn)

            def value_shape(self):
                return (2, )

        class Interpdiff(UserExpression):
            def __init__(self, x, y, **kwargs):
                super().__init__(self, **kwargs)
                self.interp = interp1d(x, y)
                self.tn = 0
                self.tnp1 = dt

            def eval(self, values, x):
                values[0] = 0
                values[1] = self.interp(self.tnp1) - self.interp(self.tn)

            def value_shape(self):
                return (2, )

        interpRpvs = Interp(time, OuterRadius, degree=1)
        interpRv = Interp(time, InnerRadius, degree=1)

        #initial values for Rv and Rpvs
        uale_top = Interpdiff(time, OuterRadius, degree=1)
        uale_bottom = Interpdiff(time, InnerRadius, degree=1)
        vf_top = Interp(time, douterRadiusdt, degree=1)
        vf_bottom = Interp(time, dinnerRadiusdt, degree=1)

        Rvfunction = interp1d(time, InnerRadius)
        Rpvsfunction = interp1d(time, OuterRadius)
        dRvdtfunction = interp1d(time, dinnerRadiusdt)

    else:

        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
        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

        vf_top = Constant((0, 0))
        uale_top = Constant((0, 0))

        ## Is there a better way to do that ?
        Rvfunction = lambda t: functionR.subs(tn, t).evalf()
        Rpvsfunction = lambda t: Rpvs
        dRvdtfunction = lambda t: functionV.subs(tn, t).evalf()

    if isSAS:
        import sympy
        tn = sympy.symbols("tn")
        sin = sympy.sin
        # We add the possibility for rigid moion of the brain
        a_rigid = args.arigid  #cm
        f_rigid = args.frigid  #Hz
        logging.info('ridig motion of the brain, amplitude : %.2e um' %
                     a_rigid)
        logging.info('ridig motion of the brain, frequency : %.2e Hz' %
                     f_rigid)

        functionY = a_rigid * sin(2 * pi * f_rigid * tn)
        functionVbone = sympy.diff(functionY, tn)  # velocity
        V_bone = sympy.printing.ccode(functionVbone)

        vf_bone = Expression(('0', V_bone), tn=0, degree=2)

    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')

    sas_bc = args.sasbc
    init_concentration_type = args.c0init
    init_concentration_value = args.c0valuePVS

    logging.info('Left BC scenario :', sas_bc)

    if lateral_bc == 'free':
        logging.info('Right : zero concentration')
    else:
        productionrate = args.productionrate
        if productionrate:
            logging.info(
                'Right : imposed solute production rate : %e ([c]/s)' %
                args.productionrate)
        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')

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

    if isSAS:
        Rv = Rvfunction(0)
        Rpvs = Rpvsfunction(0)
        DR = (Rpvs - Rv) / Nr

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

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

        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

        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', Rvfunction(0))
        field.setNumber(fid, 'YMax', Rpvsfunction(0))
        field.setNumber(fid, 'VIn', DR)
        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()

    else:
        # simple PVS mesh
        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, Rvfunction(0)),
                               Point(L, Rpvsfunction(0)), Nl, Nr)

        ## Refinement at the SAS boundary
        if args.refineleft:
            x = mesh_f.coordinates()[:, 0]
            y = mesh_f.coordinates()[:, 1]

            #Deformation of the mesh

            def deform_mesh(x, y):
                x = L * (x / L)**2.5
                return [x, y]

            x_bar, y_bar = deform_mesh(x, y)
            xy_bar_coor = np.array([x_bar, y_bar]).transpose()
            mesh_f.coordinates()[:] = xy_bar_coor
            mesh_f.bounding_box_tree().build(mesh_f)

    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

    if isSAS:

        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_out': 1,
            'pvs_tissue': 2,
            'vessel': 3,
            'sas_bone': 4,
            'sas_tissue': 5,
            'pvs_end': 6
        }

    else:
        # simple PVS mesh

        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 = {
            'sas_out': 1,
            'vessel': 2,
            'pvs_end': 3,
            'pvs_tissue': 4
        }

    facets_out << fluid_bdries

    # Now we wire up

    rate_prod = Expression('rate/surface',
                           rate=productionrate,
                           surface=1,
                           degree=1)

    if lateral_bc == 'free':
        bcs_fluid = {
            'velocity': [(facet_lookup['vessel'], vf_bottom),
                         (facet_lookup['pvs_tissue'], vf_top)],
            'traction': [],
            'pressure': [(facet_lookup['sas_out'], Constant(0)),
                         (facet_lookup['pvs_end'], 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['pvs_tissue'], vf_top)],
            'traction': [],
            'pressure': [(facet_lookup['sas_out'], Constant(0)),
                         (facet_lookup['pvs_end'], Rpressure)]
        }
    else:
        bcs_fluid = {
            'velocity':
            [(facet_lookup['vessel'], vf_bottom),
             (facet_lookup['pvs_tissue'], vf_top),
             (facet_lookup['pvs_end'], Constant(
                 (0, 0)))],  # I would like only normal flow to be zero 
            'traction': [],
            'pressure': [(facet_lookup['sas_out'], Constant(0))]
        }

    #### This is overwritten later depending on the scenario

    bcs_tracer_in = {
        'concentration': [(facet_lookup['sas_out'], 0)],
        'flux': [(facet_lookup['pvs_end'], rate_prod),
                 (facet_lookup['pvs_tissue'], Constant(0)),
                 (facet_lookup['vessel'], Constant(0))]
    }

    bcs_tracer_out = {
        'concentration': [],
        'flux': [(facet_lookup['sas_out'], Constant(0)),
                 (facet_lookup['pvs_end'], rate_prod),
                 (facet_lookup['pvs_tissue'], Constant(0)),
                 (facet_lookup['vessel'], Constant(0))]
    }

    # todo : add possibility to have other BC at pvs_end
    #if lateral_bc=='free' :
    #    bcs_tracer = {'concentration': [(facet_lookup['pvs_end'], Constant(0)),
    #                                    (facet_lookup['sas_out'], c_SAS)],
    #                'flux': [(facet_lookup['pvs_tissue'], Constant(0)),
    #                        (facet_lookup['vessel'], Constant(0))]}

    # add BC on the extra boundary in the mesh of the SAS
    if isSAS:
        bcs_fluid['velocity'].append((facet_lookup['sas_bone'], vf_bone))
        bcs_fluid['velocity'].append(
            (facet_lookup['sas_tissue'], Constant((0, 0))))

        bcs_tracer_in['flux'].append((facet_lookup['sas_bone'], Constant(0)))
        bcs_tracer_in['flux'].append((facet_lookup['sas_tissue'], Constant(0)))
        bcs_tracer_out['flux'].append((facet_lookup['sas_bone'], Constant(0)))
        bcs_tracer_out['flux'].append(
            (facet_lookup['sas_tissue'], Constant(0)))

    # BC for ALE (not used anymore)
    bcs_ale = {
        'dirichlet': [(facet_lookup['vessel'], uale_bottom),
                      (facet_lookup['pvs_tissue'], uale_top)],
        'neumann': [(facet_lookup['sas_out'], Constant((0, 0))),
                    (facet_lookup['pvs_end'], Constant((0, 0)))]
    }

    # We collect the time dependent BC for update
    driving_expressions = [uale_bottom, vf_bottom, uale_top, vf_top]

    if isSAS:
        driving_expressions.append(vf_bone)

    #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')

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

    c_SAS = Expression('m/VCSF', m=0, VCSF=40e-3, degree=2)

    #initial concentration in SAS
    if sas_bc == 'scenarioA':
        cSAS = 0
    else:
        cSAS = args.c0valueSAS

    # number of vessels used for mass balance
    Nvessels = 6090
    # initial volume of CSF in PVS
    z, r = SpatialCoordinate(mesh_f)
    ds = Measure('ds', domain=mesh_f, subdomain_data=fluid_bdries)
    n = FacetNormal(mesh_f)

    # volume of pvs
    VPVS = 2 * np.pi * assemble(Constant(1.0) * r * dx(mesh_f))

    # initial volume of CSF in SAS : assumed to be 10 times larger than volume in PVS
    VCSF = 10 * VPVS  #40e-3

    # initial pressure of the CSF
    PCSF = 4  # mmHg
    # initial volume of arterial blood
    Vblood = 4e-3  # ml
    # equivalent vessel length used for the compliance function and assessement of ICP
    leq = Vblood / (np.pi * Rvfunction(0)**2)

    # initial tracer mass in the CSF
    m = cSAS * VCSF

    # constant production of CSF
    Qprod = 6e-6  # ml/s

    # Outflow resistance
    Rcsf = 5 / 1.7e-5  # mmHg/(ml/s)
    # CSF compliance
    Ccsf = 1e-3  #ml/mmHg

    if sas_bc == 'scenarioA':
        logging.info('Left : zero concentration')
        # initial outflow of CSF (not used, just for output file)
        Qout = 0
    elif sas_bc == 'scenarioB':
        logging.info('Left : mass conservation, no CSF outflow')
        # initial outflow of CSF
        Qout = 0
    elif sas_bc == 'scenarioC':
        logging.info('Left : mass conservation, constant CSF outflow')
        # initial outflow of CSF
        Qout = Qprod
    elif sas_bc == 'scenarioD':
        logging.info(
            'Left : mass conservation, pressure dependent CSF outflow')
        # initial outflow of CSF
        Qout = Qprod
        # venous pressure
        Pss = PCSF - Qout * Rcsf

    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")

    if init_concentration_type == 'gaussian':
        logging.info("Concentration : Gaussian profile")
        logging.info("                Centered at xi = %e" % xi_gauss)
        logging.info("                STD parameter = %e" % sigma_gauss)
        logging.info("                Max value=%e" % init_concentration_value)

        c_0 = Expression('c0*exp(-a*pow(x[0]-b, 2)) ',
                         degree=1,
                         a=1 / 2 / sigma_gauss**2,
                         b=xi_gauss,
                         c0=init_concentration_value)
        c_n = project(c_0, Ct)
    elif init_concentration_type == 'constant':
        logging.info("Concentration : Uniform profile")

        if isSAS:
            logging.info("Value in PVS=%e" % init_concentration_value)
            logging.info("Value in SAS=%e" % cSAS)
            c_0 = Expression('x[0]>0 ? cPVS : cSAS ',
                             degree=2,
                             cPVS=init_concentration_value,
                             cSAS=cSAS)
            c_n = project(c_0, Ct)
        else:
            logging.info("Value=%e" % init_concentration_value)
            c_n = project(Constant(init_concentration_value), Ct)
    elif init_concentration_type == 'null':
        logging.info("Concentration : zero in the vessel")
        c_n = project(Constant(0), Ct)
    else:
        logging.info("Concentration : Uniform profile (default)")
        logging.info("Value=%e" % 0)
        ## Initialisation
        c_n = project(Constant(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 ############

    logging.info(title1("Run"))

    # Time loop
    time = 0.
    timestep = 0

    z, r = SpatialCoordinate(mesh_f)
    ds = Measure('ds', domain=mesh_f, subdomain_data=fluid_bdries)
    n = FacetNormal(mesh_f)

    # volume of pvs
    volume = 2 * np.pi * assemble(Constant(1.0) * r * dx(mesh_f))
    # integral of concentration
    intc = 2 * np.pi * assemble(r * c_n * dx(mesh_f))

    # tracer mass out of the system
    mout = 0

    csv_mass.write('%s, %s, %s, %s, %s, %s, %s, %s, %s\n' %
                   ('time', 'mass PVS', 'mass CSF', 'mass out', 'Total mass',
                    'PVS volume', 'CSF volume', 'P csf', 'Q out'))
    csv_mass.write('%e, %e, %e, %e, %e, %e, %e, %e, %e\n' %
                   (time, Nvessels * intc, m, mout, Nvessels * intc + m + mout,
                    Nvessels * volume, VCSF, PCSF, Qout))

    # ALE deformation function
    expressionDeformation = Expression((
        "0",
        "x[1]<=rpvs ? (x[1]-rpvs)/(rpvs-rvessel)*htarget+rpvstarget-x[1]:rpvstarget-rpvs"
    ),
                                       rvessel=0,
                                       rpvs=1,
                                       rpvstarget=1,
                                       htarget=1,
                                       degree=1)

    # Extend normal to 3d as GradAxisym(scalar) is 3-vector
    normal = as_vector((Constant(-1), Constant(0), Constant(0)))

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

        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':
            Flow = assemble(2 * pi * r * dot(uf_n, n) *
                            ds(facet_lookup['pvs_end']))

            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)

        # Or just compute the deformation
        xy = mesh_f.coordinates()
        x, y = xy.T

        expressionDeformation.rpvstarget = Rpvsfunction(time)
        expressionDeformation.htarget = Rpvsfunction(time) - Rvfunction(time)
        expressionDeformation.rvessel = min(
            y[x > 0])  # We look only in the PVS (x>0) not the SAS
        expressionDeformation.rpvs = max(y[x > 0])  #

        #eta_f = interpolate(expressionDeformation,VectorFunctionSpace(mesh_f,"CG",1))
        eta_f = project(expressionDeformation, Va)

        ALE.move(mesh_f, eta_f)
        mesh_f.bounding_box_tree().build(mesh_f)

        # update the coordinates
        z, r = SpatialCoordinate(mesh_f)
        ds = Measure('ds', domain=mesh_f, subdomain_data=fluid_bdries)
        n = FacetNormal(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)

        # Solve tracer problem
        tracer_parameters["T0"] = time
        tracer_parameters["nsteps"] = 1
        tracer_parameters["dt"] = dt

        # If the fluid is exiting the PVS we compute the amount of mass entering the SAS. The tracer left BC is free.
        # If the fluid is entering the PVS then we impose the concentration in the SAS at the left BC.

        #Fluid flow at the BC
        FluidFlow = assemble(2 * pi * r * dot(uf_, n) *
                             ds(facet_lookup['sas_out']))

        #  n is directed in the outward direction : is it ?

        print('fluid flow : ', FluidFlow)

        if FluidFlow > 0:
            # then the fluid is going out and we impose natural BC for concentration
            bcs_tracer = bcs_tracer_out
        else:
            # then the fluid is going in and we impose the SAS concentration
            cmean = assemble(
                2 * pi * r * c_n * ds(facet_lookup['sas_out'])) / assemble(
                    2 * pi * r * Constant(1) * ds(facet_lookup['sas_out']))
            # we allow the possibility to use a relaxation here
            alpha = 0.  # 0 means no relaxation
            c_imposed = (1 - alpha) * cSAS + alpha * cmean
            c_imposed = max(c_imposed, 0)

            bcs_tracer = bcs_tracer_in
            bcs_tracer['concentration'] = [(facet_lookup['sas_out'],
                                            Constant(c_imposed))]

        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)

        Massflow = assemble(2 * pi * r * dot(uf_ - eta_f / Constant(dt), n) *
                            c_ * ds(facet_lookup['sas_out']))
        Massdiffusion = tracer_parameters["kappa"] * assemble(2 * pi * r * dot(
            cyl.GradAxisym(c_), normal) * ds(facet_lookup['sas_out']))

        if sas_bc == 'scenarioD':

            # update CSF outflow
            Qout = max((PCSF - Pss) / Rcsf, 0)  # valve
            # update CSF pressure
            PCSF += dt / Ccsf * (Qprod - Qout) + np.pi * leq * (
                Rvfunction(time + dt)**2 - Rvfunction(time)**2) / Ccsf

            # link between leq and Nvessels ?

        if sas_bc == 'scenarioA':
            if FluidFlow >= 0:
                # mainly advection
                mout += dt * Nvessels * Massflow
                # lost mass in the PVS due to diffusion
                mout += -dt * Nvessels * Massdiffusion

        else:
            # Advected mass
            m += dt * Nvessels * Massflow - dt * Qout * cSAS
            if FluidFlow >= 0:  # when in-flow we impose c sas at the boundary so no c gradient
                # Adding diffusion
                m += -dt * Nvessels * Massdiffusion

            mout += Qout * cSAS * dt

        # update the volume of CSF
        #VCSF+=dt*Nvessels*FluidFlow
        # should correspond to the volume change due to vessel dilation
        #VCSF+=np.pi*leq*(Rvfunction(time+dt)**2-Rvfunction(time)**2)

        # update tracer concentration in SAS
        cSAS = m / VCSF

        rate_prod.surface = assemble(2 * pi * r * ds(facet_lookup['pvs_end']))

        # 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[x > 0])
            ymax = max(y[x > 0])

            # update the coordinates
            z, r = SpatialCoordinate(mesh_f)
            ds = Measure('ds', domain=mesh_f, subdomain_data=fluid_bdries)
            n = FacetNormal(mesh_f)

            #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_file.flush()

            csv_rv.write(('%e, %e\n') % (time, ymin))
            csv_rv.flush()

            # volume of pvs
            volume = 2 * np.pi * assemble(Constant(1.0) * r * dx(mesh_f))
            # integral of concentration
            intc = 2 * np.pi * assemble(r * c_ * dx(mesh_f))

            csv_mass.write('%e, %e, %e, %e, %e, %e, %e, %e, %e\n' %
                           (time, Nvessels * intc, m, mout, Nvessels * intc +
                            m + mout, Nvessels * volume, VCSF, PCSF, Qout))
            csv_mass.flush()
Exemplo n.º 6
0
                       ds(facet_lookup['out']))
    #Pn+1=pn+dt*(E*P*qoutn)
    #Pout.Pn=Pn+dt*E*Pn*Qout
    # dP/dt=dP/dV.dV/dt=dP/dV.qout=E*P*qout
    # ln(p)-ln(p0)=E int_0^t Qout
    #p=p0exp(E int_0^t Qout)
    intQout += Qout * dt
    Pout.Pn = P0 * math.exp(E * intQout)

    print('Qout', Qout)
    print('integral Qout', intQout)

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

    tracer_parameters["T0"] = time

    # Solve tracer problem
    c_, T0 = solve_adv_diff(Ct,
                            velocity=uf_,
                            mesh_displacement=uf_ * 0,
                            f=df.Constant(0),
                            phi_0=c_n,
                            bdries=facet_f,
                            bcs=bcs_tracer,
                            parameters=tracer_parameters)