Search code examples
pythonpdefipy

FiPy convection with a given velocity field


I'm using FiPy to model convection/diffusion of a chemical in a given velocity field, and I'm having problems setting this field as ConvectionTerm coefficient.

My velocity field is expressed by two bidimensional arrays, let's say Ugrid for horizontal velocities and Vgrid for vertical ones, representing the values at the faces of each cell. For this reason, I'd say that the proper way to set this field as coeff parameter for the ConvectionTerm would be assigning it to a FaceVariable.

However, I don't get how to pass these two arrays as value for the FaceVariable. Apparently, I have no problems in setting the field as CellVariable by using value = [np.ravel(Ugrid),np.ravel(Vgrid)] and the convection simulation appears to make sense as well, but I don't think this is correct, as I briefly mentioned above.

Any suggestions?


Solution

  • An important consideration with FiPy is that the mesh indexing is not based on grid indexing so mapping from a grid array to cell values should not assume that the mesh is ordered in any particular way. This makes it necessary to use some form of interpolation. Let's first construct a velocity field with grid indexing where the points lie on the grid points (not cell centers).

    from fipy import Grid2D, CellVariable, FaceVariable
    from fipy import ConvectionTerm, DiffusionTerm, TransientTerm
    import numpy as np
    from scipy import interpolate
    
    dx = 0.5
    nx = 7
    dy = 0.5
    ny = 7
    
    xy = np.zeros((nx, ny, 2))
    xy[:, :,  0] = np.mgrid[0:nx, 0:ny][0] * dx
    xy[:, :, 1] = np.mgrid[0:nx, 0:ny][1] * dy
    
    u = xy[..., 0] + xy[..., 1]
    v = xy[..., 0] * xy[..., 1]
    

    We now have a (u, v) velocity field each of shape nx, ny and the corresponding coordinates, xy, of shape (nx, ny, 2). Let's say we want to interpolate that to a FiPy mesh with the same domain, but a different grid.

    m = Grid2D(nx=3, ny=3, dx=1.0, dy=1.0)
    

    The mesh doesn't necessarily need to align with the grid points for the velocity field. We can then interpolate to that mesh with

    xy_interp = np.array(m.faceCenters).swapaxes(0, 1)
    u_interp = interpolate.griddata(xy.reshape(-1, 2), u.flatten(), xy_interp, method='cubic')
    v_interp = interpolate.griddata(xy.reshape(-1, 2), v.flatten(), xy_interp, method='cubic')
    

    where xy_interp are the mesh's face centers. Note that using griddata requires that the xy_interp are inside the xy otherwise it gives nan values. Once we have the interpolated values, we can set up the FiPy velocity field.

    velocity = FaceVariable(mesh=m, rank=1)
    velocity[0, :] = u_interp
    velocity[1, :] = v_interp
    

    Note that the coefficient for the ConvectionTerm can be a FaceVariable or a CellVariable. Once we have the velocity, we're ready to set up and solve the equation.

    var = CellVariable(mesh=m)
    eqn = (TransientTerm() + ConvectionTerm(velocity) == DiffusionTerm(1.0))
    eqn.solve(var, dt=1.0)
    

    This runs without error for me.

    Link to complete script for this problem