Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the classes Basis, BasisField and BasisArray public #835

Merged
merged 1 commit into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ All notable changes to this project will be documented in this file. The format
- Import the `assembly` module to the global namespace.
- Isolate the submodules, i.e. a submodule only uses the public API of another submodule. If necessary, this will help to change one or more modules to a future extension package.
- Enforce contiguous arrays for the region shape-function and -gradient arrays `h` and `dhdX`. This recovers the integral-form assembly performance from v8.6.0.
- Make the private basis classes public (`assembly.expression.Basis`, `assembly.expression.BasisField` and `assembly.expression.BasisArray`) as especially their docstrings are useful to understand how a *Basis* is created on a field.

### Deprecated
- Deprecate `SolidBodyGravity`, `SolidBodyForce` should be used instead.
Expand Down
18 changes: 18 additions & 0 deletions docs/felupe/assembly.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ Define weak-form expressions on-the-fly for flexible and general form expression
.. autosummary::

Form
assembly.expression.Basis
assembly.expression.BasisField
assembly.expression.BasisArray

Create an item out of bilinear and linear weak-form expressions for a Step.

Expand All @@ -62,6 +65,21 @@ Create an item out of bilinear and linear weak-form expressions for a Step.

.. autofunction:: felupe.Form

.. autoclass:: felupe.assembly.expression.Basis
:members:
:undoc-members:
:inherited-members:

.. autoclass:: felupe.assembly.expression.BasisField
:members:
:undoc-members:
:inherited-members:

.. autoclass:: felupe.assembly.expression.BasisArray
:members:
:undoc-members:
:inherited-members:

.. autoclass:: felupe.FormItem
:members:
:undoc-members:
Expand Down
4 changes: 3 additions & 1 deletion src/felupe/assembly/expression/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from ._basis import Basis
from ._basis import Basis, BasisArray, BasisField
from ._decorator import FormExpressionDecorator as Form

__all__ = [
"Basis",
"BasisArray",
"BasisField",
"Form",
]
144 changes: 99 additions & 45 deletions src/felupe/assembly/expression/_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,36 @@


class BasisArray(np.ndarray):
"""Add the grad-attribute to an existing array [1]_.
"""Add the grad-attribute to an existing array [1]_, [2]_.

Parameters
----------
input_array : array_like
The input array.
grad : array_like or None, optional
The array for the grad-attribute (default is None).

Examples
--------
.. pyvista-plot::

>>> import numpy as np
>>> import felupe as fem
>>>
>>> x = fem.assembly.expression.BasisArray(np.ones(3), grad=np.zeros((3, 3)))
>>> x
BasisArray([1., 1., 1.])

>>> x.grad
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])

References
----------
.. [1] https://numpy.org/doc/stable/user/basics.subclassing.html

.. [2] https://numpy.org/doc/stable/user/basics.subclassing.html#slightly-more-realistic-example-attribute-added-to-existing-array
"""

def __new__(cls, input_array, grad=None):
Expand All @@ -44,31 +69,12 @@ def __array_finalize__(self, obj):


class BasisField:
r"""A basis and its gradient built on top of a scalar- or vector-valued
field. *Basis* refers to the trial and test field, either values or
gradients evaluated at quadrature points. The first two indices of a basis
are used for looping over the element shape functions ``a`` and its
components ``i``. The third index represents the vector component ``j`` of
the field. The two trailing axes ``(q, c)`` contain the evaluated element
shape functions at quadrature points ``q`` per cell ``c``.

.. math::

\varphi_{aijpc} = \delta_{ij} \left( h_a \right)_{pc}


For gradients, the fourth index is used for the vector component of the
partial derivative ``k``.

.. math::

\text{grad}(\varphi)_{aijkpc} = \delta_{ij}
\left( \frac{\partial h_a}{\partial X_K} \right)_{pc}
r"""Basis and its gradient for a field.

Parameters
----------
field : Field
A field on which the basis should be created.
A field on which the basis is created.
parallel : bool, optional (default is False)
Flag to activate parallel (threaded) basis evaluation.

Expand All @@ -79,6 +85,49 @@ class BasisField:
grad : ndarray
The evaluated gradient of the basis (if provided by the region).

Notes
-----
*Basis* refers to the trial and test field, either values or gradients evaluated at
quadrature points. The first two indices of a basis are used for looping over the
element shape functions ``a`` and its components ``i``. The third index represents
the vector component ``j`` of the field. The two trailing axes ``(q, c)`` contain
the evaluated element shape functions at quadrature points ``q`` per cell ``c``.

.. math::

\varphi_{ai~j~qc} = \delta_{ij} \left( h_a \right)_{qc}

For gradients, the fourth index is used for the vector component of the
partial derivative ``k``.

.. math::

\text{grad}(\varphi)_{ai~jk~qc} = \delta_{ij}
\left( \frac{\partial h_a}{\partial X_K} \right)_{qc}

Examples
--------
.. pyvista-plot::

>>> import numpy as np
>>> import felupe as fem
>>>
>>> mesh = fem.Rectangle()
>>> region = fem.RegionQuad(mesh)
>>> displacement = fem.Field(region, dim=2)
>>>
>>> bf = fem.assembly.expression.BasisField(displacement)
>>> bf.basis.shape
(4, 2, 2, 4, 1)

>>> bf.basis.shape
(4, 2, 2, 2, 4, 1)

See Also
--------
felupe.assembly.expression.Basis : Bases and their gradients for the fields of a
field container.

"""

def __init__(self, field, parallel=False):
Expand All @@ -104,26 +153,7 @@ def __init__(self, field, parallel=False):


class Basis:
r"""A basis and its gradient built on top of a scalar- or vector-valued
field container. *Basis* refers to the trial and test field, either values or
gradients evaluated at quadrature points. The first two indices of a basis
are used for looping over the element shape functions ``a`` and its
components ``i``. The third index represents the vector component ``j`` of
the field. The two trailing axes ``(q, c)`` contain the evaluated element
shape functions at quadrature points ``q`` per cell ``c``.

.. math::

\varphi_{aijpc} = \delta_{ij} \left( h_a \right)_{pc}


For gradients, the fourth index is used for the vector component of the
partial derivative ``k``.

.. math::

\text{grad}(\varphi)_{aijkpc} = \delta_{ij}
\left( \frac{\partial h_a}{\partial X_K} \right)_{pc}
r"""Bases and their gradients for the fields of a field container.

Parameters
----------
Expand All @@ -133,9 +163,33 @@ class Basis:
Attributes
----------
basis : ndarray
The evaluated basis functions at quadrature points.
grad : ndarray
The evaluated gradient of the basis (if provided by the region).
The list of bases.

Examples
--------
.. pyvista-plot::

>>> import numpy as np
>>> import felupe as fem
>>>
>>> mesh = fem.Rectangle()
>>> region = fem.RegionQuad(mesh)
>>> displacement = fem.Field(region, dim=2)
>>> field = fem.FieldContainer([displacement])
>>>
>>> bases = fem.assembly.expression.Basis(field)
>>> len(bases[:])
>>> 1

>>> bases[0].basis.shape
(4, 2, 2, 4, 1)

>>> bases[0].basis.grad.shape
(4, 2, 2, 2, 4, 1)

See Also
--------
felupe.assembly.expression.BasisField : Basis and its gradient for a field.

"""

Expand Down
Loading