hermit.domain ============= .. py:module:: hermit.domain .. autoapi-nested-parse:: ``ShellDomain`` -- mesh, shell state space and index maps, built once. No CSDL, no per-evaluation cost. Carries the mixed state space ``W``, mesh tags and regions, and the file/FE index maps the ``Field`` builders need. Deliberately does not depend on ``ShellPDE``: the dependency runs the other way, with ``hermit._solve`` handing ``domain.W`` to the ``ShellPDE`` it caches on the domain. .. !! processed by numpydoc !! Classes ------- .. autoapisummary:: hermit.domain.ShellDomain Functions --------- .. autoapisummary:: hermit.domain.read_mesh Module Contents --------------- .. py:class:: ShellDomain(mesh, *, element='CG2CG1', cell_tags=None, regions=None, quadrature_degree=4) Mesh, shell state space, index maps and region tags, built once. The first object in every Hermit workflow. It carries no CSDL and no per-solve cost, so build it once and reuse it across every load case, sweep or optimizer iteration. :Parameters: **mesh** : dolfinx.mesh.Mesh A **serial**, straight-sided (P1 geometry) surface mesh of triangles or quadrilaterals. **element** : {'CG2CG1', 'CG1CG1', 'CG2CR1'}, optional Displacement x rotation element pair. Default ``'CG2CG1'``. ``'CG2CR1'`` uses a Crouzeix-Raviart rotation that resists shear locking on thin shells, and is **triangle meshes only**. **cell_tags** : dolfinx.mesh.MeshTags, optional Cell tags, for per-region output integrals. **regions** : dict, optional Maps region names to tag values, so outputs can take ``region="skin"``. **quadrature_degree** : int, optional Degree for every integral this package pins by hand: the penalty-BC facet measures, the stress measures, the DG0 ``'average'`` field method and the oriented elastic energy. Default 4, which is deep in the converged regime for the shell integrand. :Attributes: **W** : dolfinx.fem.FunctionSpace **The** mixed state space for this domain, shared by everything downstream. **n_nodes, n_cells** : int .. **node_coords** : ndarray ``(n_nodes, 3)`` vertex coordinates in **file** order. **cell_centroids** : ndarray ``(n_cells, 3)`` centroids in **file** order. **node_input_idx, cell_input_idx** : ndarray File-to-FE gather indices, ``fe_order = file_order[node_input_idx]``. **reverse_node_idx, reverse_cell_idx** : ndarray Their inverses, ``file_order = fe_order[reverse_node_idx]``. :Raises: ValueError If the mesh is not serial (its ``input_global_indices`` must form a node permutation), or if CG1 / DG0 dof order does not coincide with the mesh's own vertex / cell order. .. rubric:: Notes **Serial meshes only.** This is a requirement of every use, not only of the shape-derivative path: an MPI-partitioned mesh raises here, before any solve. **Three coefficient orderings** coexist on any mesh: *file* (the mesh-file vertex and cell numbering, which external arrays use), *local* (DOLFINx's post-read reordering) and *FE dof* (per function space, indexing ``Function.x.array``). :func:`~hermit.from_nodal` and :func:`~hermit.from_cells` take file order and permute; :func:`~hermit.from_coeffs` takes FE dof order directly. **One state space per domain.** DOLFINx does not treat two independently built but structurally identical function spaces as interchangeable for boundary conditions: a strong BC located against a second instance is silently dropped, with no exception and a wrong answer. Everything downstream therefore shares ``domain.W``. .. rubric:: Examples >>> domain = hm.ShellDomain(hm.read_mesh("plate.xdmf"), element="CG2CG1") .. !! processed by numpydoc !! .. py:method:: check_cell_orientation_consistency(tol=0.0) Verify that cell normals do not flip across shared interior facets. Called by :func:`~hermit.pressure` and :func:`~hermit.edge_pressure`, whose sign convention is only well defined on a consistently wound mesh. :Parameters: **tol** : float, optional Two adjacent normals are inconsistent when their dot product is at or below this. Default 0. :Raises: ValueError Naming the offending cell pair. Fix the mesh winding upstream, or use :func:`~hermit.traction`, which takes an explicit global vector. .. rubric:: Notes Cheap and memoized; a no-op after the first successful call. .. !! processed by numpydoc !! .. py:method:: dof_coords(space) Coordinates of a space's scalar dofs, in FE dof order. :Parameters: **space** : tuple ``(family, degree)`` or ``(family, degree, value_shape)``. :Returns: ndarray Shape ``(n_scalar_dofs, 3)``. For a blocked (vector or tensor) space these are per scalar dof, not per component: all components of one dof share a coordinate. .. seealso:: :obj:`hermit.from_coeffs`, :obj:`hermit.from_function` build coefficients on this space. .. !! processed by numpydoc !! .. py:method:: function_space(space) The DOLFINx function space for a space descriptor. :Parameters: **space** : tuple ``(family, degree)`` or ``(family, degree, value_shape)``. :Returns: dolfinx.fem.FunctionSpace Memoized, one per normalized descriptor. .. !! processed by numpydoc !! .. py:method:: local_frames() The orthonormal local shell frame of every cell. :Returns: ndarray Shape ``(n_cells, 3, 3)``, rows ``e0``, ``e1`` in-plane and ``e2`` the element normal, at the reference geometry, in **FE** cell order. Memoized. .. !! processed by numpydoc !! .. py:method:: local_frames_at(points, cells) The local shell frame at chosen points inside chosen cells. :Parameters: **points** : array_like Reference-cell coordinates: one point broadcast to every query, or one point per query. **cells** : array_like of int Cell ids in **file** order. :Returns: ndarray Shape ``(n, 3, 3)``; see :meth:`local_frames` for the row convention. .. !! processed by numpydoc !! .. py:attribute:: W .. py:attribute:: cell_centroids .. py:attribute:: cell_input_idx .. py:attribute:: cell_tags :value: None .. py:attribute:: element :value: 'CG2CG1' .. py:attribute:: mesh .. py:attribute:: n_cells .. py:attribute:: n_nodes .. py:attribute:: node_coords .. py:attribute:: node_input_idx .. py:attribute:: quadrature_degree :value: 4 .. py:attribute:: regions .. py:attribute:: reverse_cell_idx .. py:attribute:: reverse_node_idx .. py:function:: read_mesh(path, name='Grid') Read a mesh from an XDMF file. :Parameters: **path** : str or pathlib.Path .. **name** : str, optional Grid name inside the file. Default ``"Grid"``. :Returns: dolfinx.mesh.Mesh Read on ``MPI.COMM_WORLD``. Run serially -- :class:`ShellDomain` requires a serial mesh. .. rubric:: Examples >>> domain = hm.ShellDomain(hm.read_mesh("plate.xdmf")) .. !! processed by numpydoc !!