Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
4e4ab74
Rename SolidBodyThermalSurfaceConvection to SolidBodyThermalSurfaceHe…
AGeissler Mar 22, 2026
1c0dfa6
Add SolidBodyThermal example suggestion. WIP.
AGeissler Mar 22, 2026
fe1fe6f
Add actual functionality to SolidBodyThermal example. Still WIP.
AGeissler Mar 22, 2026
53fb632
Shorten 'HeatTransfer' file and class names. Debug example, runs thro…
AGeissler Mar 22, 2026
2a5cb26
Add results views (not very refined).
AGeissler Mar 22, 2026
4dcfa97
Update introduction text. Update material data values.
AGeissler Mar 22, 2026
fe498dd
Adapt class notes text.
AGeissler Mar 22, 2026
dc18cbf
format black, run isort
adtzlr Mar 23, 2026
19d6aa9
Update _solidbody_surface_heat_transfer.py
adtzlr Mar 23, 2026
8146238
Update _solidbody_surface_heat_transfer.py
adtzlr Mar 23, 2026
04eb524
update tests for `thermal.SolidBodySurfaceHeatTransfer`
adtzlr Mar 23, 2026
fb0b177
Update CHANGELOG.md
adtzlr Mar 23, 2026
b0094e8
Merge branch 'main_fork' into thermal_domain
AGeissler Mar 23, 2026
c501d57
Merge branch 'adtzlr:main' into thermal_domain
AGeissler Apr 13, 2026
c36a277
Merge branch 'main_fork' into thermal_domain
AGeissler Apr 24, 2026
0ea024d
Editorial changes to class documentation.
GeisslerA Apr 27, 2026
909dde1
Add class 'SolidBodySurfaceConvection'. WIP, code save.
GeisslerA Apr 27, 2026
b31ef2f
Merge branch 'main_fork' into thermal_domain
AGeissler Apr 27, 2026
e47f380
Fix equation alignment.
GeisslerA Apr 28, 2026
dac43c2
Update SolidBodySurfaceConvection code. Next step: test.
GeisslerA Apr 28, 2026
3617ad4
Documentation refinement. Comment out unused parameter. Test still pe…
GeisslerA Apr 28, 2026
16f6c2c
Address various pytest issues (surface_convection). Now seems to run,…
GeisslerA Apr 28, 2026
4437d56
Remove 'sigma'. Various further doc edits.
GeisslerA Apr 28, 2026
7db1ac8
Merge branch 'main_fork' into thermal_domain
AGeissler May 2, 2026
4a43cf5
Fix bug - all ramp lists seem to necessarily be of the same length. Duh.
GeisslerA May 5, 2026
8701f4e
Adapt documentation. Adapt example to actually calculate h_c for a ho…
GeisslerA May 6, 2026
3a74899
Variant of hc_fun inclusion. Also does not work.
GeisslerA May 6, 2026
a763092
Refine example documentation.
GeisslerA May 6, 2026
5d7dad6
Change "Ra over the limit" calculation of Nu to constant "Ra limit".
GeisslerA May 6, 2026
166812e
Adapt Ra limit values to engineering notation.
GeisslerA May 6, 2026
962a68a
Add convection class to documentation (API). Update example descripti…
GeisslerA May 6, 2026
0dec89a
Update .gitignore.
GeisslerA May 6, 2026
1120897
Merge branch 'main' into thermal_domain
GeisslerA May 6, 2026
06360ca
Further update example description after renewed render.
GeisslerA May 6, 2026
593dab9
Yet another update of example doc.
GeisslerA May 6, 2026
08d343d
In this version, function call seems to work. Testing required.
GeisslerA May 6, 2026
c4eea2a
Refactor the example. The function call now really seems to be workin…
GeisslerA May 6, 2026
7c8ab19
Merge branch 'main_fork' into thermal_domain
AGeissler May 6, 2026
d4f4d38
Update .gitignore.
GeisslerA May 6, 2026
b04c6e5
Add reference for horizontal plate convection coefficient.
GeisslerA May 7, 2026
d8a6427
Add tester function code for _convection example. Can be deleted afte…
GeisslerA May 7, 2026
25136f8
Slight clean-up. Adapt naming.
GeisslerA May 7, 2026
9d96d3d
Undo change to .gitignore on main.
GeisslerA May 8, 2026
52aaf7f
Merge branch 'main' of https://github.com/AGeissler/felupe_fork
GeisslerA May 8, 2026
9ca3a91
Merge branch 'main' into thermal_domain
GeisslerA May 8, 2026
23d4fb8
Merge branch 'adtzlr:main' into main
AGeissler May 8, 2026
e11c38d
Merge branch 'main' into thermal_domain
GeisslerA May 8, 2026
a1236bd
Fix h_c calculation from q_c/Dt. Remove obsolete hc_fun().
GeisslerA May 8, 2026
56a27a3
Merge branch 'adtzlr:main' into main
AGeissler May 8, 2026
c8bfdac
Merge branch 'adtzlr:main' into main
AGeissler May 9, 2026
ffccab9
Merge branch 'adtzlr:main' into main
AGeissler May 10, 2026
43491cf
Merge branch 'main_fork' into thermal_domain
AGeissler May 10, 2026
9c9c58e
Merge branch 'adtzlr:main' into main
AGeissler May 12, 2026
d1eb3d2
Merge branch 'main' of https://github.com/AGeissler/felupe_fork into …
AGeissler May 14, 2026
c03fa0b
Test parameter updating. No success.
AGeissler May 17, 2026
68710e0
Merge branch 'adtzlr:main' into main
AGeissler May 17, 2026
9ff56cd
Merge branch 'main' of https://github.com/AGeissler/felupe_fork
GeisslerA May 18, 2026
b3fe146
Tester now basically works. Embedded example not checked, make html g…
AGeissler May 18, 2026
36812f5
Merge branch 'main_fork' into thermal_domain
AGeissler May 18, 2026
427ff03
Pytest now returns 'passed'.
GeisslerA May 19, 2026
b1e399c
Add code outline for line-graph of h_c, t_s, t_i.
GeisslerA May 20, 2026
2edd4be
Switch plot code to matplotlib 'parasite simple' approach. Works as e…
GeisslerA May 20, 2026
17b0a61
Add alternative hc calculation results.
GeisslerA May 20, 2026
5040991
Merge branch 'adtzlr:main' into main
AGeissler May 30, 2026
afef9f7
Merge branch 'main_fork' into thermal_domain
AGeissler May 30, 2026
bacac56
Add more complex thermal example.
AGeissler May 31, 2026
9f52c0f
Generate simplified geometry. Looks as expected.
AGeissler May 31, 2026
00a814b
Add basic fem model (regions and fields).
AGeissler May 31, 2026
534dbcd
Add basic code to set heat flux at 'pipe' surfaces. Actual center poi…
AGeissler May 31, 2026
81db8aa
Code save for tester line plot creation (different approach w/o "esot…
AGeissler May 31, 2026
072fdac
Complete modelling. Basically works, however, results show issues (pr…
AGeissler Jun 1, 2026
d178f51
Fix of geometry creation w/ refactored approach. Issue (probably): bo…
AGeissler Jun 1, 2026
00296fa
Add explicit 'square edge point' calculation. Remove unused material …
AGeissler Jun 3, 2026
f36ff14
Code save prior to clean-up.
GeisslerA Jun 3, 2026
05ef285
Basically works with simple heat transfer. Extension with side surfac…
GeisslerA Jun 3, 2026
6468c7b
Defining the side heat transfer separately works. Now base "simple he…
GeisslerA Jun 3, 2026
1392fdd
Initial steps to add class 'FreeConvection' as a kind of material (no…
GeisslerA Jun 3, 2026
1fac1c0
Address various typos and minor code issues. Code save.
GeisslerA Jun 4, 2026
2cb0625
Free convection function via class FreeConvection now works in tester…
GeisslerA Jun 4, 2026
52f55fe
Adapt surface radiation class definition to calculate radiation coeff…
GeisslerA Jun 4, 2026
66680cb
Extend example 23 to use detailed convection and radiation transfer m…
GeisslerA Jun 4, 2026
53085c2
Start writing documentation for FreeConvection class.
GeisslerA Jun 4, 2026
572b030
Add 2nd day with heat extraction via hydronic system. Seems to work.
GeisslerA Jun 4, 2026
1641db6
Code save.
GeisslerA Jun 5, 2026
28bff45
Add heat transfer and pipe flux figure to ex23. Adapt code documentat…
AGeissler Jun 9, 2026
f352f01
Add absolute pressure as variable. Identify issue with too similar va…
AGeissler Jun 11, 2026
fb1cc38
Add 'side of plate' toggle. Extend documentation of class (not finish…
AGeissler Jun 11, 2026
a3690d1
Update ex23 to use correct plate sides for convection. Results for h_…
AGeissler Jun 11, 2026
5c4161b
Add reference to class 'free_convection'.
AGeissler Jun 11, 2026
f79726a
Further extend documentation of class free_convection. WIP.
AGeissler Jun 11, 2026
9f2c682
Clean up ex23.
AGeissler Jun 13, 2026
e4f55d3
Add SolidBodySurfaceConvection to test_thermal.py. Not sure how this …
AGeissler Jun 14, 2026
bad6edd
Remove convection tester.
AGeissler Jun 14, 2026
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ examples/result.xdmf
docs/examples/
docs/tutorial/*
!docs/tutorial/examples
docs/mesh.png
sg_execution_times.rst
result.h5
result.xdmf
6 changes: 6 additions & 0 deletions docs/felupe/thermal.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Thermal

thermal.SolidBodyThermal
thermal.SolidBodySurfaceHeatTransfer
thermal.SolidBodySurfaceConvection
thermal.SolidBodySurfaceRadiation
thermal.SolidBodyHeatFlux

Expand All @@ -36,6 +37,11 @@ Thermal
:undoc-members:
:show-inheritance:

.. autoclass:: felupe.thermal.SolidBodySurfaceConvection
:members:
:undoc-members:
:show-inheritance:

.. autoclass:: felupe.thermal.SolidBodySurfaceRadiation
:members:
:undoc-members:
Expand Down
344 changes: 344 additions & 0 deletions examples/ex23_solid_body_thermal-tabs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,344 @@
r"""
Thermal Analysis
----------------

.. topic:: Analysis of a thermally activated slab setup.

* use :class:`~felupe.thermal.SolidBodyThermal`,
:class:`~felupe.thermal.SolidBodyHeatFlux`,
:class:`~felupe.thermal.SolidBodySurfaceRadiation` and
:class:`~felupe.thermal.SolidBodySurfaceConvection`

* calculate detailed convection transfer coefficient using
:class:`~felupe.constitution.heat_transfer.FreeConvection`

* evaluate the surface heat flux at top and bottom boundaries
with a job :class:`~felupe.Plugin`

* view top/bottom surface heat flux, convective and radiative transfer
coefficients and the temperature field


This example describes a thermally activated concrete slab using a simplified
model and geometry. The model is two-dimensional. The system is set up with two
:class:`solids <felupe.thermal.SolidBodyThermal>`. The temperature boundary
conditions include the floor temperature, the ceiling temperature and the room
air temperatures, each with a :math:`\pm \Delta\theta` K sinusoidal variation
around its average value with a period of 24 h.

The heat injection via the pipe layer is constant at 231 W/m2 and directly
injected at the internal concrete surfaces (no pipe material is modelled).

Surface heat transfer at the top and bottom surfaces is modelled separately for
convection and radiation.
"""
import matplotlib.pyplot as plt
import numpy as np

import felupe as fem

# %%
# Material properties are defined as lists for (reinforced) concrete and insulation.
# This includes mass density, specific heat capacity and thermal conductivity.
density = [2100, 20] # kg/m^3
specific_heat = [1000, 1450] # J/(kg K)
thermal_conductivity = [2.1, 0.035] # W/(m K)

# %%
# One mesh per material is set up. If a material consists of multiple areas, these
# are collected in a :class:`mesh container <felupe.MeshContainer>` and are
# merged into one mesh per material. These meshes per material are then added
# to a mesh container for the construction.
concrete_1a = fem.Rectangle(a=(0.0, 0.0), b=(0.18, 0.22), n=(19, 23)) # left / right
concrete_1b = fem.Rectangle(a=(0.0, 0.0), b=(0.02, 0.10), n=(3, 11)) # pipe bottom / top
concrete_1 = fem.MeshContainer(
[
concrete_1a.translate(0.02, axis=0), # left
concrete_1b.translate(0.20, axis=0), # pipe 1, bottom
concrete_1b.translate(0.20, axis=0).translate(0.12, axis=1), # pipe1, top
],
merge=True,
decimals=6,
).stack()

concrete = fem.MeshContainer(
[
concrete_1, # left
concrete_1.translate(0.2, axis=0), #
concrete_1.translate(0.4, axis=0), #
concrete_1.translate(0.6, axis=0), #
concrete_1a.translate(0.82, axis=0), # right
],
merge=True,
decimals=6,
).stack()

insulation_1 = fem.Rectangle(a=(0.0, 0.0), b=(0.02, 0.22), n=(3, 23)) # left / right
insulation = fem.MeshContainer(
[
insulation_1,
insulation_1.translate(1.0, axis=0),
],
merge=True,
decimals=6,
).stack()

container = fem.MeshContainer([concrete, insulation], merge=True, decimals=6)

container.plot(
colors=["lightgrey", "sepia"],
labels=["Concrete", "Insulation"],
show_edges=False,
).show()

# %%
# A top-level temperature field is defined on the whole construction with an
# initial temperature value of 20 °C, and separate fields are defined for each
# material. Thermal solid bodies are created for each material.
regions = [fem.RegionQuad(m) for m in container]
fields = [fem.Field(r, dim=1).as_container() for r in regions]
mesh = container.stack()
region = fem.RegionQuad(mesh)
temperature = fem.Field(region, dim=1, values=20.0) # initial temperature 20 °C
field = fem.FieldContainer([temperature])

materials = []
for mfield, rho, cp, k in zip(fields, density, specific_heat, thermal_conductivity):
materials.append(
fem.thermal.SolidBodyThermal(
field=mfield,
mass_density=rho,
specific_heat_capacity=cp,
thermal_conductivity=k,
)
)

# %%
# The surface heat transfer is defined for the side, top and bottom surfaces.
side_region1 = fem.RegionQuadBoundary(mesh, mask=mesh.x == mesh.x.min())
side_temperature1 = fem.Field(side_region1, dim=1)
side_field1 = fem.FieldContainer([side_temperature1])

side_region2 = fem.RegionQuadBoundary(mesh, mask=mesh.x == mesh.x.max())
side_temperature2 = fem.Field(side_region2, dim=1)
side_field2 = fem.FieldContainer([side_temperature2])

bottom_region = fem.RegionQuadBoundary(mesh, mask=mesh.y == mesh.y.min())
bottom_temperature = fem.Field(bottom_region, dim=1)
bottom_field = fem.FieldContainer([bottom_temperature])

top_region = fem.RegionQuadBoundary(mesh, mask=mesh.y == mesh.y.max())
top_temperature = fem.Field(top_region, dim=1)
top_field = fem.FieldContainer([top_temperature])

# For the sides, combined transfer coefficients are used.
side1_heat_transfer = fem.thermal.SolidBodySurfaceHeatTransfer(
field=side_field1,
coefficient=7.69, # W/(m^2 K)
temperature=20.0, # °C
)
side2_heat_transfer = fem.thermal.SolidBodySurfaceHeatTransfer(
field=side_field2,
coefficient=7.69, # W/(m^2 K)
temperature=20.0, # °C
)

# %%
# For the top and bottom surfaces, the detailed calculation approaches defined
# in :class:`~felupe.thermal.SolidBodySurfaceConvection` and
# :class:`~felupe.thermal.SolidBodySurfaceRadiation` are used for convection
# and radiation, respectively. For convection, the convection coefficient
# function defined in :class:`~felupe.constitution.heat_transfer.FreeConvection`
# is used.
hc_top = np.vectorize(fem.FreeConvection(5, 5, 'top').hc_fun)
hc_bottom = np.vectorize(fem.FreeConvection(5, 5, 'bottom').hc_fun)

top_convection = fem.thermal.SolidBodySurfaceConvection(
field=top_field,
convection_coefficient=hc_top, # W/(m^2 K)
temperature=20.0, # °C
)
bottom_convection = fem.thermal.SolidBodySurfaceConvection(
field=bottom_field,
convection_coefficient=hc_bottom, # W/(m^2 K)
temperature=20.0, # °C
)

top_radiation = fem.thermal.SolidBodySurfaceRadiation(
field=top_field,
emissivity=0.9,
temperature=20.0, # °C
)

bottom_radiation = fem.thermal.SolidBodySurfaceRadiation(
field=bottom_field,
emissivity=0.9,
temperature=20.0, # °C
)

# %%
# Heat flux on pipe walls is defined.
center_points = np.asarray([[0.21, 0.11], [0.41, 0.11], [0.61, 0.11], [0.81, 0.11]])

pipe_region = []
pipe_field = []
pipe_flux = []
for idx, p in enumerate(center_points):
# Inelegant, but seems to work:
mask = np.isclose(mesh.points[:, None, :], p[:], rtol=0.05, atol=0.0101).all(axis=2).any(axis=1)
pipe_region.append(fem.RegionQuadBoundary(mesh, mask=mask))
pipe_field.append(fem.FieldContainer([fem.Field(pipe_region[idx], dim=1)]))
pipe_flux.append(fem.thermal.SolidBodyHeatFlux(
field=pipe_field[idx],
heat_flux=-231.25, # W / m^2, 74/(4*4*0.02)
))

# %%
# A callback-function records the mean surface heat flux at the top and bottom
# boundaries, the top and bottom convection coefficients as well as the top and
# bottom radiation coefficients after each completed time step.
# The mean surface heat flux is calculated by the
# :meth:`~felupe.thermal.SolidBodyThermal.heat_flux_boundary` method of the
# thermal solid body, which returns the integrated surface heat flux for a given
# boundary region and time step.
#
# All values are stored in the ``tstep_data`` dictionary, which is passed to
# the callback function as an argument.
def callback(stepnumber, substepnumber, substep, tstep_data):
"""Save mean surface heat flux at internal and external boundaries."""

heat_flux = materials[0].heat_flux_boundary
tstep_data["top"].append(heat_flux(region=top_region))
tstep_data["bottom"].append(heat_flux(region=bottom_region))

tstep_data["hc_top.W.m-2.K-1"].append(
top_convection.results.convection_coefficient.mean())
tstep_data["hr_top.W.m-2.K-1"].append(
top_radiation.results.radiation_coefficient.mean())

tstep_data["hc_bottom.W.m-2.K-1"].append(
bottom_convection.results.convection_coefficient.mean())
tstep_data["hr_bottom.W.m-2.K-1"].append(
bottom_radiation.results.radiation_coefficient.mean())

pflux = 0
for p_ in pipe_region:
pflux += heat_flux(region=p_)
tstep_data["pipes"].append(pflux)

N_DAYS = 2
time_steps = fem.math.linsteps([0, N_DAYS * 24 * 3600],
num=int(N_DAYS * 24 * 3600 / 720))[1:]

t_air = 20 + 2 * np.sin(2 * np.pi * time_steps / 86400)
t_ceil = 20 + 0.5 * np.sin(2 * np.pi * time_steps / 86400)
t_floor = 18 + 0.5 * np.sin(2 * np.pi * time_steps / 86400)

pipe_heat_flux = np.concatenate(
(fem.math.linsteps([-231.25, -231.25], num=int(len(time_steps)/2)-1),
fem.math.linsteps([231.25, 231.25], num=int(len(time_steps)/2)-1))
)


# %%
# The time step item is created with the thermal solid bodies. It must be located
# as the first item in the step to properly update the time step in the materials.
# The side, top and bottom heat transfer item values as well as the pipe flux
# values are defined in the ramp, which specifies how their values change over
# time. Finally, a job is created with the step and the callback function, and
# evaluated with the top-level temperature field. A result file is created for
# visualization in Paraview, and the temperature field is saved as point-data
# in the result file.
model_list = [*materials, side1_heat_transfer, side2_heat_transfer,
top_convection, bottom_convection, top_radiation, bottom_radiation]

time = fem.thermal.TimeStep(model_list)
ramp = {
time: time_steps,
side1_heat_transfer: t_air,
side2_heat_transfer: t_air,
top_convection: t_air,
bottom_convection: t_air,
top_radiation: t_ceil,
bottom_radiation: t_floor,
pipe_flux[0]: pipe_heat_flux,
pipe_flux[1]: pipe_heat_flux,
pipe_flux[2]: pipe_heat_flux,
pipe_flux[3]: pipe_heat_flux,
}
step = fem.Step(
items=[time] + model_list + pipe_flux,
ramp=ramp,
)

tstep_data = {"top": [], "bottom": [],
"hc_top.W.m-2.K-1": [], "hr_top.W.m-2.K-1": [],
"hc_bottom.W.m-2.K-1": [], "hr_bottom.W.m-2.K-1": [],
"pipes": []}

job = fem.Job(steps=[step], callback=callback, tstep_data=tstep_data).evaluate(
x0=field,
filename="result.xdmf", # create a result file for Paraview
point_data={"Temperature": lambda field, substep: temperature.values},
point_data_default=False,
cell_data_default=False,
)

# %%
# Top and bottom surface heat flux values are plotted over time.
#
# .. note::
#
# The heat flux is **positive** when **heat leaves the construction** (here,
# on both top and bottom surfaces in 'heating mode', and **negative** when
# **heat enters the construction** (here, on both the top and bottom
# surfaces in 'cooling mode'.
fig, ax = plt.subplots()
ax.plot(time_steps / 3600, tstep_data["top"], color="C3", label="top")
ax.plot(time_steps / 3600, tstep_data["bottom"], color="C0", label="bottom")

tmin, tmax = ax.get_xlim()
ax.plot([tmin, tmax], np.zeros(2), "black", lw=0.5)

text_kwargs = dict(transform=ax.transAxes, ha="center", va="center")
ax.text(0.5, 0.97, "heat leaves construction", **text_kwargs)
ax.text(0.5, 0.03, "heat enters construction", **text_kwargs)

ax.legend()
ax.set(xlim=(tmin, tmax), xlabel="time in h", ylabel=r"surface heat flux in W/m$^2$")

# %%
# Top and bottom convection and radiation surface heat transfer coefficients
# and pipe heat flux are plotted over time.
fig, ax = plt.subplots()
fig.subplots_adjust(right=0.75)

twin1 = ax.twinx()
twin2 = ax.twinx()

ax.set_xlabel("Time (s)")
ax.set_ylabel("Convection coefficient in W/(m$^2$ K)")
twin1.set_ylabel("Temperature in °C")
twin2.set_ylabel("Pipe heat flux in W/m$^2$")

time_steps_h = time_steps / 3600

p1 = ax.plot(time_steps_h, tstep_data["hc_top.W.m-2.K-1"],
label="hc_top", color='lightblue')
p2 = ax.plot(time_steps_h, tstep_data["hc_bottom.W.m-2.K-1"],
label="hc_bottom", color='darkblue')
p3 = twin1.plot(time_steps_h, tstep_data["hr_top.W.m-2.K-1"],
label="hr_top", color='blue')
p4 = twin1.plot(time_steps_h, tstep_data["hr_bottom.W.m-2.K-1"],
label="hr_bottom", color='red')
p5 = twin2.plot(time_steps_h, tstep_data["pipes"],
label="pipe_flux", color='magenta')

ax.legend(handles=p1+p2+p3+p4+p5, labelcolor="linecolor")

twin2.spines['right'].set_position(('outward', 45))

# %%
# A view on the temperature field at the end of the simulation period visualizes
# the temperature distribution.
field.plot("Field", scalar_bar_vertical=True).show()
2 changes: 2 additions & 0 deletions src/felupe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
linear_elastic,
linear_elastic_plastic_isotropic_hardening,
linear_elastic_viscoelastic,
FreeConvection,
)
from .dof import Boundary, BoundaryDict
from .element import ArbitraryOrderLagrange as ArbitraryOrderLagrangeElement
Expand Down Expand Up @@ -202,6 +203,7 @@
"VolumeChange",
"linear_elastic",
"linear_elastic_viscoelastic",
"FreeConvection",
"linear_elastic_plastic_isotropic_hardening",
"Boundary",
"BoundaryDict",
Expand Down
Loading
Loading