hermit.loads

Loads – distributed, edge and point loads; a + b composes them.

Each builder returns a Loads carrying one term. pressure / traction / moment are distributed over the shell surface; inertial_load is the d’Alembert / gravity load of the structure’s own mass; edge_pressure / edge_traction / edge_moment act on selected exterior facets; point_load is a consistent (weak Dirac) point load; load_vector is a direct generalised RHS in domain.W dof ordering.

Every term reaches hermit.solve() as its own residual and compliance contribution, on its own space, with no interpolation between terms. pressure follows the live, shape-differentiable ufl.CellNormal.

combined_traction / combined_moment reduce several terms onto one shared space. They are not part of the solve path – they exist for callers that drive the raw FEniCSx operations directly.

Classes

Loads

A composable bundle of load terms.

Functions

edge_moment() → Loads)

Moment per unit length on selected exterior facets.

edge_pressure() → Loads)

Pressure per unit length along the shell normal, on selected exterior facets.

edge_traction() → Loads)

Force per unit length on selected exterior facets.

inertial_load(→ Loads)

The load of the structure's own mass in an accelerating frame.

load_vector(→ Loads)

A generalised right-hand side given directly in state-space dof order.

moment() → Loads)

Distributed moment per unit area, in global components.

point_load(→ Loads)

A consistent point force and/or moment at a physical coordinate.

pressure() → Loads)

Scalar pressure acting along the shell normal.

traction() → Loads)

Distributed force per unit area, in global components.

Module Contents

class hermit.loads.Loads(domain, *, traction_terms=(), moment_terms=(), pressure_terms=(), edge_traction_terms=(), edge_moment_terms=(), edge_pressure_terms=(), inertial_terms=(), direct=None)

A composable bundle of load terms.

Build one with pressure(), traction(), moment(), edge_pressure(), edge_traction(), edge_moment(), inertial_load(), point_load() or load_vector() rather than calling this constructor directly. a + b merges two Loads on the same domain, concatenating the term lists and summing the direct right-hand sides.

Parameters:
domainShellDomain
traction_terms, moment_termssequence of Field, optional

Distributed (3,) vector fields.

pressure_termssequence of Field, optional

Distributed scalar fields, acting along the shell normal.

edge_traction_terms, edge_moment_terms, edge_pressure_termssequence, optional

Edge terms, each pairing a field with the exterior-facet measure it acts on.

inertial_termssequence, optional

Inertial terms, each holding a material’s thickness and density fields and an acceleration. A surrogate solve that reads the load terms directly must handle these too.

directcsdl.Variable, optional

A generalised right-hand side in domain.W dof ordering.

Examples

>>> loads = hm.pressure(domain, 2.0) + hm.point_load(domain, at=tip, force=[0, 0, -1])
combined_moment(space=('Lagrange', 1, (3,))) → hermit._field.Field | None

Sum the distributed moment terms onto one space.

Parameters:
spacetuple, optional

Target space. Exact when every term is already on it.

Returns:
Field or None

None when there are no moment terms.

combined_traction(space=('Lagrange', 1, (3,))) → hermit._field.Field | None

Sum the traction and pressure terms onto one space.

Pressure is converted to a traction with a numpy snapshot of the reference normal. Inertial terms are not included. solve() does not use this – it takes each term directly, with the live normal.

Parameters:
spacetuple, optional

Target space. Exact when every term is already on it.

Returns:
Field or None

None when there are no such terms.

direct_vector(ndof=None) → csdl_alpha.Variable

The combined point-load and load-vector right-hand side.

Parameters:
ndofint, optional

Length to use when there is no direct term. Defaults to the number of domain.W dofs.

Returns:
csdl.Variable

Shape (ndof,) in domain.W dof order; zeros when there is no point load or load vector.

direct = None
domain
edge_moment_terms = []
edge_pressure_terms = []
edge_traction_terms = []
inertial_terms = []
moment_terms = []
pressure_terms = []
traction_terms = []
hermit.loads.edge_moment(domain, m, *, where, space=('Lagrange', 1)) → Loads

Moment per unit length on selected exterior facets.

Parameters:
domainShellDomain
mField or array_like

A (3,) global vector, or a Field of (3,) vectors.

wherecallable

Coordinate predicate selecting the loaded edge; see edge_traction().

spacetuple, optional

Space for a non-Field value. Default ("Lagrange", 1).

Returns:
Loads
Raises:
ValueError

If m does not resolve to a (3,) vector field.

hermit.loads.edge_pressure(domain, p, *, where, space=('DG', 0)) → Loads

Pressure per unit length along the shell normal, on selected exterior facets.

Parameters:
domainShellDomain
pField, float or array_like

Scalar pressure; positive acts along +n.

wherecallable

Coordinate predicate selecting the loaded edge; see edge_traction().

spacetuple, optional

Space for a non-Field value. Default ("DG", 0).

Returns:
Loads
Raises:
ValueError

If space is not scalar, or if the domain’s cell normals are not consistently oriented.

hermit.loads.edge_traction(domain, t, *, where, space=('Lagrange', 1)) → Loads

Force per unit length on selected exterior facets.

Parameters:
domainShellDomain
tField or array_like

A (3,) global vector, or a Field of (3,) vectors.

