Known limitations#

Honest list of what femorph-solver does not do, what it does imperfectly today, and the failure modes a user can hit by exceeding the scope. Read this page before integrating femorph-solver into a workflow that depends on a capability listed here.

Items in this list are the ones we’d rather a user know about up front than discover three weeks into a project. The Roadmap page tracks which of these are scheduled to be fixed; this page focuses on the current failure modes and workarounds.

Material model#

  • Small-strain linear elasticity only. Every element kernel assumes geometric linearity and a linear elastic constitutive law. No plasticity (yield, hardening, creep), no hyperelasticity (Mooney-Rivlin, Ogden, Yeoh), no viscoelasticity, no damage / fracture. A nonlinear-material analysis run through femorph-solver silently treats the material as elastic — the numbers come back, but they’re wrong.

  • Anisotropic / orthotropic materials are partial. Isotropic with EX, PRXY, DENS is the well-trodden path. An orthotropic constitutive matrix can be assembled by hand and passed to the per-element kernel, but the public assign() API does not yet expose an orthotropic material card.

Geometric model#

  • No large deformation. Linear strain–displacement (small rotations, small strains). A geometric-nonlinear analysis with significant rotation or stretch is out of scope and will return wrong answers without raising.

  • No buckling solve yet. See Roadmap — linear buckling and pre-stressed modal are scheduled but not yet shipped.

  • No contact. Surface-surface contact, gap elements, and bonded-contact MPCs are not implemented. CP (coupled DOFs) is supported as a workaround for rigid bonded contact in some cases.

Element library#

  • Locking modes are present where the literature documents them. HEX8 with full integration shear-locks on bending- dominated meshes (use the EAS variant or HEX20). Pure-axial TRUSS2 has zero stiffness in the transverse DOFs (auto-pinned during the solve). See Mesh quality and Troubleshooting flowchart for the diagnostic flowchart.

  • No drilling DOF on QUAD4_SHELL. The DKT shell carries five DOFs per node; coupling a shell to a solid that expects six DOFs requires an explicit CP between the shell rotation and the solid translation.

  • Beam fibre stress recovery on BEAM2 is recent (v0.20.0). Stress at the section fibres ships, but only for the cross- sections registered today (rectangular, circular, I, T). Custom sections compute correctly for the matrices but not for fibre-stress recovery.

Solver backends#

  • Pardiso mixed-precision is MKL-implementation-dependent. Model.solve_modal(mixed_precision=True) and Model.solve_harmonic(mixed_precision=True) honour the request only when the linked MKL exposes iparm(28). Some Conda / vendor MKL builds silently no-op the request — see the note on solve_modal(). CyclicModel.solve_modal does not yet accept mixed_precision — its inner shift-invert factor lives below the kwarg-pass-through layer; tracked as a follow-up.

  • Out-of-core (OOC) solver paths are estimator-only. The estimate_solve() cost predictor knows about OOC multipliers, but the actual solve does not run out-of-core; problems that need OOC factorisation will run out of RAM rather than fall through to disk.

Foreign-deck interop#

  • Import-only. All four readers (NASTRAN, Abaqus, MAPDL, OptiStruct) read decks; none currently write. Round-tripping a CDB deck through femorph-solver back to MAPDL requires writing a fresh deck against the original solver’s grammar.

  • MAPDL native ``.dat`` files are not yet readable directly. The CDB path (cdwrite) is the supported entry point — see #513 for the native .dat reader work.

  • Coverage of card / KEYOPT combinations is rolling forward. The Vendor verification-manual coverage matrix tracks which problems round-trip cleanly through each reader. Cards that the deck parser doesn’t recognise are skipped silently — verify against the matrix before trusting a parsed deck on a new card.

  • No vendor binary write. RST / EMAT / FULL / HBMAT writers are out of scope for now; binary read is supported as a parity fixture.

Result formats#

  • The native ``.pv`` format is the only round-trip-safe one. Model.save / Model.load and the result classes’ .save / .load methods round-trip the full state through zstd-compressed pyvista. Saving a result as VTU loses the per-mode / per-step metadata; consume those formats only for external visualisation.

  • Stress / strain are derived on demand, not stored. The .pv files store displacement (and time / frequency / mode number) only. Result.stress(model=…) recomputes from the displacement plus the model’s element kernels. This is by design (lean files, lossless math), but it means the model must be available when reading a result back — the saved file alone is not enough to recover stress.

Performance#

  • Single-process only. Element assembly and the inner factorise / back-solve run on a single host with BLAS / OpenMP threading. No MPI, no GPU. See Thread control for thread-pool tuning.

  • Memory bound by the linear-solver backend. A 1 M-DOF HEX20 model needs ~10 GB peak RSS for a CHOLMOD factorisation. The estimate_solve() predictor reports pre-solve so the user can size the host before launching.

Documentation#

  • Documentation overhaul in progress. See #583. Until the autosummary refactor in #587 lands, some cross-references in the docs (:class:`UnitSystem`, :class:`ELEMENTS`) resolve to plain code formatting rather than autodoc pages. Functionality is unaffected.

Reporting a new limitation#

If you hit a failure mode not on this list, please file an issue at femorph/solver#issues with:

  • the smallest input that reproduces it,

  • the expected vs observed result, and

  • femorph_solver.Report() output (it captures the BLAS / MKL / backend versions the failure depends on).

Limitations that come up repeatedly get promoted onto this page; listed limitations get linked tracking issues so you can subscribe to progress.

See also#