The Model ========= :class:`femorph_solver.Model` is the pre-processing wrapper. It holds a :class:`pyvista.UnstructuredGrid` (nodes + cells), the global material and real-constant tables, the element-type registry, and the current Dirichlet / force records. From it the solver family assembles the global sparse :math:`K` and :math:`M`. Two ways to construct one ------------------------- From an existing mesh If you already have a :class:`pyvista.UnstructuredGrid` or a :class:`mapdl_archive.Archive`:: import mapdl_archive import femorph_solver archive = mapdl_archive.Archive("blade.cdb") m = femorph_solver.Model.from_grid(archive.grid) ``from_grid`` expects the MAPDL-style cell/point arrays (``ansys_node_num``, ``ansys_elem_num``, ``ansys_elem_type_num``, ``ansys_material_type``, ``ansys_real_constant``). Missing arrays are auto-filled with sequential 1-based ids, so a plain pyvista mesh also works. By hand, native API The first-class entry point is :meth:`Model.assign`, which declares the element kernel + material in one call:: import femorph_solver as fs model = fs.Model.from_grid(grid) model.assign( fs.ELEMENTS.HEX8, {"EX": 2.0e11, "PRXY": 0.30, "DENS": 7850.0}, ) By hand, APDL-dialect For users porting an APDL deck command-by-command, :class:`femorph_solver.interop.mapdl.APDL` exposes the ``N`` / ``E`` / ``ET`` / ``MAT`` / ``MP`` verbs over the same Model. MAPDL element-catalogue spellings are translated to neutral kernel names at this boundary (``"SOLID185"`` → ``"HEX8"`` etc.):: from femorph_solver.interop.mapdl import APDL model = fs.Model() with APDL(model) as apdl: apdl.et(1, "SOLID185") # ET,1,SOLID185 apdl.type(1) # TYPE,1 apdl.mat(1) # MAT,1 apdl.n(1, 0, 0, 0) # N,1, 0, 0, 0 apdl.n(2, 1, 0, 0) # ... nodes 3..8 ... apdl.e(1, 2, 3, 4, 5, 6, 7, 8) # E,1,2,3,4,5,6,7,8 What's on a Model ----------------- The grid is the canonical mesh representation:: m.grid # pyvista.UnstructuredGrid m.grid.point_data["ansys_node_num"] m.grid.cell_data["ansys_elem_num"] m.grid.cell_data["ansys_elem_type_num"] m.grid.cell_data["ansys_material_type"] m.grid.cell_data["ansys_real_constant"] Shortcut accessors return typed views of the same data: .. list-table:: :widths: 30 70 :header-rows: 1 * - Attribute - Returns * - :attr:`n_nodes` - ``int`` — number of points on the grid. * - :attr:`n_elements` - ``int`` — number of cells. * - :attr:`node_numbers` - ``(N,) int`` — 1-based MAPDL node numbers. * - :attr:`element_numbers` - ``(M,) int`` — 1-based MAPDL element numbers. * - :attr:`etypes` - ``{et_id: name}`` — declared element types. * - :attr:`materials` - ``{mat_id: {prop: value}}`` — material property tables. * - :attr:`real_constants` - ``{real_id: np.ndarray}`` — real-constant vectors. Assembly -------- Once pre-processing is done, materialise the global matrices:: K = m.stiffness_matrix() # scipy.sparse.csr_array M = m.mass_matrix() # scipy.sparse.csr_array (consistent) M_lumped = m.mass_matrix(lumped=True) The same cached grid feeds every call, so successive assemblies reuse the CSR sparsity pattern. The global DOF layout is exposed via :meth:`Model.dof_map` — an ``(N, 2)`` array of ``(mapdl_node_num, local_dof_idx)`` that lets you translate between solver vectors and physical node / component. Solve shortcuts --------------- For the three most common analyses you can bypass the solver module and ask the Model directly:: static = m.solve() # linear static modal = m.modal_solve(n_modes=10) # free-vibration modal transient = m.transient_solve(dt=1e-4, n_steps=1000, F=load_vec) These delegate to :func:`~femorph_solver.solvers.static.solve_static`, :func:`~femorph_solver.solvers.modal.solve_modal`, and :func:`~femorph_solver.solvers.transient.solve_transient` respectively, passing the current Dirichlet / force records. For finer control (non-``auto`` backends, explicit thread limits, custom ``prescribed`` dicts) call those solver functions directly with :attr:`K` and :attr:`M` — see :doc:`/user-guide/solving/index`. See also -------- - :doc:`elements/index` — which element types you can register. - :doc:`materials` — the ``mp`` command and the property enum. - :doc:`real-constants` — per-element real-constant layouts. - :doc:`boundary-conditions` — Dirichlet and force commands. - :class:`femorph_solver.Model` — full API reference.