hermit.outputs ============== .. py:module:: hermit.outputs .. autoapi-nested-parse:: Postprocess a :class:`hermit.ShellState` into scalar and field outputs. Every function here takes the solved state and nothing else -- the state back-references its domain, geometry, material, loads and boundary conditions. Scalar outputs return ``csdl.Variable``\s; field outputs return :class:`hermit.Field`\s. All of them are differentiable in reverse mode, including with respect to the mesh coordinates when the solve was given a live geometry. .. !! processed by numpydoc !! Functions --------- .. autoapisummary:: hermit.outputs.aggregated_stress hermit.outputs.center_of_gravity hermit.outputs.compliance hermit.outputs.displacement_field hermit.outputs.elastic_energy hermit.outputs.failure_field hermit.outputs.failure_index hermit.outputs.mass hermit.outputs.nodal_displacement hermit.outputs.nodal_rotation hermit.outputs.pnorm_stress hermit.outputs.rotation_field hermit.outputs.strain_fields hermit.outputs.stress_field hermit.outputs.stress_scaling Module Contents --------------- .. py:function:: aggregated_stress(state, *, rho=100, m=1e-06, region=None, surface='top', quadrature_degree=None) Smooth aggregate of isotropic von Mises stress, ``(1/m) * pnorm**(1/rho)``. A differentiable stand-in for the peak stress, suitable as an optimizer constraint. :Parameters: **state** : ShellState .. **rho** : float, optional Aggregation exponent. Default 100. **m** : float, optional Stress scaling; see :func:`pnorm_stress`. Default 1e-6. **region** : str or int, optional Restrict to a mesh-tagged region. **surface** : {'top', 'bottom', 'mid'}, optional Through-thickness station. Default ``'top'``. **quadrature_degree** : int, optional Overrides the domain's degree for this integral. :Returns: csdl.Variable Scalar, in stress units. :Warns: UserWarning If ``m`` is degenerate for this problem, which would otherwise return a number that barely depends on the solution. .. rubric:: Notes Approaches ``max(vm)`` **from below** as ``rho`` grows: this is the area-averaged integral p-norm, bounded above by the pointwise maximum, unlike the discrete log-sum-exp aggregate :func:`failure_index` uses. .. rubric:: Examples >>> m = hm.stress_scaling(state) >>> peak = hm.aggregated_stress(state, m=m) .. !! processed by numpydoc !! .. py:function:: center_of_gravity(state) Mass-weighted centre of gravity, in global Cartesian coordinates. :Parameters: **state** : ShellState .. :Returns: csdl.Variable Shape ``(3,)``. .. !! processed by numpydoc !! .. py:function:: compliance(state) Work done by the applied loads on the solution. :Parameters: **state** : ShellState .. :Returns: csdl.Variable Scalar. Conjugate to the exact ``Loads`` object that was solved, including edge and point terms. .. !! processed by numpydoc !! .. py:function:: displacement_field(state) Mid-surface displacement as a field. :Parameters: **state** : ShellState .. :Returns: Field ``(3,)`` vector field on the displacement subspace of the element, in global Cartesian components. .. seealso:: :obj:`nodal_displacement` the same quantity at mesh vertices, in file order. .. !! processed by numpydoc !! .. py:function:: elastic_energy(state) Stored shell strain energy. :Parameters: **state** : ShellState .. :Returns: csdl.Variable Scalar. For a linear solve this is half the compliance, up to the round-off of the direct solve. :Raises: ValueError If the material carries no ``A``/``B``/``D``/``As`` (a :func:`~hermit.thickness_only` material). .. !! processed by numpydoc !! .. py:function:: failure_field(state, *, sampling='average') Per-cell, per-ply-face Tsai-Wu failure indices. :Parameters: **state** : ShellState .. **sampling** : {'average', 'midpoint'}, optional How the DG0 strain measures are sampled per cell. Default ``'average'``. :Returns: Field DG0 field with one component per ply face. :Raises: ValueError If the material carries no layup. Only :func:`~hermit.laminate` sets one. .. !! processed by numpydoc !! .. py:function:: failure_index(state, *, rho=100, sampling='average') KS-aggregated Tsai-Wu failure index over the whole laminate. :Parameters: **state** : ShellState .. **rho** : float, optional KS aggregation exponent. Default 100. **sampling** : {'average', 'midpoint'}, optional How the DG0 strain measures are sampled per cell. Default ``'average'``. :Returns: csdl.Variable Scalar. Below 1 means no ply face has failed; the log-sum-exp KS aggregate bounds the true maximum from **above**. :Raises: ValueError If the material carries no layup. Only :func:`~hermit.laminate` sets one. .. !! processed by numpydoc !! .. py:function:: mass(state) Structural mass, ``int density * thickness dx``. :Parameters: **state** : ShellState .. :Returns: csdl.Variable Scalar. .. !! processed by numpydoc !! .. py:function:: nodal_displacement(state) Displacements at the mesh vertices. :Parameters: **state** : ShellState .. :Returns: csdl.Variable Shape ``(n_nodes, 3)``, in **file** vertex order -- the ordering an external geometry pipeline uses. .. !! processed by numpydoc !! .. py:function:: nodal_rotation(state) Director rotations at the mesh vertices. :Parameters: **state** : ShellState .. :Returns: csdl.Variable Shape ``(n_nodes, 3)``, in **file** vertex order. .. !! processed by numpydoc !! .. py:function:: pnorm_stress(state, *, rho=100, m=1e-06, region=None, surface='top', quadrature_degree=None) Area-normalized p-norm stress integral, ``(1/A) int (m*vm)**rho dx``. :Parameters: **state** : ShellState .. **rho** : float, optional Aggregation exponent. Default 100. **m** : float, optional Stress scaling; see Notes. Default 1e-6. **region** : str or int, optional Restrict the integral to a mesh-tagged region. Needs a domain built with ``cell_tags=`` and ``regions=``. **surface** : {'top', 'bottom', 'mid'}, optional Through-thickness station the stress is recovered at. Default ``'top'``. **quadrature_degree** : int, optional Overrides the domain's degree for this integral. :Returns: csdl.Variable Scalar. :Raises: ValueError If the material carries no ``E`` and ``nu`` (stress recovery is isotropic-only -- use :func:`failure_index` for laminates), or if ``region=`` is given without mesh tags. KeyError If ``region`` is not among the mesh tags. .. seealso:: :obj:`aggregated_stress` the same quantity reduced back to stress units. .. rubric:: Notes ``m`` is a problem-specific scaling, not a smoothing knob. It enters as ``(m*vm)**rho``, so it must put ``m*max(vm)`` near 1 or the integrand runs off the end of double precision: with the default ``m`` and a peak von Mises of 1.4e4, ``(m*vm)**100`` is 1e-186. Use :func:`stress_scaling` to compute one. ``m`` must also be **constant** with respect to the design variables. It is not differentiated and cancels out of the aggregate exactly; recomputing it inside the recorded graph each optimizer iteration silently makes the reported derivative wrong. .. !! processed by numpydoc !! .. py:function:: rotation_field(state) Director rotation as a field. :Parameters: **state** : ShellState .. :Returns: Field ``(3,)`` vector field on the rotation subspace of the element, in global Cartesian components. .. !! processed by numpydoc !! .. py:function:: strain_fields(state, *, space=('DG', 2), method='project', frame=None) Membrane strain, bending curvature and transverse shear. :Parameters: **state** : ShellState .. **space** : tuple, optional Target space for all three fields. Default ``("DG", 2)``. **method** : {'project', 'interpolate', 'average'}, optional Recovery method. ``'average'`` is the DG0 cell average. Default ``'project'``. **frame** : {'local', 'global'}, optional Component frame. Defaults to the element-local in-plane frame on a DG space, and to global Cartesian on a CG space, where per-cell frames would be ambiguous at shared nodes. :Returns: tuple of Field ``(mid_strain, curvature, shear_strain)``. The component layout follows the frame: in the element-local frame the first two are in-plane engineering Voigt ``[xx, yy, 2xy]`` and the third is ``[xz, yz]``; in the global frame they become full symmetric tensors, ``[xx, yy, zz, 2yz, 2xz, 2xy]`` and a 3-vector. :Raises: ValueError If ``method`` or ``frame`` is not one of the accepted values, or if a local frame is requested on a continuous (CG) space. .. seealso:: :obj:`hermit.Field.to_frame`, :obj:`hermit.Field.to_global` re-express the components. .. rubric:: Examples >>> eps, kappa, gamma = hm.strain_fields(state) >>> kappa_global = kappa.to_global().values .. !! processed by numpydoc !! .. py:function:: stress_field(state, *, space=('DG', 2), method='project', surface='top') Isotropic von Mises stress field. :Parameters: **state** : ShellState .. **space** : tuple, optional Target space. Default ``("DG", 2)``. **method** : {'project', 'interpolate', 'average'}, optional Recovery method. Default ``'project'``. **surface** : {'top', 'bottom', 'mid'}, optional Through-thickness station. Default ``'top'``. :Returns: Field Scalar field. :Raises: ValueError If the material carries no ``E`` and ``nu``; von Mises recovery is isotropic-only. :func:`~hermit.composite` accepts ``E=`` / ``nu=`` for this. .. !! processed by numpydoc !! .. py:function:: stress_scaling(state, *, surface='top', space=('DG', 2), method='project') Suggest the stress scaling ``m = 1 / max|von Mises|`` for the aggregates. :Parameters: **state** : ShellState .. **surface** : {'top', 'bottom', 'mid'}, optional Through-thickness station. Default ``'top'``. **space** : tuple, optional Space the stress field is recovered on. Default ``("DG", 2)``. **method** : {'project', 'interpolate', 'average'}, optional Field recovery method. Default ``'project'``. :Returns: float A plain Python float, deliberately: it is a snapshot taken outside the differentiated path, so it cannot contaminate the derivative of :func:`aggregated_stress`. :Raises: ValueError If the stress field has no value (run under an inline ``csdl.Recorder``), or if the peak is not finite and positive. .. rubric:: Notes Costs one extra stress-field assembly. Call it once when setting a problem up, not inside an optimizer loop -- a design-dependent ``m`` makes the reported gradient wrong even though the value looks better scaled. .. !! processed by numpydoc !!