# Node surface on a \*RIGID BODY node of plane elements, even an unused one: ccx adds a z-SPC and stops with "dependent side of a MPC and a SPC"

**URL:** <https://calculix.discourse.group/t/node-surface-on-a-rigid-body-node-of-plane-elements-even-an-unused-one-ccx-adds-a-z-spc-and-stops-with-dependent-side-of-a-mpc-and-a-spc/4264>\
**Category:** Analysis issues\
**Created:** [October 22, 2026, 7:16pm UTC](https://calculix.discourse.group/t/node-surface-on-a-rigid-body-node-of-plane-elements-even-an-unused-one-ccx-adds-a-z-spc-and-stops-with-dependent-side-of-a-mpc-and-a-spc/4264 "2026-10-22T19:16:35Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sandervdb](https://avatars.discourse-cdn.com/v4/letter/s/49beb7/32.png) [@Sandervdb](https://calculix.discourse.group/u/Sandervdb)\
**Post date:** [October 22, 2026, 7:16pm UTC](https://calculix.discourse.group/t/node-surface-on-a-rigid-body-node-of-plane-elements-even-an-unused-one-ccx-adds-a-z-spc-and-stops-with-dependent-side-of-a-mpc-and-a-spc/4264/1 "2026-10-22T19:16:35Z")

</div>

## Summary

A `*RIGID BODY` on nodes of plane stress, plane strain or axisymmetric elements runs in ccx 2.23 (the test deck `scheibe.inp`, “rigid body motion of plane strain elements”, does this). As soon as one of the rigid body’s nodes is also in a node surface (`*SURFACE, TYPE=NODE`), ccx stops before the first increment:

```auto
 *ERROR in cascade: the DOF corresponding to 
 node 5 in direction 3 is detected on the 
 dependent side of a MPC and a SPC

```

(exit 201). The deck has no SPC on node 5, and the surface does not have to be used anywhere: one node in an otherwise unused node surface is enough. The same deck without the surface runs, and so does the surface on a node outside the rigid body.

The SPC comes from `gen3dsurf.f`, which links every node of a node surface on plane elements to its expanded mid-plane node and fixes the original node in z. Section 7.129 (\*SURFACE) and section 7.113 (\*RIGID BODY) of the 2.23 manual mention no such constraint.

The surface can also be one that the model needs. A rigid CPS4 punch pressed onto a CPS4 block by node-to-surface contact, with the punch’s bottom nodes as the slave node surface, stops with the same message (for node 11). Section 7.22 (\*CONTACT PAIR) allows a nodal slave surface (“The dependent surface can be defined as a nodal surface”). With the same nodes given as an element face surface, the deck runs.

## 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 that identifies the cause (searched 22 Oct 2026). Not fixed: the plane-element branch of `gen3dsurf.f` is unchanged on master (9ba5d76); master only renamed its node-to-element arrays.

Related:

- [Error solving: SPC meaning](https://calculix.discourse.group/t/2583) (2025): the same stop (“node 1 in direction 3 is detected on the dependent side of a MPC and a SPC”) in a 2-D gear model ([Kinematic keyword definition](https://calculix.discourse.group/t/2577) is the same model), whose pinion had a node-based `*COUPLING` surface with `*KINEMATIC` 1, 3, and whose contact node sets shared nodes with the couplings. The thread did not find the cause; the error went away after the surfaces were changed. Probably the same `gen3dsurf.f` z-SPC: here, `rb_nosurf.inp` with its `*RIGID BODY` line replaced by `*SURFACE, NAME=SC, TYPE=NODE` / `RB` / `*COUPLING, REF NODE=100, SURFACE=SC, CONSTRAINT NAME=C1` / `*KINEMATIC` / `1, 3` stops with the same message for node 5, although section 7.27 asks for a face-based coupling surface.
- [Issues · Dhondtguido/CalculiX · GitHub](https://github.com/Dhondtguido/CalculiX/issues/59:) `*RIGID BODY` with plane elements in explicit dynamics stops on linear and nonlinear MPCs depending on each other. A different stop, in a different procedure; the static decks here run without the node surface.
- [https://calculix.discourse.group/t/1910/5:](https://calculix.discourse.group/t/1910/5:) a user adds an otherwise unused node surface in a 2-D model on purpose, to make an initial condition on a node set work. So the link between the user’s node and the expanded node that `gen3dsurf.f` makes is useful; the fix below keeps it.

## Minimal input

`rb_surf.inp`: two CPS4 elements; the right edge (nodes 5, 6) is a rigid body, pulled in x. The rigid body’s out-of-plane motions (reference node in z, rotations about x and y) are held. Node 5 is in a node surface that nothing uses.

```auto
** two CPS4 elements; the right edge (nodes 5, 6) is a rigid body with
** reference node 100, pulled in x; node 5 is also in a node surface S
** that nothing uses
*NODE, NSET=NALL
1, 0., 0., 0.
2, 1., 0., 0.
3, 1., 1., 0.
4, 0., 1., 0.
5, 2., 0., 0.
6, 2., 1., 0.
100, 2.5, 0.5, 0.
101, 2.5, 0.5, 0.
*ELEMENT, TYPE=CPS4, ELSET=EALL
1, 1, 2, 3, 4
2, 2, 5, 6, 3
*NSET, NSET=RB
5, 6
*SURFACE, TYPE=NODE, NAME=S
5
*RIGID BODY, NSET=RB, REF NODE=100, ROT NODE=101
*MATERIAL, NAME=M
*ELASTIC
1000., 0.3
*SOLID SECTION, ELSET=EALL, MATERIAL=M
1.
*BOUNDARY
1, 1, 2
4, 1, 1
100, 3, 3
101, 1, 2
*STEP
*STATIC
*CLOAD
100, 1, 1.
*NODE PRINT, NSET=RB
U
*END STEP

```

Variants:

- `rb_nosurf.inp`: the two lines `*SURFACE, TYPE=NODE, NAME=S` and `5` removed.
- `rb_surf_off.inp`: the surface holds node 1 (not in the rigid body) instead of node 5.

`rb_contact.inp`: a rigid CPS4 punch (element 2) pushed onto a CPS4 block (element 1) by node-to-surface contact; the punch’s bottom nodes form the slave node surface.

```auto
** a CPS4 block (element 1, bottom held) and a rigid CPS4 punch on top of it
** (element 2, *RIGID BODY, reference node 100); node-to-surface contact with
** the punch's bottom nodes 11, 12 as a node surface (slave) and the block's
** top edge as master; the punch is pushed down by 0.01
*NODE, NSET=NALL
1, 0., 0., 0.
2, 1., 0., 0.
3, 1., 1., 0.
4, 0., 1., 0.
11, 0.25, 1., 0.
12, 0.75, 1., 0.
13, 0.75, 1.5, 0.
14, 0.25, 1.5, 0.
100, 0.5, 1.5, 0.
101, 0.5, 1.5, 0.
*ELEMENT, TYPE=CPS4, ELSET=EB
1, 1, 2, 3, 4
*ELEMENT, TYPE=CPS4, ELSET=EP
2, 11, 12, 13, 14
*ELSET, ELSET=EALL
EB, EP
*NSET, NSET=PBOT
11, 12
*SURFACE, TYPE=NODE, NAME=SLAVE
PBOT
*SURFACE, NAME=MASTER
1, S3
*RIGID BODY, ELSET=EP, REF NODE=100, ROT NODE=101
*MATERIAL, NAME=M
*ELASTIC
1000., 0.3
*SOLID SECTION, ELSET=EALL, MATERIAL=M
1.
*SURFACE INTERACTION, NAME=SI
*SURFACE BEHAVIOR, PRESSURE-OVERCLOSURE=LINEAR
1.e5
*CONTACT PAIR, INTERACTION=SI, TYPE=NODE TO SURFACE
SLAVE, MASTER
*BOUNDARY
1, 1, 2
2, 2, 2
100, 1, 1
100, 3, 3
101, 1, 3
*STEP
*STATIC
*BOUNDARY
100, 2, 2, -0.01
*NODE PRINT, NSET=NALL
U
*END STEP

```

`rb_contact_face.inp`: the slave surface given as the punch’s bottom face instead:

```diff
-*SURFACE, TYPE=NODE, NAME=SLAVE
-PBOT
+*SURFACE, NAME=SLAVE
+2, S1

```

## How to run

```auto
ccx rb_surf
ccx rb_nosurf
ccx rb_surf_off
ccx rb_contact
ccx rb_contact_face

```

## Expected

The surface in `rb_surf` is not used, so `rb_surf` should give what `rb_nosurf` gives. `rb_contact` should run like `rb_contact_face`, since both name the same slave nodes.

## Actual

`rb_surf` and `rb_contact` stop with exit status 201:

```auto
 *ERROR in cascade: the DOF corresponding to 
 node 5 in direction 3 is detected on the 
 dependent side of a MPC and a SPC

```

(`rb_contact`: node 11). `rb_nosurf` and `rb_surf_off` run (exit 0) and print the same displacements:

```auto
         5 1.967819E-03 -1.417759E-04 0.000000E+00
         6 1.967819E-03 -1.417759E-04 0.000000E+00

```

`rb_contact_face` runs (exit 0): the punch nodes 11-14 move -1.000000E-02 in y, and the block’s top nodes 3 and 4 move -9.801560E-03 and -9.805991E-03.

## Where it goes wrong

After expanding the plane elements, `src/gen3delem.f` calls `gen3dsurf.f` in the first step (master line 453). `src/gen3dsurf.f` goes through every set whose name ends in ‘S’, which is how a node surface is stored (line 57), and for each node of a plane, plane strain or axisymmetric element:

- ties its x and y to the expanded mid-plane node by MPCs (lines 206-250);
- fixes the original node in z (lines 252-264):

```fortran
! fixing the original node in z-direction
!     
              val=0.d0
              k=3
              if(nam.gt.0) iamplitude=0
              type='M'
              call bounadd(node,k,k,val,nodeboun,

```

The comment at lines 193-199 gives the reason: the original node may end up in a contact spring element, and its z DOF would otherwise be free and make the system singular.

A `*RIGID BODY` makes nonlinear MPCs for all three translations of each member node, with the member’s DOF as the dependent term; for a plane-element node that includes z. `gen3dsurf.f` adds its z-SPC without checking whether that DOF is already the dependent of an MPC, and `cascade.c` (lines 76-90) then stops on the DOF that is both.

Section 6.2.22 (CPS8 and CPS8R) says: “The displacement in z-direction of the midplane is zero. This condition is introduced in the form of SPC’s. MPC’s must not be defined in z-direction!” As I read it, that concerns the expanded mid-plane nodes, not the user’s node. When ccx links a user’s node of a plane element to its mid-plane node, it leaves z out on purpose: `gen3dmpc.f` (lines 403-408, the test `idir.ne.3`) and `gen3dsurf.f` (lines 209-214, `do idir=1,2`) link only x and y. So the rigid body’s z-MPC stays on the user’s node and does not touch the mid-plane SPCs. That is why `rb_nosurf` and `scheibe.inp` run. The only conflict is the z-SPC that `gen3dsurf.f` puts on the same DOF.

The check does not depend on whether a card uses the surface: every node surface is processed.

## Fix

Possible fix (not built or tested): in `gen3dsurf.f`, skip the z-SPC when DOF 3 of the original node is already the dependent DOF of an MPC (look up `8*(node-1)+3` in `ikmpc`, as the routine already does for the mid-node DOFs). The MPC then already gives that DOF a value, which is what the SPC is meant to do for contact spring elements. The x/y link to the mid-plane node stays as it is.

Workaround: leave rigid-body nodes of plane elements out of node surfaces; for contact, give the slave surface as element faces.

---

<div class="post-metadata">

**Author:** ![Calc\_em](https://avatars.discourse-cdn.com/v4/letter/c/43a26b/32.png) [@Calc\_em](https://calculix.discourse.group/u/Calc_em)\
**Post date:** [October 23, 2026, 5:55am UTC](https://calculix.discourse.group/t/node-surface-on-a-rigid-body-node-of-plane-elements-even-an-unused-one-ccx-adds-a-z-spc-and-stops-with-dependent-side-of-a-mpc-and-a-spc/4264/2 "2026-10-23T05:55:35Z")

</div>

Confirmed using official build of ccx 2.23 on Windows, needs a GitHub ticket.

rb\_surf:

```auto
 STEP 1

 Static analysis was selected

 Decascading the MPC's

 *ERROR in cascade: the DOF corresponding to
 node 5 in direction 3 is detected on the
 dependent side of a MPC and a SPC

```

rb\_contact:

```auto
 STEP 1

 *WARNING reading *STATIC: a nonlinear analysis is requested
          but no time increment nor step is specified
          the defaults (1,1) are used

 Static analysis was selected

 Newton-Raphson iterative procedure is active

 Decascading the MPC's

 *ERROR in cascade: the DOF corresponding to
 node 11 in direction 3 is detected on the
 dependent side of a MPC and a SPC

```

---

<div class="post-metadata">

**Author:** ![Sandervdb](https://avatars.discourse-cdn.com/v4/letter/s/49beb7/32.png) [@Sandervdb](https://calculix.discourse.group/u/Sandervdb)\
**Post date:** [October 23, 2026, 5:57am UTC](https://calculix.discourse.group/t/node-surface-on-a-rigid-body-node-of-plane-elements-even-an-unused-one-ccx-adds-a-z-spc-and-stops-with-dependent-side-of-a-mpc-and-a-spc/4264/3 "2026-10-23T05:57:10Z")

</div>

posted: [Node surface on a \*RIGID BODY node of plane elements, even an unused one: ccx adds a z-SPC and stops with "dependent side of a MPC and a SPC" · Issue #294 · Dhondtguido/CalculiX · GitHub](https://github.com/Dhondtguido/CalculiX/issues/294)
