How to get rid of segfault when using assemble()

Hi everyone !
I’m a beginner with Fenics and i apologize if my question has already been answered eslwhere, but it seems not for now.
I’m trying to simulate heat transfer between a newtonian fluid flow and a solid.
I’m using Incremental Pressure Correction Scheme (IPCS) for solving Navier-stokes equation, but unfortunately i get a segfault when assembling the first step’s linear form:
A1 = assemble(a1)

I can’t get around this, and when trying to run the code on another computer, either segfault or kernel crash without error message happens.

I’m using Fenics on Ubuntu 20.04 lts

Here is a link to a Minimal Working Example:
https://github.com/Fra26802/gpr_modelling/tree/Fra26802-MWE_segfault

Also for better understanding, here is a domain map (water is purple, stainless steel is yellow)
water-steel

full error message: ‘Erreur de segmentation (core dumped)’

Many Thanks !

This seems to be related to using a mesh from MeshView in assembly. Maybe @cdaversin has any suggestions?

Thanks a lot for your answer @dokken !
Do you know if i can get rid of either MeshView or Assemble() and still be able to compute the IPCS scheme only on a part of the mesh ?

If you assemble on a subdomain using the full mesh, but with a MeshFunction as input to the integration measure:

dx_ = Measure("dx", domain=mesh, subdomain_data=mesh_function)
a = ...*dx_(cell_marker)
A = assemble(a)
A.ident_zeros()

as shown in for instance:

or

2 Likes

sorry, link on the first post leads to wrong code. here is the right one :
https://github.com/Fra26802/gpr_modelling/blob/Julien/Minimal_working_example.py

'''
this code simulates 2D heat transfer between flowing water and solid stainless steel (ss).
'''

from fenics import *
from mshr import *
import numpy as np
import matplotlib.pyplot as plt

#tensors needed for flow equation:
def epsilon(u):
    return sym(nabla_grad(u))

def sigma(u, p):
    return 2*mu*epsilon(u) - p*Identity(len(u))
