Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form compiler has to compute CellVolume #140

Closed
jorgensd opened this issue Dec 30, 2022 · 3 comments
Closed

Form compiler has to compute CellVolume #140

jorgensd opened this issue Dec 30, 2022 · 3 comments

Comments

@jorgensd
Copy link
Sponsor Member

Is there any specific reason for the following code:

@memoized_handler
def cell_volume(self, o):
if self._preserve_types[o._ufl_typecode_]:
return o
domain = o.ufl_domain()
if not domain.is_piecewise_linear_simplex_domain():
# Don't lower for non-affine cells, instead leave it to
# form compiler
warnings.warn("Only know how to compute the cell volume of an affine cell.")
return o
r = self.jacobian_determinant(JacobianDeterminant(domain))
r0 = ReferenceCellVolume(domain)
return abs(r * r0)

To me, it seems like this should work for both affine and non-affine cells. I tested this locally with DOLFINx (by commenting out the if clause, with the following code:

import gmsh
import numpy as np
import ufl
from dolfinx import fem, io
from mpi4py import MPI

# Generate a mesh with non-affine cells
gdim = 2
mesh_comm = MPI.COMM_WORLD
model_rank = 0
if mesh_comm.rank == model_rank:
    gmsh.initialize()
    rectangle = gmsh.model.occ.addRectangle(0, 0, 0, 1, 1, tag=1)
    obstacle = gmsh.model.occ.addDisk(0.5, 0.5, 0, 0.3, 0.3)
    fluid = gmsh.model.occ.cut([(gdim, rectangle)], [(gdim, obstacle)])
    gmsh.model.occ.synchronize()
    volumes = gmsh.model.getEntities(dim=gdim)
    gmsh.model.addPhysicalGroup(volumes[0][0], [volumes[0][1]], 1)
    gmsh.option.setNumber("Mesh.Algorithm", 8)
    gmsh.option.setNumber("Mesh.RecombinationAlgorithm", 2)
    gmsh.option.setNumber("Mesh.RecombineAll", 1)
    gmsh.option.setNumber("Mesh.SubdivisionAlgorithm", 1)
    gmsh.model.mesh.generate(gdim)
domain, _, _ = io.gmshio.model_to_mesh(
    gmsh.model, mesh_comm, model_rank, gdim=gdim)
gmsh.finalize()


Ve = fem.FunctionSpace(domain, ("DG", 0))
elmVol_ufl = ufl.CellVolume(domain)
elmVol_expr = fem.Expression(elmVol_ufl, Ve.element.interpolation_points())
elmVol = fem.Function(Ve, name="Element Volume (expression)")
elmVol.interpolate(elmVol_expr)

q_degree = 3
vol2 = fem.Function(Ve)
fem.petsc.assemble_vector(vol2.vector, fem.form(
    1*ufl.TestFunction(Ve)*ufl.dx(metadata={"quadrature_degree": q_degree})))
vol2.x.scatter_forward()
print(vol2.x.array - elmVol.x.array)
assert np.allclose(vol2.x.array, elmVol.x.array)
vol2.name = "ElementVolume (assembly)"

with io.XDMFFile(domain.comm, "cell_vol.xdmf", "w") as xdmf:
    xdmf.write_mesh(domain)
    xdmf.write_function(elmVol)
    xdmf.write_function(vol2)

Yielding
cellvolume

@wence-
Copy link
Collaborator

wence- commented Dec 30, 2022

That lowering is a one point quadrature for computing the cell volume. If your cell is a way from affine, this is a bad approximation I think.

@jorgensd
Copy link
Sponsor Member Author

jorgensd commented Dec 30, 2022

That lowering is a one point quadrature for computing the cell volume. If your cell is a way from affine, this is a bad approximation I think.

How can you see that the lowering is to a single point quadrature? (I know the expression interpolation in DOLFINx is equivalent to a one point quadrature, but that is not the main point here).

I cannot spot that assumption in the referenced ufl code, as I would expect JacobianDeterminant to be what we use in general for integral scaling of non-affine and affine geometries, but maybe I've missed something.

@jorgensd
Copy link
Sponsor Member Author

jorgensd commented Jan 2, 2023

That lowering is a one point quadrature for computing the cell volume. If your cell is a way from affine, this is a bad approximation I think.

Oh, right. It is because this doesn't give the form compiler any instructions on summing the jacobians for each quadrature point before multiplying by anything else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants