3D problem (sphere) Navier-Stokes

Hi,

I try to solve a simple 3D Navier-Stokes 3D (sphere) problem.
And for this, I have considered this example:Test problem 2: Flow past a cylinder (DFG 2D-3 benchmark) โ€” FEniCSx tutorial
However, I am more used to FEniCS 2019, where I just mark the BC. But, in FEniCS-X ns_code2 example, the BC is marked with facets.

I have managed to read the mesh and create the function space in FEniCS-X

import dolfinx
import numpy as np
from mpi4py import MPI
from dolfinx.cpp.mesh import CellType
from dolfinx.io import (XDMFFile, extract_gmsh_geometry,
                        extract_gmsh_topology_and_markers, ufl_mesh_from_gmsh)
from dolfinx.fem import (Constant, DirichletBC, Function, FunctionSpace, apply_lifting, assemble_matrix, 
                         assemble_scalar, assemble_vector, create_vector, locate_dofs_topological, set_bc)
from petsc4py import PETSc
from ufl import (FacetNormal, FiniteElement, Identity, Measure, TestFunction, TrialFunction, VectorElement,
                 as_vector, div, dot, ds, dx, inner, lhs, grad, nabla_grad, rhs, sym)

print(f"DOLFINx version: {dolfinx.__version__} is installed")

filename="sphere-2.xdmf"
with dolfinx.io.XDMFFile(MPI.COMM_WORLD, "sphere-2.xdmf", "r") as xdmf:
       mesh = xdmf.read_mesh(name="Grid")

t = 0
T = 1 #8                    # Final time
dt = 1/1600                 # Time step size
num_steps = int(T/dt)
k = Constant(mesh, dt)        
mu = Constant(mesh, 0.001)  # Dynamic viscosity
rho = Constant(mesh, 1)     # Density

v_cg2 = VectorElement("CG", mesh.ufl_cell(), 2)
s_cg1 = FiniteElement("CG", mesh.ufl_cell(), 1)
V = FunctionSpace(mesh, v_cg2)
Q = FunctionSpace(mesh, s_cg1)

fdim = mesh.topology.dim

For a similar problem in FEniCS 2019, I have set the BC:

# Define function spaces for pressure and velocity
V = VectorFunctionSpace(mesh, "Lagrange", degree=2, dim=3)
Q = FunctionSpace(mesh, "Lagrange", 1)


