Skip to content

Commit aa228f1

Browse files
committed
Working UFL version
1 parent f817c31 commit aa228f1

1 file changed

Lines changed: 52 additions & 38 deletions

File tree

doc/demo/demo_hyperelasticity.py

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232

3333
# %%
3434
# Geometry and mesh (2D)
35-
L = 10.0 # Length
35+
L = 1.0 # Length
3636
W = 1.0 # Height
37-
nx, ny = 80, 8
37+
nx, ny = 40, 40
3838

3939
# %%
4040
domain = mesh.create_rectangle(MPI.COMM_WORLD, [[0.0, 0.0], [L, W]], [nx, ny], cell_type=CellType.quadrilateral)
@@ -44,44 +44,37 @@
4444

4545

4646
# %%
47-
# Boundary markers for Dirichlet and Neumann BCs
48-
def left(x):
49-
return np.isclose(x[0], 0.0)
50-
def right(x):
51-
return np.isclose(x[0], L)
47+
def bottom(x):
48+
return np.isclose(x[1], 0.0)
49+
def top(x):
50+
return np.isclose(x[1], W)
5251

5352

54-
# %%
55-
5653
# %%
5754
fdim = domain.topology.dim - 1
58-
left_facets = mesh.locate_entities_boundary(domain, fdim, left)
59-
right_facets = mesh.locate_entities_boundary(domain, fdim, right)
55+
bottom_facets = mesh.locate_entities_boundary(domain, fdim, bottom)
56+
top_facets = mesh.locate_entities_boundary(domain, fdim, top)
6057

6158
# %%
62-
# Mark facets: 1=left (fixed), 2=right (tension)
63-
marked_facets = np.hstack([left_facets, right_facets])
64-
marked_values = np.hstack([np.full_like(left_facets, 1), np.full_like(right_facets, 2)])
59+
marked_facets = np.hstack([bottom_facets, top_facets])
60+
marked_values = np.hstack([np.full_like(bottom_facets, 1), np.full_like(top_facets, 2)])
6561
sorted_facets = np.argsort(marked_facets)
6662
facet_tag = mesh.meshtags(domain, fdim, marked_facets[sorted_facets], marked_values[sorted_facets])
6763

68-
# %%
69-
# Dirichlet BC: fix left edge (all dofs)
70-
u_bc = np.array((0,) * domain.geometry.dim, dtype=default_scalar_type)
71-
left_dofs = fem.locate_dofs_topological(V, facet_tag.dim, facet_tag.find(1))
72-
bcs = [fem.dirichletbc(u_bc, left_dofs, V)]
64+
bottom_dofs = fem.locate_dofs_topological(V, facet_tag.dim, facet_tag.find(1))
65+
top_dofs = fem.locate_dofs_topological(V.sub(1), facet_tag.dim, facet_tag.find(2))
66+
u_D_bottom = np.array((0,) * domain.geometry.dim, dtype=default_scalar_type)
67+
u_D_top = fem.Constant(domain, 0.0)
68+
69+
bcs_u = [
70+
fem.dirichletbc(u_D_top, top_dofs, V.sub(1)),
71+
fem.dirichletbc(u_D_bottom, bottom_dofs, V),
72+
]
7373

74-
# %%
75-
# Body force and traction (2D)
76-
B = fem.Constant(domain, default_scalar_type((0, 0)))
77-
T = fem.Constant(domain, default_scalar_type((0, 0)))
7874

7975
# %%
80-
# Solution and test functions
8176
u = fem.Function(V)
8277
v = ufl.TestFunction(V)
83-
84-
# %%
8578
d = len(u)
8679
I = ufl.variable(ufl.Identity(d))
8780
F = ufl.variable(I + ufl.grad(u))
@@ -95,25 +88,50 @@ def right(x):
9588
nu = default_scalar_type(0.3)
9689
mu = fem.Constant(domain, E / (2 * (1 + nu)))
9790
lmbda = fem.Constant(domain, E * nu / ((1 + nu) * (1 - 2 * nu)))
98-
99-
# %%
10091
# Strain energy and first Piola-Kirchhoff stress
10192
psi = (mu / 2) * (Ic - 2) - mu * ufl.ln(J) + (lmbda / 2) * (ufl.ln(J)) ** 2
10293
P = ufl.diff(psi, F)
94+
dP = ufl.diff(P, F)
10395

