Hey there,
I was wondering if anyone had any idea on how one could go about calculating more complex areas in FEnicSx? I’ve been stuck with trying to calculate the area of a deformed object using the Jacobian in FEnicSx.
My problem is that I want to calculate the area of a deformed object (A=?) with the untransformed area being a circle of unitary area (A_0 =1). The value of J will be updated at every time step in my linear elasticity problem.
QUESTION: How do we calculate Area(E), assuming D is the undeformed reference configuration (circle), E is the deformed domain, and J is the Jacobian:
Area(E)=\int \int_E \space dx \space dy =\int \int_D |J| \space du \space dv = ?
In legacy FEnicS, I believe it would have been calculated using:
assemble(J*dx)
However, been unable to understand how to do this with the dolfinx documentation to determine how J=ufl.det(F) and ufl.det objects interact in this new scenario. Potentially need to interpolate into some function space? I’ve also attached some code with the last few lines being roughly how I originally envisioned calculating the area (originally was doing this without J). Moreso here for anyone to see how I’m generating the mesh, measures, function space, and jacobian:
#----------------
# GENERAL IMPORTS
#----------------
import ufl
import numpy as np
import gmsh
from petsc4py import PETSc
from mpi4py import MPI
import dolfinx
from dolfinx import fem, mesh, plot, log, default_scalar_type, geometry
from dolfinx.io import gmshio
from dolfinx.fem.petsc import assemble_matrix, create_vector, assemble_vector, apply_lifting
import basix
#-------------------
# CREATE CIRCLE MESH
#-------------------
# Initialise the GMSH module
gmsh.initialize()
# Create the membrane and start the computations by the GMSH CAD kernel, to generate the relevant underlying data structures
# Create Circular Mesh with area of A0 = 1
membrane = gmsh.model.occ.addDisk(0, 0, 0, np.sqrt(1/np.pi), np.sqrt(1/np.pi)) # x, y, z, x-radius, y-radius
gmsh.model.occ.synchronize()
# Make membrane a physical surface for GMSH to recognise when generating the mesh
gdim = 2 # 2D Geometric Dimension of the Mesh
gmsh.model.addPhysicalGroup(gdim, [membrane], 0) # Dimension, Entity tag, Physical tag
# Generate 2D Mesh with uniform mesh size
gmsh.option.setNumber("Mesh.CharacteristicLengthMin", 0.023)
gmsh.option.setNumber("Mesh.CharacteristicLengthMax", 0.023)
gmsh.model.mesh.generate(gdim)
# Create a mesh from the GMSH model
gmsh_model_rank = 0
mesh_comm = MPI.COMM_WORLD
domain, cell_markers, facet_markers = gmshio.model_to_mesh(gmsh.model, mesh_comm, gmsh_model_rank, gdim=gdim)
domain.name = "initial_mesh"
gmsh.write("circle.msh")
# Finalize GMSH
gmsh.finalize()
#---------------------------------
# GENERAL MEASURES AND COORDINATES
#---------------------------------
mesh_degree = domain.geometry.cmap.degree
# Global Spatial Coordinates as a Vector-Valued Expression i.e. x[0] = x, x[1] = y
x_spatial = ufl.SpatialCoordinate(domain)
metadata = {"quadrature_degree": 4}
# Define Measure Over Cells of Mesh
dx = ufl.Measure('dx', domain=domain, metadata=metadata)
# Define Measure Over Boundary of Mesh
ds = ufl.Measure('ds', domain=domain, metadata=metadata)
#----------------------------------------
# LINEAR ELASTICITY VECTOR FUNCTION SPACE
#----------------------------------------
# Vector-Valued Function Space for Linear Elasticity
v_cg1 = basix.ufl.element(family="Lagrange", cell=domain.topology.cell_name(), degree=mesh_degree, shape=(domain.geometry.dim, ))
V = fem.functionspace(mesh=domain, element=v_cg1)
# Trial and Test Functions for Linear Elasticity Problem (Mechanics Vectors)
# Initial Conditions: Mechanical System is at Rest
u = ufl.TrialFunction(V)#fem.Function(V)
v = ufl.TestFunction(V)
u_n = fem.Function(V)
u_n.name = "u_n"
u_0 = fem.Constant(domain, 0.0)
u_n.sub(0).interpolate(lambda x: np.full((x.shape[1],), u_0))
u_n.sub(1).interpolate(lambda x: np.full((x.shape[1],), u_0))
u_n.sub(0).collapse()
u_n.sub(1).collapse()
u_n.x.scatter_forward()
#-------------------
# CALCULATE JACOBIAN
#-------------------
# Spatial Dimension
spa_dim = len(x_spatial)
# Identity Tensor
I = ufl.variable(ufl.Identity(spa_dim))
# Deformation Gradient Tensor
F = ufl.variable(I + ufl.grad(u))
F_inv = ufl.variable(ufl.inv(F)) # F^-1
F_inv_tra = ufl.variable(F_inv.T) # F^-T
# Jacobian Function
J = ufl.det(F)
J_n = J
#------------------------------
# EXAMPLE INCORRECT CALCULATION
#------------------------------
# Calculate Mesh Area
def mesh_area(mesh_domain, jacobian):
area = fem.assemble_scalar(fem.form(fem.Constant(mesh_domain, 1.0)*jacobian*dx))
return area
A=mesh_area(domain, J)
Cheers,
Volkan