Wing-box modeled as a multi-domain assembly#

create_wingbox() builds the rectangular, untapered wing-box of Elalfy, De Breuker and Castro, case High-AR-t5 (their Tables 1 and 2, p. 7), with skins, spars, ribs and optionally blade stringers, all of them plate domains, 'plate_clpt_donnell', connected with penalty stiffnesses, see panels.multidomain.wingbox. The wing-box is clamped at the root and loaded by a vertical force at the tip. The ribs are connected to the skins with 'BFxcte' and to the spars with 'BFxycte' (rib_spar=True, the default); the stringers pass through the ribs without a connection.

wingbox_tip_force_lb() runs the linear buckling analysis: the pre-buckling state is the linear static solution, solved with structsolve.solve, which removes the null rows and columns of the clamped root, and gives the geometric stiffness matrix of MultiDomain.calc_kG(). Without stringers, with 45 domains, the first buckling mode is a local buckling of the upper skin of the root bay. The first buckling load of their Abaqus model is 173.11 N (Table 3, p. 8). With the connections imposed exactly, conn_method='null-space', the load converges from above to 176.4 N, 1.9% above Abaqus, whereas with the default penalty connections it converges to 161.9 N, 6.5% below: the default penalty constants of calc_kt_kr() leave some relative motion at the joints. The 172.78 N of the default model, penalty connections with 6264 Ritz constants, close to Abaqus, is therefore a coincidence of the number of terms and the penalty constants.

First buckling load (N) against the number of terms (m, n) of the domains (panels 0.14.2, one BLAS thread, the time of wingbox_tip_force_lb() in parentheses):

skins

spars

ribs

Ritz constants

null-space

penalty

8 x 8

8 x 5

4 x 6

6264

190.41 (8 s)

172.78 (12 s)

10 x 10

10 x 6

5 x 7

9585

177.74 (13 s)

162.75 (20 s)

12 x 12

12 x 7

6 x 8

13608

176.44 (24 s)

161.85 (37 s)

14 x 14

14 x 8

7 x 9

18333

176.48 (67 s)

161.86 (83 s)

16 x 16

16 x 9

8 x 10

23760

176.47 (117 s)

161.85 (123 s)

The defaults of create_wingbox() are the first row. The test uses the third one, with the null-space method:

@pytest.mark.slow
def test_wingbox_tip_force_lb():
    # case High-AR-t5 without stringers, 9 bays, 45 domains, connections
    # imposed with the null-space method, skins of 12 x 12 terms, spars of
    # 12 x 7 and ribs of 6 x 8, 13608 Ritz constants, 1 N at the tip
    terms = dict(skin=(12, 12), spar=(12, 7), rib=(6, 8))
    md, c, eigvals, eigvecs = wingbox_tip_force_lb(num_eigvalues=4,
            conn_method='null-space', terms=terms)
    Pcr = eigvals[0]
    print('first buckling tip force: %.2f N, Abaqus %.2f N, error %.2f%%'
          % (Pcr, ABAQUS_HIGH_AR_T5, 100*(Pcr/ABAQUS_HIGH_AR_T5 - 1)))
    # 176.44 N, converged to 0.03% (176.47 N with skins of 16 x 16 terms),
    # 1.9% above Abaqus
    assert np.isclose(Pcr, 176.44, rtol=1e-3)
    assert abs(Pcr/ABAQUS_HIGH_AR_T5 - 1) < 0.03
    root_top = md.panels[0]
    v = abs(eigvecs[:, 0])
    assert v.argmax() in range(root_top.col_start, root_top.col_end)

The blade stringers are added with nstr, the number of stringers per skin, which also splits the skins into nstr + 1 strips:

from panels.multidomain import wingbox_tip_force_lb

md, c, eigvals, eigvecs = wingbox_tip_force_lb(nstr=4, hs=3.e-3,
                                               ts=1.5e-3)

With 4 stringers per skin, hs = 3 mm and ts = 1.5 mm, 225 domains and 19872 Ritz constants, the default terms and penalty connections, the first buckling load is 708.9 N (43 s with one BLAS thread), a buckling of the upper skin and of its stringers in the two bays next to the root, with a global bending part; no reference value is available for this configuration, which is not one of the paper.