class Inflow(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and (abs(x[0] - 0.) < DOLFIN_EPS)


class Outflow(SubDomain):
    def inside(self, x, on_boundary):
        return on_boundary and (abs(x[0] - 10.) < DOLFIN_EPS)


class Walls(SubDomain):
    def inside(self, x, on_boundary):
        result = on_boundary and ((abs(x[1] + 0.) < DOLFIN_EPS) or (abs(x[1] - 5.) < DOLFIN_EPS) or
                                  (abs(x[2] - 0.) < DOLFIN_EPS) or (abs(x[2] - 5.) < DOLFIN_EPS))
        print(result)
        return result


class Sphere(SubDomain):
    def inside(self, x, on_boundary):
        result = on_boundary\
        and x[0] > 2.0 - DOLFIN_EPS and x[0] < 4.0 + DOLFIN_EPS\
        and x[1] > 2.0 - DOLFIN_EPS and x[1] < 4.0 + DOLFIN_EPS\
        and x[2] > 2.0 - DOLFIN_EPS and x[2] < 4.0 + DOLFIN_EPS
        return result


boundaries = MeshFunction("size_t", mesh, mesh.topology().dim() , 0)

Inflow().mark(boundaries, 1)
Outflow().mark(boundaries, 2)
Walls().mark(boundaries, 3)
Sphere().mark(boundaries, 4)

inflow_profile = ('1.', '0.', '0.')

bcu_inflow = DirichletBC(V, Expression(inflow_profile, degree=3), boundaries, 1)
bcp_outflow = DirichletBC(Q, Constant(0.), boundaries, 2)
bcu_walls = DirichletBC(V, Constant((0., 0., 0.)), boundaries, 3)
bcu_sphere = DirichletBC(V, Constant((0., 0., 0.)), boundaries, 4)
bcu = [bcu_inflow, bcu_walls, bcu_sphere]
bcp = [bcp_outflow]

Could you please tell me how to do it in a similar way in FEniCS-X or is there any other smart way to do set the BC?

See for instance: Implementation โ€” FEniCSx tutorial
which uses dolfinx.fem.locate_dofs_geometrical, which is similar to the previous subdomain, but using a python function instead of a specific class.

Thank you!
Now I have formulated to as you suggested. However, I am not sure if this is correct.
Could you please further guide?
Moreover, I am having an error with the Expression function. I do not know if this is deprecated or do not know from where to import it.

import dolfinx
import numpy as np
from mpi4py import MPI
from dolfinx.cpp.mesh import CellType
from dolfinx.io import (XDMFFile, extract_gmsh_geometry,
                        extract_gmsh_topology_and_markers, ufl_mesh_from_gmsh)
from dolfinx.fem import (Constant, DirichletBC, Function, FunctionSpace, apply_lifting, assemble_matrix, 
                         assemble_scalar, assemble_vector, create_vector, locate_dofs_topological, set_bc)
from petsc4py import PETSc
from ufl import (FacetNormal, FiniteElement, Identity, Measure, TestFunction, TrialFunction, VectorElement,
                 as_vector, div, dot, ds, dx, inner, lhs, grad, nabla_grad, rhs, sym, Expression)

print(f"DOLFINx version: {dolfinx.__version__} is installed")

filename="sphere-2.xdmf"
with dolfinx.io.XDMFFile(MPI.COMM_WORLD, "sphere-2.xdmf", "r") as xdmf:
       mesh = xdmf.read_mesh(name="Grid")

t = 0
T = 1 #8                    # Final time
dt = 1/1600                 # Time step size
num_steps = int(T/dt)
k = Constant(mesh, dt)        
mu = Constant(mesh, 0.001)  # Dynamic viscosity
rho = Constant(mesh, 1)     # Density

import dolfinx.fem as fem
V = fem.FunctionSpace(mesh, ("CG", 2))
Q = fem.FunctionSpace(mesh, ("CG", 1))

fdim = mesh.topology.dim

DOLFIN_EPS = 0.000001

def Inflow(x):
       return Inflow and (abs(x[0] - 0.) < DOLFIN_EPS)
       
       
def Outflow(x):
       return Outflow and (abs(x[0] - 5.) < DOLFIN_EPS)
              
              
def Walls(x):
        result = Walls and ((abs(x[1] + 0.) < DOLFIN_EPS) or (abs(x[1] - 5.) < DOLFIN_EPS) or
                                  (abs(x[2] - 0.) < DOLFIN_EPS) or (abs(x[2] - 5.) < DOLFIN_EPS))
        return result

def Sphere(x):
       result = Sphere\
                and x[0] > 2.0 - DOLFIN_EPS and x[0] < 4.0 + DOLFIN_EPS\
                and x[1] > 2.0 - DOLFIN_EPS and x[1] < 4.0 + DOLFIN_EPS\
                and x[2] > 2.0 - DOLFIN_EPS and x[2] < 4.0 + DOLFIN_EPS
       return result

inflow_profile = ('1.', '0.', '0.')

inflow_boundary_dofs = fem.locate_dofs_geometrical(V, Inflow)
outflow_boundary_dofs = fem.locate_dofs_geometrical(Q, Outflow)
walls_boundary_dofs = fem.locate_dofs_geometrical(V, Walls)
sphere_boundary_dofs = fem.locate_dofs_geometrical(V, Sphere)

bcu_inflow = fem.DirichletBC(inflow_boundary_dofs, Expression(inflow_profile, degree=3))
bcu_outflow = fem.DirichletBC(outflow_boundary_dofs, Constant(0.))
bcu_walls = fem.DirichletBC(walls_boundary_dofs, Constant(0.))
bcu_sphere = fem.DirichletBC(sphere_boundary_dofs, Constant(0.))

bcu = [bcu_inflow, bcu_walls, bcu_sphere]
bcp = [bcp_outflow]

This should simply be

def Inflow(x):
      return (abs(x[0] - 0.) < DOLFIN_EPS)

and similarly for all other functions used to locate boundary conditions.

The Expression class in dolfin has been deprecated, as it hid alot of magic (including interpolation into an appropriate space).
See:
https://jorgensd.github.io/dolfinx-tutorial/chapter1/fundamentals_code.html#defining-the-boundary-conditions
For for details on how to implement spatially varying boundary conditions

Thank you!
I am still not able to further continue with walls and sphere.

def Inflow(x):
       return (abs(x[0] - 0.) < DOLFIN_EPS)
              
def Outflow(x):
       return (abs(x[0] - 5.) < DOLFIN_EPS)
              
def Walls(x):
       return (abs(x[1] + 0.) < DOLFIN_EPS) or (abs(x[1] - 5.) < DOLFIN_EPS) or\
              (abs(x[2] - 0.) < DOLFIN_EPS) or (abs(x[2] - 5.) < DOLFIN_EPS)
              
def Sphere(x):
       return x[0] > 2.0 - DOLFIN_EPS and x[0] < 4.0 + DOLFIN_EPS\
              and x[1] > 2.0 - DOLFIN_EPS and x[1] < 4.0 + DOLFIN_EPS\
              and x[2] > 2.0 - DOLFIN_EPS and x[2] < 4.0 + DOLFIN_EPS

And I am getting the following error:

DOLFINx version: 0.3.1.0 is installed
Traceback (most recent call last):
  File "fluid.py", line 55, in <module>
    walls_boundary_dofs = fem.locate_dofs_geometrical(V, Walls)
  File "/python3.8/site-packages/dolfinx/fem/dirichletbc.py", line 66, in locate_dofs_geometrical
    return cpp.fem.locate_dofs_geometrical(_V, marker)
  File "fluid.py", line 42, in Walls
    return (abs(x[1] + 0.) < DOLFIN_EPS) or (abs(x[1] - 5.) < DOLFIN_EPS) or\
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

And I have tried to used the (a<b).any() (a<b).all(), then I am getting some sort of memory error:

DOLFINx version: 0.3.1.0 is installed
Traceback (most recent call last):
  File "fluid.py", line 51, in <module>
    walls_boundary_dofs = fem.locate_dofs_geometrical(V, Walls)
  File "/python3.8/site-packages/dolfinx/fem/dirichletbc.py", line 66, in locate_dofs_geometrical
    return cpp.fem.locate_dofs_geometrical(_V, marker)
MemoryError: std::bad_alloc

Please read carefully through the tutorial, as it explains most of these steps.
Iโ€™ve attached a minimal code that achieves what you want to do:

import dolfinx.fem as fem
import dolfinx
import numpy as np
from mpi4py import MPI


from dolfinx.generation import UnitCubeMesh
print(f"DOLFINx version: {dolfinx.__version__} is installed")

mesh = UnitCubeMesh(MPI.COMM_WORLD, 10, 10, 10)
t = 0
T = 1  # 8                    # Final time
dt = 1 / 1600                 # Time step size
num_steps = int(T / dt)
k = fem.Constant(mesh, dt)
mu = fem.Constant(mesh, 0.001)  # Dynamic viscosity
rho = fem.Constant(mesh, 1)     # Density

V = fem.VectorFunctionSpace(mesh, ("CG", 2))
Q = fem.FunctionSpace(mesh, ("CG", 1))

fdim = mesh.topology.dim

DOLFIN_EPS = 0.000001


def Inflow(x):
    return np.abs(x[0] - 0.) < DOLFIN_EPS


def Outflow(x):
    return np.abs(x[0] - 5.) < DOLFIN_EPS


def Walls(x):
    result = np.logical_or(np.abs(x[1] + 0.) < DOLFIN_EPS, np.abs(x[1] - 5.) < DOLFIN_EPS)
    result2 = np.logical_or(np.abs(x[2] - 0.) < DOLFIN_EPS, np.abs(x[2] - 5.) < DOLFIN_EPS)
    return np.logical_or(result, result2)


def Sphere(x):
    result = np.logical_and(x[0] > 2.0 - DOLFIN_EPS, x[0] < 4.0 + DOLFIN_EPS)
    result2 = np.logical_and(x[1] > 2.0 - DOLFIN_EPS, x[1] < 4.0 + DOLFIN_EPS)
    result3 = np.logical_and(x[2] > 2.0 - DOLFIN_EPS, x[2] < 4.0 + DOLFIN_EPS)
    return np.logical_and(np.logical_and(result, result2), result3)


def inflow_profile(x):
    values = np.zeros(x.shape)
    values[0, :] = 1
    return values


u_in = fem.Function(V)
u_in.interpolate(inflow_profile)

u_zero = fem.Function(V)
u_zero.x.array[:] = 0
p_zero = fem.Function(Q)
p_zero.x.array[:] = 0

inflow_boundary_dofs = fem.locate_dofs_geometrical(V, Inflow)
outflow_boundary_dofs = fem.locate_dofs_geometrical(Q, Outflow)
walls_boundary_dofs = fem.locate_dofs_geometrical(V, Walls)
sphere_boundary_dofs = fem.locate_dofs_geometrical(V, Sphere)

bcu_inflow = fem.DirichletBC(u_in, inflow_boundary_dofs)
bcp_outflow = fem.DirichletBC(p_zero, outflow_boundary_dofs)
bcu_walls = fem.DirichletBC(u_zero, walls_boundary_dofs)
bcu_sphere = fem.DirichletBC(u_zero, sphere_boundary_dofs)

bcu = [bcu_inflow, bcu_walls, bcu_sphere]
bcp = [bcp_outflow]

Many thanks for the minimal code!
But, still, I am having some issues with the interpolate function:

$ python3 fluid.py
DOLFINx version: 0.3.1.0 is installed
DOLFINx version: 0.3.1.0 is installed
[[0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]]
[[1. 1. 1. ... 1. 1. 1.]
 [0. 0. 0. ... 0. 0. 0.]
 [0. 0. 0. ... 0. 0. 0.]]
Traceback (most recent call last):
  File "/python3.8/site-packages/dolfinx/fem/function.py", line 301, in _interpolate
    self._cpp_object.interpolate(u._cpp_object)
AttributeError: 'function' object has no attribute '_cpp_object'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "fluid.py", line 64, in <module>
    u_in.interpolate(inflow_profile)
  File "/python3.8/site-packages/dolfinx/fem/function.py", line 309, in interpolate
    _interpolate(u)
  File "/Python/3.8.6-GCCcore-10.2.0/lib/python3.8/functools.py", line 875, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
  File "python3.8/site-packages/dolfinx/fem/function.py", line 303, in _interpolate
    self._cpp_object.interpolate(u)
RuntimeError: Interpolation data has the wrong shape.

I have referred to another issue, similar to this one.
Should I use: values = np.zeros(x.shape[1])

As you have not provided a minimal example to reproduce your issue I cannot help you any further.
Please consider the minimal code I sent you, as it executes with no error messages.

Compared to your original code, I replaced

with

as you want the velocity to be a vector function.

Thanks! that problem solved. Now I am getting error with PETSc comm.

import dolfinx
import numpy as np
from mpi4py import MPI
from dolfinx.cpp.mesh import CellType
from dolfinx.io import (XDMFFile, extract_gmsh_geometry,
                        extract_gmsh_topology_and_markers, ufl_mesh_from_gmsh)
from dolfinx.fem import (Constant, DirichletBC, Function, FunctionSpace, apply_lifting, assemble_matrix, 
                         assemble_scalar, assemble_vector, create_vector, locate_dofs_topological, set_bc)
from petsc4py import PETSc
from ufl import (FacetNormal, FiniteElement, Identity, Measure, TestFunction, TrialFunction, VectorElement,
                 as_vector, div, dot, ds, dx, inner, lhs, grad, nabla_grad, rhs, sym)

print(f"DOLFINx version: {dolfinx.__version__} is installed")

filename="sphere-2.xdmf"
with dolfinx.io.XDMFFile(MPI.COMM_WORLD, "sphere-2.xdmf", "r") as xdmf:
       mesh = xdmf.read_mesh(name="Grid")


#### local mesh ####
## mesh = UnitCubeMesh(MPI.COMM_WORLD, 10, 10, 10)
###################

t = 0
T = 1 #8                    # Final time
dt = 1/1600                 # Time step size
num_steps = int(T/dt)
k = Constant(mesh, dt)        
mu = Constant(mesh, 0.001)  # Dynamic viscosity
rho = Constant(mesh, 1)     # Density

import dolfinx.fem as fem
V = fem.VectorFunctionSpace(mesh, ("CG", 2))
Q = fem.FunctionSpace(mesh, ("CG", 1))

DOLFIN_EPS = 0.000001

def Inflow(x):
    return np.abs(x[0] - 0.) < DOLFIN_EPS

def Outflow(x):
    return np.abs(x[0] - 5.) < DOLFIN_EPS

def Walls(x):
    result = np.logical_or(np.abs(x[1] + 0.) < DOLFIN_EPS, np.abs(x[1] - 5.) < DOLFIN_EPS)
    result2 = np.logical_or(np.abs(x[2] - 0.) < DOLFIN_EPS, np.abs(x[2] - 5.) < DOLFIN_EPS)
    return np.logical_or(result, result2)

def Sphere(x):
    result = np.logical_and(x[0] > 2.0 - DOLFIN_EPS, x[0] < 4.0 + DOLFIN_EPS)
    result2 = np.logical_and(x[1] > 2.0 - DOLFIN_EPS, x[1] < 4.0 + DOLFIN_EPS)
    result3 = np.logical_and(x[2] > 2.0 - DOLFIN_EPS, x[2] < 4.0 + DOLFIN_EPS)
    return np.logical_and(np.logical_and(result, result2), result3)

def inflow_profile(x):
    values = np.zeros(x.shape)
    values[0,:]=1
    return values

u_in = fem.Function(V)
u_in.interpolate(inflow_profile)

u_zero = fem.Function(V)
u_zero.x.array[:] = 0
p_zero = fem.Function(Q)
p_zero.x.array[:] = 0

inflow_boundary_dofs = fem.locate_dofs_geometrical(V, Inflow)
outflow_boundary_dofs = fem.locate_dofs_geometrical(Q, Outflow)
walls_boundary_dofs = fem.locate_dofs_geometrical(V, Walls)
sphere_boundary_dofs = fem.locate_dofs_geometrical(V, Sphere)

bcu_inflow = fem.DirichletBC(u_in, inflow_boundary_dofs)
bcp_outflow = fem.DirichletBC(p_zero, outflow_boundary_dofs)
bcu_walls = fem.DirichletBC(u_zero, walls_boundary_dofs)
bcu_sphere = fem.DirichletBC(u_zero, sphere_boundary_dofs)

bcu = [bcu_inflow, bcu_walls, bcu_sphere]
bcp = [bcp_outflow]

print(f"DOLFINx version: {dolfinx.__version__} is installed")

# Define trial and test functions
u = TrialFunction(V)
v = TestFunction(V)
p = TrialFunction(Q)
q = TestFunction(Q)

# Define functions for solutions at previous and current time steps
u_n = Function(V)
u_ = Function(V)
p_n = Function(Q)
p_ = Function(Q)

# Define expressions used in variational forms
U = 0.5 * (u_n + u)
n = FacetNormal(mesh)
f = Constant(mesh, PETSc.ScalarType((0,0,0)))
k = Constant(mesh, PETSc.ScalarType(dt))
mu = Constant(mesh, PETSc.ScalarType(.001))
rho = Constant(mesh, PETSc.ScalarType(1))

# Define symmetric gradient
def epsilon(u):
    return sym(nabla_grad(u))

# Define stress tensor
def sigma(u, p):
    return 2 * mu * epsilon(u) - p * Identity(len(u))

# Define variational problem for step 1
F1 = rho * dot((u - u_n) / k, v) * dx \
     + rho * dot(dot(u_n, nabla_grad(u_n)), v) * dx \
     + inner(sigma(U, p_n), epsilon(v)) * dx \
     + dot(p_n * n, v) * ds - dot(mu * nabla_grad(U) * n, v) * ds \
     - dot(f, v) * dx
a1 = lhs(F1)
L1 = rhs(F1)

# Define variational problem for step 2
a2 = dot(nabla_grad(p), nabla_grad(q)) * dx
L2 = dot(nabla_grad(p_n), nabla_grad(q)) * dx - (1 / k) * div(u_) * q * dx

# Define variational problem for step 3
a3 = dot(u, v) * dx
L3 = dot(u_, v) * dx - k * dot(nabla_grad(p_ - p_n), v) * dx

# Assemble matrices
A1 = assemble_matrix(a1, bcs=bcu)
A1.assemble()
b1 = create_vector(L1)
A2 = assemble_matrix(a2, bcs=bcp)
A2.assemble()
b2 = create_vector(L2)
A3 = assemble_matrix(a3)
A3.assemble()
b3 = create_vector(L3)

print(f"DOLFINx version: {dolfinx.__version__} is installed")

# Solver for step 1
solver1 = PETSc.KSP().create(mesh.comm)
solver1.setOperators(A1)
solver1.setType(PETSc.KSP.Type.BCGS)
pc1 = solver1.getPC()
pc1.setType(PETSc.PC.Type.JACOBI)

# Solver for step 2
solver2 = PETSc.KSP().create(mesh.comm)
solver2.setOperators(A2)
solver2.setType(PETSc.KSP.Type.MINRES)
pc2 = solver2.getPC()
pc2.setType(PETSc.PC.Type.HYPRE)
pc2.setHYPREType("boomeramg")

# Solver for step 3
solver3 = PETSc.KSP().create(mesh.comm)
solver3.setOperators(A3)
solver3.setType(PETSc.KSP.Type.CG)
pc3 = solver3.getPC()
pc3.setType(PETSc.PC.Type.SOR)

And I am getting the following error:

Traceback (most recent call last):
  File "fluid.py", line 156, in <module>
    solver1 = PETSc.KSP().create(mesh.comm)
AttributeError: 'dolfinx.cpp.mesh.Mesh' object has no attribute 'comm'

Could you please help with this?

Could you supply the output of the following/

python3 -c "import dolfinx; import dolfinx.common; print(dolfinx.__version__, dolfinx.common.git_commit_hash)"

Here it is:

$ python3 -c "import dolfinx; import dolfinx.common; print(dolfinx.__version__, dolfinx.common.git_commit_hash)"
0.3.1.0 7f15bfc9a3b72a2ab6ab7a991aa2a439c7523438

How did you install dolfinx? This commit hash is not in our git system as far as I can tell.

I have installed using Jake installation script: GitHub - jhale/fenicsx-iris-cluster: Scripts for building FEniCSX on the University of Luxembourg iris cluster

However, if I replace mesh.comm with solver1 = PETSc.KSP().create(MPI.COMM_WORLD) it is working.

Maybe @jackhale can shed some light on what version of dolfinx that script builds. Seems like it is using a slightly outdated dolfinx API.

Sure, thanks! will check that. I am also having another question, I have not used .xdmf files before in Paraview or VisIt. Is there any way to write a time series solution in .vtk or .vtu files in FEniCS-X or in the .xdmf file? Or is it good to use the .xdmf file for visualization, if so why I am not able to see velocity and pressure contours?

We have support for VTK, VTX and Fides as well. See dolfinx/python/test/unit/io at main ยท FEniCS/dolfinx ยท GitHub
For how to use them.
XDMF is preferrable to VTK when executing in parallel as it uses hdf5 to store the data, while vtk writes everything to file in plain-text.

I have explained how to extract blocks from XDMFFiles for visualization at: Using Paraview for visualization โ€” FEniCSx tutorial

1 Like

Thanks! I was able to see the solution using Paraview. However, I am getting errors, solutions, probably I am making the mistake when I do BC. Or does it have anything to do with choosing iterative solvers? Moreover, I am trying just laminar flow.




If the problem comes from defining the BC, perhaps, I can name the mesh (inlet, outlet, walls, and sphere), in that case, how can I define those naming in BC from exported mesh files.

Start by making a minimal example.
Then check your boundary conditions.
Finally, start by using direct solvers to eliminate the solver as a source of error.
With all these steps in place you should be able to make a more accurate minimal example pinpointing your issue

1 Like

Thanks!

  • Start by making a minimal example.
    The example I am trying is already a minimal one
  • Then check your boundary conditions.
    There was some error as of now, the outlet should be at 10.0 not at 5.0
  • Finally, start by using direct solvers to eliminate the solver as a source of error.
    I see that you have put up some examples for LU decomposion, will try that

The problem is when I try to define the BC for the obstacle/sphere in the fluid domain.

def Sphere(x):
    result = np.logical_and(x[0] > 2.0 - DOLFIN_EPS, x[0] < 4.0 + DOLFIN_EPS)
    result2 = np.logical_and(x[1] > 2.0 - DOLFIN_EPS, x[1] < 4.0 + DOLFIN_EPS)
    result3 = np.logical_and(x[2] > 2.0 - DOLFIN_EPS, x[2] < 4.0 + DOLFIN_EPS)
    return np.logical_and(np.logical_and(result, result2), result3)

Could you please tell me if I am making some mistake in here? Or now I have tagged mesh (inlet, outlet, walls, and obstacle), would that work if I try one of your options ( 3. How to load msh files into dolfin-X),
then I can try BC as you defined in here: flow past obstacle