Skip to content

Commit

Permalink
Add BoundaryDict
Browse files Browse the repository at this point in the history
 with methods to plot, screenshot and imshow
  • Loading branch information
adtzlr committed Dec 1, 2024
1 parent 6b59077 commit 389ed1d
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. The format
- Add `SolidBody.evaluate.stress(field)` to evaluate the (first Piola-Kirchhoff) stress tensor (engineering stress in linear elasticity).
- Add a free-vibration modal analysis Step/Job `FreeVibration(items, boundaries)` with methods to evaluate `FreeVibration.evaluate()` and to extract `field, frequency = FreeVibration.extract(n)` its n-th result.
- Add `Boundary.plot()` to plot the points and prescribed directions of a boundary.
- Add `BoundaryDict` as a subclassed dict with methods to `plot()`, `screenshot()` and `imshow()`.

### Changed
- The first Piola-Kirchhoff stress tensor is evaluated if `ViewSolid(stress_type=None)`.
Expand Down
6 changes: 6 additions & 0 deletions docs/felupe/dof.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This module contains the definition of a boundary condition, tools related to th
.. autosummary::

Boundary
BoundaryDict


**Tools**
Expand Down Expand Up @@ -37,6 +38,11 @@ This module contains the definition of a boundary condition, tools related to th
:undoc-members:
:inherited-members:

.. autoclass:: felupe.BoundaryDict
:members:
:undoc-members:
:inherited-members:

.. autofunction:: felupe.dof.partition

.. autofunction:: felupe.dof.apply
Expand Down
3 changes: 2 additions & 1 deletion src/felupe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
linear_elastic,
linear_elastic_plastic_isotropic_hardening,
)
from .dof import Boundary
from .dof import Boundary, BoundaryDict
from .element import ArbitraryOrderLagrange as ArbitraryOrderLagrangeElement
from .element import (
BiQuadraticQuad,
Expand Down Expand Up @@ -168,6 +168,7 @@
"linear_elastic",
"linear_elastic_plastic_isotropic_hardening",
"Boundary",
"BoundaryDict",
"ArbitraryOrderLagrangeElement",
"BiQuadraticQuad",
"ConstantHexahedron",
Expand Down
2 changes: 2 additions & 0 deletions src/felupe/dof/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from ._boundary import Boundary
from ._dict import BoundaryDict
from ._loadcase import biaxial, shear, symmetry, uniaxial
from ._tools import apply, get_dof0, get_dof1, partition

__all__ = [
"Boundary",
"BoundaryDict",
"biaxial",
"shear",
"symmetry",
Expand Down
14 changes: 12 additions & 2 deletions src/felupe/dof/_boundary.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,14 @@ def update(self, value):
self.value = value #

def plot(
self, plotter=None, color="black", scale=0.125, point_size=10, width=3, **kwargs
self,
plotter=None,
color="black",
scale=0.125,
point_size=10,
width=3,
label=None,
**kwargs,
):
"Plot the points and their prescribed directions of a boundary condition."

Expand All @@ -283,13 +290,16 @@ def plot(
)

if len(self.points) > 0:
if label is None:
label = self.name

magnitude = min(mesh.points.max(axis=0) - mesh.points.min(axis=0)) * scale

_ = plotter.add_points(
mesh.points[self.points],
color=color,
point_size=point_size,
label=self.name,
label=label,
)

for skip, direction in zip(self.skip, np.eye(mesh.dim)):
Expand Down
64 changes: 64 additions & 0 deletions src/felupe/dof/_dict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
class BoundaryDict(dict):
"A dict of boundary conditions."

def plot(self, plotter=None, colors=None, **kwargs):
"Plot the boundary conditions."

if colors is None:
import matplotlib.colors as mcolors

colors = list(mcolors.TABLEAU_COLORS.values())

colors_list = []
while len(colors_list) < len(self.keys()):
colors_list = [*colors_list, *colors]

for (key, boundary), color in zip(self.items(), colors_list):
label = key
if boundary.name != "default":
label = boundary.name

plotter = boundary.plot(label=label, color=color, plotter=plotter, **kwargs)

plotter.add_legend(size=(0.1, 0.1), bcolor="white", face="rectangle")

return plotter

def screenshot(
self,
*args,
filename="boundaries.png",
transparent_background=None,
scale=None,
colors=None,
plotter=None,
**kwargs,
):
"Take a screenshot of the boundary conditions."

if plotter is None:
mesh = self[list(self.keys())[0]].field.region.mesh
plotter = mesh.plot(off_screen=True)

plotter = self.plot(plotter=plotter, colors=colors, **kwargs)

return plotter.screenshot(
filename=filename,
transparent_background=transparent_background,
scale=scale,
)

def imshow(self, *args, ax=None, dpi=None, **kwargs):
"""Take a screenshot of the boundary conditions, show the image data in
a figure and return the ax.
"""

if ax is None:
import matplotlib.pyplot as plt

fig, ax = plt.subplots(dpi=dpi)

ax.imshow(self.screenshot(*args, filename=None, **kwargs))
ax.set_axis_off()

return ax
14 changes: 14 additions & 0 deletions tests/test_dof.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,22 @@ def test_boundary_plot():
_ = boundaries["left"].plot()


def test_boundary_dict():
field = fem.Field(
fem.RegionHexahedron(fem.Cube(b=(3, 1, 1), n=5)), dim=1
).as_container()
boundaries = fem.BoundaryDict(
left=fem.Boundary(field[0], fx=0, skip=(0, 0, 1)),
right=fem.Boundary(field[0], name="my_label", fx=3, skip=(0, 1, 0)),
)
plotter = boundaries.plot()
img = boundaries.screenshot()
ax = boundaries.imshow()


if __name__ == "__main__":
test_boundary()
test_boundary_dict()
test_boundary_multiaxial()
test_boundary_plot()
test_loadcase()

0 comments on commit 389ed1d

Please sign in to comment.