Degrees of Freedom#

This module contains the definition of a boundary condition as well as tools related to the partition of degrees of freedom and the application of boundary conditions on a field container.

class felupe.Boundary(field, name='default', fx=<ufunc 'isnan'>, fy=<ufunc 'isnan'>, fz=<ufunc 'isnan'>, value=0.0, skip=(False, False, False), mask=None, mode='or')[source]#

A Boundary as a collection of prescribed degrees of freedom (numbered coordinate components of a field at points of a mesh).

Parameters:
  • field (felupe.Field) – Field on wich the boundary is created.

  • name (str, optional (default is "default")) – Name of the boundary.

  • fx (float or callable, optional) – Mask-function for x-component of mesh-points which returns True at points on which the boundary will be applied (default is np.isnan). If a float is passed, this is transformed to lambda x: np.isclose(x, fx).

  • fy (float or callable, optional) – Mask-function for y-component of mesh-points which returns True at points on which the boundary will be applied (default is np.isnan). If a float is passed, this is transformed to lambda y: np.isclose(y, fy).

  • fz (float or callable, optional) – Mask-function for z-component of mesh-points which returns True at points on which the boundary will be applied (default is np.isnan). If a float is passed, this is transformed to lambda z: np.isclose(z, fz).

  • value (ndarray or float, optional) – Value(s) of the selected (prescribed) degrees of freedom (default is 0.0).

  • skip (tuple of bool or int, optional) – A tuple to define which axes of the selected points should be skipped, i.e. not prescribed (default is (False, False, False)).

  • mask (ndarray) – Boolean mask for the prescribed degrees of freedom. If a mask is passed, fx, fy and fz are ignored. However, skip is still applied on the mask.

  • mode (string, optional) – A string which defines the logical operation for the selected points per axis (default is or).

mask#

1d- or 2d-boolean mask array for the prescribed degrees of freedom.

Type:

ndarray

dof#

1d-array of ints which contains the prescribed degrees of freedom.

Type:

ndarray

points#

1d-array of ints which contains the point ids on which one or more degrees of freedom are prescribed.

Type:

ndarray

value#

Value of the selected (prescribed) degrees of freedom.

Type:

ndarray or float

Examples

A boundary condition prescribes values for chosen degrees of freedom of a given field (not a field container). This is demonstrated for a plane-strain vector field on a quad-mesh of a circle.

>>> import felupe as fem
>>> mesh = fem.Circle(radius=1, n=6)
>>> x, y = mesh.points.T
>>> region = fem.RegionQuad(mesh)
>>> displacement = fem.FieldPlaneStrain(region, dim=2)
>>> field = fem.FieldContainer([displacement])

A boundary on the displacement field which prescribes all components of the field on the outermost left point of the circle is created. The easiest way is to pass the desired value to fx. The same result is obtained if a callable function is passed to fx.

>>> left = fem.Boundary(displacement, fx=x.min())
>>> left = fem.Boundary(displacement, fx=lambda x: np.isclose(x, x.min()))
>>> plotter = mesh.plot(off_screen=True)
>>> plotter.add_points(
>>>     np.pad(mesh.points[left.points], ((0, 0), (0, 1))),
>>>     point_size=20,
>>>     color="red",
>>> )
>>> img = plotter.screenshot("boundary_left.png", transparent_background=True)
../_images/boundary_left.png

If fx and fy are given, the masks are combined by logical-or.

>>> axes = fem.Boundary(displacement, fx=0, fy=0, mode="or")
../_images/boundary_axes.png

This may be changed to logical-and if desired.

>>> center = fem.Boundary(displacement, fx=0, fy=0, mode="and")
../_images/boundary_center.png

For the most-general case, a user-defined boolean mask for the selection of the mesh-points is provided. While the two upper methods are useful to select points separated per point-coordinates, providing a mask is more flexible as it may involve all three coordinates (or any other quantities of interest).

>>> mask = np.logical_and(np.isclose(x**2 + y**2, 1), x <= 0)
>>> surface = fem.Boundary(displacement, mask=mask)
../_images/boundary_surface.png

A boundary condition may be skipped on given axes, i.e. if only the x-components of a field should be prescribed on the selected points, then the y-axis must be skipped.

>>> axes_x = fem.Boundary(displacement, fx=0, fy=0, skip=(False, True))

Values for the prescribed degress of freedom are either applied during creation or by the update-method.

>>> left = fem.Boundary(displacement, fx=x.min(), value=-0.2)
>>> left.update(-0.3)

Sometimes it is useful to create a boundary with all axes skipped. This boundary has no prescribed degrees of freedom and hence, is without effect. However, it may still be used in a characteristic job for the boundary to be tracked.

See also

felupe.CharacteristicCurve

A job with a boundary to be tracked.

felupe.dof.partition

Partition degrees of freedom into prescribed and active dof.

felupe.dof.apply

