Boundary conditions#

The boundary conditions of a domain are imposed in three ways, from the most to the least common:

Flags of the edges#

A flag 0 removes the value (e.g. x1w) or the slope normal to the edge (e.g. x1wr, the derivative with respect to \(x\) at \(x = 0\)) of a field on the whole edge, and a flag 1 leaves it free, the natural boundary condition following from the energy. The edges are \(x = 0\) (x1), \(x = a\) (x2), \(y = 0\) (y1) and \(y = b\) (y2). For the models based on the classical laminated plate theory (CLPT), on the edge \(x = 0\), with \(v\) the displacement tangential to the edge and \(u\) the normal one:

condition

flags equal to 0, the others 1

simply supported, \(u\) and \(v\) restrained

x1u, x1v, x1w (default)

simply supported, \(u\) free

x1v, x1w

clamped

x1u, x1v, x1w, x1wr

free

none

symmetry plane

x1u, x1vr, x1wr

and likewise on the other edges, with the roles of \(u\) and \(v\) exchanged on the edges \(y = const\). With the default flags, a Shell is simply supported on its four edges with the in-plane displacements restrained.

The models based on shear deformation theories, FSDT and TSDT, have the rotations \(\phi_x\) and \(\phi_y\) as independent fields, with the flags x1phix, x1phixr, …, y2phiyr. By default only the rotation tangential to each edge is removed, x1phiy = x2phiy = 0 and y1phix = y2phix = 0, the hard simply supported condition. A clamped edge keeps the cross-section planar and unrotated, \(u(z) = v(z) = 0\) through the thickness, which removes on the edge \(x = 0\):

model

flags of the clamped edge \(x = 0\) equal to 0

CLPT

x1u, x1v, x1w, x1wr

FSDT

x1u, x1v, x1w, x1phix, x1phiy

TSDT

x1u, x1v, x1w, x1phix, x1phiy, x1wr

The rotation of the FSDT is constant through the thickness, and its slope of \(w\) stays free. The in-plane displacement of the TSDT, \(u(z) = u + z \phi_x + p(z) (\phi_x + w_{,x})\) with the cubic \(p(z)\) of Eq. (3), also contains the slope \(w_{,x}\), which must be removed for \(u(z)\) to vanish at every \(z\); the rotation at the reference surface, \(\theta_x\) of Eq. (5), is then zero for any offset. The meaning of the default flags is described in Shell.

The function set_edge of the tests sets the simply supported (with the normal displacement free), clamped and free edges of the three plate models in this way:

def set_edge(s, edge, kind):
    r"""Boundary condition of one edge

    ``kind`` is ``'S'`` for simply supported (SS-1), ``'C'`` for clamped or
    ``'F'`` for free. The tangential displacement and rotation of an edge of
    constant `x` are `v` and `\phi_y`, and of constant `y`, `u` and
    `\phi_x`. The clamped edge removes `u, v, w`, the slope of `w` normal
    to the edge for the CLPT, the rotations for the FSDT, and both the
    rotations and the slope for the TSDT.
    """
    tangential, normal = ('v', 'u') if edge.startswith('x') else ('u', 'v')
    rot_tangential, rot_normal = (('phiy', 'phix') if edge.startswith('x')
                                  else ('phix', 'phiy'))
    for field in ('u', 'v', 'w', 'phix', 'phiy'):
        setattr(s, edge + field, 1.)
        setattr(s, edge + field + 'r', 1.)
    if kind == 'S':
        setattr(s, edge + tangential, 0.)
        setattr(s, edge + 'w', 0.)
        setattr(s, edge + rot_tangential, 0.)
    elif kind == 'C':
        for field in ('u', 'v', 'w', 'phix', 'phiy'):
            setattr(s, edge + field, 0.)
        # the classical plate theory clamps the slope of w and the FSDT the
        # rotations, with the slope free; the TSDT clamps both, such that
        # the warping term p(z) (phi + w,n) of u(z) and v(z) vanishes too
        # and the section stays planar and unrotated
        if 'clpt' in s.model or 'tsdt' in s.model:
            setattr(s, edge + 'wr', 0.)
    elif kind != 'F':
        raise ValueError(kind)