#Density :
class Density(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = 1. #water, no units
        else:
            values[0] = 7.9 #stainless steel, no units
    def value_shape(self):
            return ()

T = 10.0           # final time
num_steps = 10    # number of time steps
dt = T / num_steps # time step size


#domain and subdomains definition as in demo_block-assembly-2D2D-nonlinear.py : https://bitbucket.org/fenics-project/dolfin/src/39253449ee544fe04eb8bf387eab115e094d325e/python/demo/undocumented/block-assembly-2D2D/demo_block-assembly-2D2D-nonlinear.py?at=cecile%2Fmixed-dimensional

domain = Rectangle(Point(0, 0), Point(16,8))
domain_water = Rectangle(Point(0, 0), Point(16,4))
domain_ss = domain-domain_water

domain.set_subdomain(1, domain_water)
domain.set_subdomain(2, domain_ss)

#mesh definition
mesh = generate_mesh(domain,16)

# subdomain markers and integration measure
markers = MeshFunction('size_t', mesh, 2, mesh.domains())
dx = Measure("dx", domain=mesh, subdomain_data=markers)
ds = Measure("ds", domain=mesh, subdomain_data=markers)

#submesh definition for CFD
#meshwater = MeshView.create(markers, 1)


#physical properties defined as in fenics tutorial ft11 updated : https://github.com/hplgit/fenics-tutorial/issues/65 :

#water viscosity
mu=1  #Pa.s
rho = Density(markers, degree=1)

#formulation of CFD variationnal problem as in fenics tutorial demo ft07: https://github.com/gdmcbain/fenics-tuto-in-skfem/commit/3d4803e2fd61a7672cd7d1a4fb4f4ccfedde6084

V = VectorFunctionSpace(mesh, 'P', 2)
Q = FunctionSpace(mesh, 'P', 1)
boundaries = MeshFunction("size_t", mesh, mesh.topology().dim()-1, 0)

inflow  = 'near(x[0], 0, 1E-14) and x[1]<=4+1E-14'
outflow = 'near(x[0], 0, 1E-14) and x[1]<=4+1E-14'
walls   = 'near(x[1], 0, 1E-14) || near(x[1], 4, 1E-14)'

bcu_noslip  = DirichletBC(V, Constant((0, 0)), walls)
bcp_inflow  = DirichletBC(Q, Constant(8), inflow)
bcp_outflow = DirichletBC(Q, Constant(0), outflow)
bcu = [bcu_noslip]
bcp = [bcp_inflow, bcp_outflow]

u = TrialFunction(V)
v = TestFunction(V)
p = TrialFunction(Q)
q = TestFunction(Q)

u_n = Function(V)
u_  = Function(V)
p_n = Function(Q)
p_  = Function(Q)

U   = 0.5 * (u_n + u)
n   = FacetNormal(mesh)
f   = Constant((0, 0))
k   = Constant(dt)
mu  = Constant(mu)

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

a2 = dot(nabla_grad(p), nabla_grad(q))*dx(1)
L2 =dot(nabla_grad(p_n), nabla_grad(q))*dx(1) - (1/k)*div(u_)*q*dx(1)

a3 = dot(u, v)*dx(1)
L3 = dot(u_, v)*dx(1) - k*dot(nabla_grad(p_ - p_n), v)*dx(1)

A1 = assemble(a1, keep_diagonal=True)
A1.ident_zeros()
A2 = assemble(a2, keep_diagonal=True)
A2.ident_zeros()
A3 = assemble(a3, keep_diagonal=True)
A3.ident_zeros()
[bc.apply(A1) for bc in bcu]
[bc.apply(A2) for bc in bcp]


xdmffile_u = XDMFFile('example/navstok.xdmf')
t = 0
for n in range(num_steps):

    t += dt

    b1 = assemble(L1)           # Step 1: Tentative velocity step
    [bc.apply(b1) for bc in bcu]
    solve(A1, u_.vector(), b1)

    b2 = assemble(L2)           # Step 2: Pressure correction step
    [bc.apply(b2) for bc in bcp]
    solve(A2, p_.vector(), b2)

    b3 = assemble(L3)           # Step 3: Velocity correction step
    solve(A3, u_.vector(), b3)
    xdmffile_u.write(u_, t)

    u_n.assign(u_)
    p_n.assign(p_)

print ('quiver fails to plot vector of length zero ')
plt.plot(u_)
plt.show()

You need to format your code properly using 3xbacktick (`), so that identation is preserved.

Do you have a particular issue with this code? if so, what is the error message, and in what line do you obtain an error message?

Thanks, code is well formatted now. Your first answer partially solved my problem : i don’t have a segfault anymore but it get this error message line 140 :

  File "/usr/lib/python3/dist-packages/matplotlib/units.py", line 155, in get_converter
    return self[type(x)]
KeyError: <class 'numpy.ndarray'>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/matplotlib/units.py", line 155, in get_converter
    return self[type(x)]
KeyError: <class 'ufl.indexed.Indexed'>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "mwejul.py", line 140, in <module>
    plt.plot(u_)
  File "/usr/lib/python3/dist-packages/matplotlib/pyplot.py", line 2787, in plot
    return gca().plot(
  File "/usr/lib/python3/dist-packages/matplotlib/axes/_axes.py", line 1665, in plot
    lines = [*self._get_lines(*args, data=data, **kwargs)]
  File "/usr/lib/python3/dist-packages/matplotlib/axes/_base.py", line 225, in __call__
    yield from self._plot_args(this, kwargs)
  File "/usr/lib/python3/dist-packages/matplotlib/axes/_base.py", line 391, in _plot_args
    x, y = self._xy_from_xy(x, y)
  File "/usr/lib/python3/dist-packages/matplotlib/axes/_base.py", line 244, in _xy_from_xy
    by = self.axes.yaxis.update_units(y)
  File "/usr/lib/python3/dist-packages/matplotlib/axis.py", line 1487, in update_units
    converter = munits.registry.get_converter(data)
  File "/usr/lib/python3/dist-packages/matplotlib/units.py", line 165, in get_converter
    return self.get_converter(first)
  File "/usr/lib/python3/dist-packages/matplotlib/units.py", line 158, in get_converter
    first = cbook.safe_first_element(x)
  File "/usr/lib/python3/dist-packages/matplotlib/cbook/__init__.py", line 1670, in safe_first_element
    return next(iter(obj))
  File "/usr/lib/python3/dist-packages/ufl/core/expr.py", line 394, in __iter__
    for i in range(len(self)):
  File "/usr/lib/python3/dist-packages/ufl/core/expr.py", line 390, in __len__
    raise NotImplementedError("Cannot take length of non-vector expression.")
NotImplementedError: Cannot take length of non-vector expression.

you need to use dolfin’s plot function, i.e.
plot(u_)

1 Like

Thanks ! it’s better indeed. However, I still get an error message line 140 :

/usr/lib/python3/dist-packages/matplotlib/quiver.py:696: RuntimeWarning: divide by zero encountered in double_scalars
  length = a * (widthu_per_lenu / (self.scale * self.width))
/usr/lib/python3/dist-packages/matplotlib/quiver.py:696: RuntimeWarning: invalid value encountered in multiply
  length = a * (widthu_per_lenu / (self.scale * self.width))

I wonder where this “divide by zero” happens and why. Tried to locate it unsuccessfully

Its quite simple to locate it.
Call the following:

    print(min(u_.vector().get_local()), max(u_.vector().get_local()))

after

and

and observe that the first values all are 0, the second all nan.

1 Like

Hi @dokken ! thanks for your answer ! The NaN was caused by || used instead of and in boundary conditions definition. Then I didn’t get the fact that ds element uses a marker meshfunction of size n-1 instead of n, thus the code wasn’t finding the facets needed to apply boundary conditions. Took me a while to figure that out ! All sorted out now.
For information, this code works:

'''
this code simulates 2D heat transfer between flowing water and solid stainless steel (ss).
'''

from fenics import *
from mshr import *
import numpy as np
import matplotlib.pyplot as plt

T = 10.0           # final time
num_steps = 10    # number of time steps
dt = T / num_steps # time step size

#tensors needed for flow equation:
def epsilon(u):
    return sym(nabla_grad(u))

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

#domain and subdomains definition as in demo_block-assembly-2D2D-nonlinear.py : https://bitbucket.org/fenics-project/dolfin/src/39253449ee544fe04eb8bf387eab115e094d325e/python/demo/undocumented/block-assembly-2D2D/demo_block-assembly-2D2D-nonlinear.py?at=cecile%2Fmixed-dimensional

domain = Rectangle(Point(0, 0), Point(16,8))
domain_water = Rectangle(Point(0, 0), Point(16,4))
domain_ss = domain-domain_water

domain.set_subdomain(1, domain_water)
domain.set_subdomain(2, domain_ss)

#mesh definition
mesh = generate_mesh(domain,16)

# subdomain markers, facet markers and integration measures
markers = MeshFunction('size_t', mesh, mesh.topology().dim(), mesh.domains())
plot(markers)
facetmarkers = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)

dx = Measure("dx", domain=mesh, subdomain_data=markers)
ds = Measure("ds", domain=mesh, subdomain_data=facetmarkers)

print(markers.array(), min(markers.array()), max(markers.array()))
print(facetmarkers.array(), min(facetmarkers.array()), max(facetmarkers.array()))

#physical properties defined as in fenics tutorial ft11 updated : https://github.com/hplgit/fenics-tutorial/issues/65 :

#water viscosity
mu=1  #Pa.s

#Density :
class Density(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = 1. #water, no units
        else:
            values[0] = 7.9 #stainless steel, no units
    def value_shape(self):
            return ()


rho = Density(markers, degree=1)

V = VectorFunctionSpace(mesh, 'P', 2)
Q = FunctionSpace(mesh, 'P', 1)

#DEFINITION OF BOUNDARY CONDITIONS USING SECOND MARKER FUNCTION---------------------------------
#source:https://fenicsproject.discourse.group/t/no-slip-boundary-condition-not-being-applied/3924/2

#inflow  = 'near(x[0], 0, 1E-10) and x[1]<=4+1E-10'
#outflow = 'near(x[0], 0, 1E-10) and x[1]<=4+1E-10'
#walls   = 'near(x[1], 0, 1E-10) || near(x[1], 4, 1E-10)'

# Sub domain for walls (mark whole boundary, inflow and outflow will overwrite)
class Walls(SubDomain):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def inside(self, x, on_boundary):
        return on_boundary or near(x[1], 4, 1E-10)

# Sub domain for inflow (right)
class Inflow(SubDomain):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def inside(self, x, on_boundary):
        return near(x[0], 0, 1E-10) and x[1]<=4+1E-14 and on_boundary
    

# Sub domain for outflow (left)
class Outflow(SubDomain):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def inside(self, x, on_boundary):
        return x[0] >16-1E-14 and x[1]<=4+1E-14 and on_boundary




# Mark all facets as facetmarkers sub domain 3
facetmarkers.set_all(3)

# Mark no-slip facets as facetmarkers sub domain 0,
walls = Walls(markers)
walls.mark(facetmarkers, 0)

# Mark inflow as facetmarkers sub domain 1,
inflow = Inflow(markers)
inflow.mark(facetmarkers, 1)

# Mark outflow as facetmarkers sub domain 2
outflow = Outflow(markers)
outflow.mark(facetmarkers, 2)

print(facetmarkers.array(), min(facetmarkers.array()), max(facetmarkers.array()))

#inflow  = 'near(x[0], 0, 1E-10) and x[1]<=4+1E-10'
#outflow = 'near(x[0], 0, 1E-10) and x[1]<=4+1E-10'
#walls   = 'near(x[1], 0, 1E-10) and near(x[1], 4, 1E-10)'

bcu_noslip  = DirichletBC(V, Constant((0, 0)), walls)
bcp_inflow  = DirichletBC(Q, Constant(8), inflow)
bcp_outflow = DirichletBC(Q, Constant(0), outflow)

bcu = [bcu_noslip]
bcp = [bcp_inflow, bcp_outflow]



#FUNCTIONS DEFINITION-----------------------------------------------------------------------
u = TrialFunction(V)
v = TestFunction(V)
p = TrialFunction(Q)
q = TestFunction(Q)

u_n = Function(V)
u_  = Function(V)
p_n = Function(Q)
p_  = Function(Q)

U   = 0.5 * (u_n + u)
n   = FacetNormal(mesh)
f   = Constant((0, 0))
k   = Constant(dt)
mu  = Constant(mu)


#IPCS IMPLEMENTATION---------------------------------------------------------------------------
#Source :fenics tutorial demo ft07: https://github.com/gdmcbain/fenics-tuto-in-skfem/commit/3d4803e2fd61a7672cd7d1a4fb4f4ccfedde6084


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

a2 = dot(nabla_grad(p), nabla_grad(q))*dx(1)
L2 =dot(nabla_grad(p_n), nabla_grad(q))*dx(1) - (1/k)*div(u_)*q*dx(1)

a3 = dot(u, v)*dx(1)
L3 = dot(u_, v)*dx (1)- k*dot(nabla_grad(p_ - p_n), v)*dx(1)

A1 = assemble(a1, keep_diagonal=True)
A1.ident_zeros()

A2 = assemble(a2, keep_diagonal=True)
A2.ident_zeros()

A3 = assemble(a3, keep_diagonal=True)
A3.ident_zeros()

[bc.apply(A1) for bc in bcu]
[bc.apply(A2) for bc in bcp]

xdmffile_u = XDMFFile('example/navstok.xdmf')

t = 0
for n in range(num_steps):

    t += dt

    b1 = assemble(L1)           # Step 1: Tentative velocity step
    [bc.apply(b1) for bc in bcu]
    solve(A1, u_.vector(), b1)
    print(min(u_.vector().get_local()), max(u_.vector().get_local()))
    
    b2 = assemble(L2)           # Step 2: Pressure correction step
    [bc.apply(b2) for bc in bcp]
    solve(A2, p_.vector(), b2)
    print(min(u_.vector().get_local()), max(u_.vector().get_local()))
    
    b3 = assemble(L3)           # Step 3: Velocity correction step
    solve(A3, u_.vector(), b3)
    print(min(u_.vector().get_local()), max(u_.vector().get_local()))
    
    u_n.assign(u_)
    p_n.assign(p_)
 
    xdmffile_u.write(u_, t)

plot(u_)
plt.show()

link to the Github