Prblem with the size of a matrix

I’m trying to solve a linear system. I have three functions: one vector function and two scalar functions. The mesh is two-dimensional. I am using:

problem = dolfinx.fem.petsc.LinearProblem(Ar, bl, bcs=bc, petsc_options={"ksp_type": "gmres", "pc_type": "ilu","ksp_max_it": 1000 })

Phi = problem.solve()

The vector space for each is defined as follows:

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

The mesh has 61,644 elements.

When I compile, I get the following error:


MemoryError:  Unable to allocate 3.13 TiB for an array with shape (656100, 656100) and data type float64

I do not understand the dimensions of that matrix. How can I tell it that the matrix is sparse rather than dense?

I’m not including the entire code due to its length, but if you need anything else, I can provide it without any problems.

Thank you very much!

It’s extremely difficult to give guidance without a minimal working example. But I assume you’re trying to initialise a dense NumPy matrix/array rather than a sparse matrix. Consider using a sparse matrix using PETSc, SciPy or similar.

I send you the whole code because I don’t know how to do it minimal… Let’s assume that the equations are well implemented.
The final part is where I try to solve the linear system.

import dolfinx
import gmsh
from mpi4py import MPI
from petsc4py import PETSc
import numpy as np
import math
import ufl
from ufl import (FacetNormal, FiniteElement, Identity, Measure, TestFunction, TrialFunction, VectorElement,
                 as_vector, div, dot, ds, dx, inner, lhs, grad, nabla_grad, rhs, sym, MixedElement)
from dolfinx.fem.petsc import (apply_lifting, assemble_matrix, assemble_vector, 
                               create_vector, create_matrix, set_bc)
import matplotlib.pyplot as plt

from dolfinx.fem import (Constant, Function, FunctionSpace, 
                         assemble_scalar, dirichletbc, form, locate_dofs_topological, set_bc)

from dolfinx.mesh import create_unit_square
from petsc4py.PETSc import ScalarType
from dolfinx import fem
from dolfinx import geometry
from dolfinx.io import gmshio
import dolfinx.cpp as _cpp
import dolfinx.fem as _fem
from dolfinx.nls.petsc import NewtonSolver

print("Tamaño del comunicador:", MPI.COMM_WORLD.size)

domain, cell_tags, ft = gmshio.read_from_msh("Mesh/cylinder.msh", MPI.COMM_WORLD, 0, gdim=2)
ft.name = "Facet markers"

#Encontrar los id segun las coordenadas

tdim = domain.topology.dim
tree = dolfinx.geometry.bb_tree(domain, tdim)
num_entities_local = domain.topology.index_map(tdim).size_local + domain.topology.index_map(tdim).num_ghosts
entities = np.arange(num_entities_local, dtype = np.int32)
mid_tree = dolfinx.geometry.create_midpoint_tree(domain, tdim,entities)
mesh_geom = domain.geometry.x
tol = 1e-8

def closest_point(mesh, point,tol):
    points = point
    while True:
        try:
            entity = dolfinx.geometry.compute_closest_entity(tree, mid_tree, mesh, points)
            break
        except RuntimeError:
            print(points)
            for j in range(len(mesh.geometry.x)):
                if (np.abs(mesh_geom[j][0]-points[0])< tol and np.abs(mesh_geom[j][1]-points[1])< tol):
                     return points, j              
    
    geom_dof = dolfinx.cpp.mesh.entities_to_geometry(mesh._cpp_object,tdim,entity, False)
    mesh_nodes = mesh_geom[geom_dof][0]
    dis = dolfinx.geometry.compute_distance_gjk(points, mesh_nodes)
    index = -100
    for i in range(len(mesh_nodes)):
        #print(mesh_nodes[i])
        if (np.abs(mesh_nodes[i][0]-points[0]+ dis[0]) < tol and np.abs(mesh_nodes[i][1]-points[1]+ dis[1]) < tol):
            index = i
            
    if (index == -100):
        return point, index
    else:
        return points[0] - dis[0], points[1] - dis[1] , geom_dof[0][index]



#Calculo del campo vectorial normal a las superficies
    
