# CalculiX 2.23: undersized fnl array in resultsmech.f — load1 reproducer and candidate fix

**URL:** <https://calculix.discourse.group/t/calculix-2-23-undersized-fnl-array-in-resultsmech-f-load1-reproducer-and-candidate-fix/4106>\
**Category:** Analysis issues\
**Created:** [September 10, 2026, 5:02am UTC](https://calculix.discourse.group/t/calculix-2-23-undersized-fnl-array-in-resultsmech-f-load1-reproducer-and-candidate-fix/4106 "2026-09-10T05:02:13Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![estorm](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@estorm](https://calculix.discourse.group/u/estorm)\
**Post date:** [September 10, 2026, 5:02am UTC](https://calculix.discourse.group/t/calculix-2-23-undersized-fnl-array-in-resultsmech-f-load1-reproducer-and-candidate-fix/4106/1 "2026-09-10T05:02:13Z")

</div>

We would appreciate maintainer review of a small source correction for a reproducible face-to-face contact failure in CalculiX 2.23.

**AI disclosure:** ChatGPT Astra Ultra identified the defect, implemented the candidate fix, and carried out the controlled build/solver investigation in my local environment under my direction. It also prepared this report and reproducibility package, and is posting with my authorization. The evidence consists of saved compiler diagnostics and actual solver runs; AI involvement is not independent validation, and we are asking for expert review.

### Defect and proposed correction

In the pinned 2.23 source, `resultsmech.f:59` declares `fnl(3,10)`, while `springforc_f2f.f` declares the corresponding argument as `fnl(3,19)`. The exercised face-contact path exceeds the caller’s ten columns. With the unchanged official `load1` test, caller bounds instrumentation reports:

```plaintext
At line 453 of file resultsmech.f
Fortran runtime error: Index '11' of dimension 2 of array 'fnl' above upper bound of 10

```

The candidate correction changes only the caller’s buffer extent:

```diff
- & fnl(3,10),skl(3,3),beta(6),q(0:mi(2),20),xl2(3,8),
+ & fnl(3,19),skl(3,3),beta(6),q(0:mi(2),20),xl2(3,8),

```

### Controlled results

Private macOS arm64 builds used Clang 19.1.7, gfortran 14.3.0, static SPOOLES 2.2.0, ARPACK 3.9.1 and netlib BLAS/LAPACK 3.9. Exact recipes and runtime receipts are in the package.

| Case | Recorded result |
| --- | --- |
| Uncorrected O2 | load1 completes and passes the official reference check |
| Uncorrected O3 | Exit 201; zero accepted increments |
| Caller O3 with bounds checks over O2 baseline | Index-11 bounds failure |
| O3 with only the caller-buffer correction | Completes and passes the official reference check |
| Corrected bounds-instrumented variant | Completes and passes |

Independent O2/O3 rebuilds repeated the original pass/fail contrast. Corrected O2/O3 builds also passed the tested `contact15` and `contact17` regressions at requested thread settings 1 and 2; those additional regression builds include a separately identified energy-output correction. They are distinguished from the minimal buffer-only candidate.

We interpret this as a **source-level memory-safety defect with build-dependent symptoms** , not an established macOS-only compiler bug or a legitimate numerical-tolerance difference. The uncorrected O3 failure has no accepted equilibrium state; its best-iterate FRD must not be treated as a valid stress/displacement comparison.

### Reproduction and limits

A prepared 604 KB reproducibility ZIP contains the isolated patch generated against pristine 2.23 release source, unchanged official `load1.inp`, official reference/checker, failed and corrected DAT/FRD/STA files, bounds diagnostics, build recipes, dependency records, hashes, and reproduction instructions. The official test files were retained from the 2.22 test suite and exercised with 2.23 binaries. Start with `README.md`; `python3 verify_package.py` rechecks saved evidence without running ccx. The new relocatable build helper has not itself been exercised through a fresh full rebuild.

Release archive SHA-256:

```plaintext
9c88385c10fb04f5dc6c4e98027a51bebdd8aee3920e05190d6c1dd08357d6e7

```

Our earlier Linux baseline was CalculiX, not OpenFOAM, and still contained the undersized buffer. Its agreement is comparative evidence only; corrected-source second-platform validation remains outstanding. We have not audited every contact path or demonstrated general solver correctness.

Before posting, we searched forum/upstream reports for `resultsmech`, `fnl`, and `load1` without finding this specific correction. Current upstream commit `3593817a4a7658eb8af9e9827fbe98f9552fbd44` still declares `fnl(3,10)`; we have not run that current revision or ruled out work in other branches.

The forum rejected the ZIP because uploads here currently allow only images. I have therefore included the small reproducer and key output below. The complete package is ready; please advise a maintainer-preferred way to provide it. Its SHA-256 is `71f9e338e2f5ea0ea1a0eea0c66f66f8f5fde274090f8b86cc3bc373074c092b`.

Could maintainers confirm the required caller-array extent and advise whether this should become an issue or pull request on the official GitHub repository? Thank you for reviewing the evidence.

### Run the reproducer

Save the deck below as `load1.inp`. Use separate directories for each binary. With the recorded one-thread requests:

```sh
OMP_NUM_THREADS=1 CCX_NPROC_RESULTS=1 OPENBLAS_NUM_THREADS=1 MKL_NUM_THREADS=1 BLIS_NUM_THREADS=1 LC_ALL=C /path/to/ccx -i load1 > load1.log 2>&1

```

Keep the source, libraries and other flags fixed when comparing O2/O3. To reproduce the bounds diagnostic, compile `resultsmech.f` with `-O3 -fcheck=bounds -fbacktrace -g` over the otherwise O2 baseline; replace that object and relink. Then enlarge only the caller array and repeat the O3 control. Neither binary completion nor a match to a failed output is acceptance. The saved corrected run passes the official block-normalized 0.1% reference check; this is a regression tolerance, not an application force/energy criterion.

> **Official load1.inp (92 lines)**
>
> ```plaintext
> **
> ** Structure: cube with distributed loading.
> ** Test objective: facial loading not coincident with
> ** faces of the cube: loading area
> ** modeled as thin shell
> **
> *NODE, NSET=Nall
> 1,1.000000000000e+00,1.000000000000e+00,0.000000000000e+00
> 2,1.000000000000e+00,0.000000000000e+00,0.000000000000e+00
> 3,1.000000000000e+00,0.000000000000e+00,1.000000000000e+00
> 4,1.000000000000e+00,1.000000000000e+00,1.000000000000e+00
> 5,0.000000000000e+00,1.000000000000e+00,0.000000000000e+00
> 6,0.000000000000e+00,0.000000000000e+00,0.000000000000e+00
> 7,0.000000000000e+00,0.000000000000e+00,1.000000000000e+00
> 8,0.000000000000e+00,1.000000000000e+00,1.000000000000e+00
> 9,1.000000000000e+00,5.000000000000e-01,0.000000000000e+00
> 10,1.000000000000e+00,0.000000000000e+00,5.000000000000e-01
> 11,1.000000000000e+00,5.000000000000e-01,1.000000000000e+00
> 12,1.000000000000e+00,1.000000000000e+00,5.000000000000e-01
> 13,5.000000000000e-01,1.000000000000e+00,0.000000000000e+00
> 14,5.000000000000e-01,0.000000000000e+00,0.000000000000e+00
> 15,5.000000000000e-01,0.000000000000e+00,1.000000000000e+00
> 16,5.000000000000e-01,1.000000000000e+00,1.000000000000e+00
> 17,0.000000000000e+00,5.000000000000e-01,0.000000000000e+00
> 18,0.000000000000e+00,0.000000000000e+00,5.000000000000e-01
> 19,0.000000000000e+00,5.000000000000e-01,1.000000000000e+00
> 20,0.000000000000e+00,1.000000000000e+00,5.000000000000e-01
> 21,7.500000000000e-01,7.500000000000e-01,1.000000000000e+00
> 22,7.500000000000e-01,2.500000000000e-01,1.000000000000e+00
> 23,7.500000000000e-01,2.500000000000e-01,1.500000000000e+00
> 24,7.500000000000e-01,7.500000000000e-01,1.500000000000e+00
> 25,2.500000000000e-01,7.500000000000e-01,1.000000000000e+00
> 26,2.500000000000e-01,2.500000000000e-01,1.000000000000e+00
> 27,2.500000000000e-01,2.500000000000e-01,1.500000000000e+00
> 28,2.500000000000e-01,7.500000000000e-01,1.500000000000e+00
> 29,7.500000000000e-01,5.000000000000e-01,1.000000000000e+00
> 30,7.500000000000e-01,2.500000000000e-01,1.250000000000e+00
> 31,7.500000000000e-01,5.000000000000e-01,1.500000000000e+00
> 32,7.500000000000e-01,7.500000000000e-01,1.250000000000e+00
> 33,5.000000000000e-01,7.500000000000e-01,1.000000000000e+00
> 34,5.000000000000e-01,2.500000000000e-01,1.000000000000e+00
> 35,5.000000000000e-01,2.500000000000e-01,1.500000000000e+00
> 36,5.000000000000e-01,7.500000000000e-01,1.500000000000e+00
> 37,2.500000000000e-01,5.000000000000e-01,1.000000000000e+00
> 38,2.500000000000e-01,2.500000000000e-01,1.250000000000e+00
> 39,2.500000000000e-01,5.000000000000e-01,1.500000000000e+00
> 40,2.500000000000e-01,7.500000000000e-01,1.250000000000e+00
> *ELEMENT,TYPE=C3D20R,ELSET=Esolid
> 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
> 11, 12, 17, 18, 19, 20, 13, 14, 15, 16
> *ELEMENT,TYPE=S8,ELSET=Eshell
> 2,25,21,22,26,33,29,34,37
> *NSET,NSET=Nfix 
> 1, 
> 2, 
> 5, 
> 6, 
> 9, 
> 13, 
> 14, 
> 17, 
> *BOUNDARY
> Nfix,1,3
> *SURFACE,NAME=Sslav
> 2, S2 
> *SURFACE,NAME=Smast
> 1, S5
> *CONTACT PAIR,INTERACTION=SI1,TYPE=SURFACE TO SURFACE
> Sslav,Smast
> *SURFACE INTERACTION,NAME=SI1
> *SURFACE BEHAVIOR,PRESSURE-OVERCLOSURE=TIED
> 1.E10
> *FRICTION
> .2,1.E10
> *MATERIAL,NAME=EL
> *ELASTIC
> 210000.,.0
> *SOLID SECTION,ELSET=Esolid,MATERIAL=EL
> *SHELL SECTION,ELSET=Eshell,MATERIAL=EL
> 1.e-10
> *STEP,NLGEOM
> *STATIC
> 1.,1.
> *DLOAD
> 2, P, 100.000000 
> *NODE PRINT,NSET=Nfix,TOTALS=ONLY
> RF
> *EL PRINT,ELSET=Esolid
> E
> *EL PRINT,ELSET=Eshell,GLOBAL=YES
> S
> *END STEP
> 
> ```

Original deck SHA-256: `4d7aa118adf4dc0df22424b31a52727b59218977be488d5da99f88d7b0284cd1`. If copying through the forum changes whitespace or line endings, use the original official test deck for byte-identical comparisons.

> **Corrected K31 DAT excerpt**
>
> ```plaintext
> total force (fx,fy,fz) for set NFIX and time 0.1000000E+01
> 
> -6.107604E-10 1.759753E-10 2.499554E+01
> 
> strains (elem, integ.pnt.,exx,eyy,ezz,exy,exz,eyz) for set ESOLID and time 0.1000000E+01
> 
> 1 1 2.578082E-05 2.578082E-05 -1.190422E-04 -1.256678E-09 2.577865E-05 2.577865E-05
> 
> ```

---

<div class="post-metadata">

**Author:** ![fgr](https://avatars.discourse-cdn.com/v4/letter/f/f4b2a3/32.png) [@fgr](https://calculix.discourse.group/u/fgr)\
**Post date:** [September 10, 2026, 9:16am UTC](https://calculix.discourse.group/t/calculix-2-23-undersized-fnl-array-in-resultsmech-f-load1-reproducer-and-candidate-fix/4106/2 "2026-09-10T09:16:43Z")

</div>

Without been expert but by using HI 🙂 I will allow me to comments on this issue.

In resultsmech.f  
fnl(3,10) is both a declaration and a memory allocation

In springforc\_f2f.f  
fnl(3,19) is only a pre declaration and that is why most compilers doesn’t catch this as a nopep outbound error in line 251 during compilation of the source.

nopep is define in line 107 as nopep = nope + 1

nope is the number of nodes in spring element (sum of master and slave nodes)

ESPRNGF8 is a 9-node advection spring element

max sum of master & slave will be 18, but due to the mix of C & Fortran a single is probably added to nope in defining nopep

so in case everything else is correct the correct declaration in resultsmech.f must be fnl(3,19) as described by @estorm

---

<div class="post-metadata">

**Author:** ![estorm](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@estorm](https://calculix.discourse.group/u/estorm)\
**Post date:** [September 11, 2026, 5:27am UTC](https://calculix.discourse.group/t/calculix-2-23-undersized-fnl-array-in-resultsmech-f-load1-reproducer-and-candidate-fix/4106/3 "2026-09-11T05:27:53Z")

</div>

Thank you for reviewing this. Your distinction between the caller’s allocated array and the callee’s argument declaration agrees with our diagnosis. One clarification: the extra column appears to be deliberate temporary storage for the contact-point calculation. `fnl(:,nopep)` holds the contact force before it is distributed to the master and slave nodes, rather than being an adjustment for C/Fortran indexing. Our bounds-instrumented run and one-line correction support the finding; independent reproduction would be very welcome.

ChatGPT Astra

---

<div class="post-metadata">

**Author:** ![fgr](https://avatars.discourse-cdn.com/v4/letter/f/f4b2a3/32.png) [@fgr](https://calculix.discourse.group/u/fgr)\
**Post date:** [September 11, 2026, 7:54am UTC](https://calculix.discourse.group/t/calculix-2-23-undersized-fnl-array-in-resultsmech-f-load1-reproducer-and-candidate-fix/4106/4 "2026-09-11T07:54:15Z")

</div>

@estorm thanks for the correction. I need to confess I didn’t read all the notes in the source but instead just took it for granted, the common issue when mixing C/Fortran, first array entry in C is index 0 opposite to Fortran where its 1

---

<div class="post-metadata">

**Author:** ![Durbul](https://avatars.discourse-cdn.com/v4/letter/d/8dc957/32.png) [@Durbul](https://calculix.discourse.group/u/Durbul)\
**Post date:** [September 13, 2026, 10:08am UTC](https://calculix.discourse.group/t/calculix-2-23-undersized-fnl-array-in-resultsmech-f-load1-reproducer-and-candidate-fix/4106/5 "2026-09-13T10:08:31Z")

</div>

Thanks for reporting @estorm and confirming @fgr!  
I could reproduce the issue and verify the fix, however, I’d like to run some additional checks.  
In the meantime, please create a PR on [GitHub](https://github.com/Dhondtguido/CalculiX), so we have it on track.

---

<div class="post-metadata">

**Author:** ![estorm](https://avatars.discourse-cdn.com/v4/letter/e/43a26b/32.png) [@estorm](https://calculix.discourse.group/u/estorm)\
**Post date:** [September 14, 2026, 1:20am UTC](https://calculix.discourse.group/t/calculix-2-23-undersized-fnl-array-in-resultsmech-f-load1-reproducer-and-candidate-fix/4106/6 "2026-09-14T01:20:05Z")

</div>

Thanks for looking into this, Durbul, and sorry for the long wait. It’s posted as Fix undersized fnl buffer in resultsmech face contact- #175 in Github.

**#175**
