Summary
*DLOAD accepts the body force labels BX, BY and BZ for any element type (dloads.f, label check). On solid elements e_c3d.f integrates them over the element volume as a force per unit volume along global x, y or z. Beams keep the label too, and so do membranes in the first step.
On shell elements dloads.f renames every label except EDNORx and I to P1. A body force B therefore becomes a pressure B on the shell, acting along the shell normal. Three things go wrong at once, without a message:
- Direction: BX and BY (in-plane loads on a flat plate in the x-y plane) bend the plate out of plane. BZ follows the shell normal, not global z.
- Magnitude: the value is applied per unit area instead of per unit volume, so the load is 1/t times too large (10 times for t = 0.1).
- Node order: two identical plates under the same
BZdeflect in opposite directions when one plate’s connectivity runs the other way round.
The same card on M3D4 membranes is a body force in the first step and a pressure from the second step on: after the first step the membranes are expanded and match the shell test.
The labels BX, BY and BZ are not in section 7.44 (*DLOAD) of the 2.23 manual. Their intended meaning is in the LOGBOOK of the source tree, entry of 4 April 2009: “provided for BX, BY and BZ as volumetric loading including nonuniform loading (BXNU…)”. ccx itself agrees with that everywhere except on shells: the same label is a body force per unit volume on solids, beams and first-step membranes. On shells the result depends on the node numbering, and a force per unit volume is used as a force per unit area.
Version
ccx 2.23 (macOS arm64). Source: master 9ba5d76 (16 Oct 2026).
Already reported or fixed?
Not reported: I found no matching GitHub issue (open or closed) or pull request in Dhondtguido/CalculiX, and no calculix.discourse.group topic (searched 21 Oct 2026). Not fixed: dloads.f is unchanged on master (9ba5d76) and still renames the label in both shell branches.
Related:
- *DLOAD label P on membrane elements in the first step: segfault (M3D4, M3D8) or silently lost load (M3D3, M3D6) · Issue #216 · Dhondtguido/CalculiX · GitHub covers the pressure label P on membranes in the first step (same shell test in dloads.f, but about which elements count as shells; it does not involve BX/BY/BZ).
Minimal input
shell_body.inp: four separate one-element S4 cantilevers (1 x 1, t = 0.1, E = 1000, nu = 0, rho = 1), clamped at x = 0. Elements 1 and 2 are identical plates, except that element 2 lists its nodes the other way round (normal along -z). Element 3 carries the same body force as GRAV, as the reference.
*HEADING
Four one-element S4 cantilevers (1 x 1, t = 0.1, rho = 1), clamped at x = 0
*NODE
1, 0., 0., 0.
2, 1., 0., 0.
3, 1., 1., 0.
4, 0., 1., 0.
11, 0., 2., 0.
12, 1., 2., 0.
13, 1., 3., 0.
14, 0., 3., 0.
21, 0., 4., 0.
22, 1., 4., 0.
23, 1., 5., 0.
24, 0., 5., 0.
31, 0., 6., 0.
32, 1., 6., 0.
33, 1., 7., 0.
34, 0., 7., 0.
*ELEMENT, TYPE=S4, ELSET=EALL
1, 1, 2, 3, 4
2, 11, 14, 13, 12
3, 21, 22, 23, 24
4, 31, 32, 33, 34
*SHELL SECTION, ELSET=EALL, MATERIAL=M
0.1
*MATERIAL, NAME=M
*ELASTIC
1000., 0.
*DENSITY
1.
*NSET, NSET=FIX
1, 4, 11, 14, 21, 24, 31, 34
*NSET, NSET=TIP
2, 3, 12, 13, 22, 23, 32, 33
*BOUNDARY
FIX, 1, 6
*STEP
*STATIC
*DLOAD
1, BZ, 2.
2, BZ, 2.
3, GRAV, 2., 0., 0., 1.
4, BX, 2.
*NODE PRINT, NSET=TIP
U
*END STEP
membrane_step.inp: the same BX card on an M3D4 membrane, in step 1 and in step 2
One M3D4 element (1 x 1, t = 0.1), clamped at x = 0, all nodes held in z. Step 1 has no load; step 2 has BX, 2.. With the *DLOAD lines moved into step 1, the tip moves U1 = 1.000000E-03 (closed form B L^2 / (2 E)).
*NODE
1, 0., 0., 0.
2, 1., 0., 0.
3, 1., 1., 0.
4, 0., 1., 0.
*ELEMENT, TYPE=M3D4, ELSET=EALL
1, 1, 2, 3, 4
*MEMBRANE SECTION, ELSET=EALL, MATERIAL=M
0.1
*MATERIAL, NAME=M
*ELASTIC
1000., 0.
*NSET, NSET=FIX
1, 4
*NSET, NSET=TIP
2, 3
*BOUNDARY
FIX, 1, 3
TIP, 3, 3
*STEP
*STATIC
*NODE PRINT, NSET=TIP
U
*END STEP
*STEP
*STATIC
*DLOAD
1, BX, 2.
*NODE PRINT, NSET=TIP
U
*END STEP
How to run
OMP_NUM_THREADS=1 ccx shell_body
OMP_NUM_THREADS=1 ccx membrane_step
Expected
- Element 3 (GRAV, the reference): force per unit area rho g t = 0.2, so q = 0.2 per unit length of the 1-wide strip. Beam theory gives w = q L^4 / (8 E I) = 0.2 / (8 x 1000 x 0.1^3 / 12) = 0.300; the one-element S4 gives U3 = 0.302.
- Elements 1 and 2 (BZ = 2 per unit volume along global z, the same load as element 3): U3 = +0.302 at both tips. Node order must not change the result.
- Element 4 (BX = 2, in plane): U1 = B L^2 / (2 E) = 1.0E-03, U3 = 0.
- membrane_step, step 2: U1 = 1.000000E-03, which is what the same card gives in step 1.
Actual
Exit 0, no warning. shell_body.dat:
displacements (vx,vy,vz) for set TIP and time 0.1000000E+01
2 2.303713E-15 2.604738E-15 3.020000E+00
3 -2.303713E-15 2.963482E-15 3.020000E+00
12 4.718448E-16 1.346252E-15 -3.020000E+00
13 -1.193490E-15 2.757810E-15 -3.020000E+00
22 -1.092876E-16 -1.965190E-16 3.020000E-01
23 2.532696E-16 -1.910079E-16 3.020000E-01
32 7.716050E-15 9.392568E-15 3.020000E+00
33 -6.522560E-15 9.146878E-15 3.020000E+00
| element | load | expected tip | actual tip |
|---|---|---|---|
| 1 | BZ 2 | U3 = 0.302 | U3 = 3.020 (10x = 1/t) |
| 2 | BZ 2, nodes reversed | U3 = 0.302 | U3 = -3.020 (opposite sense) |
| 3 | GRAV 2 along z | U3 = 0.302 | U3 = 0.302 |
| 4 | BX 2 | U1 = 1.0E-03, U3 = 0 | U1 = 7.7E-15, U3 = 3.020 |
Element 1 moves exactly as under a pressure: with its line replaced by 1, P, 2. the tip U3 is the same 3.020000E+00. With element 4’s line changed to 4, BY, 2., its tip also moves U3 = 3.020000E+00.
membrane_step.dat, step 2: U1 = 7.105427E-21 and 1.980599E-34 at nodes 2 and 3 instead of 1.000000E-03. The body force became a pressure along z, which the z supports take.
Where it goes wrong
dloads.f accepts the label for every element type (master lines 322-334, (label(1:2).ne.'BX').and. ...). For a shell, both the single-element branch (lines 373-393) and the element-set branch (lines 495-515) then end in a catch-all:
elseif((lakon(l)(1:1).eq.'S').or.
& (lakon(l)(7:7).eq.'L')) then
...
else
label(1:2)='P1'
endif
The magnitude is passed on unchanged (xxmagnitude=xmagnitude), so BX/BY/BZ becomes P1, a pressure on face 1 of the expanded brick, along the shell normal. The catch-all fits the manual’s statement for shells (section 7.44), “there is only one kind of loading: pressure in the direction of the normal on the shell”, but BX/BY/BZ are volumetric loads (LOGBOOK, 4 April 2009), not pressures.
For solid elements e_c3d.f (master lines 1214-1251) integrates the label as a body force per unit volume:
if(sideload(id)(1:2).eq.'BX')
& ff(jj1)=ff(jj1)+xload(1,id)*shpj(4,jj)*weight
The expanded shell is a brick of thickness t, so this path would give B t per unit area, which is what GRAV gives through the density.
Membranes are expanded by gen3delem.f with the same marker as shells (lakon(i)(1:7)='C3D8 L' for M3D4, line 364). Before that, in the first step, the lakon is M3D4 and BX stays a body force; in later steps it hits the shell branch.
Fix
Not tested (no build here):
-
In both shell branches of dloads.f, keep labels that start with B (BX, BY, BZ and their NU forms) instead of renaming them to P1, e.g. add
elseif(label(1:1).eq.'B') then(no change) before the finalelse. e_c3d.f then integrates the body force over the expanded brick, as for solids. -
Document BX, BY and BZ in section 7.44 (*DLOAD): unit (force per unit volume), the element types that take them, and what OP=NEW does with them. For axisymmetric elements the manual could also say that BZ (normal to the r-z plane) is not allowed: on one CAX4 ring (r 1 to 2, E = 1000, nu = 0, held axially at the bottom)
EALL, BZ, 1.moves the nodes radially by -2.13E-05 / -2.24E-05, -1.0 % of whatBX, 1.gives, with exit 0 and no message (not traced).cax_bz.inp
*NODE 1, 1., 0. 2, 2., 0. 3, 2., 1. 4, 1., 1. *ELEMENT, TYPE=CAX4, ELSET=EALL 1, 1, 2, 3, 4 *NSET, NSET=BOT 1, 2 *NSET, NSET=ALLN 1, 2, 3, 4 *MATERIAL, NAME=M *ELASTIC 1000., 0. *SOLID SECTION, ELSET=EALL, MATERIAL=M *BOUNDARY BOT, 2, 2 *STEP *STATIC *DLOAD EALL, BZ, 1. *NODE PRINT, NSET=ALLN U *END STEPResult (exit 0): U1 = -2.134727E-05 at nodes 1 and 4 (r = 1), -2.242735E-05 at nodes 2 and 3 (r = 2), U2 = 0 at the held nodes. With
EALL, BX, 1.instead: U1 = 2.118271E-03 and 2.225447E-03.