Apply prescribed values for a list of boundaries.

update(value)[source]#

Update the value of the boundary in-place.

felupe.dof.partition(field, bounds)[source]#

Partition a list of degrees of freedom into prescribed (dof0) and active (dof1) degrees of freedom.

Parameters:
Returns:

  • dof0 (ndarray) – 1d-array of int with all prescribed degress of freedom.

  • dof1 (ndarray) – 1d-array of int with all active degrees of freedom.

Examples

>>> import felupe as fem
>>> mesh = fem.Rectangle(a=(0, 0), b=(1, 1), n=(3, 3))
>>> region = fem.RegionQuad(mesh)
>>> displacement = fem.FieldPlaneStrain(region, dim=2)
>>> field = fem.FieldContainer([displacement])

A plot shows the point-ids along with the associated degrees of freedom.

>>> plotter = mesh.plot(off_screen=True)
>>> plotter.add_point_labels(
>>>     points=np.pad(mesh.points, ((0, 0), (0, 1))),
>>>     labels=[
>>>         f"Point {i}: DOF {a}, {b}"
>>>         for i, (a, b) in enumerate(displacement.indices.dof)
>>>     ],
>>> )
>>> img = plotter.screenshot("dof_partition.png", transparent_background=True)
../_images/dof_partition.png
>>> boundaries = dict(
>>>     left=fem.Boundary(displacement, fx=0, value=0.2),
>>>     right=fem.Boundary(displacement, fx=1),
>>> )
>>> dof0, dof1 = fem.dof.partition(field, boundaries)
>>> ext0 = fem.dof.apply(field, boundaries, dof0=dof0)
>>> dof0
array([ 0,  1,  4,  5,  6,  7, 10, 11, 12, 13, 16, 17])
>>> dof1
array([ 2,  3,  8,  9, 14, 15])
>>> ext0
array([0.2, 0.2, 0. , 0. , 0.2, 0.2, 0. , 0. , 0.2, 0.2, 0. , 0. ])

dof0=None is required (default) if the prescribed displacement array should be returned for all degrees of freedom.

>>> fem.dof.apply(field, boundaries).reshape(
>>>     displacement.values.shape
>>> )
array([[0.2, 0.2],
       [0. , 0. ],
       [0. , 0. ],
       [0.2, 0.2],
       [0. , 0. ],
       [0. , 0. ],
       [0.2, 0.2],
       [0. , 0. ],
       [0. , 0. ]])

See also

felupe.Boundary

A collection of prescribed degrees of freedom.

felupe.dof.apply

Apply prescribed values for a list of boundaries.

felupe.dof.apply(field, bounds, dof0=None)[source]#

Apply prescribed values for a list of boundaries and return all (default) or only the prescribed components of the field based on dof0.

Parameters:
  • field (felupe.FieldContainer) – FieldContainer which holds the fields used in the boundaries.

  • bounds (dict of felupe.Boundary) – Dict of boundaries.

  • dof0 (ndarray or None, optional) – 1d-array of int with prescribed degrees of freedom (default is None). If not None, only the given deegrees of freedom dof0 of the field values, prescribed by the boundaries, are returned.

Returns:

Field values at mesh-points for all (default) or only the prescribed components of the field based on dof0.

Return type:

ndarray

Examples

>>> import felupe as fem
>>> mesh = fem.Rectangle(a=(0, 0), b=(1, 1), n=(3, 3))
>>> region = fem.RegionQuad(mesh)
>>> displacement = fem.FieldPlaneStrain(region, dim=2)
>>> field = fem.FieldContainer([displacement])
>>> boundaries = dict(
>>>     left=fem.Boundary(displacement, fx=0, value=0.2),
>>>     right=fem.Boundary(displacement, fx=1),
>>> )
>>> dof0, dof1 = fem.dof.partition(field, boundaries)
>>> ext0 = fem.dof.apply(field, boundaries, dof0=dof0)
>>> dof0
array([ 0,  1,  4,  5,  6,  7, 10, 11, 12, 13, 16, 17])
>>> dof1
array([ 2,  3,  8,  9, 14, 15])
>>> ext0
array([0.2, 0.2, 0. , 0. , 0.2, 0.2, 0. , 0. , 0.2, 0.2, 0. , 0. ])

dof0=None is required (default) if the prescribed displacement array should be returned for all degrees of freedom.

>>> fem.dof.apply(field, boundaries).reshape(
>>>     displacement.values.shape
>>> )
array([[0.2, 0.2],
       [0. , 0. ],
       [0. , 0. ],
       [0.2, 0.2],
       [0. , 0. ],
       [0. , 0. ],
       [0.2, 0.2],
       [0. , 0. ],
       [0. , 0. ]])

See also

felupe.Boundary

A collection of prescribed degrees of freedom.

felupe.dof.partition

Partition degrees of freedom into prescribed and active dof.