hermit.fenics.shell_pde ======================= .. py:module:: hermit.fenics.shell_pde .. autoapi-nested-parse:: ``ShellPDE`` -- function spaces + UFL form factories for the R-M shell. Pure FEniCSx (DOLFINx 0.9 / 0.11), no CSDL. Port of ``rm_shell_pde_composite.py`` (femo dev_coupling), unified ABD backend. The argument functions live on the object so the custom operations can update them by array between assemblies. .. !! processed by numpydoc !! Classes ------- .. autoapisummary:: hermit.fenics.shell_pde.ShellPDE Module Contents --------------- .. py:class:: ShellPDE(mesh, element='CG2CG1', element_wise_material=False, elementwise_pressure=False, W=None, quadrature_degree=4) ``W=``, given, is an existing mixed state space to reuse instead of building a fresh ``state_space(mesh, element)`` -- ``hm.solve`` (via ``hermit._solve._pde_for``) passes ``domain.W`` here so the residual / BCs / ops it builds all share the *one* ``FunctionSpace`` object a ``BoundaryConditions`` was compiled against (a strong ``DirichletBC`` located against a structurally identical but distinct ``FunctionSpace`` is silently dropped, not an error). .. !! processed by numpydoc !! .. py:method:: area_form(measure=ufl.dx) .. py:method:: cg_forms(thickness=None, density=None) Mass moments, optionally from arbitrary-space coefficients (else the fixed ``density`` / ``h`` forms). .. !! processed by numpydoc !! .. py:method:: coefficient(name, space) -> dolfinx.fem.Function Persistent ``Function`` for ``name`` on ``space``, memoised by ``(name, normalized space)`` -- repeated calls with the same arguments return the exact same object. That matters: a residual form built against one ``Function`` instance is wrong (or raises, for a strong BC -- see ``ShellDomain``'s class docstring) if later evaluated with a different instance, and the custom ops write into the coefficient by array every solve, so it must be the one the compiled form actually references. General seam for any per-mesh input field a form needs as a UFL coefficient on a space the caller picks (materials, loads, orientation, ...) rather than one of the PDE's fixed-space attributes (``self.A`` / ``self.h`` / ...). .. !! processed by numpydoc !! .. py:method:: compliance_form(loads=None) ``loads=None`` (default) -- the work conjugate of the fixed ``self.f``/``self.m`` VF-space coefficients. ``loads``, given, is the same ``(kind, Function)`` list ``residual_form`` takes -- the matching compliance term per load kind (``inner(u, f)`` / ``inner(theta, m)`` / ``p * dot(n, u)``), so this stays the exact work conjugate of ``residual_form``'s distributed terms (every load kind must contribute both a residual term and a compliance term, or the two drift apart silently). The ``point_load``/``load_vector`` direct-RHS contribution is *not* included here (it has no distributed form) -- callers add ``csdl.vdot(direct, w)``. .. !! processed by numpydoc !! .. py:method:: elastic_energy_form(orientation=None, material=None) .. py:method:: elastic_model(w=None, orientation=None, material=None) ``orientation`` is ``(name, Function)`` with ``name`` in ``("fiber_angle", "fiber_direction")``, or ``None``. The no-orientation path reuses the memoised ``ElasticModel`` (bit-identical to the unoriented form); an oriented call always builds a fresh one -- it is only built once per ``ShellSolveOp`` / ``ShellScalarFormsOp`` construction (themselves memoised by the structural form cache), so there is nothing to gain by caching it too. ``material``, given, is a ``(A, B, D, As)`` tuple of ``Function``\s overriding the PDE's own fixed-space ``self.A``/``self.B``/``self.D``/ ``self.As``: a caller-chosen ``constitutive_space`` (any space, via :meth:`coefficient`) reaches the solve instead of only the fixed ``VABD``/``VAs`` space ``element_wise_material`` picks. ``None`` (default) keeps the fixed-space attrs -- also why the ``material=None`` unoriented path is the only one eligible for the ``self._elastic`` memo (a ``material=`` override is only ever built once per op anyway, same as an oriented call). .. !! processed by numpydoc !! .. py:method:: force_to_pressure_matrix() VF consistent mass matrix M such that M @ pressure = consistent nodal force. .. !! processed by numpydoc !! .. py:method:: mass_form(thickness=None, density=None) ``thickness=None``/``density=None`` (default) use the fixed-space ``self.h``/``self.density``. Given, they override with an arbitrary-space ``Function`` (from :meth:`coefficient`). .. !! processed by numpydoc !! .. py:method:: pnorm_stress_form(dx_measure, m=1e-06, rho=100.0, surface='top', thickness=None, E=None, nu=None) .. py:method:: residual_form(penalty=True, dss=None, dSS=None, bc_dof_mask=None, penalty_terms=None, penalty_targets=None, orientation=None, material=None, loads=None) ``penalty_terms``, given, is a list of ``(dss, dSS, bc_dof_mask)`` triples whose penalty contributions are summed -- multi-region penalty (``hm.clamp(...) + hm.symmetry(...)``); with it omitted (the common case) this is exactly the single ``(dss, dSS, bc_dof_mask)`` triple. ``orientation`` is ``(name, Function)``, ``material`` is ``(A, B, D, As)`` Functions -- see :meth:`elastic_model`. ``loads``, given, is a list of ``(kind, Function)`` pairs (``kind`` in ``"traction"``/``"moment"``/``"pressure"``): each term gets its own residual contribution on its own space, via ``ElasticModel.weak_residual``'s ``load_terms`` (instead of the fixed ``self.f``/``self.m`` VF-space coefficients this method uses with ``loads=None``, the default). An empty list is valid (e.g. a point-load-only ``Loads`` has no distributed term at all) -- only ``None`` selects the fixed ``f``/``m`` path. .. !! processed by numpydoc !! .. py:method:: restore_geometry() -> None .. py:method:: set_geometry(mesh_nodes) -> None Write ``mesh.geometry.x`` from user-ordered node coords (n_nodes, gdim). .. !! processed by numpydoc !! .. py:method:: von_mises_form(surface='top', thickness=None, E=None, nu=None) .. py:attribute:: As .. py:attribute:: E .. py:attribute:: VABD .. py:attribute:: VAs .. py:attribute:: VF .. py:attribute:: VT .. py:attribute:: W .. py:attribute:: X .. py:attribute:: density .. py:attribute:: f .. py:attribute:: g .. py:attribute:: gdim .. py:attribute:: h .. py:attribute:: m .. py:attribute:: mesh .. py:attribute:: nu .. py:attribute:: quadrature_degree :value: 4 .. py:attribute:: w .. py:attribute:: x_ref