How to Implement Different Loading Conditions in PhaseFieldX Simulations
PhaseFieldX decouples loading definitions from the finite-element solver through a three-step workflow: create load objects using helper functions, collect them in a list with boundary measures, and provide an update_loading callable to modify values at each time step.
The castillonmiguel/phasefieldx repository provides a modular framework for phase-field fracture simulations where you can implement different loading conditions without modifying the core solver. This architecture supports static, time-dependent, cyclic, and spatially varying loads through a clean separation between load definition and solution algorithms.
The Three-Step Loading Workflow
Step 1: Create Load Objects
Begin by constructing load objects using the helper functions in src/phasefieldx/Loading/loading_functions.py. These utilities generate dolfinx.fem.Constant objects that represent traction or body forces:
loading_Tx: Creates a scalar traction in the x-directionloading_Txy: Creates a 2D traction vector (x and y components)loading_Txyz: Creates a 3D traction vector (x, y, and z components)
from phasefieldx.Loading.loading_functions import loading_Txy
# Create a constant vertical traction (initially zero)
T_top = loading_Txy(mesh, value_x=0.0, value_y=0.0)
Step 2: Collect Loads with Boundary Measures
The solvers expect loads packaged as a list of tuples, where each tuple pairs a load constant with a boundary measure (ds). The measure identifies the specific boundary or sub-domain where the traction acts:
# Define the top boundary facet marker in the mesh
ds_top = ds(boundary_id=top_facet_marker)
# Assemble the load list
T_list_u = [(T_top, ds_top)]
Step 3: Define the Update Function
Pass an update_loading callable to the solver. This function executes at every pseudo-time step, receiving the current load list and scalar time value. Inside this function, you can modify the Constant values, replace loads entirely, or change associated measures.
The function signature, as defined in src/phasefieldx/Element/Phase_Field_Fracture/solver/solver.py, follows this pattern:
def update_loading(T_list_u, time):
"""Modify loads at each time step."""
# Update logic here
return Tx, Ty, Tz # Return values for bookkeeping
Implementing Time-Dependent Loading
The elasticity example in examples/Elasticity/plot_1101.py demonstrates force-controlled loading where vertical traction increases linearly with pseudo-time:
def update_loading(T_list_u, time):
"""Increase the y-component of the top traction linearly with time."""
val = 0.1 * time # Linear ramp
T_list_u[0][0].value[1] = petsc4py.PETSc.ScalarType(val)
return 0, val, 0 # (Tx, Ty, Tz) for bookkeeping
Invoke the solver with this update function:
solve(Data,
msh,
final_time=11.0,
V_u=V_u,
bcs_list_u=bcs_list_u,
update_boundary_conditions=update_boundary_conditions,
f=None,
T_list_u=T_list_u,
update_loading=update_loading,
ds_list=ds_list,
dt=1.0,
path=None,
quadrature_degree=2,
bcs_list_u_names=bcs_list_u_names)
Advanced Loading Scenarios
Cyclic (Fatigue) Loading
For fatigue simulations, implement update_loading with periodic functions or piece-wise ramps based on time % period. The fatigue example in examples/Fatigue/plot_1800.py follows this pattern, applying sinusoidal or repeated loading cycles without modifying the underlying solver.
Spatially Varying Traction
Replace dolfinx.fem.Constant with dolfinx.fem.Function to create spatially dependent loads. Use the mesh coordinates to define traction that varies across the boundary surface. Reference loading_Txy in loading_functions.py as a template, substituting the constant with a function interpolated over the boundary.
Prescribed Displacement (Dirichlet) Loading
Control displacement boundaries through the update_boundary_conditions callable, which operates in parallel to update_loading. This function updates Dirichlet boundary conditions at each time step, enabling displacement-controlled simulations. See plot_1101.py for the update_boundary_conditions implementation pattern.
Combined Body Force and Surface Traction
Populate both f_list_u (volumetric body forces) and T_list_u (boundary tractions) simultaneously. The solver automatically sums these contributions according to the signature in solver.py lines 82-84, which accepts both arguments and combines them in the variational form.
Summary
- PhaseFieldX separates loading logic from solvers through the
update_loadingcallable pattern implemented insrc/phasefieldx/Element/Phase_Field_Fracture/solver/solver.py. - Create load objects using helpers in
src/phasefieldx/Loading/loading_functions.pysuch asloading_Txyandloading_Txyz. - Package loads as tuples
[(constant, measure), ...]and pass them to the solver viaT_list_u. - Implement time-dependent, cyclic, or spatially varying loads by modifying the
update_loadingfunction without changing core solver code. - Reference working examples in
examples/Elasticity/plot_1101.pyandexamples/Fatigue/plot_1800.pyfor force-controlled and fatigue loading implementations.
Frequently Asked Questions
How do I apply a constant traction that does not change over time?
Create the load using loading_Txy or loading_Txyz with your desired values, package it in T_list_u, and pass this list to the solver without providing an update_loading function. The solver will apply the constant traction at every step without modification.
Can I apply different loads to different boundaries simultaneously?
Yes. Construct multiple load objects and pair each with its specific boundary measure, then include all tuples in T_list_u. For example: T_list_u = [(T_top, ds_top), (T_side, ds_side)]. The solver processes each load-boundary pair independently.
What is the difference between update_loading and update_boundary_conditions?
The update_loading function modifies Neumann boundary conditions (tractions and body forces) by updating the values of Constant or Function objects in T_list_u. The update_boundary_conditions function modifies Dirichlet boundary conditions (prescribed displacements) by updating the values passed to dolfinx.fem.dirichletbc objects. Use update_loading for force-controlled simulations and update_boundary_conditions for displacement-controlled simulations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →