Non-linear static analyses#
The geometrically non-linear static analyses are run with
Analysis, which receives four callables of the model and finds
the configurations \(\boldsymbol{u}\) in equilibrium with the external load scaled by
the load factor \(\lambda\):
The elements give the terms of the residual and of its Jacobian, the
solvers of pyfe3d.solver the increments and the iterations.
From the elements to the callables#
Callable |
Returns |
With the elements |
|---|---|---|
|
\(\boldsymbol{F}_{ext}\), scaled by |
the nodal loads of the model |
|
\(\boldsymbol{F}_{int}(\boldsymbol{c})\) |
|
|
\(\boldsymbol{K}_{C0}\), or \(\boldsymbol{K}_{C0} + \boldsymbol{K}_{CNL}(\boldsymbol{c}) + \boldsymbol{K}_{GNL}(\boldsymbol{c})\) with |
|
|
\(\boldsymbol{K}_G(\boldsymbol{c})\) |
|
calc_kC() + calc_kG() is then the exact Jacobian of calc_fint,
\(\boldsymbol{K}_T = \partial \boldsymbol{R}/\partial \boldsymbol{u}\), and the full Newton-Raphson method
converges quadratically. The class Model of
tests/test_solver_nonlinear_static.py, see Non-linear static analysis with pyfe3d.solver,
wraps a list of elements of one type into these four callables.
calc_kC(), the linear stiffness matrix, also gives the scaling of the
convergence criterion.
Boundary conditions and prescribed displacements#
With Analysis(..., bu=bu), the callables receive and return the
vectors and matrices of all the N dofs, as assembled by the elements,
and FreeDofs restricts them to the free dofs bu. The solution
vectors an.cs have size N, with zeros at the constrained dofs.
With uk, the constrained dofs have the prescribed displacements
\(\lambda \boldsymbol{u}_k\), imposed exactly, proportional to the load factor:
uk[~bu] are the values at \(\lambda = 1\), and a load-free analysis,
calc_fext returning zeros, is displacement controlled. The reaction at
a prescribed dof is calc_fint(u) at that dof minus the load applied
there, see test_prescribed_displacement_and_reaction in
Non-linear static analysis with pyfe3d.solver.
Without bu, the callables return the vectors and matrices of the free
dofs only. The solvers do not remove null rows and columns: a null row or
column of the linear stiffness matrix, a dof without stiffness, raises a
numpy.linalg.LinAlgError naming the dofs, see
check_null_rows_cols().
Solvers#
an.NL_method selects the solver, and Analysis.static() with
NLgeom=True runs it, returning the converged load factors
an.increments and solutions an.cs:
'NR', the default: load control with the Newton-Raphson method,newton_raphson._solver_NR(), full or modified (an.modified_NR), see Crisfield (1991), Sections 1.2.2 and 1.2.3, with an optional line search (an.line_search). The first increment isan.initialInc; a step that fails is repeated with half the increment, and the increment grows after a step that converged without being cut, up toan.maxInc. Beyond a limit point of the load it may converge to another branch of the equilibrium path.'arc_length_riks'and'arc_length_crisfield': the arc-length methods following Riks (1979) and Crisfield (1981),arc_length._solver_arc_length(), in which the load factor is an unknown of each step, such that limit points, snap-through and snap-back are traced. The first arc length corresponds to the load factor incrementan.initialIncalong the initial tangent.
Both stop at the load factor 1.0, or earlier when the increment falls
below an.minInc or, for the arc-length methods, when the cumulative
arc length reaches an.maxArcLength. A run that did not finish is
detected with:
increments, cs = an.static(NLgeom=True)
if not increments or increments[-1] != 1.:
... # stopped at increments[-1], see the log messages
The linear static analysis, an.static(NLgeom=False), solves
\(\boldsymbol{K}_{C0} \boldsymbol{u} = \boldsymbol{F}_{ext}\) with solve() and returns a single
increment.
Convergence criterion#
The iterations of each increment stop when the residual is small according
to an.convergence, see convergence:
'crisfield', the default: the residual scaled with the diagonal of the linear stiffness matrix of the free dofs, \(d_j = K_{{C0}_{jj}}\), the entries of the diagonal scaling vector \(\boldsymbol{d}\),\[\zeta = \frac{\|\boldsymbol{R}\|_{\boldsymbol{d}}}{\max( \|\lambda \boldsymbol{F}_{ext}\|_{\boldsymbol{d}}, \|\boldsymbol{F}_{int}\|_{\boldsymbol{d}}, \ldots)} \le \text{relTOL}, \qquad \|v\|_{\boldsymbol{d}} = \sqrt{\sum_j v_j^2/|d_j|}\]with
an.relTOL = 1e-9by default, seecrisfield_zeta()for the references in the denominator. It does not depend on the units of each dof, e.g. on whether the rotations are in radians or in milliradians, and it ignores the support reactions;'relative': the Euclidean norm of the residual over the largest Euclidean norm of the references, which adds the squares of forces and of moments.
an.absTOL also accepts the iterations whose largest absolute residual
is smaller, in the units of force of the model. With both criteria, an
iteration has also converged at the round-off floor of the residual,
with \(\varepsilon\) the machine precision, \(|\boldsymbol{K}_{C0}|\) and \(|\boldsymbol{u}|\) the
elementwise absolute values of the linear stiffness matrix and of the
displacements of the free dofs, and the Euclidean norm with
'relative', see roundoff_floor(): the residual cannot be
computed more accurately, and, under large self-equilibrated axial forces,
e.g. of an arch near a null load, \(\zeta\) would otherwise stagnate above
relTOL and the analysis stop, see test_fung_kaplan_beam_arch in
Non-linear static analysis with pyfe3d.solver. The log messages mark the iterations converged
at the round-off floor. With a consistent tangent
stiffness matrix and full Newton-Raphson, \(\zeta\) falls quadratically, as
verified in Non-linear static analysis with pyfe3d.solver; a slow decrease of \(\zeta\) reveals
an inconsistent tangent stiffness matrix, e.g. a missing calc_kG, which
changes the iterations but not the converged solution.
Configuration-dependent loads#
A load that depends on the configuration, e.g. a follower pressure or the
aerodynamic load of the piston theory, is given through optional keyword
arguments, passed only to the callables that declare them, see
callbacks:
calc_fint(c, inc=...)receives the load factor and includes the configuration-dependent part of the load, \(-\lambda \boldsymbol{F}(\boldsymbol{c})\), andcalc_kC(c, NLgeom=True, inc=...)its derivative, the load stiffness matrix \(\boldsymbol{K}_F = \lambda \boldsymbol{K}_{F_{ref}}\), with \(\boldsymbol{K}_{F_{ref}} = -\partial \boldsymbol{F}/\partial \boldsymbol{c}\), which is unsymmetric in general, see below; the solvers use LU factorizations;calc_fext(inc=1., c=...)returns the load vector of the configurationcfor a unit load factor, \(-\partial \boldsymbol{R}/\partial \lambda\), used by the arc-length methods.
The aerodynamic load of the piston theory, \(\lambda \beta
\boldsymbol{K}_{A_\beta} \boldsymbol{u}\), with update_KA_beta of Quad4R or
Quad4, is such a load, see test_piston_theory_load_unsymmetric_tangent
in Non-linear static analysis with pyfe3d.solver. The keyword argument lbd of
calc_fext gives a load vector that depends on the load factor, which is
how FreeDofs imposes the prescribed displacements.
\(\boldsymbol{K}_F\) is symmetric, and the load conservative, only in particular cases.
For a pressure normal to the deformed surface, Hibbitt (1979, p. 938)
splits the load stiffness of a uniform pressure into a symmetric surface
integral and an antisymmetric integral along the boundary of the loaded
surface, which vanishes where the displacements are prescribed: a uniform
pressure on a fully enclosed volume, or on a surface whose boundaries have
prescribed displacements, gives a symmetric \(\boldsymbol{K}_F\), whereas free edges,
where the pressure changes, and a non-uniform pressure give unsymmetric
terms (p. 939). In Table 2 of Schweizerhof and Ramm (1984), the domain
terms are symmetric for a uniform pressure, and for a non-uniform one only
when the pressure field is fixed in space, and the boundary terms vanish
under one of the conditions of their Sec. 3.2.1, Eqs. (32)-(35): the
pressure is zero on the whole boundary; at least two displacement
components are prescribed at the edge; the edge is restrained normal to a
continuous surface, e.g. the undeformed surface, \(w = 0\) for a plate on
the \(XY\) plane; or the boundary terms add up to zero. pyfe3d does not
symmetrise \(\boldsymbol{K}_F\): the tangent stiffness matrix, with the matrix returned
by calc_kC, is factorized with scipy.sparse.linalg.splu(), as in
solve(), such that a consistent unsymmetric \(\boldsymbol{K}_F\) keeps the
quadratic convergence of the Newton-Raphson method, as verified by
test_newton_raphson_quadratic_with_follower_load of
tests/test_solver_follower_loads.py.
Log messages#
The solvers print their progress, the increments and the \(\zeta\) of each
iteration, with pyfe3d.solver.logger, unless silent=True is
passed to Analysis.static(). The callables must accept silent.
References#
Riks, E., An incremental approach to the solution of snapping and buckling problems, International Journal of Solids and Structures, 15(7), 529-551, 1979. https://doi.org/10.1016/0020-7683(79)90081-7
Crisfield, M. A., A fast incremental/iterative solution procedure that handles “snap-through”, Computers & Structures, 13(1-3), 55-62, 1981. https://doi.org/10.1016/0045-7949(81)90108-5
Crisfield, M. A., Non-linear Finite Element Analysis of Solids and Structures, Volume 1: Essentials, John Wiley & Sons, Chichester, 1991.
Hibbitt, H. D., Some follower forces and load stiffness, International Journal for Numerical Methods in Engineering, 14(6), 937-941, 1979. https://doi.org/10.1002/nme.1620140613
Schweizerhof, K. and Ramm, E., Displacement dependent pressure loads in nonlinear finite element analyses, Computers & Structures, 18(6), 1099-1114, 1984. https://doi.org/10.1016/0045-7949(84)90154-8