def facet_normal_approximation(V, mt, mt_id, tangent=False): 
                               #jit_options: dict = {}, form_compiler_options: dict = {}):

    comm = V.mesh.comm
    n = ufl.FacetNormal(V.mesh)
    nh = _fem.Function(V)
    u, v = ufl.TrialFunction(V), ufl.TestFunction(V)
    ds = ufl.ds(domain=V.mesh, subdomain_data=mt, subdomain_id=mt_id)
    if tangent:
        if V.mesh.geometry.dim == 1:
            raise ValueError("Tangent not defined for 1D problem")
        elif V.mesh.geometry.dim == 2:
            a = ufl.inner(u, v) * ds
            L = ufl.inner(ufl.as_vector([-n[1], n[0]]), v) * ds
        else:
            def tangential_proj(u, n):
                """
                See for instance:
                https://link.springer.com/content/pdf/10.1023/A:1022235512626.pdf
                """
                return (ufl.Identity(u.ufl_shape[0]) - ufl.outer(n, n)) * u
            c = fem.Constant(V.mesh, [1, 1, 1])
            a = ufl.inner(u, v) * ds
            L = ufl.inner(tangential_proj(c, n), v) * ds
    else:
        a = (ufl.inner(u, v) * ds)
        L = ufl.inner(n, v) * ds

    # Find all dofs that are not boundary dofs
    imap = V.dofmap.index_map
    all_blocks = np.arange(imap.size_local, dtype=np.int32)
    top_blocks = _fem.locate_dofs_topological(V, V.mesh.topology.dim - 1, mt.find(mt_id))
    deac_blocks = all_blocks[np.isin(all_blocks, top_blocks, invert=True)]

    # Note there should be a better way to do this
    # Create sparsity pattern only for constraint + bc
    bilinear_form = _fem.form(a)
    pattern = _fem.create_sparsity_pattern(bilinear_form)
    pattern.insert_diagonal(deac_blocks)
    pattern.finalize()
    u_0 = _fem.Function(V)
    u_0.vector.set(0)

    bc_deac = _fem.dirichletbc(u_0, deac_blocks)
    A = _cpp.la.petsc.create_matrix(comm, pattern)
    A.zeroEntries()

    # Assemble the matrix with all entries
    form_coeffs = dolfinx.cpp.fem.pack_coefficients(bilinear_form._cpp_object)
    form_consts = _cpp.fem.pack_constants(bilinear_form._cpp_object)
    _cpp.fem.petsc.assemble_matrix(A, bilinear_form._cpp_object,
                                   form_consts, form_coeffs, [bc_deac._cpp_object])
    if bilinear_form.function_spaces[0] is bilinear_form.function_spaces[1]:
        A.assemblyBegin(PETSc.Mat.AssemblyType.FLUSH)  # type: ignore
        A.assemblyEnd(PETSc.Mat.AssemblyType.FLUSH)  # type: ignore
        _cpp.fem.petsc.insert_diagonal(A, bilinear_form.function_spaces[0], [bc_deac._cpp_object], 1.0)
    A.assemble()
    linear_form = _fem.form(L)
    b = _fem.petsc.assemble_vector(linear_form)

    _fem.petsc.apply_lifting(b, [bilinear_form], [[bc_deac]])
    b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE)  # type: ignore
    _fem.petsc.set_bc(b, [bc_deac])

    # Solve Linear problem
    solver = PETSc.KSP().create(V.mesh.comm)  # type: ignore
    solver.setType("cg")
    solver.rtol = 1e-8
    solver.setOperators(A)
    solver.solve(b, nh.vector)
    nh.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)  # type: ignore
    return nh    



Lx = 40

def upstream(x):
    a = np.less(x[0],0)
    return np.logical_and(np.greater(x[0]**2 + x[1]**2, 5**2),a)
def downstream(x):
    return np.isclose(x[0],Lx)

def walls(x):
    a = np.greater(x[0],0)
    b = np.less(x[0],Lx)
    return np.logical_and(np.greater(x[0]**2 + x[1]**2, 5**2), np.logical_and(a,b))

def obstacle(x):
    return np.less(x[0]**2 + x[1]**2, 5**2)

fdim = domain.topology.dim -1

up_facets = dolfinx.mesh.locate_entities_boundary(domain, fdim, upstream)
down_facets = dolfinx.mesh.locate_entities_boundary(domain, fdim, downstream)
wall_facets = dolfinx.mesh.locate_entities_boundary(domain, fdim, walls)
obstacle_facets = dolfinx.mesh.locate_entities_boundary(domain, fdim, obstacle)
    

    ########################################################################################################

    # Definition of Spaces. (dim and polinomial type)

v_cg1 = VectorElement("CG", domain.ufl_cell(), 1)
s_cg1 = FiniteElement("CG", domain.ufl_cell(), 1)
V = dolfinx.fem.FunctionSpace(domain, v_cg1)
Q = dolfinx.fem.FunctionSpace(domain, s_cg1)
Z = MixedElement([v_cg1, s_cg1, s_cg1])
W = dolfinx.fem.FunctionSpace(domain, Z)

    # Boundary subdomains and coditions