10496
# %%
10597
# Measures for integration
10698
metadata = {"quadrature_degree": 2}
10799
ds = ufl.Measure("ds", domain=domain, subdomain_data=facet_tag, metadata=metadata)
108100
dx = ufl.Measure("dx", domain=domain, metadata=metadata)
109101

102+
# %%
103+
# from dolfinx.fem import Expression, functionspace, Function
104+
# import basix
105+
106+
# # Choose quadrature degree and get quadrature points for the cell type
107+
# quadrature_degree = 2
108+
# cell_name = domain.topology.cell_name()
109+
# quadrature_points, _ = basix.make_quadrature(getattr(basix.CellType, cell_name), quadrature_degree)
110+
111+
# # Create a quadrature element and function space for tensor-valued P
112+
# Qe = basix.ufl.quadrature_element(cell_name, value_shape=(d, d), degree=quadrature_degree, scheme="default")
113+
# Q = functionspace(domain, Qe)
114+
115+
# # Create Expression for P at quadrature points
116+
# P_expr = Expression(P, quadrature_points, dtype=default_scalar_type)
117+
118+
# # Evaluate P at all cells (including ghosts)
119+
# map_c = domain.topology.index_map(domain.topology.dim)
120+
# num_cells = map_c.size_local + map_c.num_ghosts
121+
# cells = np.arange(num_cells, dtype=np.int32)
122+
# P_eval = P_expr.eval(domain, cells)
123+
124+
# # Optionally, assemble into a Function for visualization/post-processing
125+
# P_func = Function(Q)
126+
# P_func.x.array[:] = P_eval.flatten()
127+
110128
# %%
111129
# Residual form (weak form)
112-
F = ufl.inner(ufl.grad(v), P) * dx - ufl.inner(v, B) * dx - ufl.inner(v, T) * ds(2)
130+
F = ufl.inner(ufl.grad(v), P) * dx
113131

114132
# %%
115133
# Nonlinear problem and Newton solver
116-
problem = NonlinearProblem(F, u, bcs)
134+
problem = NonlinearProblem(F, u, bcs_u)
117135
solver = NewtonSolver(domain.comm, problem)
118136
solver.atol = 1e-8
119137
solver.rtol = 1e-8
@@ -125,17 +143,17 @@ def right(x):
125143

126144
# %%
127145
# Apply a tensile load by incrementally increasing traction on the right edge
128-
n_steps = 5
129-
max_traction = 10.0
146+
n_steps = 100
147+
max_traction = 1.0
130148
u.name = "displacement"
131149

132150
for step in range(1, n_steps + 1):
133-
T.value[0] = step * max_traction / n_steps # Apply in x-direction
151+
u_D_top.value = step * max_traction / n_steps
134152
num_its, converged = solver.solve(u)
135153
assert converged, f"Newton solver did not converge at step {step}"
136154
u.x.scatter_forward()
137155
if domain.comm.rank == 0:
138-
print(f"Step {step}: Traction {T.value[0]:.2f}, Newton its: {num_its}")
156+
print(f"Step {step}: Traction {u_D_top.value:.2f}, Newton its: {num_its}")
139157
# Save solution for each step
140158
with XDMFFile(domain.comm, "tensile2d_u.xdmf", "a") as xdmf:
141159
xdmf.write_function(u, step)
@@ -153,7 +171,3 @@ def right(x):
153171
# xdmf.write_mesh(domain)
154172
# stresses.name = "von_mises"
155173
# xdmf.write_function(stresses)
156-
157-
# %%
158-
if domain.comm.rank == 0:
159-
print("2D simulation complete. Displacement and von Mises stress written to XDMF files.")

0 commit comments

Comments
 (0)