hermit.material =============== .. py:module:: hermit.material .. autoapi-nested-parse:: ``Material`` + ``Orientation`` -- the constitutive input bundle. A ``Material`` bundles the ``Field`` objects the residual and the mass / stress / failure outputs consume. The constitutive tensors are stored **in the laminate's own material axes, unrotated**: the rotation into each element's frame happens inside the shell form, so there is no space restriction on any of these fields -- ``A``/``B``/``D``/``As`` and ``orientation`` may each live on their own space. .. !! processed by numpydoc !! Classes ------- .. autoapisummary:: hermit.material.Material hermit.material.Orientation Functions --------- .. autoapisummary:: hermit.material.composite hermit.material.fiber_angle hermit.material.fiber_direction hermit.material.isotropic hermit.material.laminate hermit.material.thickness_only Module Contents --------------- .. py:class:: Material(A, B, D, As, thickness, density, *, orientation=None, E=None, nu=None, layup=None) The constitutive input bundle consumed by the solve and the outputs. Build one with :func:`isotropic`, :func:`laminate`, :func:`composite` or :func:`thickness_only` rather than calling this constructor directly. :Parameters: **A, B, D** : Field or None Membrane, coupling and bending stiffness, each a ``(3, 3)`` field in the laminate's own material axes, **unrotated**. ``None`` only for a :func:`thickness_only` material. **As** : Field or None Transverse-shear stiffness, a ``(2, 2)`` field in the ``(xz, yz)`` ordering the shell form uses. **thickness, density** : Field Scalar fields, on any space. **orientation** : Orientation, optional Applied to ``A``/``B``/``D``/``As`` inside the shell form. ``None`` means no rotation, which is correct for an isotropic material. **E, nu** : Field, optional Isotropic constants, needed by the von Mises stress outputs. **layup** : Layup, optional The ply stack, needed by the Tsai-Wu failure outputs. :Attributes: **domain** : ShellDomain Taken from ``thickness``. .. !! processed by numpydoc !! .. py:attribute:: E :value: None .. py:attribute:: density .. py:property:: domain .. py:attribute:: layup :value: None .. py:attribute:: nu :value: None .. py:attribute:: orientation :value: None .. py:attribute:: thickness .. py:class:: Orientation(domain, *, kind, value) The laminate fibre orientation carried on a :class:`Material`. Build one with :func:`fiber_angle` or :func:`fiber_direction`. It does not rotate anything at construction time: the rotation into each element's frame happens inside the shell form during :func:`~hermit.solve`, and again in the Tsai-Wu failure recovery. :Parameters: **domain** : ShellDomain .. **kind** : {'angle', 'direction'} Whether ``value`` is an in-plane angle or a global direction vector. **value** : Field Scalar field of angles (rad) for ``kind='angle'``, or a ``(3,)`` vector field for ``kind='direction'``. .. !! processed by numpydoc !! .. py:attribute:: domain .. py:attribute:: kind .. py:attribute:: value .. py:function:: composite(domain, *, A, B, D, As, thickness, density, orientation=None, E=None, nu=None) -> Material Material from pre-computed ABD stiffness fields. Nothing is assembled here, so there is no ``constitutive_space`` to choose: each field keeps whatever space it was built on. :Parameters: **domain** : ShellDomain .. **A, B, D** : Field or array_like ``(3, 3)`` membrane, coupling and bending stiffness, in laminate axes. **As** : Field or array_like ``(2, 2)`` transverse-shear stiffness, ``(xz, yz)`` ordering. **thickness, density** : Field, float or array_like .. **orientation** : Orientation, optional Rotates the supplied ABD into each element's frame inside the shell form. **E, nu** : Field, float or array_like, optional Supply these to enable the isotropic von Mises stress outputs. :Returns: Material .. .. rubric:: Notes The result carries no ``layup``, so the Tsai-Wu outputs (:func:`~hermit.failure_index`, :func:`~hermit.failure_field`) do not work on it. Those need :func:`laminate`, which knows the ply stack the criterion is evaluated over. .. !! processed by numpydoc !! .. py:function:: fiber_angle(domain, angle) -> Orientation Orientation given as an angle from each element's own in-plane axis. :Parameters: **domain** : ShellDomain .. **angle** : Field, float or array_like Angle in radians from the element's ``e0`` to the fibre direction, on any space. A ``csdl.Variable`` makes it a differentiable design field. :Returns: Orientation .. :Raises: ValueError If ``angle`` is not a scalar field. .. seealso:: :obj:`fiber_direction` orientation given as a global direction. .. rubric:: Notes The angle is measured from ``e0``, which follows the mesh parametrisation. On a mesh where ``e0`` is not uniform, a continuous (CG) angle field makes the physical fibre direction kink slightly at element interfaces -- fine on a flat or structured mesh, otherwise prefer :func:`fiber_direction`. .. !! processed by numpydoc !! .. py:function:: fiber_direction(domain, direction) -> Orientation Orientation given as a global fibre direction. :Parameters: **domain** : ShellDomain .. **direction** : Field or array_like A ``(3,)`` global vector, or a ``Field`` of ``(3,)`` vectors on any space (e.g. a per-cell curvilinear fibre path). :Returns: Orientation .. :Raises: ValueError If ``direction`` is not a ``(3,)`` vector field. .. seealso:: :obj:`fiber_angle` orientation given as an element-relative angle. .. rubric:: Notes The shell form projects the direction into each element's tangent plane and never forms the angle explicitly, so there is no branch cut. The projection is degenerate only where ``direction`` is parallel to the shell normal, which is detected when concrete values reach the form. .. !! processed by numpydoc !! .. py:function:: isotropic(domain, *, E, nu, thickness, density, constitutive_space=None, orientation=None) -> Material Isotropic single-layer material. ``A``/``B``/``D``/``As`` are assembled from the closed form in plain CSDL, with a 0.833 shear-correction factor. :Parameters: **domain** : ShellDomain .. **E, nu, thickness, density** : Field, float or array_like Young's modulus, Poisson's ratio, shell thickness and mass density. Each may be a scalar (broadcast), a per-vertex / per-cell array, or a ``Field`` on its own space. A ``csdl.Variable`` makes it a design variable. **constitutive_space** : tuple, optional Space the ABD fields are evaluated on. Defaults to ``("DG", d)`` where ``d`` is the highest degree among ``E``, ``nu`` and ``thickness``. **orientation** : Orientation, optional Accepted and ignored -- an isotropic in-plane stiffness has no preferred axis, so rotating it is a no-op. The parameter exists so that one orientation object can be passed uniformly to any material constructor. :Returns: Material .. .. rubric:: Notes The ABD fields are an *interpolant* of the closed form at the ``constitutive_space`` dofs, not an exact representation of it: ``E*t`` and ``t**3`` have higher polynomial degree than any fixed space carries. Raise ``constitutive_space`` if that matters for a strongly graded thickness. .. rubric:: Examples >>> mat = hm.isotropic(domain, E=4.32e8, nu=0.0, thickness=0.2, density=1.0) .. !! processed by numpydoc !! .. py:function:: laminate(domain, *, layup, density, orientation=None, shear_correction=0.833, constitutive_space=None) -> Material Composite material from a ply stack, via classical lamination theory. :Parameters: **domain** : ShellDomain .. **layup** : Layup The ply stack (materials, angles, heights). Its angles and heights may be ``csdl.Variable``\s, making the ABD differentiable in the layup. **density** : Field, float or array_like Mass density. **orientation** : Orientation, optional Rotates the laminate axes into each element's frame inside the shell form. Without it the laminate 0-degree axis is taken to be the element ``e0``. **shear_correction** : float, optional Multiplies the CLT transverse-shear stiffness. Default 0.833, the same factor :func:`isotropic` applies. **constitutive_space** : tuple, optional Space the ABD fields are broadcast onto. Defaults to ``("DG", d)`` where ``d`` is the highest degree among ``density`` and ``orientation``. :Returns: Material Carrying ``layup``, so :func:`~hermit.failure_index` and :func:`~hermit.failure_field` work on the resulting state. .. rubric:: Notes One layup is broadcast uniformly to every cell; spatial variation of the stack itself is not part of this API. Use :func:`composite` with per-point ABD fields for that. .. rubric:: Examples >>> layup = hm.Layup(ud, np.radians([0.0, 90.0, 0.0]), np.full(3, 0.002)) >>> mat = hm.laminate(domain, layup=layup, density=1.6e3, ... orientation=hm.fiber_direction(domain, [1.0, 0.0, 0.0])) .. !! processed by numpydoc !! .. py:function:: thickness_only(domain, *, thickness, density) -> Material Thickness and density only, for a surrogate solve. ``A`` through ``As`` stay ``None``, so :func:`~hermit.solve` rejects this material: it is for a surrogate that carries its own constitutive model but still needs :func:`~hermit.mass` and :func:`~hermit.center_of_gravity`. :Parameters: **domain** : ShellDomain .. **thickness, density** : Field, float or array_like .. :Returns: Material .. .. !! processed by numpydoc !!