########################################################################################################


boundaries = [(1,up_facets),(2,down_facets),(3,wall_facets),(4,obstacle_facets)]

facet_indices, facet_markers = [], []
for (marker, face ) in boundaries:
    facet_indices.append(face)
    facet_markers.append(np.full_like(face, marker))
facet_indices = np.hstack(facet_indices).astype(np.int32)
facet_markers = np.hstack(facet_markers).astype(np.int32)
sorted_facets = np.argsort(facet_indices)
facet_tag = dolfinx.mesh.meshtags(domain, fdim, facet_indices[sorted_facets], facet_markers[sorted_facets])

domain.topology.create_connectivity(domain.topology.dim-1, domain.topology.dim)
    
V1, _ = W.sub(0).collapse()
Q1, _ = W.sub(1).collapse()
Q1_v, _ = W.sub(2).collapse()  

#############################################################################################################

    # Define ds measure

ds = Measure("ds", domain=domain, subdomain_data=facet_tag)  



#############################################################################################################

n = FacetNormal(domain)   
nh = facet_normal_approximation(V1, facet_tag, 4, tangent=False)

    
dataname = 'Data/data.txt'
data_np = np.loadtxt(dataname)
data_aux = data_np[:,0:2]

indices = []
for i in range(len(data_aux)):
    a,y,j = closest_point(domain,data_aux[i],0.001)
    indices.append(int(j))

u = Function(V)
p = Function(Q)
nu_t1 = Function(Q)
d = Function(Q1)
u_aux = Function(V)

    # AnsysFluent to FEniCSX 
    
    
###################################################################################################################

#      0 = x_coordinate  1 = y_coordinate   2 = nu turbulenta  3 = nu effective  4 = x_velocity  5 = y_velocity  6 = density  7 = pressure  # 

###################################################################################################################

for i in range(len(indices)):
    nu_t1.x.array[indices[i]] = data_np[i,2]
    
    u_aux.x.array[2*indices[i]]=data_np[i,4]
    
    u_aux.x.array[2*indices[i]+1]=data_np[i,5]
    
    d.x.array[indices[i]] = data_np[i,8]
    
    p.x.array[indices[i]]=data_np[i,7]
    
u.interpolate(u_aux)

nu_t = Function(Q1)
nu_t.interpolate(nu_t1)
 
  
    
# Constantes del modelo
Cv1 = Constant(domain, PETSc.ScalarType(7.1))
nu_p = Constant(domain, PETSc.ScalarType(9.4e-5))
# Lista de valores para nu_t
nu_t_list = nu_t.x.array[:]  # Aquí colocas tus valores para nu_t

nu = 9.4e-5           # Valor de la viscosidad cinemática molecular

C_v1 = 7.1

# Función para resolver el polinomio para cada nu_t
def calcular_tilde_nu(nu_t, nu, C_v1):
    # Coeficientes del polinomio de cuarto grado
    coeffs = [1, -nu_t, 0, 0, -nu_t * (C_v1**3)*nu**3]
    
    # Encontrar las raíces del polinomio
    roots = np.roots(coeffs)
    
    # Seleccionar la raíz real positiva
    tilde_nu = np.real(roots[roots > 0])
    
    # Selecciona la raíz más pequeña real positiva
    return tilde_nu[0] if len(tilde_nu) > 0 else 0.0000000001



# Aplicar la función a cada valor de la lista nu_t
tilde_nu_list = [calcular_tilde_nu(nu_t, nu, C_v1) for nu_t in nu_t_list]


nu_tilde = Function(Q1)
nu_tilde.x.array[:] = tilde_nu_list
nu_tilde.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)

    
    
grad_u = ufl.grad(u)
Omega = 0.5 * (grad_u - ufl.transpose(grad_u))    

V_adj = V        # para ψ₍ᵤ₎
Q_adj = Q        # para ψ₍ₚ₎
Q1_adj = Q  # para ψ₍ν̃₎

# =============================================================================
# 4. Parámetros y expresiones auxiliares (modelo SA con expresiones explícitas)
# =============================================================================
rho_val   = 1.225
mu_val    = 1e-3
sigma_val = 2.0/3.0
c_b1      = 0.1355
c_b2      = 0.3
c_w1      = 0.3
kappa     = 0.41

# --- Relación clásica para la viscosidad turbulenta ---
# Para ρ=1, la viscosidad cinemática ν = mu_val.
# Definimos: χ = nu_tilde/nu = nu_tilde/mu_val.
C_v1 = Constant(domain, PETSc.ScalarType(7.1))
chi_expr = nu_tilde/nu
f_v1_expr = chi_expr**3/(chi_expr**3 + C_v1**3)
f_v2_expr = 1 - chi_expr/(1 + chi_expr * f_v1_expr)
# Derivada de f_v1:
df_v1_dchi = 3 * chi_expr**2 * C_v1**3/(chi_expr**3 + C_v1**3)**2
df_v1_dnu_tilde = df_v1_dchi*(1.0/nu)
df_v2_dnu_tilde = -(((1.0/nu)*(1 + chi_expr*f_v1_expr)
                    - chi_expr*(1.0/nu)*(f_v1_expr + chi_expr*df_v1_dchi))
                    /(1+chi_expr*f_v1_expr)**2)
# Definir la viscosidad turbulenta efectiva (primal) de forma explícita:
nu_t_expr = nu_tilde * f_v1_expr

dnu_t_dnu_tilde = f_v1_expr + nu_tilde*(df_v1_dchi/nu)
mu_t_prime = dnu_t_dnu_tilde*rho_val


S_expr = ufl.sqrt(2*ufl.inner(Omega, Omega) + 1e-12)
tilde_S_expr = S_expr + nu_tilde/(kappa**2*(d+1e-4)**2)*f_v2_expr
dtildeS_dnu = 1.0/(kappa**2*(d+1e-4)**2)

# --- Modelo SA: Definir f_w y su derivada ---
# Definir: r = nu_tilde/(tilde_S * kappa^2 * (d+ε)^2)
r_expr = nu_tilde/(tilde_S_expr*kappa**2*(d+1e-4)**2)
C_w2 = Constant(domain, PETSc.ScalarType(0.3))
C_w3 = Constant(domain, PETSc.ScalarType(2.0))
g_expr = r_expr + C_w2*(r_expr**6 - r_expr)
f_w_expr = g_expr * ((1 + C_w3**6)/(g_expr**6 + C_w3**6))**(1/6)
# Derivada de r respecto a nu_tilde:
dr_dnu = 1/(tilde_S_expr*kappa**2*(d+1e-4)**2) - nu_tilde/(tilde_S_expr**2*kappa**2*(d+1e-4)**2)*dtildeS_dnu
# Derivada de f_w respecto a g:
phi_expr = ((1+C_w3**6)/(g_expr**6+C_w3**6))**(1/6)
df_w_dg = phi_expr - g_expr*(6*g_expr**5)/(g_expr**6+C_w3**6)*(1/6)*phi_expr
dg_dr = 1 + C_w2*(6*r_expr**5 - 1)
df_w_dnu = df_w_dg * dg_dr * dr_dnu

# --- Parte difusiva de la ecuación de transporte para ν̃ ---
# Se define: K(ν̃) = μ + σρ ν̃ y K'(ν̃)= σρ.
K_expr = nu + nu_tilde
K_prime = 1

mu_t_expr_total = nu_t_expr*rho_val

# --- Acoplamiento de la dependencia de μ_t en la ecuación de momentum ---
# Usamos la relación explícita definida arriba: mu_t_expr = nu_t_expr.
# Su derivada con respecto a nu_tilde es: dnu_t/dnu_tilde = dnu_t_dnu_tilde.
    
# =============================================================================
# 5. Medidas para el dominio y la frontera
# =============================================================================
dx = ufl.dx
ds = ufl.Measure("ds", domain=domain, subdomain_data=facet_tag)
ds_inlet  = ds(1)
ds_outlet = ds(2)
ds_walls  = ds(3)
ds_cyl    = ds(4)

# =============================================================================
# 6. Construir el espacio mixto para el sistema adjunto
# =============================================================================
element_u = V_adj.ufl_element()  # para ψ_u (vector)
element_p = Q_adj.ufl_element()  # para ψ_p (escalar)
element_nu = Q1_adj.ufl_element()  # para ψ_nu (escalares)
mixed_elem = MixedElement([element_u, element_p, element_nu])
W_adj = fem.FunctionSpace(domain, mixed_elem)

# Definir funciones de ensayo y de ensayo en el espacio mixto:
Psi = ufl.TrialFunction(W_adj)  # (ψ_u, ψ_p, ψ_nu)
Phi = ufl.TestFunction(W_adj)   # (v, q, w)
psi_u_m, psi_p_m, psi_nu_m = ufl.split(Psi)
v, q, w = ufl.split(Phi)