wherecallable

Coordinate predicate selecting the loaded edge, with the same contract as clamp(): it receives a (3, N) coordinate array and returns an (N,) boolean mask. Only exterior facets are selected.

spacetuple, optional

Space for a non-Field value. Default ("Lagrange", 1).

Returns:
Loads
Raises:
ValueError

If t does not resolve to a (3,) vector field.

Examples

>>> tip = hm.edge_traction(domain, [0.0, 0.0, -1.0], where=hm.near("x", 10.0))
hermit.loads.inertial_load(domain, material, *, acceleration, angular_acceleration=None, about=None) → Loads

The load of the structure’s own mass in an accelerating frame.

Force per unit area density * thickness * (a + alpha x (x - about)), with a = acceleration and alpha = angular_acceleration, taken from material’s own thickness and density fields on whatever spaces they were built on. The resultant is exactly hm.mass(state) * a for a uniform a.

acceleration is the load per unit mass, with the sign of gravity: pass [0, 0, -9.81] for self weight and n * [0, 0, -9.81] for an n-g manoeuvre. For a body accelerating at a_body under gravity g it is g - a_body (the d’Alembert force per unit mass).

Parameters:
domainShellDomain
materialMaterial

Supplies thickness and density; a thickness_only() material works too. It should be the material passed to solve(), or the load describes a different structure.

accelerationcsdl.Variable or array_like

(3,) load per unit mass, in global components.

angular_accelerationcsdl.Variable or array_like, optional

(3,) angular acceleration, same sign convention. Default zero.

aboutarray_like, optional

(3,) point at which the load per unit mass equals acceleration. Default the global origin. Fixed, not differentiable.

Returns:
Loads
Raises:
ValueError

If material was built on a different domain, or if an acceleration does not have three components.

Notes

Differentiable in both accelerations, the thickness and density fields, and the mesh coordinates. The mass is the shell’s translational mass only; the rotary inertia of the thickness (density * thickness**3 / 12) is neglected, as in mass().

Examples

>>> loads = hm.pressure(domain, p) + hm.inertial_load(
...     domain, material, acceleration=[0.0, 0.0, -2.5 * 9.81])
hermit.loads.load_vector(domain, vec) → Loads

A generalised right-hand side given directly in state-space dof order.

Parameters:
domainShellDomain
veccsdl.Variable or array_like

One entry per domain.W dof, in that space’s dof ordering.

Returns:
Loads
Raises:
ValueError

If vec does not have exactly domain.W’s dof count.

hermit.loads.moment(domain, m, *, space=('Lagrange', 1)) → Loads

Distributed moment per unit area, in global components.

Contributes int m . dtheta dx to the residual.

Parameters:
domainShellDomain
mField or array_like

A (3,) global vector, or a Field of (3,) vectors.

spacetuple, optional

Space for a non-Field value. Default ("Lagrange", 1).

Returns:
Loads
Raises:
ValueError

If m does not resolve to a (3,) vector field.

hermit.loads.point_load(domain, *, at, force=None, moment=None) → Loads

A consistent point force and/or moment at a physical coordinate.

The cell containing at is located, the state-space basis is evaluated there, and the result is scattered into the direct right-hand side – the weak form of a Dirac delta, int F . delta(x - at) . du dx = F . du(at). The point need not be a mesh vertex.

Parameters:
domainShellDomain
atarray_like

Physical coordinate, shape (3,).

forcecsdl.Variable or array_like, optional

(3,) point force.

momentcsdl.Variable or array_like, optional

(3,) point moment.

Returns:
Loads
Raises:
ValueError

If neither force nor moment is given, or if at lies in no cell.

Notes

Differentiable in force and moment, but not in at: the containing cell and the point’s reference coordinates in it are fixed at construction. Under a mesh perturbation the load therefore stays on the same material point, and since the basis values there do not depend on the node positions, its right-hand side has an exactly zero mesh derivative.

hermit.loads.pressure(domain, p, *, space=('DG', 0)) → Loads

Scalar pressure acting along the shell normal.

Positive p acts along +n. The residual uses the live ufl.CellNormal, so the load is differentiable with respect to the mesh coordinates.

Parameters:
domainShellDomain
pField, float or array_like

Scalar pressure.

spacetuple, optional

Space for a non-Field value. Default ("DG", 0).

Returns:
Loads
Raises:
ValueError

If space is not scalar, or if the domain’s cell normals are not consistently oriented. On a badly-wound imported mesh a uniform pressure would otherwise become a sign-alternating load with no other symptom.

See also

traction

an explicit global vector, independent of the normal.

hermit.loads.traction(domain, t, *, space=('Lagrange', 1)) → Loads

Distributed force per unit area, in global components.

Contributes int t . du dx to the residual. Unlike pressure() this never touches the shell normal. For the weight of the structure itself use inertial_load(), which follows the thickness and density.

Parameters:
domainShellDomain
tField or array_like

A (3,) global vector, or a Field of (3,) vectors.

spacetuple, optional

Space for a non-Field value. Default ("Lagrange", 1).

Returns:
Loads
Raises:
ValueError

If t does not resolve to a (3,) vector field.

See also

pressure

a scalar load following the shell normal.

edge_traction

the same load on selected exterior facets.