Apply boundary conditions#

Boundary conditions prescribe loads and constraints on the degrees of freedom of a _Simu. They are applied to node sets via add_* methods on the simulation object and are accessible in the EasyFEA.Simulations namespace. Node sets come from coordinate conditions or from mesh tags — see Use tags to apply boundary conditions for the tag-based approach.


Query available unknowns#

Each simulation exposes the DOF names it solves for via Get_unknowns():

print(simu.Get_unknowns())
# Elastic 2D:       ['x', 'y']
# Elastic 3D:       ['x', 'y', 'z']
# HyperElastic 2D:  ['x', 'y']
# Thermal:           ['t']
# Beam (planar):     ['x', 'y', 'rz']
# PhaseField:        ['x', 'y'] for elastic sub-problem, ['d'] for damage

Pass these strings as the unknowns argument to every add_* method. You can also pass a subset — for example, fix only ["x"] to constrain horizontal motion while leaving the vertical DOF free.


Summary of BC methods#

Method

Physical meaning

Integration

add_dirichlet()

Prescribed DOF value (displacement, temperature, …)

add_neumann()

Concentrated nodal force / flux

Point

add_lineLoad()

Force per unit length

Along a line

add_surfLoad()

Force per unit area (pressure in 2D, traction in 3D)

Over a surface

add_volumeLoad()

Body force per unit volume

Over a volume

add_pressureLoad()

Normal pressure (outward positive)

Over a boundary surface


Dirichlet conditions (add_dirichlet())#

Prescribes the value of one or more DOFs on a set of nodes.

# fix all displacement DOFs to zero — clamped wall (Elastic simulation)
nodes = mesh.Nodes_Conditions(lambda x, y, z: x == 0)
simu.add_dirichlet(nodes, [0, 0], ["x", "y"])

# impose temperature 100 °C on the top surface (Thermal simulation)
nodes_top = mesh.Nodes_Conditions(lambda x, y, z: y == H)
simu.add_dirichlet(nodes_top, [100.0], ["t"])

# prescribed displacement that varies along x
simu.add_dirichlet(nodes, [lambda x, y, z: 0.01 * x, 0], ["x", "y"])

Concentrated force (add_neumann())#

Applies a concentrated force (or flux) directly on the selected nodes. No integration is performed — the value is added as-is to the right-hand side. Useful for point loads on beams or reactions at a single node.

# point load at the beam tip (Elastic simulation)
nodes_tip = mesh.Nodes_Point((L, h / 2))
simu.add_neumann(nodes_tip, [0, -500], ["x", "y"])

Distributed loads#

Line load (add_lineLoad())#

Force per unit length integrated along the selected boundary edges. Used in 2D for loads applied along a line, or in 3D for edge loads.

# uniform downward load of −1000 N/m along the top edge
nodes_top = mesh.Nodes_Conditions(lambda x, y, z: y == H)
simu.add_lineLoad(nodes_top, [-1000], ["y"])

# spatially varying line load
simu.add_lineLoad(nodes_top, [lambda x, y, z: -500 * (1 + x / L)], ["y"])

Surface load (add_surfLoad())#

Force per unit area integrated over the selected boundary faces. Typical for pressure loads in 3D, or traction/pressure in 2D (force per unit area × thickness).

# uniform pressure of −800 Pa in x on the right face
nodes_right = mesh.Nodes_Conditions(lambda x, y, z: x == L)
simu.add_surfLoad(nodes_right, [-800], ["x"])

# traction vector on a 3D face
simu.add_surfLoad(nodes_right, [-1e6], ["z"])

Volume load (add_volumeLoad())#

Body force per unit volume integrated over the selected elements. Typical use is gravity.

# gravity in −y, ρ = 7800 kg/m³
simu.add_volumeLoad(mesh.nodes, [-7800 * 9.81], ["y"])

Pressure load (add_pressureLoad())#

Applies a normal pressure of given magnitude on a boundary surface. The direction is automatically computed from the outward normal at each boundary face.

# internal pressure of 1 MPa on a cylinder inner surface
simu.add_pressureLoad(inner_surface_nodes, magnitude=1e6)

Spatially varying values#

All values arguments accept:

  • a float — uniform value applied to all selected nodes,

  • a NumPy array of length Nn — one value per node,

  • a lambda function lambda x, y, z: ... — evaluated at node (or integration-point) coordinates.

# temperature that increases linearly along x
simu.add_dirichlet(nodes, [lambda x, y, z: 20 + 80 * x / L], ["t"])

# load proportional to distance from center
simu.add_surfLoad(nodes, [lambda x, y, z: -100 * (x - L/2)**2], ["x"])

Functions always receive three arguments x, y, z regardless of the problem dimension.


Visualize applied conditions#

from EasyFEA import Display, PyVista

Display.Plot_BoundaryConditions(simu)   # matplotlib
PyVista.Plot_BoundaryConditions(simu)   # interactive 3D

Reset boundary conditions#

Call Bc_Init() to clear all previously defined conditions (e.g., between load steps):

simu.Bc_Init()

Use tags to apply boundary conditions#

Tags are named node and element sets attached to the mesh — they correspond to physical groups defined in the meshing tool (Gmsh, Medit, …). Once a mesh is imported with its physical groups, tags are the most reliable way to identify boundaries without hard-coding coordinates.

List available tags#

# List all tag names on the main element group
print(mesh.groupElem.nodeTags)
# e.g. ['bottom', 'top', 'left', 'right', 'inlet', 'wall']

Retrieve nodes or elements by tag#

# Nodes associated with a tag
nodes_bottom = mesh.Nodes_Tags("bottom")

# Combine multiple tags into one node set
nodes_fixed = mesh.Nodes_Tags("left", "right")

# Elements associated with a tag
elems_inlet = mesh.Elements_Tags("inlet")

Assign a custom tag#

You can also define your own tags from a coordinate condition and reuse them later:

nodes = mesh.Nodes_Conditions(lambda x, y, z: x == 0)
mesh.Set_Tag(nodes, "clamped_end")

# later in the script
simu.add_dirichlet(mesh.Nodes_Tags("clamped_end"), [0] * dim, simu.Get_unknowns())

Apply boundary conditions from tags#

Node sets retrieved from tags can be passed directly to add_dirichlet or add_neumann, exactly like node sets obtained from coordinate conditions:

from EasyFEA import Simulations, Models

# fixed displacement on the "fixed" boundary
simu.add_dirichlet(mesh.Nodes_Tags("fixed"), [0, 0], ["x", "y"])

# prescribed displacement on the "top" surface
simu.add_dirichlet(mesh.Nodes_Tags("top"), [-0.1], ["y"])

# uniform pressure on the "inlet" surface
simu.add_neumann(mesh.Nodes_Tags("inlet"), [-100], ["x"])