# =============================================================================
# 7. Formular el sistema adjunto monolítico (volumétrico + frontera)
# =============================================================================
# 7.1. Ecuación adjunta de Continuidad:
a_cont = ufl.inner(ufl.div(psi_u_m), q)*dx + ufl.inner(psi_u_m, q*ufl.FacetNormal(domain))*ds_outlet

# 7.2. Ecuación adjunta de Momentum:
a_mom = (
    -rho_val*ufl.inner(ufl.dot(u, ufl.grad(psi_u_m)), v)*dx
    + ufl.inner(ufl.transpose(ufl.grad(u))*psi_u_m, v)*dx
    - ufl.inner(ufl.grad(psi_p_m), v)*dx
    - ufl.inner((mu_val+mu_t_expr_total)*(ufl.grad(psi_u_m)+ufl.transpose(ufl.grad(psi_u_m))), ufl.grad(v))*dx
    + ufl.inner(psi_nu_m*ufl.grad(nu_tilde), v)*dx
    + ufl.inner(ufl.div(c_b1 * nu_tilde * psi_nu_m*(Omega/S_expr)), v)*dx
)
a_mom += ufl.inner(
    (mu_val+mu_t_expr_total)*(ufl.grad(psi_u_m)+ufl.transpose(ufl.grad(psi_u_m)))*ufl.FacetNormal(domain)
    - rho_val*psi_u_m*ufl.dot(u, ufl.FacetNormal(domain)), v)*ds_outlet

# 7.3. Ecuación adjunta de Transporte (para ν̃):
a_nu_diff = (
    (1/sigma_val)*ufl.inner(K_expr*ufl.grad(psi_nu_m), ufl.grad(w))*dx
    + (2*c_b2/sigma_val)*ufl.inner(ufl.grad(psi_nu_m), ufl.grad(w))*dx
    + rho_val*ufl.inner(ufl.grad(nu_tilde), ufl.grad(psi_nu_m))*w*dx
)
a_nu_couple = mu_t_prime*ufl.inner((ufl.grad(u)+ufl.transpose(ufl.grad(u))), ufl.grad(psi_u_m))*w*dx
a_nu_vol = a_nu_diff + a_nu_couple

# Términos de frontera para la parte difusiva (según la derivación):
n = ufl.FacetNormal(domain)
BT_diff = (
    - (1/sigma_val)*ufl.inner(psi_nu_m, K_prime*ufl.dot(ufl.grad(nu_tilde), n) + K_expr*ufl.dot(ufl.grad(w), n))*ds_outlet
    + (1/sigma_val)*ufl.inner(K_expr*ufl.dot(ufl.grad(psi_nu_m), n), w)*ds_outlet
    - (2*c_b2/sigma_val)*ufl.inner(ufl.dot(ufl.grad(nu_tilde), n), w)*ds_outlet
)
a_nu_total = a_nu_vol + BT_diff

# Términos extra en la ecuación de transporte por producción y destrucción:
a_nu_prod_extra = - c_b1*(tilde_S_expr + nu_tilde*dtildeS_dnu)*psi_nu_m*w*dx
a_nu_dest_extra = c_w1*(f_w_expr + nu_tilde*df_w_dnu)*(nu_tilde/d**2)*psi_nu_m*w*dx

a_nu_total = a_nu_total + a_nu_prod_extra + a_nu_dest_extra

# Sumar todos los bloques del sistema adjunto:
a_total = a_cont + a_mom + a_nu_total
L_total = 0  # Suponemos que no hay fuente externa (o se añaden ∂J/∂variable si se conoce)

# =============================================================================
# 8. Imponer condiciones de frontera para el sistema adjunto
# =============================================================================

V1, _ = W.sub(0).collapse()  # Para ψ₍ᵤ₎ (vector)
Q1_sub, _ = W.sub(1).collapse()  # Para ψ₍ₚ₎ (escalar)
Q2_sub, _ = W.sub(2).collapse()  # Para ψ₍ν̃₎ (escalar)

fdim = domain.topology.dim - 1

def upstream(x):
    a = np.less(x[0], 0)
    return np.logical_and(np.greater(x[0]**2 + x[1]**2, 5**2), a)

def downstream(x):
    return np.isclose(x[0], Lx)

def walls(x):
    a = np.greater(x[0], 0)
    b = np.less(x[0], Lx)
    return np.logical_and(np.greater(x[0]**2 + x[1]**2, 5**2),
                          np.logical_and(a, b))

