NASTRAN migration ================= If your starting point is a NASTRAN deck (MSC, NX, Simcenter, or one of the open-source dialects), this page is the bridge into femorph-solver. The mapping is mostly mechanical — the language is different but every concept has a direct counterpart. For the one-table cheat-sheet, see :doc:`terminology`. For the deep-dive on which BDF cards we read today, keep going. Loading a BDF deck ------------------ Single call (``from_bdf``) reads the ASCII bulk-data deck and returns a :class:`~femorph_solver.Model` ready to assemble:: from femorph_solver.interop.nastran import from_bdf model = from_bdf("rotor.bdf") model.fix(nodes=clamped_nodes, dof="ALL") result = model.solve_static() The reader handles MSC Nastran 2014+ free-format and fixed-format decks, NX Nastran (Simcenter Nastran) decks back to v8, and the open-source ``pyNastran`` BDF format. Decks written from older Nastran versions (pre-v68) sometimes use fixed-format only — pass them through ``pyNastran``'s ``write_bdf`` first to normalise. What's read ----------- The reader covers the linear-elastic structural-mechanics slice femorph-solver supports today: ========================== ============================================ NASTRAN card Maps to ========================== ============================================ ``GRID`` :meth:`Model.grid` point with global coordinates ``CORD2R`` / ``CORD2C`` Coordinate-system reference (only ``CORD2R`` rectangular today) ``CHEXA(8)`` ``ELEMENTS.HEX8`` ``CHEXA(20)`` ``ELEMENTS.HEX20`` ``CTETRA(10)`` ``ELEMENTS.TET10`` ``CPENTA(15)`` ``ELEMENTS.WEDGE15`` ``CPYRAM(13)`` ``ELEMENTS.PYR13`` ``CQUAD4`` (PSHELL) ``ELEMENTS.QUAD4_SHELL`` (and PLANE for plane-stress decks) ``CTRIA3`` (PSHELL) (planned — currently warns) ``CBAR`` / ``CBEAM`` ``ELEMENTS.BEAM2`` (no warping; rectangular / circular sections) ``CROD`` / ``CTUBE`` ``ELEMENTS.TRUSS2`` ``CELAS1`` / ``CELAS2`` ``ELEMENTS.SPRING`` ``CONM1`` / ``CONM2`` ``ELEMENTS.POINT_MASS`` (translational only — rotational inertia tensor ignored with a warning) ``MAT1`` Isotropic material (E, nu, rho fields) ``MAT9`` Orthotropic material (full anisotropic-elasticity matrix) ``PSOLID`` / ``PSHELL`` Property → element binding ``PROD`` / ``PBAR`` Property → element binding ``SPC`` / ``SPC1`` :meth:`Model.fix(dof=...)` per pinned DOF ``FORCE`` / ``MOMENT`` :meth:`Model.apply_force(fx=, fy=, ..., mx=, ...)` ``GRAV`` Gravity body force ``PLOAD2`` / ``PLOAD4`` Distributed surface pressure ``MPC`` Multi-point constraint (cyclic-symmetry only at present) ========================== ============================================ What's flagged but not read --------------------------- The reader emits a warning and skips: - ``MAT2`` / ``MAT3`` / ``MAT8`` / ``MAT11`` — composite laminate cards. Composite layups need the planned ``QUAD4_SHELL`` composite extension; not yet shipped. - ``CHEXA`` with 27 / 64 nodes — non-standard high-order forms; HEX20 covers the common quadratic case. - ``RBE2`` / ``RBE3`` — rigid-body / interpolation elements. Add as MPC constraints when supported. - ``MAT9ORT`` orthotropic-with-thermal — thermal coupling not yet shipped. - ``CDAMP`` damping elements — Rayleigh damping at the model level is the current path. Solution sequences ------------------ NASTRAN decks declare the analysis type via the **Executive Control** ``SOL N`` line. The reader is BDF-only and ignores SOL — you choose the analysis type via the ``Model`` API after the deck is loaded: ============================== ============================================ NASTRAN SOL femorph-solver call ============================== ============================================ ``SOL 101`` static :meth:`Model.solve_static` ``SOL 103`` modal :meth:`Model.solve_modal` ``SOL 105`` linear buckling not yet shipped (planned) ``SOL 108`` direct freq :meth:`Model.solve_harmonic` ``SOL 109`` direct transient :meth:`Model.solve_transient` ``SOL 111`` modal freq :meth:`Model.solve_harmonic` (mode-superposition mode) ``SOL 112`` modal transient :meth:`Model.solve_transient` (mode-superposition mode) ============================== ============================================ This separation is intentional — it lets you re-use the same geometry for multiple analysis types without re-parsing the deck. Result-format readback ---------------------- The reader is BDF-only. Reading NASTRAN ``.op2`` / ``.f06`` / ``.h5`` result files isn't currently supported — you'd run the solve through femorph-solver, export the result to the canonical ``.pv`` format, and visualise from there: .. code-block:: python from femorph_solver.interop.nastran import from_bdf model = from_bdf("model.bdf") result = model.solve_static() result.save("model.pv", model) If you specifically need NASTRAN-format output for downstream post-processing, file an issue with the use case — the ``op2`` writer is on the planned roadmap. Edge cases worth flagging ------------------------- **DOF ordering.** NASTRAN orders DOFs as ``(UX, UY, UZ, RX, RY, RZ)``. femorph-solver matches: see :meth:`Model.dof_map` documentation. If you read a BDF deck that was originally written by Abaqus' BDF-export and re-imported, the DOF ordering may have been mangled — always sanity-check on a known-good static solve before trusting the readback. **Free-format vs fixed-format.** Modern NASTRAN decks mix both (e.g. ``GRID*`` long-form for high-precision coordinates). The reader handles both transparently. **Comment cards** (``$``, ``$#``). Stripped silently. **Bulk-data Continuation** (``+``-cards). Joined transparently. **Free-field separators** (``,``). Handled. **Case-control input** — not parsed. The reader is bulk-data only; if your deck contains essential ``SUBCASE`` information for load-step assignment, you'll need to encode that in the femorph-solver Model directly (one ``Model`` per load case). Concrete migration recipe ------------------------- For a typical static-analysis deck: .. code-block:: python from femorph_solver.interop.nastran import from_bdf # 1. Load the deck. All BDF cards above become # Model state — geometry, materials, BCs, loads. model = from_bdf("vehicle_frame.bdf") # 2. Optionally inspect or modify the model: print(f"{model.grid.n_points} nodes, {model.grid.n_cells} cells") # 3. Solve and recover result quantities. result = model.solve_static() # 4. Write to canonical ``.pv`` for downstream # post-processing in the femorph-solver gallery # recipes (:doc:`/gallery/post-processing/index`). result.save("vehicle_frame.pv", model) # 5. Stress recovery + design check follow the # standard recipes — same code regardless of which # deck you started from: from femorph_solver.recover import compute_nodal_stress, stress_invariants sigma = compute_nodal_stress(model, result.displacement.ravel()) inv = stress_invariants(sigma) print(f"Peak σ_VM = {inv['von_mises'].max() / 1e6:.2f} MPa") Cross-references ---------------- - :doc:`terminology` — the one-table Rosetta covering every concept across femorph-solver / MAPDL / NASTRAN / Abaqus / LS-DYNA. - :doc:`/getting-started/mapdl-interop` — the MAPDL equivalent of this page. - :doc:`/reference/elements/index` — per-element technical sheets, each carrying a cross-vendor mapping table that starts from the femorph-solver name and lists the NASTRAN card.