and the natural frequencies of thin isotropic square plates with combinations of these edges agree with the reference values of Leissa (1973) given in the test, for the three models:

@pytest.mark.parametrize('model', [CLPT, FSDT, TSDT])
@pytest.mark.parametrize('bcs', list(LEISSA_PLATES))
def test_frequency_thin_isotropic_plate_leissa(bcs, model):
    r"""Leissa (1973), square plates, `\lambda = \omega a^2 \sqrt{\rho h/D}`

    For a thin plate, `h/a = 0.001`, the shear deformation theories must
    recover the classical plate theory for any boundary condition.
    """
    a = 1.
    h = 0.001*a
    E = 70.e9
    nu = 0.3
    s = make_plate(model, a, h, [0], (E, nu), bcs=bcs)
    # removing the in-plane rigid-body motions, which do not change the
    # flexural modes of the isotropic plate
    s.x1u = s.x2u = 0.
    D = E*h**3/(12*(1 - nu**2))
    omega = lowest_frequencies(s)[0]
    # the references are given with 5 significant digits
    assert np.isclose(omega*a**2*np.sqrt(RHO*h/D), LEISSA_PLATES[bcs],
                      rtol=5e-5)

For these thin plates the slope \(w_{,x}\) of a TSDT clamped edge changes the frequencies by less than \(1.2 \times 10^{-5}\), e.g. 28.95027 with the slope free and 28.95059 with x1wr = 0 for the plate 'SCSC', against 28.951 of Leissa. For thick plates the difference is large: for the square isotropic plate with \(h/a = 0.1\) clamped on four edges, the first frequency \(\omega a^2 \sqrt{\rho h/D}\) of the TSDT is 30.18 with the slope free and 32.64 with the slope clamped, close to the 32.62 of the FSDT.

The removed terms leave null rows and columns in the matrices, which the solvers of structsolve remove before solving. A free domain, all flags 1, has rigid-body modes, and its stiffness matrix is singular.

Prescribed displacements#

Displacements different from zero, or zero displacements at points or along lines inside the domain, are prescribed with Shell.add_point_pd(), Shell.add_distr_pd_fixed_x() and Shell.add_distr_pd_fixed_y(), constant (cte=True) or proportional to the load factor (cte=False). They are imposed by the MultiDomain that contains the shell, also an assembly of one shell without connections, with pd_method:

  • 'null-space': exactly, as linear constraints eliminated together with the connections, the solution being \(\boldsymbol{c} = \boldsymbol{Z}\boldsymbol{c}_r + \boldsymbol{c}_{p0} + \lambda \boldsymbol{c}_{p1}\), with the reactions of MultiDomain.reaction_pd() and MultiDomain.reaction_resultant(), see Prescribed displacements imposed exactly;

  • 'penalty', the default: with springs between the structure and the support, whose stiffness the user adds to the stiffness matrix, e.g. with fkCpd(), and whose forces enter the external force vector, MultiDomain.calc_fext().

A single Shell can be supported at a point by the penalty springs of Shell.calc_stiffness_point_constraint(), added by the user to the constitutive stiffness matrix.

The in-plane displacements \(u\) and \(v\) are prescribed at the reference surface, \(z = 0\), or at the thickness coordinate given by the keyword z of these methods, with the same z given to the penalty kernels.

The example below prescribes a uniform end shortening of a simply supported plate with the null-space method, and verifies that it gives the same critical state as the equivalent applied load:

@pytest.mark.slow
def test_linear_buckling_plate_end_shortening_equals_load():
    r"""Simply supported plate, the lateral edges free in-plane: a uniform
    end-shortening `\delta` and the equivalent load `N_x = E h \delta/a`
    give the same membrane state and the same critical load"""
    a, b, h = 0.3, 0.2, 1e-3
    p = plate(a, b, h, m=10, n=10)
    end_shortening(p, 1.)
    p.add_point_pd(0., 0., 0, None, 1., 0., 0, None)
    md = MultiDomain([p], conn=[], pd_method='null-space')
    eigvals, eigvecs = md.linear_buckling(num_eigvalues=3)
    assert eigvecs.shape == (p.get_size(), 3)

    q = plate(a, b, h, m=10, n=10)
    q.x1u = 0.
    q.add_point_pd(0., 0., 0, None, 1., 0., 0, None)
    q.add_distr_load_fixed_x(a, funcx=lambda y: -E*h/a)
    mdq = MultiDomain([q], conn=[], pd_method='null-space')
    eigvals_N, _ = mdq.linear_buckling(num_eigvalues=3)
    assert np.allclose(eigvals, eigvals_N, rtol=1e-9)
    # a constant end-shortening delta0 at x = a and an incremented one
    # lbd*delta1 at x = 0 give the same uniform state when delta0 + lbd*delta1
    # is the critical one
    dcr = eigvals[0]
    p.clear_disps()
    p.add_distr_pd_fixed_x(0., ku=1., funcu=lambda y: dcr, cte=False)
    p.add_distr_pd_fixed_x(a, ku=1., funcu=lambda y: -0.5*dcr, cte=True)
    p.add_point_pd(0., 0., 0, None, 1., 0., 0, None)
    eigvals_mixed, _ = md.linear_buckling(num_eigvalues=3)
    assert np.isclose(eigvals_mixed[0], 0.5, rtol=1e-8)
    # the same end-shortening, constant and incremented at the same line,
    # is a conflict: the line has a single prescribed value
    p.clear_disps()
    p.add_distr_pd_fixed_x(a, ku=1., funcu=lambda y: -0.5*dcr, cte=True)
    p.add_distr_pd_fixed_x(a, ku=1., funcu=lambda y: -dcr, cte=False)
    with pytest.raises(ValueError, match='each set must be consistent'):
        md.get_cp()

More examples are given in Prescribed displacements.

Face-clamped edges#

In tests, an edge is clamped by restraining the displacements of the bottom and top faces of the laminate, \(z = d \mp h/2\), the section being free to deform in between. This face clamp, \(u = v = 0\) at both faces and \(w = 0\), is prescribed with the keyword z of Shell.add_distr_pd_fixed_x() and Shell.add_distr_pd_fixed_y(); the flags of the edge are left free, 1. With the in-plane displacement at \(z\), see nullspace.pd_constraint_matrix(),

\[u(z) = u + \left(z - c_1 g(z)\right) \phi_x - c_1 g(z) w_{,x}, \qquad g(z) = (z - d)^3 + d^3\]

with \(c_1 = 4/(3 h^2)\) for the TSDT and \(c_1 = 0\) for the FSDT, the two faces give \(u = \phi_x = 0\) for the FSDT, and \(u = w_{,x} = 0\) for the CLPT, \(u(z) = u - z w_{,x}\): the face clamp is the clamp of the flags. For the TSDT the difference of the two faces gives \((h/3)(2 \phi_x - w_{,x}) = 0\) and their sum \(u = -(d/2)(1 - 4 d^2/h^2) w_{,x}\), two conditions instead of the three of the planar clamp; the section warps,

\[u(z) = \frac{w_{,x}}{2} \zeta \left(1 - \frac{4 \zeta^2}{h^2}\right), \qquad \zeta = z - d\]

which no combination of flags can express. Along the edge \(w = 0\) gives \(w_{,y} = 0\), and the two faces then give \(v = \phi_y = 0\). The edge is softer than the planar clamp and stiffer than the simple support, and, being defined by the physical faces, it does not depend on the reference surface. See the example Clamped and face-clamped edges.