def obstacle(x):
    return np.less(x[0]**2 + x[1]**2, 5**2)

def all_boundaries(x):
    return np.logical_or(np.logical_or(upstream(x), downstream(x)),
                         np.logical_or(walls(x), obstacle(x)))


# Localizar las entidades de frontera:
up_facets = dolfinx.mesh.locate_entities_boundary(domain, fdim, upstream)
wall_facets = dolfinx.mesh.locate_entities_boundary(domain, fdim, walls)
cyl_facets = dolfinx.mesh.locate_entities_boundary(domain, fdim, obstacle)
down_facets = dolfinx.mesh.locate_entities_boundary(domain, fdim, downstream)
all_facets = dolfinx.mesh.locate_entities_boundary(domain, fdim,all_boundaries)

# Usar locate_dofs_topological para cada subespacio:
up_f = dolfinx.fem.locate_dofs_topological((W.sub(0), V1), fdim, up_facets)
wall_f = dolfinx.fem.locate_dofs_topological((W.sub(0), V1), fdim, wall_facets)
cyl_f = dolfinx.fem.locate_dofs_topological((W.sub(0), V1), fdim, cyl_facets)
down_f = dolfinx.fem.locate_dofs_topological((W.sub(1), Q1_sub), fdim, down_facets)
all_f = dolfinx.fem.locate_dofs_topological((W.sub(2), Q1_sub), fdim, all_facets)

# Definir funciones de condición mediante interpolación:
def zero_vector(x):
    return np.zeros((2, x.shape[1]), dtype=np.float64)

def cylinder_condition(x):
    return np.array([[2.0]*x.shape[1],
                     [0.0]*x.shape[1]], dtype=np.float64)

u_icond = fem.Function(V1, name="u_inlet_bc")
u_wall = fem.Function(V1, name="u_wall_bc")
u_cyl = fem.Function(V1, name="u_cylinder_bc")
u_icond.interpolate(zero_vector)
u_wall.interpolate(zero_vector)
u_cyl.interpolate(cylinder_condition)

bc_u = dirichletbc(u_icond, up_f, W.sub(0))
bc_w = dirichletbc(u_wall, wall_f, W.sub(0))
bc_cyl = dirichletbc(u_cyl, cyl_f, W.sub(0))

# Para ψₚ (componente 1): se impone 0 en el downstream.
def zero_scalar(x):
    return np.zeros((1, x.shape[1]), dtype=np.float64)

p_icond = fem.Function(Q1_sub, name="p_outlet_bc")
p_icond.interpolate(zero_scalar)
bc_p = dirichletbc(p_icond, down_f, W.sub(1))
bc_nu = dirichletbc(p_icond, all_f, W.sub(2))


bc = [bc_u, bc_w, bc_cyl, bc_p, bc_nu]


# =============================================================================
Ar = lhs(a_total)

bl = rhs(a_total)



problem = dolfinx.fem.petsc.LinearProblem(Ar, bl, bcs=bc, petsc_options={"ksp_type": "gmres", "pc_type": "ilu","ksp_max_it": 1000 })

Phi = problem.solve()

psi_u_sol, psi_p_sol, psi_nu_sol = Psi.split()

I can pass on anything you need to understand it. Sorry for the length of the code.
Thank you for your support.

Dear @Karlosjusus

First of all, you have not supplied your mesh, which means that we can’t run the code.
Secondly. Could you point out what part of your code throws this error?
If so, could you remove all code that is not needed to reach the error?

Sorry, here are data.txt and the mesh.

I tried to reduce the code but, now I got

AttributeError                            Traceback (most recent call last)
Cell In[2], line 1
----> 1 import dolfinx
      2 import gmsh
      3 from mpi4py import MPI

File /usr/lib/petsc/lib/python3/dist-packages/dolfinx/__init__.py:40
     38 from dolfinx import common
     39 from dolfinx import cpp as _cpp
---> 40 from dolfinx import fem, geometry, graph, io, jit, la, log, mesh, nls, plot
     41 # Initialise logging
     42 from dolfinx.common import (TimingType, git_commit_hash, has_debug, has_kahip,
     43                             has_parmetis, list_timings, timing)

File /usr/lib/petsc/lib/python3/dist-packages/dolfinx/fem/__init__.py:11
      8 from dolfinx.cpp.fem import (IntegralType,
      9                              create_nonmatching_meshes_interpolation_data, transpose_dofmap)
     10 from dolfinx.cpp.fem import create_sparsity_pattern as _create_sparsity_pattern
