# \*FREQUENCY / \*BUCKLE after a nonlinear step: an \*EQUATION that a \*RIGID BODY or knot MPC depends on is not decascaded again, wrong eigenvalues (exit 0, no message)

**URL:** <https://calculix.discourse.group/t/frequency-buckle-after-a-nonlinear-step-an-equation-that-a-rigid-body-or-knot-mpc-depends-on-is-not-decascaded-again-wrong-eigenvalues-exit-0-no-message/4199>\
**Category:** Analysis issues\
**Created:** [October 21, 2026, 6:20pm UTC](https://calculix.discourse.group/t/frequency-buckle-after-a-nonlinear-step-an-equation-that-a-rigid-body-or-knot-mpc-depends-on-is-not-decascaded-again-wrong-eigenvalues-exit-0-no-message/4199 "2026-10-21T18:20:01Z")\
**Posts on this page:** 2\
**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 21, 2026, 6:20pm UTC](https://calculix.discourse.group/t/frequency-buckle-after-a-nonlinear-step-an-equation-that-a-rigid-body-or-knot-mpc-depends-on-is-not-decascaded-again-wrong-eigenvalues-exit-0-no-message/4199/1 "2026-10-21T18:20:01Z")

</div>

## Summary

A model has an `*EQUATION` whose dependent DOF is also a term of a nonlinear MPC: here the reference node of a `*RIGID BODY`, or a shell node that ccx made a knot. In a nonlinear first step (NLGEOM, no load), ccx prints `*INFO in cascade: linear MPCs and nonlinear MPCs depend on each other` and keeps the MPCs undecascaded, as intended for a nonlinear step. In the next step, a `*FREQUENCY` or `*BUCKLE` step, ccx does not decascade them again, and the eigenvalues come out wrong without any message (exit 0).

Equivalent inputs give different answers, which shows that this is a bug:

- the same deck with a linear first step (still no load) gives the right frequencies;
- the same deck with an identity `*TRANSFORM` on one clamped node gives the right frequencies, because any `*TRANSFORM` makes ccx decascade in every step.

## Version

ccx 2.23 (macOS arm64), OMP\_NUM\_THREADS=1. Source: master 9ba5d76 (16 Oct 2026).

## Already reported or fixed?

Not reported: there is no matching GitHub issue (open or closed) or pull request in Dhondtguido/CalculiX, and no calculix.discourse.group topic (all 1,234 topic titles and keyword searches checked, 21 Oct 2026). Not fixed: the decascading condition in `CalculiX.c` (line 1178) and `cascade.c` are unchanged on master (9ba5d76).

Related but different: [CalculiX crashes on an \*EQUATION between the nodes of two rigid bodies · Issue #178 · Dhondtguido/CalculiX · GitHub](https://github.com/Dhondtguido/CalculiX/issues/178) (closed: an `*EQUATION` between two rigid bodies crashed ccx in a single nonlinear step; here every step runs and the linear step after it is wrong).

## Minimal input

`eq_rigid.inp`:

```auto
** C3D8 cantilever 200 x 20 x 20 clamped at x = 0; its tip face is a *RIGID BODY;
** an *EQUATION ties the reference node's z to node 6 (x = 100, z = 20)
*NODE
1, 0., 0., 0.
2, 0., 0., 20.
3, 0., 20., 0.
4, 0., 20., 20.
5, 100., 0., 0.
6, 100., 0., 20.
7, 100., 20., 0.
8, 100., 20., 20.
9, 200., 0., 0.
10, 200., 0., 20.
11, 200., 20., 0.
12, 200., 20., 20.
100, 200., 10., 10.
101, 200., 10., 10.
*ELEMENT, TYPE=C3D8, ELSET=E
1, 1, 5, 7, 3, 2, 6, 8, 4
2, 5, 9, 11, 7, 6, 10, 12, 8
*NSET, NSET=FIX
1, 2, 3, 4
*NSET, NSET=TIP
9, 10, 11, 12
*MATERIAL, NAME=M
*ELASTIC
210000., 0.3
*DENSITY
7.8e-9
*SOLID SECTION, ELSET=E, MATERIAL=M
*RIGID BODY, NSET=TIP, REF NODE=100, ROT NODE=101
*EQUATION
2
100, 3, 1., 6, 3, -1.
*BOUNDARY
FIX, 1, 3
*STEP, NLGEOM
*STATIC
*END STEP
*STEP
*FREQUENCY
3
*END STEP

```

Twins:

- `eq_rigid_lin.inp`: `*STEP` instead of `*STEP, NLGEOM` in step 1.
- `eq_rigid_tr.inp`: these lines inserted before `*EQUATION` (an identity transformation on a clamped node):

```auto
*NSET, NSET=T
1
*TRANSFORM, NSET=T
1., 0., 0., 0., 1., 0.

```

## How to run

`ccx eq_rigid`, `ccx eq_rigid_lin`, `ccx eq_rigid_tr`; compare the eigenvalue output in the .dat files.

## Expected

The frequencies of the twins, which agree with each other:

| mode | `eq_rigid_lin` (Hz) | `eq_rigid_tr` (Hz) |
| --- | --- | --- |
| 1 | 1336.581 | 1336.581 |
| 2 | 2601.245 | 2601.245 |
| 3 | 5176.374 | 5176.374 |

## Actual

`eq_rigid` (exit 0, no warning):

| mode | `eq_rigid` (Hz) | vs. the twins |
| --- | --- | --- |
| 1 | 1336.581 | same |
| 2 | 4126.420 | +58.6 % |
| 3 | 6836.295 | +32.1 % |

In step 2 the output goes straight to “Determining the structure of the matrix:”; in `eq_rigid_tr` that line follows a new “Decascading the MPC’s”.

`*BUCKLE` is affected the same way: with step 2 replaced by `*BUCKLE` (2 factors) and `*CLOAD` `100, 1, -1000.`, the first factor is 434.1789, 3.6 % lower than the 450.3799 of the `*TRANSFORM` twin (the twin with a linear first step gives 450.3799 too). The second factor agrees (1729.632 vs 1729.636).

> **The same with knots: an S4 cantilever whose tip nodes ccx makes knots (2669.851 Hz instead of 461.6533 Hz)**
>
> `eq_knot.inp` (the B31 elements only make ccx create knots at shell nodes 3 and 6):
> 
> ```auto
> ** S4 cantilever 20 x 10 x 0.2 clamped at x = 0; the B31 beams 3 and 4 only make tip nodes 3 and 6 knots
> ** one *EQUATION ties the tips' z; step 1: NLGEOM static without load; step 2: *FREQUENCY
> *NODE
> 1, 0, 0, 0
> 2, 10, 0, 0
> 3, 20, 0, 0
> 4, 0, 10, 0
> 5, 10, 10, 0
> 6, 20, 10, 0
> 903, 20.1554563176, 0.155456317551, 0.155456317551
> 904, 20.1554563176, 10.1554563176, 0.155456317551
> *ELEMENT, TYPE=S4, ELSET=E
> 1, 1, 2, 5, 4
> 2, 2, 3, 6, 5
> *NSET, NSET=FIX
> 1, 4
> *MATERIAL, NAME=M
> *ELASTIC
> 210000., 0.3
> *DENSITY
> 7.8e-9
> *SHELL SECTION, ELSET=E, MATERIAL=M
> 0.2
> *ELEMENT, TYPE=B31, ELSET=KN
> 3, 3, 903
> 4, 6, 904
> *MATERIAL, NAME=KN
> *ELASTIC
> 210000., 0.
> *DENSITY
> 0.
> *BEAM SECTION, ELSET=KN, MATERIAL=KN, SECTION=RECT
> 0.1346, 0.1346
> 1., -1., 0.
> *EQUATION
> 2
> 6, 3, 1., 3, 3, -1.
> *STEP, NLGEOM
> *STATIC
> 1., 1.
> *BOUNDARY
> FIX, 1, 6
> *END STEP
> *STEP
> *FREQUENCY
> 3
> *END STEP
> 
> ```
> 
> | | mode 1 (Hz) | mode 2 (Hz) | mode 3 (Hz) |
> | --- | --- | --- | --- |
> | `eq_knot` | 2669.851 | 9891.557 | 19014.72 |
> | step 1 without NLGEOM | 461.6533 | 5008.907 | 19014.72 |
> | identity `*TRANSFORM` on node 1 | 461.6533 | 5008.907 | 19014.72 |

## Where it goes wrong

1. In a nonlinear step, `cascade.c` treats `RIGID`, `KNOT`, `PLANE`, `BEAM` and `STRAIGHT` MPCs as nonlinear (lines 104-117: all MPCs count as linear only if `*iperturb<2`). When a nonlinear MPC has an independent term that is the dependent DOF of another MPC and the call comes from main, it sets `*icascade=2` and skips the substitution (`cascade.c:162-178`):

```c
	  /* no expansion if there is a dependence of a
	     nonlinear MPC on another linear or nonlinear MPC
	     and the call is from main */
	  if((jmpc[mpc-1]==1)||(nl==1)){
	    *icascade=2;

```

1. `nonlingeo.c` keeps a copy of these undecascaded MPCs (lines 787-795), cascades them per iteration, and restores the undecascaded copy at the end of the step (lines 4269-4277). It returns `icascade=2` in `mpcinfo[2]`.

2. In the next step, `CalculiX.c:707` sets `icascade=0` for a linear step, but `CalculiX.c:1176-1178` decascades only when

```c
    /* decascading MPC's only necessary if MPC's changed */

    if(((istep==1)||(ntrans>0)||(mpcend<0)||(nk!=nkold)||(nmpc!=nmpcold))&&(icascade==0)){

```

None of these hold here, so the linear step uses MPCs in which the `*EQUATION`’s dependent DOF (node 100, DOF 3) is still an independent term of the rigid-body MPCs. With any `*TRANSFORM` (`ntrans>0`) the condition holds and the result is right. How the matrix assembly then treats that term was not traced.

## Fix

Decascade again when the previous step left the MPCs undecascaded, e.g. remember the value before line 707:

```c
    icascadeprev=icascade;
    if((abs(nmethod)!=1)||(iperturb[0]<2))icascade=0;
    ...
    if(((istep==1)||(ntrans>0)||(mpcend<0)||(nk!=nkold)||(nmpc!=nmpcold)||
        (icascadeprev==2))&&(icascade==0)){

```

Workaround: an identity `*TRANSFORM` on any node (for example a clamped one). Where the eigenvalue step does not need the nonlinear step’s base state, running it first also avoids the problem.

---

<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 21, 2026, 7:50pm UTC](https://calculix.discourse.group/t/frequency-buckle-after-a-nonlinear-step-an-equation-that-a-rigid-body-or-knot-mpc-depends-on-is-not-decascaded-again-wrong-eigenvalues-exit-0-no-message/4199/2 "2026-10-21T19:50:30Z")

</div>

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

eq\_rigid.dat:

```auto
     E I G E N V A L U E O U T P U T

 MODE NO EIGENVALUE FREQUENCY   
                                     REAL PART IMAGINARY PART
                           (RAD/TIME) (CYCLES/TIME (RAD/TIME)

      1 0.7052614E+08 0.8397984E+04 0.1336581E+04 0.0000000E+00
      2 0.6722124E+09 0.2592706E+05 0.4126420E+04 0.0000000E+00
      3 0.1845021E+10 0.4295371E+05 0.6836295E+04 0.0000000E+00

```
