Define a vector space to solve a diffusion advection diffusion equation

Hello everyone! I want to solve a PDE like:

\partial_t \rho-\nabla \cdot(D \nabla \rho)+\nabla \cdot( I(x) \rho)=0.

Here I is a vector depend on x.
Suppose now I define a function space like:
V = fem.functionspace(domain, ("Lagrange", k))
I wonder how to define a vector function space for I(x) in the weak form as I know the weak form is -\rho I\cdot \nabla v with zero Neumann boundary condition.

You can do this with ufl.SpatialCoordinate and ufl.as_vector, i.e.

x = ufl.SpatialCoordinate(mesh)

def I_func(x):
     return (x[0], 2*x[1])

I = ufl.as_vector(I_func(x))

Thanks for your kindly reply! However, I don’t want to use ufl.SpatialCoordinate to define the vector functions. I notice that you used to publish a post for the usage of Expression in Dolfinx,
This is the way I define a function used your way:

class K():
    def __call__(self, x):
    #    return x[1]
        return np.exp(0*x[1])+np.exp(-((x[1]-100)/100)**2)*np.exp(-((x[0]-300)/100)**2)
k = fem.Function(V)
k.interpolate(K_0_true())

so I wonder if it is possible to define a vector functions as the same as above for a vector function like (\exp(x[0]), \exp(x[1])+\sin(x[0]))?

Yes,
you can do that.

Just return a tuple

def __call__(self, x):
    return (np.exp(x[0]), np.exp(x[1]) + np.sin(x[0]))

I try to write something like:

class I_func():
        def __call__(self, x):
            return (np.exp(x[0]), np.exp(x[1]) + np.sin(x[0]))

beta = ufl.as_vector(I_func())

However, it fails. The error showed is that “raise ValueError(“Expecting nested list or tuple of Exprs.”)”.

You are now mixing methods. If you don’t want to use spatial coordinate you need to interpolate into an appropriate function vector function space.

What is the reasoning behind not wanting to use spatial coordinate ?

I think I asked a silly question. I only need to change np into ufl to obtain a function. However, if I want to define a function which do not have explicit form on spatial coordinate, how to define an appropriate function vector space? For example, I have a matrix A representing values of a vector function on the grids and I want to define this function into my weak form.

The question is quite vague.

How do you define the matrix A with respect to your grid. There either has to be a spatial relation, or an implicit spatial relation by the index in A.

A minimal example of what you want to achieve would be beneficial for understanding your problem.

I will try to give an example of the vector functions.
Suppose the space domain \Omega is a unit square with gird N_x*N_y and I have the values of a vector function f=(a,b) on these grids, which are two matric A_1=[a_{i,j}], A_2=[b_{i,j}], 1\leq i\leq N_x, 1\leq j\leq N_y. Now I create a function space like:

domain = mesh.create_unit_square(MPI.COMM_WORLD, N_x, N_y, mesh.CellType.triangle)
V = fem.functionspace(domain, ("Lagrange", 1))

Then how to pass these values to a vector function in the integral form?

I think there are various ways you could do this.

  1. is to invert the map in: Reordering nodal values in accordance with meshgrid created using numpy - #3 by dokken
    which is similar to
  2. Assigning values to function: order issues - #4 by dokken
  3. Another one is to use an interpolator: Mapping 2D numpy array into dolfinx function - #4 by dokken