---> 11 from dolfinx.fem.assemble import (apply_lifting, assemble_matrix,
     12                                   assemble_scalar, assemble_vector,
     13                                   create_matrix, create_vector, set_bc)
     14 from dolfinx.fem.bcs import (DirichletBC, bcs_by_block, dirichletbc,
     15                              locate_dofs_geometrical, locate_dofs_topological)
     16 from dolfinx.fem.dofmap import DofMap

File /usr/lib/petsc/lib/python3/dist-packages/dolfinx/fem/assemble.py:22
     20 from dolfinx.cpp.fem import pack_constants as _pack_constants
     21 from dolfinx.fem.bcs import DirichletBC
---> 22 from dolfinx.fem.forms import Form
     25 def pack_constants(form: typing.Union[Form, typing.Sequence[Form]]) -> typing.Union[np.ndarray,
     26                                                                                     typing.Sequence[np.ndarray]]:
     27     """Compute form constants.
     28 
     29     Pack the `constants` that appear in forms. The packed constants can
   (...)
     42 
     43     """

File /usr/lib/petsc/lib/python3/dist-packages/dolfinx/fem/forms.py:17
     15 import ufl
     16 from dolfinx import cpp as _cpp
---> 17 from dolfinx import default_scalar_type, jit
     18 from dolfinx.fem import IntegralType
     19 from dolfinx.fem.function import FunctionSpaceBase

File /usr/lib/petsc/lib/python3/dist-packages/dolfinx/jit.py:17
     14 from mpi4py import MPI
     16 import ffcx
---> 17 import ffcx.codegeneration.jit
     18 import ufl
     20 __all__ = ["ffcx_jit", "get_options", "mpi_jit_decorator"]

File /usr/lib/python3/dist-packages/ffcx/codegeneration/jit.py:21
     18 import cffi
     20 import ffcx
---> 21 import ffcx.naming
     23 logger = logging.getLogger("ffcx")
     24 root_logger = logging.getLogger()

File /usr/lib/python3/dist-packages/ffcx/naming.py:16
     13 import ffcx
     14 import ufl
---> 16 from .element_interface import convert_element
     19 def compute_signature(ufl_objects: typing.List[
     20     typing.Union[ufl.Form, ufl.FiniteElementBase,
     21                  typing.Tuple[ufl.core.expr.Expr, npt.NDArray[np.float64]]]], tag: str) -> str:
     22     """Compute the signature hash.
     23 
     24     Based on the UFL type of the objects and an additional optional
     25     'tag'.
     26 
     27     """

File /usr/lib/python3/dist-packages/ffcx/element_interface.py:12
      9 import warnings
     11 import basix
---> 12 import basix.ufl
     13 import ufl
     14 import numpy as np

File /usr/lib/python3/dist-packages/basix/ufl.py:22
     14 from ufl.finiteelement import FiniteElementBase as _FiniteElementBase
     16 import basix as _basix
     18 _spacemap = {
     19     _basix.SobolevSpace.L2: _ufl.sobolevspace.L2,
     20     _basix.SobolevSpace.H1: _ufl.sobolevspace.H1,
     21     _basix.SobolevSpace.H2: _ufl.sobolevspace.H2,
---> 22     _basix.SobolevSpace.HInf: _ufl.sobolevspace.HInf,
     23     _basix.SobolevSpace.HDiv: _ufl.sobolevspace.HDiv,
     24     _basix.SobolevSpace.HCurl: _ufl.sobolevspace.HCurl,
     25     _basix.SobolevSpace.HEin: _ufl.sobolevspace.HEin,
     26     _basix.SobolevSpace.HDivDiv: _ufl.sobolevspace.HDivDiv,
     27 }
     30 def _ufl_sobolev_space_from_enum(s: _basix.SobolevSpace):
     31     """Convert a Basix Sobolev space enum to a UFL Sobolev space.
     32 
     33     Args:
   (...)
     37         UFL Sobolev space
     38     """

AttributeError: module 'ufl.sobolevspace' has no attribute 'HInf'

It seems like you have an incompatible version of ufl installed. See for instance similar topics such as: Difficulty getting fenics working

Please ensure that you can run your code, and provide a full error traceback.

I have uninstalled my previous version and installed version 0.9. I’m changing the parts of the code that are not up to date, but I’ve got another problem. I was using an old version of facet_normal_approximation

