When using a custom quadrature routine on each cell in a mesh, I get a different result for the \ell^1 norm when assembling two forms and adding the resulting matrices versus assembling the sum of the forms. Consider the following MWE:
#Import packages
from mpi4py import MPI
from petsc4py import PETSc
from dolfinx import mesh as dmesh, fem
import dolfinx.fem.petsc
import ufl
import numpy as np
import basix
def verts_to_bbox(verts):
assert verts.shape == (3, 4)
xL, xU = verts[0].min(), verts[0].max()
yL, yU = verts[1].min(), verts[1].max()
bbox = np.round([xL, yL, xU, yU], decimals=9)
return bbox
#Problem parameters
nx, ny = 2, 2 #Number of quadrilaterals in x and y directions
#Define quadrature rule for each quadrilateral
x_vals = np.linspace(0., 1., nx+1)
y_vals = np.linspace(0., 1., ny+1)
quad = {}
for i in range(nx):
for j in range(ny):
bbox = np.round([x_vals[i], y_vals[j], x_vals[i+1], y_vals[j+1]], decimals=9)
qp, qw = basix.make_quadrature(basix.CellType.quadrilateral, (i+j)%4+1)
quad[tuple(bbox)] = [qp, qw]
#Create mesh
mesh = dmesh.create_unit_square(MPI.COMM_WORLD, nx, ny, dmesh.CellType.quadrilateral)
comm = mesh.comm
tdim = mesh.topology.dim
imap = mesh.topology.index_map(tdim)
all_cells = np.arange(imap.size_local+imap.num_ghosts, dtype=np.int32)
cell_tags = dmesh.meshtags(mesh, tdim, entities=all_cells, values=all_cells)
dx_all = ufl.Measure('dx', domain=mesh, subdomain_id=tuple(all_cells), subdomain_data=cell_tags)
#Define function space
V = fem.functionspace(mesh, ('CG', 1))
u, v = ufl.TrialFunction(V), ufl.TestFunction(V)
#Define form0
form0 = ufl.inner(ufl.grad(u), ufl.grad(v))*dx_all
#Define form1
c2v = dmesh.entities_to_geometry(mesh, tdim, all_cells, False)
verts = mesh.geometry.x
form1 = PETSc.ScalarType(0.)
for cut_cell in all_cells:
#Get bounding box
cell_verts = verts[c2v[cut_cell]].T
bbox = verts_to_bbox(cell_verts)
#Create boundary term
qp, qw = quad[tuple(bbox)]
metadata={'quadrature_rule': 'custom', 'quadrature_points': qp, 'quadrature_weights':qw}
dx_cell = ufl.Measure('dx', domain=mesh, subdomain_id=cut_cell, subdomain_data=cell_tags, metadata=metadata)
form1 += u*v*dx_cell
#Assemble form0
mat0 = fem.petsc.assemble_matrix(fem.form(form0))
mat0.assemble()
_, _, data0 = mat0.getValuesCSR()
mat0_l1 = comm.allreduce(np.sum(np.abs(data0)), op=MPI.SUM)
#Assemble form1
mat1 = fem.petsc.assemble_matrix(fem.form(form1))
mat1.assemble()
_, _, data1 = mat1.getValuesCSR()
mat1_l1 = comm.allreduce(np.sum(np.abs(data1)), op=MPI.SUM)
#Sum assembled matrices
mat0.axpy(1., mat1)
_, _, sum_data01 = mat0.getValuesCSR()
sum_mat01_l1 = comm.allreduce(np.sum(np.abs(sum_data01)), op=MPI.SUM)
#Assemble form0+form1
form01 = form0+form1
mat01 = fem.petsc.assemble_matrix(fem.form(form01))
mat01.assemble()
_, _, data01 = mat01.getValuesCSR()
mat01_l1 = comm.allreduce(np.sum(np.abs(data01)), op=MPI.SUM)
print(comm.rank, mat0_l1, mat1_l1, sum_mat01_l1, mat01_l1)
Summing the assembled matrices and then taking the norm gives a consistent result when using a different number of ranks. On the other hand, assembling the sum of the forms gives inconsistent results. When running in serial the result is:
0 21.333333333333314 1.0000000000000002 21.124999999999986 32.24999999999998
while on two ranks the result is
0 21.333333333333318 1.0 21.12499999999999 21.8611111111111
1 21.333333333333318 1.0 21.12499999999999 21.8611111111111
Is this a known bug or am I doing something completely wrong?