def facet_normal_approximation(V, mt, mt_id, tangent=False): 
                               #jit_options: dict = {}, form_compiler_options: dict = {}):

    comm = V.mesh.comm
    n = ufl.FacetNormal(V.mesh)
    nh = _fem.Function(V)
    u, v = ufl.TrialFunction(V), ufl.TestFunction(V)
    ds = ufl.ds(domain=V.mesh, subdomain_data=mt, subdomain_id=mt_id)
    if tangent:
        if V.mesh.geometry.dim == 1:
            raise ValueError("Tangent not defined for 1D problem")
        elif V.mesh.geometry.dim == 2:
            a = ufl.inner(u, v) * ds
            L = ufl.inner(ufl.as_vector([-n[1], n[0]]), v) * ds
        else:
            def tangential_proj(u, n):
                """
                See for instance:
                https://link.springer.com/content/pdf/10.1023/A:1022235512626.pdf
                """
                return (ufl.Identity(u.ufl_shape[0]) - ufl.outer(n, n)) * u
            c = fem.Constant(V.mesh, [1, 1, 1])
            a = ufl.inner(u, v) * ds
            L = ufl.inner(tangential_proj(c, n), v) * ds
    else:
        a = (ufl.inner(u, v) * ds)
        L = ufl.inner(n, v) * ds

    # Find all dofs that are not boundary dofs
    imap = V.dofmap.index_map
    all_blocks = np.arange(imap.size_local, dtype=np.int32)
    top_blocks = _fem.locate_dofs_topological(V, V.mesh.topology.dim - 1, mt.find(mt_id))
    deac_blocks = all_blocks[np.isin(all_blocks, top_blocks, invert=True)]

    # Note there should be a better way to do this
    # Create sparsity pattern only for constraint + bc
    bilinear_form = _fem.form(a)
    pattern = _fem.create_sparsity_pattern(bilinear_form)
    pattern.insert_diagonal(deac_blocks)
    pattern.finalize()
    u_0 = _fem.Function(V)
    u_0.vector.set(0)

    bc_deac = _fem.dirichletbc(u_0, deac_blocks)
    A = _cpp.la.petsc.create_matrix(comm, pattern)
    A.zeroEntries()

    # Assemble the matrix with all entries
    form_coeffs = dolfinx.cpp.fem.pack_coefficients(bilinear_form._cpp_object)
    form_consts = _cpp.fem.pack_constants(bilinear_form._cpp_object)
    _cpp.fem.petsc.assemble_matrix(A, bilinear_form._cpp_object,
                                   form_consts, form_coeffs, [bc_deac._cpp_object])
    if bilinear_form.function_spaces[0] is bilinear_form.function_spaces[1]:
        A.assemblyBegin(PETSc.Mat.AssemblyType.FLUSH)  # type: ignore
        A.assemblyEnd(PETSc.Mat.AssemblyType.FLUSH)  # type: ignore
        _cpp.fem.petsc.insert_diagonal(A, bilinear_form.function_spaces[0], [bc_deac._cpp_object], 1.0)
    A.assemble()
    linear_form = _fem.form(L)
    b = _fem.petsc.assemble_vector(linear_form)

    _fem.petsc.apply_lifting(b, [bilinear_form], [[bc_deac]])
    b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE)  # type: ignore
    _fem.petsc.set_bc(b, [bc_deac])

    # Solve Linear problem
    solver = PETSc.KSP().create(V.mesh.comm)  # type: ignore
    solver.setType("cg")
    solver.rtol = 1e-8
    solver.setOperators(A)
    solver.solve(b, nh.vector)
    nh.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)  # type: ignore
    return nh    



and now I get this error:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[5], line 219
    216 #############################################################################################################
    218 n = FacetNormal(domain)   
--> 219 nh = facet_normal_approximation(V1, facet_tag, 4, tangent=False)
    222 dataname = 'Data/data.txt'
    223 data_np = np.loadtxt(dataname)

Cell In[5], line 114, in facet_normal_approximation(V, mt, mt_id, tangent)
    112 pattern.finalize()
    113 u_0 = _fem.Function(V)
--> 114 u_0.vector.set(0)
    116 bc_deac = _fem.dirichletbc(u_0, deac_blocks)
    117 A = _cpp.la.petsc.create_matrix(comm, pattern)

AttributeError: 'Function' object has no attribute 'vector'

What do I have to change or where can I find a new compatible version?

Thank you so much for your patience

facet_normal_approximation is a function grabbed from dolfinx_mpc, which has compatible releases with dolfinx:

See that function for updated syntax