├── .flake8
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── enhancement-suggestion.md
└── workflows
│ ├── publish-to-pypi.yml
│ └── upload-codecov.yml
├── .gitignore
├── .readthedocs.yaml
├── CHANGELOG.md
├── CITATION.cff
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── Makefile
├── _static
│ ├── benchmark.png
│ ├── custom.css
│ ├── engine-mount_animation.mp4
│ ├── ex06_rubber-metal-spring_mesh.vtk
│ ├── ex07_engine-mount_mesh-air.vtk
│ ├── ex07_engine-mount_mesh-metal.vtk
│ ├── ex07_engine-mount_mesh-rubber.vtk
│ ├── logo.png
│ ├── logo.svg
│ ├── logo_dark.svg
│ ├── logo_inkscape.svg
│ ├── logo_light.svg
│ ├── logo_tensortrax.png
│ ├── logo_without_text.svg
│ ├── mesh.vtk
│ ├── readme_animation.mp4
│ └── social_preview.svg
├── conf.py
├── felupe.rst
├── felupe
│ ├── assembly.rst
│ ├── constitution.rst
│ ├── constitution
│ │ ├── autodiff.rst
│ │ ├── autodiff
│ │ │ ├── jax.rst
│ │ │ └── tensortrax.rst
│ │ ├── core.rst
│ │ └── tools.rst
│ ├── dof.rst
│ ├── element.rst
│ ├── field.rst
│ ├── math.rst
│ ├── mechanics.rst
│ ├── mesh.rst
│ ├── quadrature.rst
│ ├── region.rst
│ ├── tools.rst
│ └── view.rst
├── howto.rst
├── howto
│ ├── axi.rst
│ ├── composite.rst
│ ├── items.rst
│ ├── meshgen.rst
│ ├── mixed.rst
│ ├── project.rst
│ ├── solid.rst
│ ├── solvers.rst
│ ├── umat.rst
│ └── umat_hyperelasticity.rst
├── index.rst
├── make.bat
└── tutorial
│ └── examples
│ ├── README.rst
│ ├── extut01_getting_started.py
│ ├── extut02_job.py
│ ├── extut03_building_blocks.py
│ └── extut03_building_blocks_sketch.svg
├── examples
├── README.rst
├── ex01_beam.py
├── ex01_beam_sketch.ipe
├── ex01_beam_sketch.png
├── ex02_plate-with-hole.py
├── ex02_plate-with-hole_sketch.svg
├── ex03_plasticity.py
├── ex03_plasticity_sketch.png
├── ex03_plasticity_sketch.svg
├── ex04_balloon.py
├── ex04_balloon_sketch.png
├── ex04_balloon_sketch.svg
├── ex05_rubber-metal-bushing.py
├── ex06_rubber-metal-spring.py
├── ex06_rubber-metal-spring_mesh.vtk
├── ex07_engine-mount.py
├── ex07_engine-mount_mesh-air.vtk
├── ex07_engine-mount_mesh-metal.vtk
├── ex07_engine-mount_mesh-rubber.vtk
├── ex08_shear.py
├── ex08_shear_sketch.svg
├── ex09_numeric-continuation.py
├── ex10_poisson-equation.py
├── ex11_notch-stress.py
├── ex12_foot-bone.py
├── ex12_foot-bones_mesh-voxels.vtu
├── ex13_morph-rubber-wheel.py
├── ex14_hyperelasticity.py
├── ex15_hexmesh-metacone.py
├── ex16_deeplearning-torch.py
├── ex17_torsion-gif.py
├── ex18_nonlinear-viscoelasticity-newton.py
├── ex19_taylor-hood.py
└── ex20_third-medium-contact.py
├── paper
├── examples.png
├── field.pdf
├── job.pdf
├── paper.bib
├── paper.md
└── strain.png
├── pyproject.toml
├── src
└── felupe
│ ├── __about__.py
│ ├── __init__.py
│ ├── assembly
│ ├── __init__.py
│ ├── _axi.py
│ ├── _cartesian.py
│ ├── _integral.py
│ └── expression
│ │ ├── __init__.py
│ │ ├── _basis.py
│ │ ├── _bilinear.py
│ │ ├── _decorator.py
│ │ ├── _expression.py
│ │ ├── _linear.py
│ │ └── _mixed.py
│ ├── constitution
│ ├── __init__.py
│ ├── _base.py
│ ├── _kinematics.py
│ ├── _material.py
│ ├── _mixed.py
│ ├── _view.py
│ ├── hyperelasticity
│ │ ├── __init__.py
│ │ ├── _neo_hooke_compressible.py
│ │ ├── _neo_hooke_nearly_incompressible.py
│ │ ├── _ogden_roxburgh.py
│ │ └── _volumetric.py
│ ├── jax
│ │ ├── __init__.py
│ │ ├── _helpers.py
│ │ ├── _hyperelastic.py
│ │ ├── _material.py
│ │ ├── _total_lagrange.py
│ │ ├── _updated_lagrange.py
│ │ └── models
│ │ │ ├── __init__.py
│ │ │ ├── hyperelastic
│ │ │ ├── __init__.py
│ │ │ ├── _blatz_ko.py
│ │ │ ├── _extended_tube.py
│ │ │ ├── _miehe_goektepe_lulei.py
│ │ │ ├── _mooney_rivlin.py
│ │ │ ├── _neo_hooke.py
│ │ │ ├── _storakers.py
│ │ │ ├── _third_order_deformation.py
│ │ │ ├── _van_der_waals.py
│ │ │ ├── _yeoh.py
│ │ │ └── microsphere
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _chain.py
│ │ │ │ ├── _framework_affine.py
│ │ │ │ └── _framework_nonaffine.py
│ │ │ └── lagrange
│ │ │ ├── __init__.py
│ │ │ ├── _morph.py
│ │ │ ├── _morph_representative_directions.py
│ │ │ ├── _morph_uniaxial.py
│ │ │ └── microsphere
│ │ │ ├── __init__.py
│ │ │ └── _framework_affine.py
│ ├── linear_elasticity
│ │ ├── __init__.py
│ │ ├── _lame_converter.py
│ │ ├── _linear_elastic.py
│ │ ├── _linear_elastic_1d.py
│ │ ├── _linear_elastic_large_strain.py
│ │ └── _linear_elastic_orthotropic.py
│ ├── poisson
│ │ ├── __init__.py
│ │ └── _laplace.py
│ ├── small_strain
│ │ ├── __init__.py
│ │ ├── _material_strain.py
│ │ └── models
│ │ │ ├── __init__.py
│ │ │ ├── _linear_elastic.py
│ │ │ └── _linear_elastic_plastic_isotropic.py
│ └── tensortrax
│ │ ├── __init__.py
│ │ ├── _helpers.py
│ │ ├── _hyperelastic.py
│ │ ├── _material.py
│ │ ├── _total_lagrange.py
│ │ ├── _updated_lagrange.py
│ │ └── models
│ │ ├── __init__.py
│ │ ├── hyperelastic
│ │ ├── __init__.py
│ │ ├── _alexander.py
│ │ ├── _anssari_benam_bucchi.py
│ │ ├── _arruda_boyce.py
│ │ ├── _blatz_ko.py
│ │ ├── _extended_tube.py
│ │ ├── _finite_strain_viscoelastic.py
│ │ ├── _lopez_pamies.py
│ │ ├── _miehe_goektepe_lulei.py
│ │ ├── _mooney_rivlin.py
│ │ ├── _morph_representative_directions.py
│ │ ├── _neo_hooke.py
│ │ ├── _ogden.py
│ │ ├── _ogden_roxburgh.py
│ │ ├── _saint_venant_kirchhoff.py
│ │ ├── _saint_venant_kirchhoff_orthotropic.py
│ │ ├── _storakers.py
│ │ ├── _third_order_deformation.py
│ │ ├── _van_der_waals.py
│ │ ├── _yeoh.py
│ │ └── microsphere
│ │ │ ├── __init__.py
│ │ │ ├── _chain.py
│ │ │ ├── _framework_affine.py
│ │ │ └── _framework_nonaffine.py
│ │ └── lagrange
│ │ ├── __init__.py
│ │ ├── _morph.py
│ │ ├── _morph_representative_directions.py
│ │ ├── _morph_uniaxial.py
│ │ └── microsphere
│ │ ├── __init__.py
│ │ └── _framework_affine.py
│ ├── dof
│ ├── __init__.py
│ ├── _boundary.py
│ ├── _dict.py
│ ├── _loadcase.py
│ └── _tools.py
│ ├── element
│ ├── __init__.py
│ ├── _base.py
│ ├── _hexahedron.py
│ ├── _lagrange.py
│ ├── _line.py
│ ├── _quad.py
│ ├── _tetra.py
│ ├── _triangle.py
│ └── _vertex.py
│ ├── field
│ ├── __init__.py
│ ├── _axi.py
│ ├── _base.py
│ ├── _container.py
│ ├── _dual.py
│ ├── _evaluate.py
│ ├── _fields.py
│ ├── _indices.py
│ └── _planestrain.py
│ ├── math
│ ├── __init__.py
│ ├── _field.py
│ ├── _math.py
│ ├── _solve.py
│ ├── _spatial.py
│ └── _tensor.py
│ ├── mechanics
│ ├── __init__.py
│ ├── _curve.py
│ ├── _free_vibration.py
│ ├── _helpers.py
│ ├── _item.py
│ ├── _job.py
│ ├── _multipoint.py
│ ├── _pointload.py
│ ├── _solidbody.py
│ ├── _solidbody_cauchy_stress.py
│ ├── _solidbody_force.py
│ ├── _solidbody_gravity.py
│ ├── _solidbody_incompressible.py
│ ├── _solidbody_pressure.py
│ ├── _step.py
│ └── _truss.py
│ ├── mesh
│ ├── __init__.py
│ ├── _container.py
│ ├── _convert.py
│ ├── _discrete_geometry.py
│ ├── _dual.py
│ ├── _geometry.py
│ ├── _helpers.py
│ ├── _interpolate.py
│ ├── _line_rectangle_cube.py
│ ├── _mesh.py
│ ├── _read.py
│ └── _tools.py
│ ├── quadrature
│ ├── __init__.py
│ ├── _gauss_legendre.py
│ ├── _gauss_lobatto.py
│ ├── _scheme.py
│ ├── _sphere.py
│ ├── _tetra.py
│ └── _triangle.py
│ ├── region
│ ├── __init__.py
│ ├── _boundary.py
│ ├── _region.py
│ └── _templates.py
│ ├── solve
│ ├── __init__.py
│ └── _solve.py
│ ├── tools
│ ├── __init__.py
│ ├── _hello_world.py
│ ├── _misc.py
│ ├── _newton.py
│ ├── _post.py
│ ├── _project.py
│ ├── _save.py
│ └── _solve.py
│ └── view
│ ├── __init__.py
│ ├── _field.py
│ ├── _mesh.py
│ ├── _scene.py
│ ├── _solid.py
│ └── _xdmf.py
├── tests
├── __init__.py
├── mesh.bdf
├── mesh_no-cells.bdf
├── test_basis.py
├── test_bilinearform.py
├── test_composite.py
├── test_constitution.py
├── test_constitution_jax.py
├── test_constitution_newton.py
├── test_dof.py
├── test_dtype.py
├── test_element.py
├── test_field.py
├── test_form.py
├── test_free_vibration.py
├── test_import.py
├── test_job.py
├── test_math.py
├── test_mechanics.py
├── test_mesh.py
├── test_mpc.py
├── test_planestrain.py
├── test_plot.py
├── test_quadrature.py
├── test_readme.py
├── test_region.py
├── test_solve.py
├── test_tools.py
└── umat.png
└── tox.ini
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 88
3 | extend-ignore = E203
4 | exclude = tests
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 |
16 | **Expected behavior**
17 | A clear and concise description of what you expected to happen.
18 |
19 | **Screenshots**
20 | If applicable, add screenshots to help explain your problem.
21 |
22 | **Environment (please complete the following information):**
23 | - OS: [e.g. win11]
24 | - Python Interpreter [e.g. 3.12]
25 | - FElupe version [e.g. 9.0.0]
26 |
27 | **Additional context**
28 | Add any other context about the problem here.
29 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/enhancement-suggestion.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Enhancement suggestion
3 | about: Suggest an enhancement for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/workflows/publish-to-pypi.yml:
--------------------------------------------------------------------------------
1 | name: Publish Python to PyPI
2 |
3 | on: push
4 |
5 | jobs:
6 | build:
7 | name: Build and publish Python to PyPI
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v4
12 | - name: Setup Python
13 | uses: actions/setup-python@v5
14 | with:
15 | python-version: '3.x'
16 | architecture: 'x64'
17 | - name: install pypa/build
18 | run: >-
19 | python -m
20 | pip install
21 | build
22 | --user
23 | - name: build wheel
24 | run: >-
25 | python -m
26 | build
27 | --sdist
28 | --wheel
29 | --outdir dist/
30 |
31 | - name: Publish package to pypi
32 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
33 | uses: pypa/gh-action-pypi-publish@release/v1
34 | with:
35 | password: ${{ secrets.PYPI_API_TOKEN }}
36 |
--------------------------------------------------------------------------------
/.github/workflows/upload-codecov.yml:
--------------------------------------------------------------------------------
1 | name: Codecov
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 |
11 | jobs:
12 | run:
13 | name: Upload coverage report to codecov.io
14 | runs-on: ubuntu-latest
15 | strategy:
16 | matrix:
17 | python-version: ["3.9", "3.13"]
18 | steps:
19 | - uses: actions/setup-python@v5
20 | with:
21 | python-version: ${{ matrix.python-version }}
22 | - uses: actions/checkout@v4
23 | - name: Test with tox
24 | run: |
25 | pip install tox
26 | tox -- --cov felupe --cov-report xml --cov-report term
27 | - name: Upload coverage to Codecov
28 | if: ${{ matrix.python-version == '3.13' }}
29 | uses: codecov/codecov-action@v4
30 | with:
31 | token: ${{ secrets.CODECOV_TOKEN }}
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .nox/
42 | .coverage
43 | .coverage.*
44 | .cache
45 | nosetests.xml
46 | coverage.xml
47 | *.cover
48 | .hypothesis/
49 | .pytest_cache/
50 |
51 | # Translations
52 | *.mo
53 | *.pot
54 |
55 | # Django stuff:
56 | *.log
57 | local_settings.py
58 | db.sqlite3
59 |
60 | # Flask stuff:
61 | instance/
62 | .webassets-cache
63 |
64 | # Scrapy stuff:
65 | .scrapy
66 |
67 | # Sphinx documentation
68 | docs/_build/
69 |
70 | # PyBuilder
71 | target/
72 |
73 | # Jupyter Notebook
74 | .ipynb_checkpoints
75 |
76 | # IPython
77 | profile_default/
78 | ipython_config.py
79 |
80 | # pyenv
81 | .python-version
82 |
83 | # celery beat schedule file
84 | celerybeat-schedule
85 |
86 | # SageMath parsed files
87 | *.sage.py
88 |
89 | # Environments
90 | .env
91 | .venv
92 | env/
93 | venv/
94 | ENV/
95 | env.bak/
96 | venv.bak/
97 |
98 | # Spyder project settings
99 | .spyderproject
100 | .spyproject
101 |
102 | # Rope project settings
103 | .ropeproject
104 |
105 | # mkdocs documentation
106 | /site
107 |
108 | # mypy
109 | .mypy_cache/
110 | .dmypy.json
111 | dmypy.json
112 |
113 | # Pyre type checker
114 | .pyre/
115 |
116 | # Jupyter notebooks
117 | .virtual_documents/
118 |
119 | # Sphinx gallery
120 | examples/result.h5
121 | examples/result.xdmf
122 | docs/examples/
123 | docs/tutorial/*
124 | !docs/tutorial/examples
125 | sg_execution_times.rst
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | build:
4 | os: ubuntu-lts-latest
5 | tools:
6 | python: "3.12"
7 | apt_packages:
8 | - pandoc
9 |
10 | sphinx:
11 | configuration: docs/conf.py
12 | fail_on_warning: false
13 |
14 | python:
15 | install:
16 | - method: pip
17 | path: .
18 | extra_requirements:
19 | - all
20 | - docs
21 | - examples
22 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | authors:
2 | - family-names: "Dutzler"
3 | given-names: "Andreas"
4 | orcid: "https://orcid.org/0000-0002-9383-9686"
5 | cff-version: 1.2.0
6 | message: "If you use this software, please cite it using these metadata."
7 | title: "FElupe: Finite Element Analysis"
8 | type: software
9 | doi: 10.5281/zenodo.4817406
10 | url: https://github.com/adtzlr/felupe
11 | license: GPL-3.0
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/_static/benchmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/benchmark.png
--------------------------------------------------------------------------------
/docs/_static/custom.css:
--------------------------------------------------------------------------------
1 | /*
2 | .bd-sidebar-primary div#rtd-footer-container {
3 | bottom:-1rem;
4 | margin:-1rem;
5 | position:fixed;
6 | }
7 | */
8 |
9 | .sphx-glr-thumbcontainer[tooltip]:hover::before,
10 | .sphx-glr-thumbcontainer[tooltip]:hover::after {
11 | display: none;
12 | }
--------------------------------------------------------------------------------
/docs/_static/engine-mount_animation.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/engine-mount_animation.mp4
--------------------------------------------------------------------------------
/docs/_static/ex06_rubber-metal-spring_mesh.vtk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/ex06_rubber-metal-spring_mesh.vtk
--------------------------------------------------------------------------------
/docs/_static/ex07_engine-mount_mesh-air.vtk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/ex07_engine-mount_mesh-air.vtk
--------------------------------------------------------------------------------
/docs/_static/ex07_engine-mount_mesh-metal.vtk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/ex07_engine-mount_mesh-metal.vtk
--------------------------------------------------------------------------------
/docs/_static/ex07_engine-mount_mesh-rubber.vtk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/ex07_engine-mount_mesh-rubber.vtk
--------------------------------------------------------------------------------
/docs/_static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/logo.png
--------------------------------------------------------------------------------
/docs/_static/logo_tensortrax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/logo_tensortrax.png
--------------------------------------------------------------------------------
/docs/_static/logo_without_text.svg:
--------------------------------------------------------------------------------
1 |
2 |
20 |
--------------------------------------------------------------------------------
/docs/_static/mesh.vtk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/mesh.vtk
--------------------------------------------------------------------------------
/docs/_static/readme_animation.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/docs/_static/readme_animation.mp4
--------------------------------------------------------------------------------
/docs/felupe.rst:
--------------------------------------------------------------------------------
1 | .. _felupe-api:
2 |
3 | API Reference
4 | =============
5 |
6 | FElupe consists of several (sub-) modules. Relevant functions and classes are available in the global namespace of FElupe where posssible. However, some classes or functions are only available in their respective submodule namespace due to naming conflicts, e.g.
7 |
8 | - :class:`~felupe.Line` (:class:`element.Line `) and :class:`mesh.Line ` or
9 | - :class:`~felupe.Triangle` (:class:`element.Triangle `) and :class:`mesh.Triangle `.
10 |
11 | .. toctree::
12 | :maxdepth: 1
13 | :caption: Modules:
14 |
15 | felupe/mesh
16 | felupe/element
17 | felupe/quadrature
18 | felupe/region
19 | felupe/field
20 | felupe/constitution
21 | felupe/assembly
22 | felupe/dof
23 | felupe/tools
24 | felupe/mechanics
25 | felupe/math
26 | felupe/view
27 |
--------------------------------------------------------------------------------
/docs/felupe/assembly.rst:
--------------------------------------------------------------------------------
1 | .. _felupe-api-assembly:
2 |
3 | Assembly
4 | ~~~~~~~~
5 |
6 | This module contains classes for the integration and assembly of (weak) integral forms
7 | into dense or sparse vectors and matrices. The integration algorithm switches
8 | automatically between general cartesian, plane strain or axisymmetric routines,
9 | dependent on the given fields.
10 |
11 | .. hint::
12 | :class:`~felupe.IntegralForm` is used in the :ref:`felupe-api-mechanics` module
13 | (e.g. in a :class:`~felupe.SolidBody`) to integrate and/or assemble a
14 | :class:`constitutive material formulation `
15 | and to provide an ``item`` for a :class:`~felupe.Step`
16 | or to use it in :func:`~felupe.newtonrhapson` directly.
17 |
18 | **Core**
19 |
20 | Take arrays for some pre-defined weak-forms and integrate them into dense or assemble
21 | them into sparse vectors or matrices.
22 |
23 | .. currentmodule:: felupe
24 |
25 | .. autosummary::
26 |
27 | IntegralForm
28 | assembly.IntegralFormCartesian
29 | assembly.IntegralFormAxisymmetric
30 |
31 |
32 | **Form Expressions**
33 |
34 | Define weak-form expressions on-the-fly for flexible and general form expressions.
35 |
36 | .. autosummary::
37 |
38 | Form
39 | assembly.expression.Basis
40 | assembly.expression.BasisField
41 | assembly.expression.BasisArray
42 |
43 | Create an item out of bilinear and linear weak-form expressions for a Step.
44 |
45 | .. autosummary::
46 |
47 | FormItem
48 |
49 | **Detailed API Reference**
50 |
51 | .. autoclass:: felupe.IntegralForm
52 | :members:
53 | :undoc-members:
54 | :inherited-members:
55 |
56 | .. autoclass:: felupe.assembly.IntegralFormCartesian
57 | :members:
58 | :undoc-members:
59 | :inherited-members:
60 |
61 | .. autoclass:: felupe.assembly.IntegralFormAxisymmetric
62 | :members:
63 | :undoc-members:
64 | :inherited-members:
65 |
66 | .. autofunction:: felupe.Form
67 |
68 | .. autoclass:: felupe.assembly.expression.Basis
69 | :members:
70 | :undoc-members:
71 | :inherited-members:
72 |
73 | .. autoclass:: felupe.assembly.expression.BasisField
74 | :members:
75 | :undoc-members:
76 | :inherited-members:
77 |
78 | .. autoclass:: felupe.assembly.expression.BasisArray
79 |
80 | .. autoclass:: felupe.FormItem
81 | :members:
82 | :undoc-members:
83 | :inherited-members:
84 |
--------------------------------------------------------------------------------
/docs/felupe/constitution.rst:
--------------------------------------------------------------------------------
1 | .. _felupe-api-constitution:
2 |
3 | Constitution
4 | ~~~~~~~~~~~~
5 |
6 | This module provides :class:`constitutive material ` formulations.
7 |
8 | .. toctree::
9 | :maxdepth: 1
10 | :caption: Constitution:
11 |
12 | constitution/core
13 | constitution/autodiff
14 | constitution/tools
15 |
16 | There are many different pre-defined constitutive material formulations available, including definitions for linear-elasticity, small-strain plasticity, hyperelasticity or pseudo-elasticity. The generation of user materials may be simplified when using frameworks for user-defined functions, like hyperelasticity (with automatic differentiation) or a small-strain based framework with state variables. However, the most general case is given by a framework with functions for the evaluation of stress and elasticity tensors in terms of the deformation gradient.
17 |
18 | **Constitutive Material Formulation**
19 |
20 | .. currentmodule:: felupe
21 |
22 | .. autosummary::
23 |
24 | ConstitutiveMaterial
25 | constitutive_material
26 |
27 | **Deformation Gradient-based Materials**
28 |
29 | .. autosummary::
30 |
31 | Material
32 |
33 | **Detailed API Reference**
34 |
35 | .. autoclass:: felupe.ConstitutiveMaterial
36 | :members:
37 | :undoc-members:
38 | :inherited-members:
39 |
40 | .. autofunction:: felupe.constitutive_material
41 |
42 | .. autoclass:: felupe.Material
43 | :members:
44 | :undoc-members:
45 | :inherited-members:
46 |
--------------------------------------------------------------------------------
/docs/felupe/constitution/autodiff.rst:
--------------------------------------------------------------------------------
1 | .. _felupe-api-constitution-autodiff:
2 |
3 | Automatic Differentiation
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~
5 |
6 | .. toctree::
7 | :maxdepth: 1
8 | :caption: Automatic Differentiation:
9 |
10 | autodiff/tensortrax
11 | autodiff/jax
12 |
13 | FElupe supports multiple backends for constitutive material formulations with
14 | automatic differentiation. The default backend is based on :mod:`tensortrax` which ships
15 | with FElupe. For more computationally expensive material formulations, :mod:`jax` may
16 | be the preferred option.
17 |
18 | It is straightforward to switch between these backends.
19 |
20 | .. tab:: tensortrax (default)
21 |
22 | .. code-block::
23 |
24 | import felupe as fem
25 | import felupe.constitution.tensortrax as mat
26 | import tensortrax.math as tm
27 |
28 | def neo_hooke(C, mu):
29 | "Strain energy function of the Neo-Hookean material formulation."
30 | return mu / 2 * (tm.linalg.det(C) ** (-1/3) * tm.trace(C) - 3)
31 |
32 | umat = mat.Hyperelastic(neo_hooke, mu=1.0)
33 |
34 |
35 | .. tab:: JAX
36 |
37 | .. code-block::
38 |
39 | import felupe as fem
40 | import felupe.constitution.jax as mat
41 | import jax.numpy as jnp
42 |
43 | def neo_hooke(C, mu):
44 | "Strain energy function of the Neo-Hookean material formulation."
45 | return mu / 2 * (jnp.linalg.det(C) ** (-1/3) * jnp.trace(C) - 3)
46 |
47 | umat = mat.Hyperelastic(neo_hooke, mu=1.0)
48 |
49 |
50 | .. note::
51 |
52 | The default backend is available in the top-level package namespace, this includes
53 | all models from :mod:`felupe.constitution.tensortrax.models.hyperelastic` and
54 | :mod:`felupe.constitution.tensortrax.models.lagrange` as well as the material
55 | classes :class:`felupe.constitution.tensortrax.Material` and
56 | :class:`felupe.constitution.tensortrax.Hyperelastic`.
57 |
--------------------------------------------------------------------------------
/docs/felupe/constitution/tools.rst:
--------------------------------------------------------------------------------
1 | .. _felupe-api-constitution-tools:
2 |
3 | Tools & Helpers
4 | ~~~~~~~~~~~~~~~
5 |
6 | This page contains tools and helpers for constitutive material formulations.
7 |
8 | **View Force-Stretch Curves on Elementary Deformations**
9 |
10 | .. currentmodule:: felupe
11 |
12 | .. autosummary::
13 |
14 | ViewMaterial
15 | ViewMaterialIncompressible
16 |
17 | **Special Constitutive Materials**
18 |
19 | .. autosummary::
20 |
21 | CompositeMaterial
22 | Volumetric
23 | LineChange
24 | AreaChange
25 | VolumeChange
26 |
27 | **Other**
28 |
29 | .. autosummary::
30 |
31 | constitution.lame_converter
32 | constitution.lame_converter_orthotropic
33 |
34 | **Detailed API Reference**
35 |
36 | .. autoclass:: felupe.ViewMaterial
37 | :members:
38 | :undoc-members:
39 | :inherited-members:
40 |
41 | .. autoclass:: felupe.ViewMaterialIncompressible
42 | :members:
43 | :undoc-members:
44 | :inherited-members:
45 |
46 | .. autoclass:: felupe.CompositeMaterial
47 | :members:
48 | :undoc-members:
49 | :inherited-members:
50 |
51 | .. autoclass:: felupe.Volumetric
52 | :members:
53 | :undoc-members:
54 | :inherited-members:
55 |
56 | .. autoclass:: felupe.LineChange
57 | :members:
58 | :undoc-members:
59 | :inherited-members:
60 |
61 | .. autoclass:: felupe.AreaChange
62 | :members:
63 | :undoc-members:
64 | :inherited-members:
65 |
66 | .. autoclass:: felupe.VolumeChange
67 | :members:
68 | :undoc-members:
69 | :inherited-members:
70 |
71 | .. autofunction:: felupe.constitution.lame_converter
72 |
73 | .. autofunction:: felupe.constitution.lame_converter_orthotropic
--------------------------------------------------------------------------------
/docs/felupe/dof.rst:
--------------------------------------------------------------------------------
1 | Degrees of Freedom
2 | ==================
3 |
4 | This module contains the definition of a boundary condition, tools related to the handling of degrees of freedom as well as boundary condition templates for simple load cases.
5 |
6 | **Core**
7 |
8 | .. currentmodule:: felupe
9 |
10 | .. autosummary::
11 |
12 | Boundary
13 | BoundaryDict
14 |
15 |
16 | **Tools**
17 |
18 | .. autosummary::
19 |
20 | dof.partition
21 | dof.apply
22 | dof.symmetry
23 |
24 |
25 | **Load Cases**
26 |
27 | .. autosummary::
28 |
29 | dof.uniaxial
30 | dof.biaxial
31 | dof.shear
32 |
33 |
34 | **Detailed API Reference**
35 |
36 | .. autoclass:: felupe.Boundary
37 | :members:
38 | :undoc-members:
39 | :inherited-members:
40 |
41 | .. autoclass:: felupe.BoundaryDict
42 | :members:
43 | :undoc-members:
44 | :inherited-members:
45 |
46 | .. autofunction:: felupe.dof.partition
47 |
48 | .. autofunction:: felupe.dof.apply
49 |
50 | .. autofunction:: felupe.dof.symmetry
51 |
52 | .. autofunction:: felupe.dof.uniaxial
53 |
54 | .. autofunction:: felupe.dof.biaxial
55 |
56 | .. autofunction:: felupe.dof.shear
57 |
--------------------------------------------------------------------------------
/docs/felupe/element.rst:
--------------------------------------------------------------------------------
1 | .. _felupe-api-element:
2 |
3 | Element
4 | =======
5 |
6 | This module provides classes for the finite element formulations.
7 |
8 | .. currentmodule:: felupe
9 |
10 | .. autosummary::
11 |
12 | Element
13 |
14 | **Linear Elements**
15 |
16 | .. autosummary::
17 |
18 | Vertex
19 | Line
20 | Quad
21 | Hexahedron
22 | Triangle
23 | Tetra
24 |
25 | **Constant Elements**
26 |
27 | .. autosummary::
28 |
29 | ConstantQuad
30 | ConstantHexahedron
31 |
32 | **Quadratic Elements**
33 |
34 | .. autosummary::
35 |
36 | QuadraticQuad
37 | QuadraticHexahedron
38 | BiQuadraticQuad
39 | TriQuadraticHexahedron
40 | QuadraticTriangle
41 | QuadraticTetra
42 |
43 | **Bubble-Enriched Elements**
44 |
45 | .. autosummary::
46 |
47 | TriangleMINI
48 | TetraMINI
49 |
50 | **Arbitrary-Order Elements**
51 |
52 | .. autosummary::
53 |
54 | element.ArbitraryOrderLagrange
55 |
56 | **Detailed API Reference**
57 |
58 | .. autoclass:: felupe.Element
59 | :members:
60 | :undoc-members:
61 | :show-inheritance:
62 |
63 | .. autoclass:: felupe.Vertex
64 | :members:
65 | :undoc-members:
66 | :show-inheritance:
67 |
68 | .. autoclass:: felupe.Line
69 | :members:
70 | :undoc-members:
71 | :show-inheritance:
72 |
73 | .. autoclass:: felupe.Quad
74 | :members:
75 | :undoc-members:
76 | :show-inheritance:
77 |
78 | .. autoclass:: felupe.Hexahedron
79 | :members:
80 | :undoc-members:
81 | :show-inheritance:
82 |
83 | .. autoclass:: felupe.Triangle
84 | :members:
85 | :undoc-members:
86 | :show-inheritance:
87 |
88 | .. autoclass:: felupe.Tetra
89 | :members:
90 | :undoc-members:
91 | :show-inheritance:
92 |
93 | .. autoclass:: felupe.ConstantQuad
94 | :members:
95 | :undoc-members:
96 | :show-inheritance:
97 |
98 | .. autoclass:: felupe.ConstantHexahedron
99 | :members:
100 | :undoc-members:
101 | :show-inheritance:
102 |
103 | .. autoclass:: felupe.QuadraticHexahedron
104 | :members:
105 | :undoc-members:
106 | :show-inheritance:
107 |
108 | .. autoclass:: felupe.TriQuadraticHexahedron
109 | :members:
110 | :undoc-members:
111 | :show-inheritance:
112 |
113 | .. autoclass:: felupe.QuadraticQuad
114 | :members:
115 | :undoc-members:
116 | :show-inheritance:
117 |
118 | .. autoclass:: felupe.BiQuadraticQuad
119 | :members:
120 | :undoc-members:
121 | :show-inheritance:
122 |
123 | .. autoclass:: felupe.QuadraticTriangle
124 | :members:
125 | :undoc-members:
126 | :show-inheritance:
127 |
128 | .. autoclass:: felupe.QuadraticTetra
129 | :members:
130 | :undoc-members:
131 | :show-inheritance:
132 |
133 | .. autoclass:: felupe.TriangleMINI
134 | :members:
135 | :undoc-members:
136 | :show-inheritance:
137 |
138 | .. autoclass:: felupe.TetraMINI
139 | :members:
140 | :undoc-members:
141 | :show-inheritance:
142 |
143 | .. autoclass:: felupe.element.ArbitraryOrderLagrange
144 | :members:
145 | :undoc-members:
146 | :show-inheritance:
147 |
--------------------------------------------------------------------------------
/docs/felupe/field.rst:
--------------------------------------------------------------------------------
1 | Field
2 | =====
3 |
4 | A :class:`~felupe.FieldContainer` with pre-defined fields is created with:
5 |
6 | .. currentmodule:: felupe
7 |
8 | .. autosummary::
9 |
10 | FieldsMixed
11 |
12 | A field container is created with a list of one or more fields.
13 |
14 | .. autosummary::
15 |
16 | FieldContainer
17 |
18 | Available kinds of fields:
19 |
20 | .. autosummary::
21 |
22 | Field
23 | FieldAxisymmetric
24 | FieldPlaneStrain
25 | FieldDual
26 |
27 | **Detailed API Reference**
28 |
29 | .. autoclass:: felupe.FieldContainer
30 | :members:
31 | :undoc-members:
32 | :inherited-members:
33 |
34 | .. autoclass:: felupe.field.EvaluateFieldContainer
35 | :members:
36 | :undoc-members:
37 | :inherited-members:
38 |
39 | .. autoclass:: felupe.Field
40 | :members:
41 | :undoc-members:
42 | :inherited-members:
43 |
44 | .. autoclass:: felupe.FieldAxisymmetric
45 | :members:
46 | :undoc-members:
47 | :inherited-members:
48 |
49 | .. autoclass:: felupe.FieldPlaneStrain
50 | :members:
51 | :undoc-members:
52 | :inherited-members:
53 |
54 | .. autoclass:: felupe.FieldDual
55 | :members:
56 | :undoc-members:
57 | :inherited-members:
58 |
59 | .. autoclass:: felupe.FieldsMixed
60 | :members:
61 | :undoc-members:
62 | :inherited-members:
--------------------------------------------------------------------------------
/docs/felupe/math.rst:
--------------------------------------------------------------------------------
1 | .. _felupe-api-math:
2 |
3 | Math
4 | ====
5 |
6 | This module contains math functions.
7 |
8 | **Core**
9 |
10 | .. currentmodule:: felupe
11 |
12 | .. autosummary::
13 |
14 | math.linsteps
15 | math.rotation_matrix
16 |
17 | **Field**
18 |
19 | .. autosummary::
20 |
21 | math.deformation_gradient
22 | math.strain
23 | math.strain_stretch_1d
24 | math.extract
25 | math.values
26 | math.norm
27 | math.interpolate
28 | math.grad
29 |
30 | **Tensor**
31 |
32 | .. autosummary::
33 |
34 | math.identity
35 | math.sym
36 | math.dya
37 | math.inplane
38 | math.inv
39 | math.det
40 | math.dev
41 | math.cof
42 | math.eig
43 | math.eigh
44 | math.eigvals
45 | math.eigvalsh
46 | math.equivalent_von_mises
47 | math.transpose
48 | math.majortranspose
49 | math.trace
50 | math.cdya_ik
51 | math.cdya_il
52 | math.cdya
53 | math.cross
54 | math.dot
55 | math.ddot
56 | math.tovoigt
57 | math.reshape
58 | math.ravel
59 |
60 | ** Equation system**
61 |
62 | .. autosummary::
63 |
64 | math.solve_2d
65 |
66 | **Detailed API Reference**
67 |
68 | .. automodule:: felupe.math
69 | :members: linsteps, rotation_matrix, deformation_gradient, strain, strain_stretch_1d, extract, values, norm, interpolate, grad, identity, sym, dya, inplane, inv, det, dev,cof, eig, eigh, eigvals, eigvalsh, equivalent_von_mises, transpose, majortranspose, trace, cdya_ik, cdya_il, cdya, cross, dot, ddot, tovoigt, reshape, ravel, solve_2d
70 |
--------------------------------------------------------------------------------
/docs/felupe/mechanics.rst:
--------------------------------------------------------------------------------
1 | .. _felupe-api-mechanics:
2 |
3 | Mechanics
4 | ~~~~~~~~~
5 |
6 | .. currentmodule:: felupe
7 |
8 | **Solid Bodies**
9 |
10 | .. autosummary::
11 |
12 | SolidBody
13 | SolidBodyNearlyIncompressible
14 | SolidBodyForce
15 | SolidBodyPressure
16 | SolidBodyCauchyStress
17 | TrussBody
18 |
19 | **Steps and Jobs**
20 |
21 | .. autosummary::
22 |
23 | Step
24 | Job
25 | CharacteristicCurve
26 | FreeVibration
27 |
28 | **Point Load and Multi-Point Constraints**
29 |
30 | .. autosummary::
31 |
32 | PointLoad
33 | MultiPointConstraint
34 | MultiPointContact
35 |
36 | **Helpers for Custom Items and State Variables**
37 |
38 | .. autosummary::
39 |
40 | StateNearlyIncompressible
41 | mechanics.Assemble
42 | mechanics.Evaluate
43 | mechanics.Results
44 |
45 | **Detailed API Reference**
46 |
47 | .. autoclass:: felupe.SolidBody
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 | .. autoclass:: felupe.SolidBodyNearlyIncompressible
53 | :members:
54 | :undoc-members:
55 | :show-inheritance:
56 |
57 | .. autoclass:: felupe.SolidBodyForce
58 | :members:
59 | :undoc-members:
60 | :show-inheritance:
61 |
62 | .. autoclass:: felupe.SolidBodyPressure
63 | :members:
64 | :undoc-members:
65 | :show-inheritance:
66 |
67 | .. autoclass:: felupe.SolidBodyCauchyStress
68 | :members:
69 | :undoc-members:
70 | :show-inheritance:
71 |
72 | .. autoclass:: felupe.PointLoad
73 | :members:
74 | :undoc-members:
75 | :show-inheritance:
76 |
77 | .. autoclass:: felupe.TrussBody
78 | :members:
79 | :undoc-members:
80 | :show-inheritance:
81 |
82 | .. autoclass:: felupe.Step
83 | :members:
84 | :undoc-members:
85 | :show-inheritance:
86 |
87 | .. autoclass:: felupe.Job
88 | :members:
89 | :undoc-members:
90 | :show-inheritance:
91 |
92 | .. autoclass:: felupe.CharacteristicCurve
93 | :members:
94 | :undoc-members:
95 | :show-inheritance:
96 |
97 | .. autoclass:: felupe.FreeVibration
98 | :members:
99 | :undoc-members:
100 | :show-inheritance:
101 |
102 | .. autoclass:: felupe.MultiPointConstraint
103 | :members:
104 | :undoc-members:
105 | :inherited-members:
106 |
107 | .. autoclass:: felupe.MultiPointContact
108 | :members:
109 | :undoc-members:
110 | :inherited-members:
111 |
112 | .. autoclass:: felupe.StateNearlyIncompressible
113 | :members:
114 | :undoc-members:
115 | :inherited-members:
116 |
117 | .. autoclass:: felupe.mechanics.Assemble
118 | :members:
119 | :undoc-members:
120 | :inherited-members:
121 |
122 | .. autoclass:: felupe.mechanics.Evaluate
123 | :members:
124 | :undoc-members:
125 | :inherited-members:
126 |
127 | .. autoclass:: felupe.mechanics.Results
128 | :members:
129 | :undoc-members:
130 | :inherited-members:
131 |
--------------------------------------------------------------------------------
/docs/felupe/mesh.rst:
--------------------------------------------------------------------------------
1 | .. _felupe-api-mesh:
2 |
3 | Mesh
4 | ====
5 |
6 | This module contains meshing-related classes and functions. Standalone mesh-tools (functions) are also available as mesh-methods.
7 |
8 | **Core**
9 |
10 | .. currentmodule:: felupe
11 |
12 | .. autosummary::
13 |
14 | Mesh
15 | MeshContainer
16 |
17 | **Geometries**
18 |
19 | .. autosummary::
20 |
21 | Point
22 | mesh.Line
23 | Rectangle
24 | Cube
25 | Grid
26 | Circle
27 | mesh.Triangle
28 | mesh.RectangleArbitraryOrderQuad
29 | mesh.CubeArbitraryOrderHexahedron
30 |
31 | **Tools**
32 |
33 | .. autosummary::
34 |
35 | mesh.expand
36 | mesh.translate
37 | mesh.rotate
38 | mesh.revolve
39 | mesh.sweep
40 | mesh.mirror
41 | mesh.merge_duplicate_points
42 | mesh.merge_duplicate_cells
43 | mesh.concatenate
44 | mesh.runouts
45 | mesh.triangulate
46 | mesh.convert
47 | mesh.collect_edges
48 | mesh.collect_faces
49 | mesh.collect_volumes
50 | mesh.add_midpoints_edges
51 | mesh.add_midpoints_faces
52 | mesh.add_midpoints_volumes
53 | mesh.flip
54 | mesh.fill_between
55 | mesh.dual
56 | mesh.stack
57 | mesh.read
58 | mesh.interpolate_line
59 | mesh.cell_types
60 |
61 | **Detailed API Reference**
62 |
63 | .. autoclass:: felupe.Mesh
64 | :members:
65 | :undoc-members:
66 | :inherited-members:
67 |
68 | .. autoclass:: felupe.MeshContainer
69 | :members:
70 | :undoc-members:
71 | :inherited-members:
72 |
73 | .. autoclass:: felupe.Point
74 | :members:
75 | :undoc-members:
76 | :show-inheritance:
77 |
78 | .. autoclass:: felupe.mesh.Line
79 | :members:
80 | :undoc-members:
81 | :show-inheritance:
82 |
83 | .. autoclass:: felupe.Rectangle
84 | :members:
85 | :undoc-members:
86 | :show-inheritance:
87 |
88 | .. autoclass:: felupe.Cube
89 | :members:
90 | :undoc-members:
91 | :show-inheritance:
92 |
93 | .. autoclass:: felupe.Grid
94 | :members:
95 | :undoc-members:
96 | :show-inheritance:
97 |
98 | .. autoclass:: felupe.Circle
99 | :members:
100 | :undoc-members:
101 | :show-inheritance:
102 |
103 | .. autoclass:: felupe.mesh.Triangle
104 | :members:
105 | :undoc-members:
106 | :show-inheritance:
107 |
108 | .. autoclass:: felupe.mesh.RectangleArbitraryOrderQuad
109 | :members:
110 | :undoc-members:
111 | :show-inheritance:
112 |
113 | .. autoclass:: felupe.mesh.CubeArbitraryOrderHexahedron
114 | :members:
115 | :undoc-members:
116 | :show-inheritance:
117 |
118 | .. automodule:: felupe.mesh
119 | :members: expand, translate, rotate, revolve, sweep, mirror, concatenate, runouts, triangulate, convert, collect_edges, collect_faces, collect_volumes, add_midpoints_edges, add_midpoints_faces, add_midpoints_volumes, flip, fill_between, dual, stack, merge_duplicate_points, merge_duplicate_cells, read, interpolate_line, cell_types
120 |
--------------------------------------------------------------------------------
/docs/felupe/quadrature.rst:
--------------------------------------------------------------------------------
1 | Quadrature
2 | ==========
3 |
4 | This module contains quadrature (numeric integration) schemes for different finite element formulations. The integration points of a boundary-quadrature are located on the first edge for 2d elements and on the first face for 3d elements.
5 |
6 | **Lines, Quads and Hexahedrons**
7 |
8 | .. currentmodule:: felupe
9 |
10 | .. autosummary::
11 |
12 | GaussLegendre
13 | GaussLegendreBoundary
14 | GaussLobatto
15 | GaussLobattoBoundary
16 |
17 | **Triangles and Tetrahedrons**
18 |
19 | .. autosummary::
20 |
21 | quadrature.Triangle
22 | quadrature.Tetrahedron
23 | TriangleQuadrature
24 | TetrahedronQuadrature
25 |
26 | **Sphere**
27 |
28 | .. autosummary::
29 |
30 | BazantOh
31 |
32 | **Detailed API Reference**
33 |
34 | .. autoclass:: felupe.quadrature.Scheme
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 | .. autoclass:: felupe.GaussLegendre
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | .. autoclass:: felupe.GaussLegendreBoundary
45 | :members:
46 | :undoc-members:
47 | :show-inheritance:
48 |
49 | .. autoclass:: felupe.GaussLobatto
50 | :members:
51 | :undoc-members:
52 | :show-inheritance:
53 |
54 | .. autoclass:: felupe.GaussLobattoBoundary
55 | :members:
56 | :undoc-members:
57 | :show-inheritance:
58 |
59 | .. autoclass:: felupe.quadrature.Triangle
60 | :members:
61 | :undoc-members:
62 | :show-inheritance:
63 |
64 | .. autoclass:: felupe.quadrature.Tetrahedron
65 | :members:
66 | :undoc-members:
67 | :show-inheritance:
68 |
69 | .. autoclass:: felupe.BazantOh
70 | :members:
71 | :undoc-members:
72 | :show-inheritance:
73 |
--------------------------------------------------------------------------------
/docs/felupe/tools.rst:
--------------------------------------------------------------------------------
1 | Tools
2 | ~~~~~
3 |
4 | .. currentmodule:: felupe
5 |
6 | **Optimization**
7 |
8 | .. autosummary::
9 |
10 | newtonrhapson
11 | tools.NewtonResult
12 |
13 | **Export of Results**
14 |
15 | .. autosummary::
16 |
17 | save
18 |
19 | **Convert Cell-Data to Point-Data**
20 |
21 | .. autosummary::
22 |
23 | topoints
24 | project
25 | tools.extrapolate
26 |
27 | **Reaction-Force and -Moment**
28 |
29 | .. autosummary::
30 |
31 | tools.force
32 | tools.moment
33 |
34 | **Detailed API Reference**
35 |
36 | .. autoclass:: felupe.tools.NewtonResult
37 |
38 | .. autofunction:: felupe.newtonrhapson
39 |
40 | .. autofunction:: felupe.save
41 |
42 | .. autofunction:: felupe.topoints
43 |
44 | .. autofunction:: felupe.project
45 |
46 | .. autofunction:: felupe.tools.extrapolate
47 |
48 | .. autofunction:: felupe.tools.force
49 |
50 | .. autofunction:: felupe.tools.moment
51 |
--------------------------------------------------------------------------------
/docs/felupe/view.rst:
--------------------------------------------------------------------------------
1 | View
2 | ~~~~
3 |
4 | Visualization methods for meshes, mesh and field containers as well as solid bodies by
5 | `PyVista `_.
6 |
7 | .. currentmodule:: felupe
8 |
9 | .. autosummary::
10 |
11 | view.Scene
12 | ViewMesh
13 | ViewField
14 | ViewSolid
15 | ViewXdmf
16 |
17 | **Detailed API Reference**
18 |
19 | .. autoclass:: felupe.view.Scene
20 |
21 | .. autofunction:: felupe.ViewMesh
22 |
23 | .. autofunction:: felupe.ViewField
24 |
25 | .. autofunction:: felupe.ViewSolid
26 |
27 | .. autofunction:: felupe.ViewXdmf
28 |
--------------------------------------------------------------------------------
/docs/howto.rst:
--------------------------------------------------------------------------------
1 | .. _how-to:
2 |
3 | How-To Guides
4 | =============
5 |
6 | .. toctree::
7 | :maxdepth: 1
8 | :caption: How-To:
9 |
10 | howto/meshgen
11 | howto/mixed
12 | howto/axi
13 | howto/solvers
14 | howto/composite
15 | howto/solid
16 | howto/umat
17 | howto/umat_hyperelasticity
18 | howto/items
19 | howto/project
20 |
--------------------------------------------------------------------------------
/docs/howto/axi.rst:
--------------------------------------------------------------------------------
1 | Two-dimensional Problems
2 | ------------------------
3 |
4 | For plane-strain and axisymmetric problems a vector-valued field has to be created for
5 | the two-dimensional in-plane displacement components.
6 |
7 | .. tab:: Axisymmetric
8 |
9 | .. code-block:: python
10 |
11 | import felupe as fem
12 |
13 | mesh = fem.Rectangle(n=3)
14 | region = fem.RegionQuad(mesh)
15 | displacement = fem.FieldAxisymmetric(region, dim=2)
16 |
17 | .. tab:: Plane-Strain
18 |
19 | .. code-block:: python
20 |
21 | import felupe as fem
22 |
23 | mesh = fem.Rectangle(n=3)
24 | region = fem.RegionQuad(mesh)
25 | displacement = fem.FieldPlaneStrain(region, dim=2)
26 |
27 |
28 | The 3x3 deformation gradient for axisymmetric and plane-strain two-dimensional problems
29 | is obtained by the :meth:`~felupe.FieldAxisymmetric.grad` or
30 | :meth:`~felupe.FieldAxisymmetric.extract` methods (same for
31 | :class:`~felupe.FieldPlaneStrain`). For these two-dimensional fields the gradient is
32 | modified to return a three-dimensional gradient.
33 |
34 | .. code-block:: python
35 |
36 | field = fem.FieldContainer([displacement])
37 | F = field.extract(grad=True, sym=False, add_identity=True)
38 |
39 | For simplicity, let's use the isotropic hyperelastic :class:`~felupe.NeoHooke` material
40 | model formulation.
41 |
42 | .. code-block:: python
43 |
44 | umat = fem.NeoHooke(mu=1, bulk=5)
45 |
46 | .. note::
47 |
48 | Internally, FElupe provides an adopted low-level
49 | :class:`~felupe.assembly.IntegralFormAxisymmetric` class for the integration and the
50 | sparse matrix assemblage of axisymmetric problems. It uses the additional
51 | information (e.g. radial coordinates at integration points) stored in
52 | :class:`~felupe.FieldAxisymmetric` to provide a consistent interface in comparison
53 | to :class:`~felupe.assembly.IntegralFormCartesian`. The top-level
54 | :class:`~felupe.IntegralForm` chooses the appropriate low-level integral form based
55 | on the kind of field inside the field container.
56 |
57 | .. code-block:: python
58 |
59 | dA = region.dV
60 |
61 | r = fem.IntegralForm(umat.gradient(F), field, dA).assemble()
62 | K = fem.IntegralForm(umat.hessian(F), field, dA, field).assemble()
63 |
64 | To sum up, for axisymmetric problems use :class:`~felupe.FieldAxisymmetric` and for
65 | plane-strain problems use :class:`~felupe.FieldPlaneStrain`. Of course, mixed-field
66 | formulations may also be used with axisymmetric or plane-strain (displacement) fields.
67 |
--------------------------------------------------------------------------------
/docs/howto/items.rst:
--------------------------------------------------------------------------------
1 | Create Custom Items
2 | ~~~~~~~~~~~~~~~~~~~
3 | Items are supported to be used in a :class:`~felupe.Step` and in
4 | :func:`~felupe.newtonrhapson`. They provide methods to assemble a vector and a sparse
5 | matrix. An item has to be created as a class which takes a
6 | :class:`~felupe.FieldContainer` as input argument. In its ``__init__(self, field)``
7 | method, the helpers :class:`~felupe.mechanics.Assemble` and
8 | :class:`~felupe.mechanics.Results` have to be evaluated and added as attributes.
9 | Internal methods which assemble the sparse vector and matrix, optionally with an updated
10 | :class:`~felupe.FieldContainer` provided by the `field` argument, have to be linked to
11 | :class:`~felupe.mechanics.Assemble`.
12 |
13 | .. note::
14 |
15 | This is only a minimal working example for an item. For more details, see the
16 | sources of :class:`~felupe.SolidBody` or
17 | :class:`~felupe.SolidBodyNearlyIncompressible`.
18 |
19 | .. pyvista-plot::
20 | :context:
21 |
22 | from scipy.sparse import csr_matrix
23 | import felupe as fem
24 |
25 |
26 | class MyItem:
27 | def __init__(self, field):
28 | self.field = field
29 | self.assemble = fem.mechanics.Assemble(vector=self._vector, matrix=self._matrix)
30 | self.results = fem.mechanics.Results()
31 |
32 | def _vector(self, field=None, **kwargs):
33 | return csr_matrix(([0.0], ([0], [0])), shape=(1, 1))
34 |
35 | def _matrix(self, field=None, **kwargs):
36 | return csr_matrix(([0.0], ([0], [0])), shape=(1, 1))
37 |
38 | This item is now added to a basic script.
39 |
40 | .. note::
41 |
42 | The vector- and matrix-shapes are automatically increased to match the shape of the
43 | other items if necessary. Hence, a sparse matrix with shape ``(1, 1)`` is a valid
44 | choice for a vector or a matrix filled with zeros.
45 |
46 | .. pyvista-plot::
47 | :context:
48 |
49 | region = fem.RegionHexahedron(mesh=fem.Cube(n=3))
50 | field = fem.FieldContainer([fem.Field(region, dim=3)])
51 | boundaries, loadcase = fem.dof.uniaxial(field, clamped=True, move=1.0)
52 |
53 | solid = fem.SolidBody(umat=fem.NeoHooke(mu=1, bulk=2), field=field)
54 | my_item = MyItem(field=field)
55 |
56 | step = fem.Step(items=[solid, my_item], boundaries=boundaries)
57 | job = fem.Job(steps=[step]).evaluate()
--------------------------------------------------------------------------------
/docs/howto/project.rst:
--------------------------------------------------------------------------------
1 | Project cell values to mesh-points
2 | ----------------------------------
3 |
4 | This section demonstrates how to move cell-values, located at the quadrature points
5 | of cells, to mesh-points. The results of :func:`~felupe.project`,
6 | :func:`~felupe.topoints` and :func:`~felupe.tools.extrapolate` are compared for the
7 | Cauchy stresses of a rectangular block under compression.
8 |
9 | .. pyvista-plot::
10 | :context:
11 |
12 | import felupe as fem
13 |
14 | region = fem.RegionQuad(mesh=fem.Rectangle(b=(2, 1), n=(11, 6)))
15 | field = fem.FieldContainer([fem.FieldPlaneStrain(region, dim=2)])
16 |
17 | boundaries = fem.dof.uniaxial(field, clamped=True, move=-0.3, axis=1)[0]
18 | solid = fem.SolidBody(umat=fem.NeoHooke(mu=1, bulk=5), field=field)
19 |
20 | job = fem.Job(steps=[fem.Step(items=[solid], boundaries=boundaries)]).evaluate()
21 |
22 | Cell-based results, like Cauchy stresses, are not projected to mesh-points by default.
23 | Different methods may be used to *move* the cell-data to the mesh-points.
24 |
25 | .. pyvista-plot::
26 | :context:
27 | :force_static:
28 |
29 | # import pyvista as pv
30 |
31 | # plotter = pv.Plotter(shape=(2, 2))
32 | # kwargs = dict(name="Cauchy Stress", component=1, plotter=plotter)
33 |
34 | # plotter.subplot(0, 0)
35 | # kwargs_sbar = dict(interactive=False, title="Cauchy Stress YY (None)")
36 | # solid.plot(project=None, **kwargs, scalar_bar_args=kwargs_sbar)
37 |
38 | # plotter.subplot(0, 1)
39 | # kwargs_sbar = dict(interactive=False, title="Cauchy Stress YY (topoints)")
40 | # solid.plot(project=fem.topoints, **kwargs, scalar_bar_args=kwargs_sbar)
41 |
42 | # plotter.subplot(1, 0)
43 | # kwargs_sbar = dict(interactive=False, title="Cauchy Stress YY (project)")
44 | # solid.plot(project=fem.project, **kwargs, scalar_bar_args=kwargs_sbar)
45 |
46 | # plotter.subplot(1, 1)
47 | # kwargs_sbar = dict(interactive=False, title="Cauchy Stress YY (extrapolate)")
48 | # solid.plot(project=fem.tools.extrapolate, **kwargs, scalar_bar_args=kwargs_sbar)
49 |
50 | # plotter.show()
--------------------------------------------------------------------------------
/docs/howto/solvers.rst:
--------------------------------------------------------------------------------
1 | Use external solvers
2 | --------------------
3 |
4 | FElupe uses SuperLU as direct sparse solver by default because it is shipped with SciPy (and SciPy is already a dependency of FElupe). While it is definitely a good choice for small to mid-sized problems, faster alternatives are easy to install and use. This section demonstrates several possibilities, e.g. a fast direct solver from `PyPardiso `_ (``pip install pypardiso``) and the :func:`~scipy.sparse.linalg.minres` iterative solver from ``SciPy``. Custom solvers may be passed to the evaluation of a :class:`~felupe.Job`.
5 |
6 | .. code-block:: python
7 |
8 | import felupe as fem
9 |
10 | from scipy.sparse.linalg import spsolve # (default)
11 |
12 | job = fem.Job(steps)
13 | job.evaluate(solver=spsolve) # function `x = spsolve(A, b)`
14 |
15 | Solvers from SciPy Sparse:
16 |
17 | .. tab:: SciPy Sparse (direct)
18 |
19 | .. code-block:: python
20 |
21 | # the default solver
22 | from scipy.sparse.linalg import spsolve
23 |
24 | .. tab:: SciPy Sparse (iterative)
25 |
26 | .. note::
27 |
28 | ``minres`` may be replaced by another iterative method.
29 |
30 | .. code-block:: python
31 |
32 | import scipy.sparse.linalg as spla
33 |
34 | def solver(A, b):
35 | "Wrapper function for iterative solvers from scipy.sparse.linalg."
36 |
37 | return spla.minres(A, b)[0]
38 |
39 | Solvers from external packages:
40 |
41 | .. tab:: PyPardiso (direct)
42 |
43 | Ensure to have `PyPardiso `_ installed.
44 |
45 | .. code-block:: bash
46 |
47 | pip install pypardiso
48 |
49 | .. code-block:: python
50 |
51 | from pypardiso import spsolve
52 |
53 | .. tab:: PyPardiso (direct, symmetric)
54 |
55 | Ensure to have `PyPardiso `_ installed.
56 |
57 | .. code-block:: bash
58 |
59 | pip install pypardiso
60 |
61 | .. code-block:: python
62 |
63 | from pypardiso import PyPardisoSolver
64 | from scipy.sparse import triu
65 |
66 | def spsolve(A, b):
67 | # mtype = 1: real and structurally symmetric, supernode pivoting
68 | # mtype = 2: real and symmetric positive definite
69 | # mtype =-2: real and symmetric indefinite,
70 | # diagonal or Bunch-Kaufman pivoting
71 | # mtype = 6: complex and symmetric
72 | return PyPardisoSolver(mtype=-2).solve(triu(A).tocsr(), b).squeeze()
73 |
--------------------------------------------------------------------------------
/docs/howto/umat.rst:
--------------------------------------------------------------------------------
1 | Small-Strain based Materials
2 | ----------------------------
3 |
4 | A user material (``umat``) based on the incremental small-strain tensor, e.g. suitable
5 | for linear elastic-plastic material formulations, is provided by
6 | :class:`~felupe.MaterialStrain`. A user-defined function must be created with the
7 | arguments and must return:
8 |
9 | +----------+---------------+---------------------------------------+
10 | | **Kind** | **Symbol** | **Description** |
11 | +==========+===============+=======================================+
12 | | Argument | dε | strain increment |
13 | +----------+---------------+---------------------------------------+
14 | | Argument | εn | old strain tensor |
15 | +----------+---------------+---------------------------------------+
16 | | Argument | σn | old stress tensor |
17 | +----------+---------------+---------------------------------------+
18 | | Argument | ζn | list of old state variables |
19 | +----------+---------------+---------------------------------------+
20 | | Return | dσdε | tangent modulus |
21 | +----------+---------------+---------------------------------------+
22 | | Return | σ | new stress tensor |
23 | +----------+---------------+---------------------------------------+
24 | | Return | ζ | list of new state variables |
25 | +----------+---------------+---------------------------------------+
26 |
27 | .. code-block:: python
28 |
29 | def material(dε, εn, σn, ζn, **kwargs):
30 | return dσdε, σ, ζ
31 |
32 | This function is further added as the ``material`` argument of
33 | :class:`~felupe.MaterialStrain`. If the material makes use of state variables, the
34 | shapes of these internal state variables must be provided.
35 |
36 | .. code-block:: python
37 |
38 | import felupe as fem
39 |
40 | umat = fem.MaterialStrain(material=material, statevars=(0,), **kwargs)
41 |
42 | FElupe contains two reference small-strain user materials, one for linear elastic
43 | materials and another one for linear elastic-plastic materials with isotropic hardening:
44 |
45 | * :func:`~felupe.linear_elastic`
46 | * :func:`~felupe.linear_elastic_plastic_isotropic_hardening`
47 |
--------------------------------------------------------------------------------
/docs/howto/umat_hyperelasticity.rst:
--------------------------------------------------------------------------------
1 | Isotropic Hyperelastic Materials
2 | --------------------------------
3 |
4 | User materials (Umat) based on the right Cauchy-Green deformation tensor, suitable for Total-Lagrangian isotropic hyperelastic material formulations, are to be created with :class:`~felupe.Hyperelastic`. Only the strain energy function must be defined. Both gradient and hessian are evaluated by forward-mode automatic differentiation. Therefore, only math-functions from :mod:`tensortrax.math` are supported. A user-defined function must be created with the argument and return values:
5 |
6 | +----------+---------------+---------------------------------------+
7 | | **Kind** | **Symbol** | **Description** |
8 | +==========+===============+=======================================+
9 | | Argument | C | right Cauchy-Green deformation tensor |
10 | +----------+---------------+---------------------------------------+
11 | | Return | W | strain energy function |
12 | +----------+---------------+---------------------------------------+
13 |
14 | .. code-block:: python
15 |
16 | import tensortrax.math as tm
17 |
18 | def strain_energy_function(C, **kwargs):
19 | return W
20 |
21 | This function is further added as the ``fun`` argument of :class:`~felupe.Hyperelastic`.
22 |
23 | .. code-block:: python
24 |
25 | import felupe as fem
26 |
27 | umat = fem.Hyperelastic(fun=strain_energy_function, **kwargs)
28 |
29 | FElupe contains several reference implementations of hyperelastic user material
30 | formulations, like
31 |
32 | * :func:`~felupe.constitution.tensortrax.models.hyperelastic.neo_hooke`,
33 | * :func:`~felupe.constitution.tensortrax.models.hyperelastic.mooney_rivlin`,
34 | * :func:`~felupe.constitution.tensortrax.models.hyperelastic.yeoh` or
35 | * :func:`~felupe.constitution.tensortrax.models.hyperelastic.ogden`.
36 |
37 | A complete list of all available model formulations is available in the
38 | :ref:`hyperelasticity ` section of the API reference.
39 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/docs/tutorial/examples/extut01_getting_started.py:
--------------------------------------------------------------------------------
1 | r"""
2 | Getting Started
3 | ---------------
4 |
5 | .. topic:: Your very first steps with FElupe.
6 |
7 | * create a meshed cube with hexahedron cells
8 |
9 | * define a numeric region along with a displacement field
10 |
11 | * load a Neo-Hookean material formulation
12 |
13 | * apply a uniaxial loadcase
14 |
15 | * solve the problem
16 |
17 | * export the displaced mesh
18 |
19 | This tutorial covers the essential high-level parts of creating and solving problems
20 | with FElupe. As an introductory example, a quarter model of a solid cube with
21 | hyperelastic material behaviour is subjected to a uniaxial elongation applied at a
22 | clamped end-face. First, let's import FElupe and create a meshed cube out of hexahedron
23 | cells with ``n`` points per axis. A numeric region, pre-defined for hexahedrons, is
24 | created on the mesh. A vector-valued displacement field is initiated on the region.
25 | Next, a field container is created on top of the displacement field.
26 | """
27 |
28 | import felupe as fem
29 |
30 | mesh = fem.Cube(n=6)
31 | region = fem.RegionHexahedron(mesh=mesh)
32 | displacement = fem.Field(region=region, dim=3)
33 | field = fem.FieldContainer(fields=[displacement])
34 |
35 | # %%
36 | # A uniaxial load case is applied on the displacement field stored inside the field
37 | # container. This involves setting up symmetry planes as well as the absolute value of
38 | # the prescribed displacement at the mesh-points on the right-end face of the cube. The
39 | # right-end face is *clamped*: only displacements in direction x are allowed. The dict
40 | # of boundary conditions for this pre-defined load case are returned as ``boundaries``
41 | # and the partitioned degrees of freedom as well as the external displacements are
42 | # stored within the returned dict ``loadcase``.
43 | boundaries, loadcase = fem.dof.uniaxial(field, move=0.2, right=1, clamped=True)
44 |
45 | # %%
46 | # The material behaviour is defined through a built-in Neo-Hookean material formulation.
47 | # The constitutive isotropic hyperelastic material formulation is applied on the
48 | # displacement field by the definition of a solid body.
49 | umat = fem.NeoHooke(mu=1.0, bulk=2.0)
50 | solid = fem.SolidBody(umat=umat, field=field)
51 |
52 | # %%
53 | # The problem is solved by an iterative :func:`Newton-Rhapson `
54 | # procedure. A verbosity level of 2 enables a detailed text-based logging.
55 | res = fem.newtonrhapson(items=[solid], verbose=2, **loadcase)
56 |
57 | # %%
58 | # Results may be viewed in an interactive window.
59 | field.plot("Displacement", component=0).show()
60 |
--------------------------------------------------------------------------------
/docs/tutorial/examples/extut02_job.py:
--------------------------------------------------------------------------------
1 | r"""
2 | Run a Job
3 | ---------
4 |
5 | .. topic:: Learn how to apply boundary conditions in a ramped manner within a **Step**
6 | and run a **Job**.
7 |
8 | * create a **Step** with ramped boundary conditions
9 |
10 | * run a **Job** and export a XDMF time-series file
11 |
12 | This tutorial once again covers the essential high-level parts of creating and solving
13 | problems with FElupe. This time, however, the external displacements are applied in a
14 | ramped manner. The prescribed displacements of a cube under non-homogenous
15 | :func:`uniaxial loading ` will be controlled within a
16 | :class:`step `. The
17 | :class:`Ogden-Roxburgh ` pseudo-elastic Mullins softening model is
18 | combined with an isotropic hyperelastic :class:`Neo-Hookean ` material
19 | formulation, which is further applied on a
20 | :class:`nearly incompressible solid body ` for a
21 | realistic analysis of rubber-like materials. Note that the bulk modulus is now an
22 | argument of the (nearly) incompressible solid body instead of the constitutive
23 | Neo-Hookean material definition.
24 | """
25 |
26 | import felupe as fem
27 |
28 | mesh = fem.Cube(n=6)
29 | region = fem.RegionHexahedron(mesh=mesh)
30 | field = fem.FieldContainer([fem.Field(region=region, dim=3)])
31 |
32 | boundaries, loadcase = fem.dof.uniaxial(field, clamped=True)
33 |
34 | umat = fem.OgdenRoxburgh(material=fem.NeoHooke(mu=1), r=3, m=1, beta=0)
35 | body = fem.SolidBodyNearlyIncompressible(umat=umat, field=field, bulk=5000)
36 |
37 | # %%
38 | # The ramped prescribed displacements for 12 substeps are created with
39 | # :func:`~felupe.math.linsteps`. A :class:`~felupe.Step` is created with a list of items
40 | # to be considered (here, one single solid body) and a dict of ramped boundary
41 | # conditions along with the prescribed values.
42 | move = fem.math.linsteps([0, 2, 1.5], num=[8, 4])
43 | uniaxial = fem.Step(
44 | items=[body], ramp={boundaries["move"]: move}, boundaries=boundaries
45 | )
46 |
47 | # %%
48 | # This step is now added to a :class:`~felupe.Job`. The results are exported after each
49 | # completed and successful substep as a time-series XDMF-file. A
50 | # :class:`~felupe.CharacteristicCurve`-job logs the displacement and sum of reaction
51 | # forces on a given boundary condition.
52 | job = fem.CharacteristicCurve(steps=[uniaxial], boundary=boundaries["move"])
53 | job.evaluate(filename="result.xdmf", verbose=True)
54 |
55 | field.plot("Principal Values of Logarithmic Strain").show()
56 |
57 | # %%
58 | # The sum of the reaction force in direction :math:`x` on the boundary condition
59 | # ``"move"`` is plotted as a function of the displacement :math:`u` on the boundary
60 | # condition ``"move"`` .
61 | fig, ax = job.plot(
62 | xlabel=r"Displacement $u$ in mm $\longrightarrow$",
63 | ylabel=r"Normal Force $F$ in N $\longrightarrow$",
64 | )
65 |
--------------------------------------------------------------------------------
/examples/README.rst:
--------------------------------------------------------------------------------
1 | .. _examples:
2 |
3 | Examples
4 | ========
5 |
6 | A gallery of examples. Coarse meshes are used whenever possible to make the examples run
7 | fast. Some examples require external packages to be installed.
8 |
--------------------------------------------------------------------------------
/examples/ex01_beam.py:
--------------------------------------------------------------------------------
1 | r"""
2 | Cantilever beam under gravity
3 | -----------------------------
4 |
5 | .. topic:: Apply a gravity load on a solid body.
6 |
7 | * create a solid body and apply the gravity load
8 |
9 | * linear-elastic analysis
10 |
11 | The displacement due to gravity of a cantilever beam with young's modulus
12 | :math:`E=206000` MPa, poisson ratio :math:`\nu=0.3`, length :math:`L=2000` mm and
13 | cross section area :math:`A=a \cdot a` with :math:`a=100` mm is to be evaluated within
14 | a linear-elastic analysis [1]_.
15 |
16 | .. image:: ../../examples/ex01_beam_sketch.png
17 |
18 | First, let's create a meshed cube out of hexahedron cells. A numeric region created on the mesh represents the cantilever beam. A three-
19 | dimensional vector-valued displacement field is initiated on the region.
20 | """
21 |
22 | # sphinx_gallery_thumbnail_number = -1
23 | import felupe as fem
24 |
25 | cube = fem.Cube(a=(0, 0, 0), b=(2000, 100, 100), n=(101, 6, 6))
26 | region = fem.RegionHexahedron(cube, uniform=True)
27 | displacement = fem.Field(region, dim=3)
28 | field = fem.FieldContainer([displacement])
29 |
30 | # %%
31 | # A fixed boundary condition is applied on the left end of the beam.
32 | boundaries = fem.BoundaryDict(fixed=fem.dof.Boundary(displacement, fx=0))
33 | boundaries.plot().show()
34 |
35 | # %%
36 | # The material behaviour is defined through a built-in isotropic linear-elastic material
37 | # formulation.
38 | umat = fem.LinearElastic(E=206000, nu=0.3)
39 | solid = fem.SolidBody(umat=umat, field=field)
40 |
41 | # %%
42 | # The body force is defined by a (constant) gravity field on a solid body.
43 | #
44 | # .. math::
45 | # \delta W_{ext} = \int_v \delta \boldsymbol{u} \cdot \rho \boldsymbol{g} ~ dv
46 | density = 7850 * 1e-12
47 | gravity = [0, 0, 9810]
48 | force = fem.SolidBodyForce(field, values=gravity, scale=density)
49 |
50 | # %%
51 | # Inside a Newton-Rhapson procedure, the weak form of linear elasticity is assembled
52 | # into the stiffness matrix and the applied gravity field is assembled into the body
53 | # force vector.
54 | step = fem.Step(items=[solid, force], boundaries=boundaries)
55 | job = fem.Job(steps=[step]).evaluate()
56 |
57 | # %%
58 | # The magnitude of the displacement field are plotted on a 300x scaled deformed
59 | # configuration.
60 | field.plot("Displacement", component=None, factor=300).show()
61 |
62 | # %%
63 | # References
64 | # ~~~~~~~~~~
65 | # .. [1] Glenk C. et al., *Consideration of Body Forces within Finite Element Analysis*,
66 | # Strojniški vestnik - Journal of Mechanical Engineering, Faculty of Mechanical
67 | # Engineering, 2018, |DOI|.
68 | #
69 | # .. |DOI| image:: https://zenodo.org/badge/DOI/10.5545/sv-jme.2017.5081.svg
70 | # :target: https://www.doi.org/10.5545/sv-jme.2017.5081
71 |
--------------------------------------------------------------------------------
/examples/ex01_beam_sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/examples/ex01_beam_sketch.png
--------------------------------------------------------------------------------
/examples/ex03_plasticity.py:
--------------------------------------------------------------------------------
1 | r"""
2 | Plasticity with Isotropic Hardening
3 | -----------------------------------
4 |
5 | .. topic:: Small-strain Plasticity
6 |
7 | * linear-elastic plastic material formulation with isotropic hardening
8 |
9 | * define a body force vector
10 |
11 | * extract state variables
12 |
13 | The normal plastic strain due to a body force applied on a solid with a linear-elastic
14 | plastic material formulation with isotropic hardening with young's modulus
15 | :math:`E=210000`, poisson ratio :math:`\nu=0.3`, isotropic hardening modulus
16 | :math:`K=1000`, yield stress :math:`\sigma_y=355`, length :math:`L=3` and cross section
17 | area :math:`A=1` is to be evaluated.
18 |
19 | .. image:: ../../examples/ex03_plasticity_sketch.png
20 |
21 | First, let's create a meshed cube out of hexahedron cells with ``n=(16, 6, 6)`` points
22 | per axis. A three-dimensional vector-valued displacement field is initiated on the
23 | numeric region.
24 | """
25 |
26 | # sphinx_gallery_thumbnail_number = -1
27 | import numpy as np
28 |
29 | import felupe as fem
30 |
31 | mesh = fem.Cube(b=(3, 1, 1), n=(10, 4, 4))
32 | region = fem.RegionHexahedron(mesh)
33 | displacement = fem.Field(region, dim=3)
34 | field = fem.FieldContainer([displacement])
35 |
36 | # %%
37 | # A fixed boundary condition is applied at :math:`x=0`.
38 | boundaries = fem.BoundaryDict(fixed=fem.dof.Boundary(displacement, fx=0))
39 | boundaries.plot().show()
40 |
41 | # %%
42 | # The material behaviour is defined through a built-in isotropic linear-elastic plastic
43 | # material formulation with isotropic hardening.
44 | umat = fem.LinearElasticPlasticIsotropicHardening(E=2.1e5, nu=0.3, sy=355, K=1e3)
45 | solid = fem.SolidBody(umat, field)
46 |
47 | # %%
48 | # The body force is created on the field of the solid body.
49 | #
50 | # .. math::
51 | #
52 | # \delta W_{ext} = \int_v \delta \boldsymbol{u} \cdot \boldsymbol{b} ~ dv
53 | bodyforce = fem.SolidBodyForce(field)
54 | b = fem.math.linsteps([0, 200], num=10, axis=0, axes=3)
55 |
56 | # %%
57 | # Inside a Newton-Rhapson procedure, the vectors and matrices are assembled for the
58 | # given *items* and the boundary conditions are incorporated into the equilibrium
59 | # equations.
60 | step = fem.Step(items=[solid, bodyforce], ramp={bodyforce: b}, boundaries=boundaries)
61 | job = fem.Job(steps=[step]).evaluate()
62 |
63 |
64 | # %%
65 | # A view on the field-container shows the deformed mesh and the normal plastic strain in
66 | # direction :math:`x` due to the applied body force. The vector of all state variables,
67 | # stored as a result in the solid body object, is splitted into separate variables. The
68 | # plastic strain is stored as the second state variable. The mean-per-cell value of the
69 | # plastic strain in direction :math:`x` is exported to the view.
70 | def plot(solid, field):
71 | "Visualize the final Normal Plastic Strain in direction X."
72 |
73 | plastic_strain = np.split(solid.results.statevars, umat.statevars_offsets)[1]
74 | view = fem.View(field, cell_data={"Plastic Strain": plastic_strain.mean(-2).T})
75 | return view.plot("Plastic Strain", component=0, show_undeformed=False)
76 |
77 |
78 | plot(solid, field).show()
79 |
--------------------------------------------------------------------------------
/examples/ex03_plasticity_sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/examples/ex03_plasticity_sketch.png
--------------------------------------------------------------------------------
/examples/ex04_balloon_sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/examples/ex04_balloon_sketch.png
--------------------------------------------------------------------------------
/examples/ex06_rubber-metal-spring_mesh.vtk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/examples/ex06_rubber-metal-spring_mesh.vtk
--------------------------------------------------------------------------------
/examples/ex07_engine-mount_mesh-air.vtk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/examples/ex07_engine-mount_mesh-air.vtk
--------------------------------------------------------------------------------
/examples/ex07_engine-mount_mesh-metal.vtk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/examples/ex07_engine-mount_mesh-metal.vtk
--------------------------------------------------------------------------------
/examples/ex07_engine-mount_mesh-rubber.vtk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/examples/ex07_engine-mount_mesh-rubber.vtk
--------------------------------------------------------------------------------
/examples/ex10_poisson-equation.py:
--------------------------------------------------------------------------------
1 | r"""
2 | Poisson Equation
3 | ----------------
4 | The `Poisson equation `_ with fixed
5 | boundaries on the bottom, top, left and right end-edges and a unit load, as given
6 | in Eq. :eq:`poisson` and Eq. :eq:`poisson-boundaries`, is solved on a rectangle.
7 |
8 | .. math::
9 | :label: poisson
10 |
11 | \text{div}(\boldsymbol{\nabla} u) + f = 0 \quad \text{in} \quad \Omega
12 |
13 | .. math::
14 | :label: poisson-boundaries
15 |
16 | u &= 0 \quad \text{on} \quad \Gamma_u
17 |
18 | f &= 1 \quad \text{in} \quad \Omega
19 |
20 | The Poisson equation is transformed into integral form representation by the
21 | `divergence (Gauss's) theorem `_, see
22 | Eq. :eq:`poisson-integral-form`.
23 |
24 | .. math::
25 | :label: poisson-integral-form
26 |
27 | \int_\Omega \boldsymbol{\nabla} (\delta u) \cdot \boldsymbol{\nabla} (\Delta u)
28 | \ d\Omega = \int_\Omega \delta u \cdot f \ d\Omega
29 |
30 | """
31 |
32 | # sphinx_gallery_thumbnail_number = -1
33 | import felupe as fem
34 |
35 | mesh = fem.Rectangle(n=2**5).triangulate()
36 | region = fem.RegionTriangle(mesh)
37 | u = fem.Field(region, dim=1)
38 | field = fem.FieldContainer([u])
39 |
40 | boundaries = fem.BoundaryDict(
41 | bottom=fem.Boundary(u, fy=0),
42 | top=fem.Boundary(u, fy=1),
43 | left=fem.Boundary(u, fx=0),
44 | right=fem.Boundary(u, fx=1),
45 | )
46 | boundaries.plot(show_lines=False).show()
47 |
48 | solid = fem.SolidBody(umat=fem.Laplace(), field=field)
49 | load = fem.SolidBodyForce(field=field, values=1.0)
50 |
51 | step = fem.Step([solid, load], boundaries=boundaries)
52 | job = fem.Job([step]).evaluate()
53 |
54 | view = mesh.view(point_data={"Field": u.values})
55 | view.plot("Field").show()
56 |
--------------------------------------------------------------------------------
/examples/ex12_foot-bone.py:
--------------------------------------------------------------------------------
1 | r"""
2 | Voxelized Foot Bones
3 | --------------------
4 | A :class:`~felupe.Region` on a voxel-based mesh with uniform hexahedrons should be
5 | created with ``uniform=True`` to enhance performance.
6 |
7 | .. admonition:: This example requires external packages.
8 | :class: hint
9 |
10 | .. code-block::
11 |
12 | pip install pypardiso
13 | """
14 |
15 | import numpy as np
16 | import pypardiso
17 |
18 | import felupe as fem
19 |
20 | mesh = fem.mesh.read("ex12_foot-bones_mesh-voxels.vtu")[0]
21 |
22 | region = fem.RegionHexahedron(mesh, uniform=True)
23 | field = fem.FieldContainer([fem.Field(region, dim=3)])
24 | boundaries = {"fixed": fem.Boundary(field[0], fx=lambda x: x <= -110)}
25 |
26 | umat = fem.LinearElastic(E=1000, nu=0.3)
27 | solid = fem.SolidBody(umat, field)
28 | gravity = fem.SolidBodyForce(field, values=[0, 0, -7e-2])
29 | bottom = fem.MultiPointContact(
30 | field, points=np.arange(mesh.npoints), centerpoint=-1, skip=(1, 1, 0)
31 | )
32 |
33 | step = fem.Step(items=[solid, gravity, bottom], boundaries=boundaries)
34 | job = fem.Job(steps=[step]).evaluate(solver=pypardiso.spsolve, parallel=True)
35 | plotter = solid.plot(
36 | "Principal Values of Cauchy Stress",
37 | show_edges=False,
38 | show_undeformed=False,
39 | clim=[0, 10],
40 | )
41 | bottom.plot(plotter=plotter, color="white", opacity=1).show()
42 |
--------------------------------------------------------------------------------
/examples/ex15_hexmesh-metacone.py:
--------------------------------------------------------------------------------
1 | r"""
2 | Script-based Hex-meshing
3 | ------------------------
4 |
5 | .. topic:: Create a 3d dynamic mesh for a metacone component out of hexahedrons.
6 |
7 | * apply :ref:`mesh-tools `
8 |
9 | * create a :class:`~felupe.MeshContainer` for meshes associated to two materials
10 | """
11 |
12 | import numpy as np
13 |
14 | import felupe as fem
15 |
16 | layers = [2, 11, 2, 11, 2]
17 | lines = [
18 | fem.mesh.Line(a=0, b=13, n=21).expand(n=1).translate(2, axis=1),
19 | fem.mesh.Line(a=0, b=13, n=21).expand(n=1).translate(2.5, axis=1),
20 | fem.mesh.Line(a=-0.2, b=10, n=21).expand(n=1).translate(4.5, axis=1),
21 | fem.mesh.Line(a=-0.2, b=10, n=21).expand(n=1).translate(5, axis=1),
22 | fem.mesh.Line(a=-0.4, b=7, n=21).expand(n=1).translate(6.5, axis=1),
23 | fem.mesh.Line(a=-0.4, b=7, n=21).expand(n=1).translate(7, axis=1),
24 | ]
25 | faces = fem.MeshContainer(
26 | [
27 | first.fill_between(second, n=n)
28 | for first, second, n in zip(lines[:-1], lines[1:], layers)
29 | ]
30 | )
31 | point = lambda m: m.points[np.unique(m.cells)].mean(axis=0) - np.array([2, 0])
32 | mask = lambda m: np.unique(m.cells)
33 | kwargs = dict(axis=1, exponent=2.5, normalize=True)
34 | faces.points[:] = (
35 | faces[1]
36 | .add_runouts([3], centerpoint=point(faces[1]), mask=mask(faces[1]), **kwargs)
37 | .points
38 | )
39 | faces.points[:] = (
40 | faces[3]
41 | .add_runouts([7], centerpoint=point(faces[3]), mask=mask(faces[3]), **kwargs)
42 | .points
43 | )
44 | faces.points[:21] = faces.points[21 : 2 * 21]
45 | faces.points[-21:] = faces.points[-2 * 21 : -21]
46 | faces.points[:] = faces[0].rotate(15, axis=2).points
47 | faces[0].y[:21] = 2
48 | faces[-1].y[-21:] = 8.5
49 | mesh = fem.MeshContainer([faces.stack([1, 3]), faces.stack([0, 2, 4])])
50 |
51 | mesh_3d = fem.MeshContainer(
52 | [m.revolve(n=73, phi=270).rotate(-90, axis=1).rotate(-90, axis=2) for m in mesh]
53 | )
54 | mesh_3d.plot(colors=[None, "white"], show_edges=True, opacity=1).show()
55 |
--------------------------------------------------------------------------------
/examples/ex19_taylor-hood.py:
--------------------------------------------------------------------------------
1 | r"""
2 | Mixed-field hyperelasticity with quadratic triangles
3 | ----------------------------------------------------
4 | A 90° section of a plane-strain circle is subjected to frictionless uniaxial compression
5 | by a vertically moved rigid top plate. A mixed-field formulation is used with quadratic
6 | triangles.
7 | """
8 |
9 | # sphinx_gallery_thumbnail_number = -1
10 | from functools import partial
11 |
12 | import numpy as np
13 |
14 | import felupe as fem
15 |
16 | # %%
17 | # A 90° section of a circle with quadratic triangles is created. The midpoints are
18 | # shifted to the outer radius. An additional point, used as center- (control-) point, is
19 | # added to the mesh.
20 | mesh = fem.Circle(n=6, sections=[0]).triangulate().add_midpoints_edges()
21 | mask = np.isclose(mesh.x**2 + mesh.y**2, 1, atol=0.05)
22 | mesh.points[mask] /= np.linalg.norm(mesh.points[mask], axis=1).reshape(-1, 1)
23 | mesh.add_points([0, 1.1])
24 | mesh.clear_points_without_cells()
25 |
26 | # %%
27 | # Let's create a region for quadratic triangles and a mixed-field container with two
28 | # dual fields, one for the pressure and another one for the volume ratio. The dual
29 | # fields are disconnected.
30 | region = fem.RegionQuadraticTriangle(mesh)
31 | field = fem.FieldsMixed(
32 | region, n=3, values=(0.0, 0.0, 1.0), planestrain=True, disconnect=True
33 | )
34 |
35 | # create a nearly-incompressible hyperelastic solid body and the rigid top plate
36 | umat = fem.NearlyIncompressible(material=fem.NeoHooke(mu=1), bulk=5000)
37 | solid = fem.SolidBody(umat=umat, field=field)
38 | top = fem.MultiPointContact(
39 | field=field,
40 | points=np.arange(mesh.npoints)[np.isclose(mesh.x**2 + mesh.y**2, 1)],
41 | centerpoint=-1,
42 | skip=(1, 0),
43 | )
44 | mesh.plot(nonlinear_subdivision=4, plotter=top.plot(line_width=5, opacity=1)).show()
45 |
46 | # %%
47 | # A step is used containts the solid body and the rigid top plate as items. The rigid
48 | # vertical movement of the top plate is applied in a ramped manner.
49 | boundaries = fem.dof.symmetry(field[0])
50 | boundaries["move"] = fem.Boundary(field[0], fy=1.1, skip=(1, 0))
51 | move = fem.math.linsteps([0, -0.4], num=4)
52 | ramp = {boundaries["move"]: move}
53 | step = fem.Step(items=[solid, top], ramp=ramp, boundaries=boundaries)
54 | job = fem.Job(steps=[step]).evaluate()
55 |
56 | # %%
57 | # The maximum principal values of the Cauchy stress tensor are plotted. The cell-based
58 | # means are projected to the mesh-points.
59 | solid.plot(
60 | "Principal Values of Cauchy Stress",
61 | nonlinear_subdivision=4,
62 | plotter=top.plot(line_width=5, opacity=1),
63 | project=partial(fem.project, mean=True),
64 | ).show()
65 |
--------------------------------------------------------------------------------
/paper/examples.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/paper/examples.png
--------------------------------------------------------------------------------
/paper/field.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/paper/field.pdf
--------------------------------------------------------------------------------
/paper/job.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/paper/job.pdf
--------------------------------------------------------------------------------
/paper/strain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/paper/strain.png
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools>=77.0.3"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | [tool.isort]
6 | profile = "black"
7 |
8 | [project]
9 | name = "felupe"
10 | description = "Finite Element Analysis"
11 | readme = "README.md"
12 | authors = [
13 | {name = "Andreas Dutzler", email = "a.dutzler@gmail.com"},
14 | ]
15 | requires-python = ">=3.9"
16 | license = "GPL-3.0-or-later"
17 | license-files = ["LICENSE"]
18 | keywords = [
19 | "computational-mechanics",
20 | "fea",
21 | "fem",
22 | "finite-elements",
23 | "finite-elements-analysis",
24 | "finite-elements-methods",
25 | "hyperelasticity",
26 | "partial-differential-equations",
27 | "pde",
28 | "python",
29 | "scientific-computing",
30 | "solid-mechanics-codes",
31 | ]
32 | classifiers = [
33 | "Development Status :: 5 - Production/Stable",
34 | "Programming Language :: Python",
35 | "Intended Audience :: Science/Research",
36 | "Operating System :: OS Independent",
37 | "Programming Language :: Python",
38 | "Programming Language :: Python :: 3",
39 | "Programming Language :: Python :: 3.9",
40 | "Programming Language :: Python :: 3.10",
41 | "Programming Language :: Python :: 3.11",
42 | "Programming Language :: Python :: 3.12",
43 | "Programming Language :: Python :: 3.13",
44 | "Topic :: Scientific/Engineering",
45 | "Topic :: Scientific/Engineering :: Mathematics",
46 | "Topic :: Utilities"
47 | ]
48 | dynamic = ["version"]
49 |
50 | dependencies = [
51 | "numpy",
52 | "scipy",
53 | ]
54 |
55 | [project.optional-dependencies]
56 | docs = [
57 | "pydata-sphinx-theme",
58 | "sphinx-autoapi",
59 | "sphinx-inline-tabs",
60 | "sphinx-copybutton",
61 | "sphinx-design",
62 | "sphinx-gallery",
63 | "pypandoc",
64 | ]
65 | autodiff = ["tensortrax", "jax"]
66 | examples = [
67 | "contique",
68 | "imageio",
69 | "pypardiso",
70 | "torch",
71 | ]
72 | io = [
73 | "h5py",
74 | "meshio",
75 | ]
76 | parallel = ["einsumt"]
77 | progress = ["tqdm"]
78 | plot = ["matplotlib"]
79 | view = ["pyvista[jupyter]"]
80 | all = ["felupe[autodiff,io,parallel,plot,progress,view]"]
81 |
82 | [tool.setuptools.dynamic]
83 | version = {attr = "felupe.__about__.__version__"}
84 |
85 | [project.urls]
86 | Homepage = "https://felupe.readthedocs.io/en/latest"
87 | Documentation = "https://felupe.readthedocs.io/en/latest"
88 | Repository = "https://github.com/adtzlr/felupe"
89 | Issues = "https://github.com/adtzlr/felupe/issues"
90 | Changelog = "https://github.com/adtzlr/felupe/blob/main/CHANGELOG.md"
91 |
--------------------------------------------------------------------------------
/src/felupe/__about__.py:
--------------------------------------------------------------------------------
1 | __version__ = "9.3.0-dev"
2 |
--------------------------------------------------------------------------------
/src/felupe/assembly/__init__.py:
--------------------------------------------------------------------------------
1 | from . import expression
2 | from ._axi import IntegralFormAxisymmetric
3 | from ._cartesian import IntegralFormCartesian
4 | from ._integral import IntegralForm
5 |
6 | __all__ = [
7 | "IntegralForm",
8 | "IntegralFormCartesian",
9 | "IntegralFormAxisymmetric",
10 | "expression",
11 | ]
12 |
--------------------------------------------------------------------------------
/src/felupe/assembly/expression/__init__.py:
--------------------------------------------------------------------------------
1 | from ._basis import Basis, BasisArray, BasisField
2 | from ._decorator import FormExpressionDecorator as Form
3 |
4 | __all__ = [
5 | "Basis",
6 | "BasisArray",
7 | "BasisField",
8 | "Form",
9 | ]
10 |
--------------------------------------------------------------------------------
/src/felupe/constitution/hyperelasticity/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | constitution.hyperelasticity
3 | ============================
4 | This module contains manually (no automatic differentiation) defined isotropic
5 | hyperelastic constitutive material formulations with gradients and hessians of strain
6 | energy density functions. For more sophisticated material model formulations see
7 | :class:`~felupe.Hyperelastic`.
8 | """
9 |
10 | from ._neo_hooke_compressible import NeoHookeCompressible
11 | from ._neo_hooke_nearly_incompressible import NeoHooke
12 | from ._ogden_roxburgh import OgdenRoxburgh
13 | from ._volumetric import Volumetric
14 |
15 | __all__ = [
16 | "NeoHooke",
17 | "NeoHookeCompressible",
18 | "OgdenRoxburgh",
19 | "Volumetric",
20 | ]
21 |
--------------------------------------------------------------------------------
/src/felupe/constitution/hyperelasticity/_volumetric.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from ._neo_hooke_nearly_incompressible import NeoHooke
20 |
21 |
22 | class Volumetric(NeoHooke):
23 | "Neo-Hookean material formulation with deactivated shear modulus."
24 |
25 | def __init__(self, bulk, parallel=False):
26 | super().__init__(mu=None, bulk=bulk, parallel=parallel)
27 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/__init__.py:
--------------------------------------------------------------------------------
1 | try:
2 | from . import models
3 | from ._helpers import isochoric_volumetric_split, vmap
4 | from ._hyperelastic import Hyperelastic
5 | from ._material import Material
6 | from ._total_lagrange import total_lagrange
7 | from ._updated_lagrange import updated_lagrange
8 |
9 | __all__ = [
10 | "Hyperelastic",
11 | "isochoric_volumetric_split",
12 | "Material",
13 | "models",
14 | "total_lagrange",
15 | "updated_lagrange",
16 | "vmap",
17 | ]
18 |
19 | except ModuleNotFoundError:
20 | __all__ = []
21 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/_total_lagrange.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | import jax
21 |
22 |
23 | def total_lagrange(material):
24 | r"""Decorate a second Piola-Kirchhoff stress Total-Lagrange material formulation as
25 | a first Piola-Kirchoff stress function.
26 |
27 | Notes
28 | -----
29 | .. math::
30 |
31 | \delta \psi = \boldsymbol{F} \boldsymbol{S} : \delta \boldsymbol{F}
32 |
33 | Examples
34 | --------
35 | >>> import felupe as fem
36 | >>> import felupe.constitution.jax as mat
37 | >>> import jax.numpy as jnp
38 | >>>
39 | >>> @mat.total_lagrange
40 | >>> def neo_hooke_total_lagrange(F, mu=1):
41 | >>> C = F.T @ F
42 | >>> dev = lambda C: C - jnp.trace(C) / 3 * jnp.eye(3)
43 | >>> S = mu * dev(jnp.linalg.det(C)**(-1/3) * C) @ jnp.linalg.inv(C)
44 | >>> return S
45 | >>>
46 | >>> umat = mat.Material(neo_hooke_total_lagrange, mu=1)
47 |
48 | See Also
49 | --------
50 | felupe.constitution.jax.Hyperelastic : A hyperelastic material definition with a
51 | given function for the strain energy density function per unit undeformed volume
52 | with Automatic Differentiation provided by jax.
53 | felupe.constitution.jax.Material : A material definition with a given function for
54 | the partial derivative of the strain energy function w.r.t. the deformation
55 | gradient tensor with Automatic Differentiation provided by jax.
56 | """
57 |
58 | @wraps(material)
59 | def first_piola_kirchhoff_stress(F, *args, **kwargs):
60 | # evaluate the second Piola-Kirchhoff stress
61 | res = material(F, *args, **kwargs)
62 |
63 | # check if the material formulation returns state variables and extract
64 | # the second Piola-Kirchhoff stress tensor
65 | if isinstance(res, jax.Array):
66 | S = res
67 | statevars_new = None
68 | else:
69 | S, statevars_new = res
70 |
71 | # first Piola-Kirchhoff stress tensor
72 | P = F @ S
73 |
74 | if statevars_new is None:
75 | return P
76 | else:
77 | return P, statevars_new
78 |
79 | return first_piola_kirchhoff_stress
80 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/_updated_lagrange.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | import jax
21 | import jax.numpy as jnp
22 |
23 |
24 | def updated_lagrange(material):
25 | r"""Decorate a Cauchy-stress Updated-Lagrange material formulation as a first Piola-
26 | Kirchoff stress function.
27 |
28 | Notes
29 | -----
30 | .. math::
31 |
32 | \delta \psi = J \boldsymbol{\sigma} \boldsymbol{F}^{-T} : \delta \boldsymbol{F}
33 |
34 | Examples
35 | --------
36 | >>> import felupe as fem
37 | >>> import felupe.constitution.jax as mat
38 | >>> import jax.numpy as jnp
39 | >>>
40 | >>> @fem.updated_lagrange
41 | >>> def neo_hooke_updated_lagrange(F, mu=1):
42 | >>> J = jnp.linalg.det(F)
43 | >>> b = F @ F.T
44 | >>> dev = lambda b: b - jnp.trace(b) / 3 * jnp.eye(3)
45 | >>> τ = mu * dev(J**(-2/3) * b)
46 | >>> return τ / J
47 | >>>
48 | >>> umat = mat.Material(neo_hooke_updated_lagrange, mu=1)
49 |
50 | See Also
51 | --------
52 | felupe.constitution.jax.Hyperelastic : A hyperelastic material definition with a
53 | given function for the strain energy density function per unit undeformed volume
54 | with Automatic Differentiation provided by jax.
55 | felupe.constitution.jax.Material : A material definition with a given function for
56 | the partial derivative of the strain energy function w.r.t. the deformation
57 | gradient tensor with Automatic Differentiation provided by jax.
58 | """
59 |
60 | @wraps(material)
61 | def first_piola_kirchhoff_stress(F, *args, **kwargs):
62 | # evaluate the Cauchy stress
63 | res = material(F, *args, **kwargs)
64 |
65 | # check if the material formulation returns state variables and extract
66 | # the Cauchy stress tensor
67 | if isinstance(res, jax.Array):
68 | σ = res
69 | statevars_new = None
70 | else:
71 | σ, statevars_new = res
72 |
73 | # first Piola-Kirchhoff stress tensor
74 | J = jnp.linalg.det(F)
75 | P = J * σ @ jnp.linalg.inv(F).T
76 |
77 | if statevars_new is None:
78 | return P
79 | else:
80 | return P, statevars_new
81 |
82 | return first_piola_kirchhoff_stress
83 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/__init__.py:
--------------------------------------------------------------------------------
1 | from . import hyperelastic, lagrange
2 |
3 | __all__ = ["hyperelastic", "lagrange"]
4 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/__init__.py:
--------------------------------------------------------------------------------
1 | from ._blatz_ko import blatz_ko
2 | from ._extended_tube import extended_tube
3 | from ._miehe_goektepe_lulei import miehe_goektepe_lulei
4 | from ._mooney_rivlin import mooney_rivlin
5 | from ._neo_hooke import neo_hooke
6 | from ._storakers import storakers
7 | from ._third_order_deformation import third_order_deformation
8 | from ._van_der_waals import van_der_waals
9 | from ._yeoh import yeoh
10 |
11 | __all__ = [
12 | "blatz_ko",
13 | "extended_tube",
14 | "miehe_goektepe_lulei",
15 | "mooney_rivlin",
16 | "neo_hooke",
17 | "storakers",
18 | "third_order_deformation",
19 | "van_der_waals",
20 | "yeoh",
21 | ]
22 |
23 | # default (stable) material parameters
24 | blatz_ko.kwargs = dict(mu=0)
25 | extended_tube.kwargs = dict(Gc=0, Ge=0, beta=1, delta=0)
26 | miehe_goektepe_lulei.kwargs = dict(mu=0, N=100, U=0, p=2, q=2)
27 | mooney_rivlin.kwargs = dict(C10=0, C01=0)
28 | neo_hooke.kwargs = dict(mu=0)
29 | storakers.kwargs = dict(mu=[0], alpha=[2], beta=[1])
30 | third_order_deformation.kwargs = dict(C10=0, C01=0, C11=0, C20=0, C30=0)
31 | van_der_waals.kwargs = dict(mu=0, beta=0, a=0, limit=100)
32 | yeoh.kwargs = dict(C10=0, C20=0, C30=0)
33 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/_blatz_ko.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import sqrt, trace
21 | from jax.numpy.linalg import det
22 |
23 | from ....tensortrax.models.hyperelastic import blatz_ko as blatz_ko_docstring
24 |
25 |
26 | @wraps(blatz_ko_docstring)
27 | def blatz_ko(C, mu):
28 | I1 = trace(C)
29 | I2 = (I1**2 - trace(C @ C)) / 2
30 | I3 = det(C)
31 |
32 | return mu * (I2 / I3 + 2 * sqrt(I3) - 5)
33 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/_extended_tube.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import array, diag, log, sqrt, trace
21 | from jax.numpy.linalg import det, eigvalsh
22 |
23 | from ....tensortrax.models.hyperelastic import extended_tube as extended_tube_docstring
24 |
25 |
26 | @wraps(extended_tube_docstring)
27 | def extended_tube(C, Gc, delta, Ge, beta):
28 | J3 = det(C) ** (-1 / 3)
29 | D = J3 * trace(C)
30 | λ1, λ2, λ3 = sqrt(J3 * eigvalsh(C + diag(array([0, 1e-4, -1e-4]))))
31 | β = beta
32 | δ = delta
33 | γ = (1 - δ**2) * (D - 3) / (1 - δ**2 * (D - 3))
34 | Wc = Gc / 2 * (γ + log(1 - δ**2 * (D - 3)))
35 | We = 2 * Ge / β**2 * (λ1**-β + λ2**-β + λ3**-β - 3)
36 | return Wc + We
37 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/_miehe_goektepe_lulei.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from ....tensortrax.models.hyperelastic import miehe_goektepe_lulei as mgl_docstring
21 | from .microsphere import langevin, linear, nonaffine_stretch, nonaffine_tube
22 |
23 |
24 | @wraps(mgl_docstring)
25 | def miehe_goektepe_lulei(C, mu, N, U, p, q):
26 | kwargs_stretch = {"mu": mu, "N": N}
27 | kwargs_tube = {"mu": mu * N * U}
28 |
29 | return nonaffine_stretch(
30 | C, p=p, f=langevin, kwargs=kwargs_stretch
31 | ) + nonaffine_tube(C, q=q, f=linear, kwargs=kwargs_tube)
32 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/_mooney_rivlin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import trace
21 | from jax.numpy.linalg import det
22 |
23 | from ....tensortrax.models.hyperelastic import mooney_rivlin as mooney_rivlin_docstring
24 |
25 |
26 | @wraps(mooney_rivlin_docstring)
27 | def mooney_rivlin(C, C10, C01):
28 | J3 = det(C) ** (-1 / 3)
29 | I1 = J3 * trace(C)
30 | I2 = (I1**2 - J3**2 * trace(C @ C)) / 2
31 | return C10 * (I1 - 3) + C01 * (I2 - 3)
32 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/_neo_hooke.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import trace
21 | from jax.numpy.linalg import det
22 |
23 | from ....tensortrax.models.hyperelastic import neo_hooke as neo_hooke_docstring
24 |
25 |
26 | @wraps(neo_hooke_docstring)
27 | def neo_hooke(C, mu):
28 | return mu / 2 * (det(C) ** (-1 / 3) * trace(C) - 3)
29 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/_storakers.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import array, diag, sqrt
21 | from jax.numpy import sum as asum
22 | from jax.numpy.linalg import eigvalsh
23 |
24 | from ....tensortrax.models.hyperelastic import storakers as storakers_docstring
25 |
26 |
27 | @wraps(storakers_docstring)
28 | def storakers(C, mu, alpha, beta):
29 | λ1, λ2, λ3 = sqrt(eigvalsh(C + diag(array([0, -1e-4, 1e-4]))))
30 | J = λ1 * λ2 * λ3
31 |
32 | μ = array(mu)
33 | α = array(alpha)
34 | β = array(beta)
35 |
36 | return asum(2 * μ / α**2 * (λ1**α + λ2**α + λ3**α - 3 + (J ** (-α * β) - 1) / β))
37 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/_third_order_deformation.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import trace
21 | from jax.numpy.linalg import det
22 |
23 | from ....tensortrax.models.hyperelastic import third_order_deformation as tod_docstring
24 |
25 |
26 | @wraps(tod_docstring)
27 | def third_order_deformation(C, C10, C01, C11, C20, C30):
28 | J3 = det(C) ** (-1 / 3)
29 | I1 = J3 * trace(C)
30 | I2 = (I1**2 - J3**2 * trace(C @ C)) / 2
31 | return (
32 | C10 * (I1 - 3)
33 | + C01 * (I2 - 3)
34 | + C11 * (I1 - 3) * (I2 - 3)
35 | + C20 * (I1 - 3) ** 2
36 | + C30 * (I1 - 3) ** 3
37 | )
38 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/_van_der_waals.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import log, sqrt, trace
21 | from jax.numpy.linalg import det
22 |
23 | from ....tensortrax.models.hyperelastic import van_der_waals as van_der_waals_docstring
24 |
25 |
26 | @wraps(van_der_waals_docstring)
27 | def van_der_waals(C, mu, limit, a, beta):
28 | J3 = det(C) ** (-1 / 3)
29 | I1 = J3 * trace(C)
30 | I2 = (trace(C) ** 2 - J3**2 * trace(C @ C)) / 2
31 | Im = (1 - beta) * I1 + beta * I2
32 | Im += 1e-4
33 | eta = sqrt((Im - 3) / (limit**2 - 3))
34 | return mu * (
35 | -(limit**2 - 3) * (log(1 - eta) + eta) - 2 / 3 * a * ((Im - 3) / 2) ** (3 / 2)
36 | )
37 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/_yeoh.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import trace
21 | from jax.numpy.linalg import det
22 |
23 | from ....tensortrax.models.hyperelastic import yeoh as yeoh_docstring
24 |
25 |
26 | @wraps(yeoh_docstring)
27 | def yeoh(C, C10, C20, C30):
28 | I1 = det(C) ** (-1 / 3) * trace(C)
29 | return C10 * (I1 - 3) + C20 * (I1 - 3) ** 2 + C30 * (I1 - 3) ** 3
30 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/microsphere/__init__.py:
--------------------------------------------------------------------------------
1 | from ._chain import langevin, linear
2 | from ._framework_affine import (
3 | affine_stretch,
4 | affine_stretch_statevars,
5 | affine_tube,
6 | affine_tube_statevars,
7 | )
8 | from ._framework_nonaffine import nonaffine_stretch, nonaffine_tube
9 |
10 | __all__ = [
11 | "affine_stretch",
12 | "affine_stretch_statevars",
13 | "affine_tube",
14 | "affine_tube_statevars",
15 | "linear",
16 | "langevin",
17 | "nonaffine_stretch",
18 | "nonaffine_tube",
19 | ]
20 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/microsphere/_chain.py:
--------------------------------------------------------------------------------
1 | from jax.numpy import log, sinh, sqrt
2 |
3 |
4 | def langevin(stretch, mu, N):
5 | """Langevin model given by the free energy of a single chain as a function of the
6 | stretch (assuming a complex valued logarithm). The inverse Langevin function is
7 | defined by a Padé approximation.
8 | """
9 |
10 | x = stretch / sqrt(N)
11 | L = x * (3 - x**2) / (1 - x**2)
12 |
13 | return mu * N * (x * L + log(L / sinh(L)))
14 |
15 |
16 | def linear(stretch, mu):
17 | """Linear model given by the free energy
18 | of a single chain as a function of the stretch."""
19 |
20 | return mu * (stretch - 1)
21 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/microsphere/_framework_affine.py:
--------------------------------------------------------------------------------
1 | from jax.numpy import einsum, sqrt
2 | from jax.numpy.linalg import det, inv
3 |
4 | from ......quadrature import BazantOh
5 |
6 |
7 | def affine_stretch(C, f, kwargs, quadrature=BazantOh(n=21)):
8 | "Micro-sphere model: Affine stretch part."
9 |
10 | r = quadrature.points
11 | w = quadrature.weights
12 |
13 | # affine stretches (distortional part)
14 | λ = det(C) ** (-1 / 6) * sqrt(einsum("ai,ij...,aj->a...", r, C, r))
15 |
16 | return einsum("a...,a->...", f(λ, **kwargs), w)
17 |
18 |
19 | def affine_stretch_statevars(C, statevars, f, kwargs, quadrature=BazantOh(n=21)):
20 | "Micro-sphere model: Affine stretch part."
21 |
22 | r = quadrature.points
23 | w = quadrature.weights
24 |
25 | # affine stretches (distortional part)
26 | λ = det(C) ** (-1 / 6) * sqrt(einsum("ai,ij...,aj->a...", r, C, r))
27 | ψ, statevars_new = f(λ, statevars, **kwargs)
28 |
29 | return einsum("a...,a->...", ψ, w), statevars_new
30 |
31 |
32 | def affine_tube(C, f, kwargs, quadrature=BazantOh(n=21)):
33 | "Micro-sphere model: Affine area-stretch part."
34 |
35 | r = quadrature.points
36 | w = quadrature.weights
37 |
38 | # affine area-stretches (distortional part)
39 | λa = det(C) ** (1 / 6) * sqrt(einsum("ai,ij...,aj->a...", r, inv(C), r))
40 |
41 | return einsum("a...,a->...", f(λa, **kwargs), w)
42 |
43 |
44 | def affine_tube_statevars(C, statevars, f, kwargs, quadrature=BazantOh(n=21)):
45 | "Micro-sphere model: Affine area-stretch part."
46 |
47 | r = quadrature.points
48 | w = quadrature.weights
49 |
50 | # affine area-stretches (distortional part)
51 | λa = det(C) ** (1 / 6) * sqrt(einsum("ai,ij...,aj->a...", r, inv(C), r))
52 | ψa, statevars_new = f(λa, statevars, **kwargs)
53 |
54 | return einsum("a...,a->...", ψa, w), statevars_new
55 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/hyperelastic/microsphere/_framework_nonaffine.py:
--------------------------------------------------------------------------------
1 | from jax.numpy import einsum, sqrt
2 | from jax.numpy.linalg import det, inv
3 |
4 | from ......quadrature import BazantOh
5 |
6 |
7 | def nonaffine_stretch(C, p, f, kwargs, quadrature=BazantOh(n=21)):
8 | "Micro-sphere model: Non-affine stretch part."
9 |
10 | r = quadrature.points
11 | w = quadrature.weights
12 |
13 | # affine stretches
14 | λ = sqrt(einsum("ai,ij...,aj->a...", r, C, r))
15 |
16 | # non-affine stretch (distortional part)
17 | Λ = det(C) ** (-1 / 6) * einsum("a...,a->...", λ**p, w) ** (1 / p)
18 |
19 | return f(Λ, **kwargs)
20 |
21 |
22 | def nonaffine_tube(C, q, f, kwargs, quadrature=BazantOh(n=21)):
23 | "Micro-sphere model: Non-affine tube part."
24 |
25 | r = quadrature.points
26 | w = quadrature.weights
27 |
28 | # affine area-stretches
29 | λa = sqrt(einsum("ai,ij...,aj->a...", r, inv(C), r))
30 |
31 | # non-affine tube contraction (distortional part)
32 | Λt = det(C) ** (q / 6) * einsum("a...,a->...", λa**q, w)
33 |
34 | return f(Λt, **kwargs)
35 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/lagrange/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Strain-energy density functions for strain energy-gradient (stress) model formulations.
3 |
4 | This module contains material model formulations to be used as the ``fun``-argument in
5 | :func:`~felupe.constitution.jax.Material`. The gradient as well as the hessian of
6 | the strain energy density function is carried out by automatic differentiation using
7 | :mod:`jax`. Hence, all math-functions must be taken from :mod:`jax.numpy`.
8 | """
9 |
10 | from ._morph import morph
11 | from ._morph_representative_directions import morph_representative_directions
12 | from ._morph_uniaxial import morph_uniaxial
13 |
14 | __all__ = [
15 | "morph",
16 | "morph_representative_directions",
17 | "morph_uniaxial",
18 | ]
19 |
20 | # default (stable) material parameters
21 | morph.kwargs = dict(p=[0, 0, 0, 0, 0, 1, 0, 0])
22 | morph_representative_directions.kwargs = dict(p=[0, 0, 0, 0, 0, 1, 0, 0])
23 | morph_uniaxial.kwargs = dict(p=[0, 0, 0, 0, 0, 1, 0, 0])
24 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/lagrange/_morph.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import array, concatenate, diag, eye, maximum, sqrt, trace, triu_indices
21 | from jax.numpy.linalg import det, eigvalsh, inv
22 | from jax.scipy.linalg import expm
23 |
24 | from ....tensortrax.models.lagrange import morph as morph_docstring
25 | from ..._total_lagrange import total_lagrange
26 |
27 |
28 | @wraps(morph_docstring)
29 | @total_lagrange
30 | def morph(F, statevars, p):
31 | # right Cauchy-Green deformation tensor
32 | C = F.T @ F
33 |
34 | # extract old state variables
35 | CTSn = statevars[0]
36 | from_triu = lambda C: C[array([[0, 1, 2], [1, 3, 4], [2, 4, 5]])]
37 | Cn = from_triu(statevars[1:7])
38 | SAn = from_triu(statevars[7:13])
39 |
40 | # distortional part of right Cauchy-Green deformation tensor
41 | I3 = det(C)
42 | CG = C * I3 ** (-1 / 3)
43 |
44 | # inverse of and incremental right Cauchy-Green deformation tensor
45 | invC = inv(C)
46 | dC = C - Cn
47 |
48 | # eigenvalues of right Cauchy-Green deformation tensor (sorted in ascending order)
49 | eigvalsh2 = lambda C: eigvalsh(C + diag(array([1e-4, -1e-4, 0])))
50 | λCG = eigvalsh2(CG)
51 |
52 | # Tresca invariant of distortional part of right Cauchy-Green deformation tensor
53 | CTG = λCG[-1] - λCG[0]
54 |
55 | # maximum Tresca invariant in load history
56 | CTS = maximum(CTG, CTSn)
57 |
58 | def sigmoid(x):
59 | "Algebraic sigmoid function."
60 | return 1 / sqrt(1 + x**2)
61 |
62 | # material parameters
63 | α = p[0] + p[1] * sigmoid(p[2] * CTS)
64 | β = p[3] * sigmoid(p[2] * CTS)
65 | γ = p[4] * CTS * (1 - sigmoid(CTS / p[5]))
66 |
67 | dev = lambda C: C - trace(C) / 3 * eye(3)
68 | sym = lambda C: (C + C.T) / 2
69 |
70 | LG = sym(dev(invC @ dC)) @ CG
71 | λLG = eigvalsh2(LG)
72 | LTG = λLG[-1] - λLG[0]
73 |
74 | # limiting stresses "L" and additional stresses "A"
75 | SL = (γ * expm(p[6] * LG / LTG * CTG / CTS) + p[7] * LG / LTG) @ invC
76 | SA = (SAn + β * LTG * SL) / (1 + β * LTG)
77 |
78 | # second Piola-Kirchhoff stress tensor
79 | S = 2 * α * dev(CG) @ invC + dev(SA @ C) @ invC
80 |
81 | i, j = triu_indices(3)
82 | to_triu = lambda C: C[i, j]
83 | statevars_new = concatenate([array([CTS]), to_triu(C), to_triu(SA)])
84 |
85 | return S, statevars_new
86 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/lagrange/_morph_representative_directions.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from ....tensortrax.models.lagrange import morph_representative_directions as morph_repr
21 | from ._morph_uniaxial import morph_uniaxial
22 | from .microsphere import affine_force_statevars
23 |
24 |
25 | @wraps(morph_repr)
26 | def morph_representative_directions(F, statevars, p, ε=1e-6):
27 | def f(λ, statevars, **kwargs):
28 | dψdλ, statevars_new = morph_uniaxial(λ, statevars, **kwargs)
29 | return 5 * dψdλ, statevars_new
30 |
31 | return affine_force_statevars(F, statevars, f=f, kwargs={"p": p, "ε": ε})
32 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/lagrange/_morph_uniaxial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from jax.numpy import abs as jabs
21 | from jax.numpy import concatenate, exp, maximum, sqrt
22 |
23 | from ....tensortrax.models.lagrange import morph_uniaxial as morph_ux
24 |
25 |
26 | @wraps(morph_ux)
27 | def morph_uniaxial(λ, statevars, p, ε=1e-6):
28 | CTSn = statevars[:21]
29 | λn = 1 + statevars[21:42]
30 | SA1n = statevars[42:63]
31 | SA2n = statevars[63:84]
32 |
33 | CT = jabs(λ**2 - 1 / λ)
34 | CTS = maximum(CT, CTSn)
35 |
36 | L1 = 2 * (λ**3 / λn - λn**2) / 3
37 | L2 = (λn**2 / λ**3 - 1 / λn) / 3
38 | LT = jabs(L1 - L2)
39 |
40 | sigmoid = lambda x: 1 / sqrt(1 + x**2)
41 | α = p[0] + p[1] * sigmoid(p[2] * CTS)
42 | β = p[3] * sigmoid(p[2] * CTS)
43 | γ = p[4] * CTS * (1 - sigmoid(CTS / p[5]))
44 |
45 | L1_LT = L1 / (ε + LT)
46 | L2_LT = L2 / (ε + LT)
47 | CT_CTS = CT / (ε + CTS)
48 |
49 | SL1 = (γ * exp(p[6] * L1_LT * CT_CTS) + p[7] * L1_LT) / λ**2
50 | SL2 = (γ * exp(p[6] * L2_LT * CT_CTS) + p[7] * L2_LT) * λ
51 |
52 | SA1 = (SA1n + β * LT * SL1) / (1 + β * LT)
53 | SA2 = (SA2n + β * LT * SL2) / (1 + β * LT)
54 |
55 | dψdλ = (2 * α + SA1) * λ - (2 * α + SA2) / λ**2
56 | statevars_new = concatenate([CTS, (λ - 1), SA1, SA2])
57 |
58 | return dψdλ, statevars_new
59 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/lagrange/microsphere/__init__.py:
--------------------------------------------------------------------------------
1 | from ._framework_affine import affine_force_statevars
2 |
3 | __all__ = [
4 | "affine_force_statevars",
5 | ]
6 |
--------------------------------------------------------------------------------
/src/felupe/constitution/jax/models/lagrange/microsphere/_framework_affine.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from jax.numpy import einsum, sqrt, trace
19 | from jax.numpy.linalg import det, inv
20 |
21 | from ......quadrature import BazantOh
22 | from ...._total_lagrange import total_lagrange
23 |
24 |
25 | @total_lagrange
26 | def affine_force_statevars(F, statevars, f, kwargs, quadrature=BazantOh(n=21)):
27 | "Micro-sphere model: Affine force (stretch) part."
28 |
29 | r = quadrature.points
30 | M = einsum("ai,aj->aij", r, r)
31 | Mw = einsum("aij,a->aij", M, quadrature.weights)
32 |
33 | # affine stretches (unimodular part)
34 | J = det(F)
35 | C = F.T @ F
36 | λ = J ** (-1 / 3) * sqrt(einsum("ij...,aij->a...", C, M))
37 |
38 | dψdλ, statevars_new = f(λ, statevars, **kwargs)
39 | dψdE = einsum("a...,aij->ij...", dψdλ / λ, Mw)
40 |
41 | S = J ** (-2 / 3) * (dψdE - trace(dψdE @ C) / 3 * inv(C))
42 |
43 | return S, statevars_new
44 |
--------------------------------------------------------------------------------
/src/felupe/constitution/linear_elasticity/__init__.py:
--------------------------------------------------------------------------------
1 | from ._lame_converter import lame_converter, lame_converter_orthotropic
2 | from ._linear_elastic import (
3 | LinearElastic,
4 | LinearElasticPlaneStrain,
5 | LinearElasticPlaneStress,
6 | LinearElasticTensorNotation,
7 | )
8 | from ._linear_elastic_1d import LinearElastic1D
9 | from ._linear_elastic_large_strain import LinearElasticLargeStrain
10 | from ._linear_elastic_orthotropic import LinearElasticOrthotropic
11 |
12 | __all__ = [
13 | "lame_converter",
14 | "lame_converter_orthotropic",
15 | "LinearElastic",
16 | "LinearElastic1D",
17 | "LinearElasticLargeStrain",
18 | "LinearElasticOrthotropic",
19 | "LinearElasticPlaneStrain",
20 | "LinearElasticPlaneStress",
21 | "LinearElasticTensorNotation",
22 | ]
23 |
--------------------------------------------------------------------------------
/src/felupe/constitution/poisson/__init__.py:
--------------------------------------------------------------------------------
1 | from ._laplace import Laplace
2 |
3 | __all__ = [
4 | "Laplace",
5 | ]
6 |
--------------------------------------------------------------------------------
/src/felupe/constitution/small_strain/__init__.py:
--------------------------------------------------------------------------------
1 | from ._material_strain import MaterialStrain
2 |
3 | __all__ = [
4 | "MaterialStrain",
5 | ]
6 |
--------------------------------------------------------------------------------
/src/felupe/constitution/small_strain/models/__init__.py:
--------------------------------------------------------------------------------
1 | from ._linear_elastic import linear_elastic
2 | from ._linear_elastic_plastic_isotropic import (
3 | LinearElasticPlasticIsotropicHardening,
4 | linear_elastic_plastic_isotropic_hardening,
5 | )
6 |
7 | __all__ = [
8 | "linear_elastic",
9 | "linear_elastic_plastic_isotropic_hardening",
10 | "LinearElasticPlasticIsotropicHardening",
11 | ]
12 |
--------------------------------------------------------------------------------
/src/felupe/constitution/small_strain/models/_linear_elastic.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from ....math import cdya_ik, dya, identity, trace
20 |
21 |
22 | def linear_elastic(dε, εn, σn, ζn, λ, μ, **kwargs):
23 | r"""3D linear-elastic material formulation to be used in
24 | :class:`~felupe.MaterialStrain`.
25 |
26 | Arguments
27 | ---------
28 | dε : ndarray
29 | Strain increment.
30 | εn : ndarray
31 | Old strain tensor.
32 | σn : ndarray
33 | Old stress tensor.
34 | ζn : list
35 | List of old state variables.
36 | λ : float
37 | First Lamé-constant.
38 | μ : float
39 | Second Lamé-constant (shear modulus).
40 |
41 | Returns
42 | -------
43 | dσdε : ndarray
44 | Elasticity tensor.
45 | σ : ndarray
46 | (New) stress tensor.
47 | ζ : list
48 | List of new state variables.
49 |
50 | Notes
51 | -----
52 |
53 | 1. Given state in point :math:`\boldsymbol{x} (\boldsymbol{\sigma}_n)` (valid).
54 |
55 | 2. Given strain increment :math:`\Delta\boldsymbol{\varepsilon}`, so that
56 | :math:`\boldsymbol{\varepsilon} = \boldsymbol{\varepsilon}_n + \Delta\boldsymbol{\varepsilon}`.
57 |
58 | 3. Evaluation of the stress :math:`\boldsymbol{\sigma}` and the algorithmic
59 | consistent tangent modulus :math:`\mathbb{C}` (=``dσdε``).
60 |
61 | .. math::
62 |
63 | \mathbb{C} &= \lambda \ \boldsymbol{1} \otimes \boldsymbol{1} +
64 | 2 \mu \ \boldsymbol{1} \odot \boldsymbol{1}
65 |
66 | \boldsymbol{\sigma} &= \boldsymbol{\sigma}_n
67 | + \mathbb{C} : \Delta\boldsymbol{\varepsilon}
68 |
69 | Examples
70 | --------
71 | .. plot::
72 |
73 | >>> import felupe as fem
74 | >>>
75 | >>> umat = fem.MaterialStrain(material=fem.linear_elastic, λ=2.0, μ=1.0)
76 | >>> ax = umat.plot()
77 |
78 | See Also
79 | --------
80 | MaterialStrain : A strain-based user-defined material definition with a given
81 | function for the stress tensor and the (fourth-order) elasticity tensor.
82 |
83 | """
84 |
85 | # change of stress due to change of strain
86 | eye = identity(dim=3, shape=(1, 1))
87 | dσ = 2 * μ * dε + λ * trace(dε) * eye
88 |
89 | # update stress
90 | σ = σn + dσ
91 |
92 | # evaluate elasticity tensor
93 | if kwargs["tangent"]:
94 | dσdε = 2 * μ * cdya_ik(eye, eye) + λ * dya(eye, eye)
95 | else:
96 | dσdε = None
97 |
98 | # update state variables (not used here)
99 | ζ = ζn
100 |
101 | return dσdε, σ, ζ
102 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/__init__.py:
--------------------------------------------------------------------------------
1 | try:
2 | from . import models
3 | from ._helpers import isochoric_volumetric_split
4 | from ._hyperelastic import Hyperelastic
5 | from ._material import Material
6 | from ._total_lagrange import total_lagrange
7 | from ._updated_lagrange import updated_lagrange
8 |
9 | __all__ = [
10 | "Hyperelastic",
11 | "isochoric_volumetric_split",
12 | "models",
13 | "total_lagrange",
14 | "updated_lagrange",
15 | "Material",
16 | ]
17 | except ModuleNotFoundError:
18 | __all__ = []
19 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/_helpers.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from functools import wraps
20 |
21 | from tensortrax.math.linalg import det
22 |
23 |
24 | def isochoric_volumetric_split(fun):
25 | """Apply the material formulation only on the isochoric part of the
26 | multiplicative split of the deformation gradient."""
27 |
28 | @wraps(fun)
29 | def apply_iso(C, *args, **kwargs):
30 | return fun(det(C) ** (-1 / 3) * C, *args, **kwargs)
31 |
32 | return apply_iso
33 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/_total_lagrange.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from tensortrax import Tensor
21 |
22 |
23 | def total_lagrange(material):
24 | r"""Decorate a second Piola-Kirchhoff stress Total-Lagrange material formulation as
25 | a first Piola-Kirchoff stress function.
26 |
27 | Notes
28 | -----
29 | .. math::
30 |
31 | \delta \psi = \boldsymbol{F} \boldsymbol{S} : \delta \boldsymbol{F}
32 |
33 | Examples
34 | --------
35 | .. plot::
36 |
37 | >>> import felupe as fem
38 | >>> import felupe.constitution.tensortrax as mat
39 | >>> import tensortrax.math as tm
40 | >>>
41 | >>> @fem.total_lagrange
42 | ... def neo_hooke_total_lagrange(F, mu=1):
43 | ... C = F.T @ F
44 | ... S = mu * tm.special.dev(tm.linalg.det(C)**(-1/3) * C) @ tm.linalg.inv(C)
45 | ... return S
46 | >>>
47 | >>> umat = mat.Material(neo_hooke_total_lagrange, mu=1)
48 |
49 | See Also
50 | --------
51 | felupe.constitution.tensortrax.Hyperelastic : A hyperelastic material definition
52 | with a given function for the strain energy density function per unit undeformed
53 | volume with Automatic Differentiation.
54 | felupe.constitution.tensortrax.Material : A material definition with a given
55 | function for the partial derivative of the strain energy function w.r.t. the
56 | deformation gradient tensor with Automatic Differentiation.
57 | """
58 |
59 | @wraps(material)
60 | def first_piola_kirchhoff_stress(F, *args, **kwargs):
61 | # evaluate the second Piola-Kirchhoff stress
62 | res = material(F, *args, **kwargs)
63 |
64 | # check if the material formulation returns state variables and extract
65 | # the second Piola-Kirchhoff stress tensor
66 | if isinstance(res, Tensor):
67 | S = res
68 | statevars_new = None
69 | else:
70 | S, statevars_new = res
71 |
72 | # first Piola-Kirchhoff stress tensor
73 | P = F @ S
74 |
75 | if statevars_new is None:
76 | return P
77 | else:
78 | return P, statevars_new
79 |
80 | return first_piola_kirchhoff_stress
81 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/_updated_lagrange.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from functools import wraps
19 |
20 | from tensortrax import Tensor
21 | from tensortrax.math.linalg import det, inv
22 |
23 |
24 | def updated_lagrange(material):
25 | r"""Decorate a Cauchy-stress Updated-Lagrange material formulation as a first Piola-
26 | Kirchoff stress function.
27 |
28 | Notes
29 | -----
30 | .. math::
31 |
32 | \delta \psi = J \boldsymbol{\sigma} \boldsymbol{F}^{-T} : \delta \boldsymbol{F}
33 |
34 | Examples
35 | --------
36 | .. plot::
37 |
38 | >>> import felupe as fem
39 | >>> import felupe.constitution.tensortrax as mat
40 | >>> import tensortrax.math as tm
41 | >>>
42 | >>> @fem.updated_lagrange
43 | ... def neo_hooke_updated_lagrange(F, mu=1):
44 | ... J = tm.linalg.det(F)
45 | ... b = F @ F.T
46 | ... σ = mu * tm.special.dev(J**(-2/3) * b) / J
47 | ... return σ
48 | >>>
49 | >>> umat = mat.Material(neo_hooke_updated_lagrange, mu=1)
50 |
51 | See Also
52 | --------
53 | felupe.constitution.tensortrax.Hyperelastic : A hyperelastic material definition
54 | with a given function for the strain energy density function per unit undeformed
55 | volume with Automatic Differentiation.
56 | felupe.constitution.tensortrax.Material : A material definition with a given
57 | function for the partial derivative of the strain energy function w.r.t. the
58 | deformation gradient tensor with Automatic Differentiation.
59 | """
60 |
61 | @wraps(material)
62 | def first_piola_kirchhoff_stress(F, *args, **kwargs):
63 | # evaluate the Cauchy stress
64 | res = material(F, *args, **kwargs)
65 |
66 | # check if the material formulation returns state variables and extract
67 | # the Cauchy stress tensor
68 | if isinstance(res, Tensor):
69 | σ = res
70 | statevars_new = None
71 | else:
72 | σ, statevars_new = res
73 |
74 | # first Piola-Kirchhoff stress tensor
75 | J = det(F)
76 | P = J * σ @ inv(F).T
77 |
78 | if statevars_new is None:
79 | return P
80 | else:
81 | return P, statevars_new
82 |
83 | return first_piola_kirchhoff_stress
84 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/__init__.py:
--------------------------------------------------------------------------------
1 | from . import hyperelastic, lagrange
2 |
3 | __all__ = ["hyperelastic", "lagrange"]
4 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Strain-energy density functions for hyperlastic model formulations.
3 |
4 | This module contains strain energy density functions for material model formulations to
5 | be used as the ``fun``-argument in :func:`~felupe.Hyperelastic`. A strain energy density
6 | function must be formulated in terms of the right Cauchy-Green deformation tensor. The
7 | gradient as well as the hessian of the strain energy density function is carried out
8 | by automatic differentiation using :mod:`tensortrax`. Hence, all math-functions must be
9 | taken from :mod:`tensortrax.math`.
10 | """
11 |
12 | from ._alexander import alexander
13 | from ._anssari_benam_bucchi import anssari_benam_bucchi
14 | from ._arruda_boyce import arruda_boyce
15 | from ._blatz_ko import blatz_ko
16 | from ._extended_tube import extended_tube
17 | from ._finite_strain_viscoelastic import finite_strain_viscoelastic
18 | from ._lopez_pamies import lopez_pamies
19 | from ._miehe_goektepe_lulei import miehe_goektepe_lulei
20 | from ._mooney_rivlin import mooney_rivlin
21 | from ._morph_representative_directions import morph_representative_directions
22 | from ._neo_hooke import neo_hooke
23 | from ._ogden import ogden
24 | from ._ogden_roxburgh import ogden_roxburgh
25 | from ._saint_venant_kirchhoff import saint_venant_kirchhoff
26 | from ._saint_venant_kirchhoff_orthotropic import saint_venant_kirchhoff_orthotropic
27 | from ._storakers import storakers
28 | from ._third_order_deformation import third_order_deformation
29 | from ._van_der_waals import van_der_waals
30 | from ._yeoh import yeoh
31 |
32 | __all__ = [
33 | "alexander",
34 | "anssari_benam_bucchi",
35 | "arruda_boyce",
36 | "blatz_ko",
37 | "extended_tube",
38 | "finite_strain_viscoelastic",
39 | "lopez_pamies",
40 | "miehe_goektepe_lulei",
41 | "mooney_rivlin",
42 | "morph_representative_directions",
43 | "neo_hooke",
44 | "ogden",
45 | "ogden_roxburgh",
46 | "saint_venant_kirchhoff",
47 | "saint_venant_kirchhoff_orthotropic",
48 | "storakers",
49 | "third_order_deformation",
50 | "van_der_waals",
51 | "yeoh",
52 | ]
53 |
54 | # default (stable) material parameters
55 | alexander.kwargs = dict(C1=0, C2=0, C3=0, gamma=100, k=0)
56 | anssari_benam_bucchi.kwargs = dict(mu=0, N=100)
57 | arruda_boyce.kwargs = dict(C1=0, limit=100)
58 | blatz_ko.kwargs = dict(mu=0)
59 | extended_tube.kwargs = dict(Gc=0, Ge=0, beta=1, delta=0)
60 | lopez_pamies.kwargs = dict(mu=[0, 0], alpha=[1, 4])
61 | miehe_goektepe_lulei.kwargs = dict(mu=0, N=100, U=0, p=2, q=2)
62 | mooney_rivlin.kwargs = dict(C10=0, C01=0)
63 | morph_representative_directions.kwargs = dict(p=[0, 0, 0, 0, 0, 1, 0, 0])
64 | neo_hooke.kwargs = dict(mu=0)
65 | ogden.kwargs = dict(mu=[0, 0], alpha=[2, -2])
66 | ogden_roxburgh.kwargs = dict(r=100, m=1, beta=0, material=neo_hooke, mu=0)
67 | saint_venant_kirchhoff.kwargs = dict(mu=0.0, lmbda=0.0, k=2)
68 | saint_venant_kirchhoff_orthotropic.kwargs = dict(
69 | mu=[0.0, 0.0, 0.0],
70 | lmbda=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
71 | r1=[1.0, 0.0, 0.0],
72 | r2=[0.0, 1.0, 0.0],
73 | r3=[0.0, 0.0, 1.0],
74 | )
75 | storakers.kwargs = dict(mu=[0], alpha=[2], beta=[1])
76 | third_order_deformation.kwargs = dict(C10=0, C01=0, C11=0, C20=0, C30=0)
77 | van_der_waals.kwargs = dict(mu=0, beta=0, a=0, limit=100)
78 | yeoh.kwargs = dict(C10=0, C20=0, C30=0)
79 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_anssari_benam_bucchi.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from tensortrax.math import log, trace
19 | from tensortrax.math.linalg import det
20 |
21 |
22 | def anssari_benam_bucchi(C, mu, N):
23 | r"""Strain energy function of the isotropic hyperelastic generalized Neo-Hookean
24 | `Anssari-Benam Bucchi `_ material
25 | formulation [1]_.
26 |
27 | Parameters
28 | ----------
29 | C : tensortrax.Tensor
30 | Right Cauchy-Green deformation tensor.
31 | mu : float
32 | Modulus :math:`\mu = nkT` - this is not the infinitesimal shear modulus.
33 | N : float
34 | Number of Kuhn segments of a chain.
35 |
36 | Notes
37 | -----
38 | The strain energy function is given in Eq. :eq:`psi-abb`
39 |
40 | .. math::
41 | :label: psi-abb
42 |
43 | \psi = \mu N \left( \frac{1}{6N} \left( \hat{I}_1 - 3 \right)
44 | - \ln \left( \frac{\hat{I}_1 - 3N}{3 - 3N} \right) \right)
45 |
46 | with the first main invariant of the distortional part of the right
47 | Cauchy-Green deformation tensor, see Eq. :eq:`invariant-abb`.
48 |
49 | .. math::
50 | :label: invariant-abb
51 |
52 | \hat{I}_1 = J^{-2/3} \text{tr}\left( \boldsymbol{C} \right)
53 |
54 | The initial shear modulus :math:`\mu_0` is given in Eq. :eq:`shear-modulus-abb`.
55 |
56 | .. math::
57 | :label: shear-modulus-abb
58 |
59 | \mu_0 = \mu \frac{1 - 3N}{3 - 3N}
60 |
61 | Examples
62 | --------
63 |
64 | .. plot::
65 |
66 | >>> import felupe as fem
67 | >>>
68 | >>> umat = fem.Hyperelastic(fem.anssari_benam_bucchi, mu=0.29, N=26.8)
69 | >>>
70 | >>> ux = fem.math.linsteps([0.6, 5], num=50)
71 | >>> ps = fem.math.linsteps([1, 5], num=50)
72 | >>> bx = fem.math.linsteps([1, 3], num=50)
73 | >>>
74 | >>> ax = umat.plot(ux=ux, ps=ps, bx=bx, incompressible=True)
75 |
76 | References
77 | ----------
78 | .. [1] A. Anssari-Benam and A. Bucchi, "A generalised neo-Hookean strain energy
79 | function for application to the finite deformation of elastomers", International
80 | Journal of Non-Linear Mechanics, vol. 128. Elsevier BV, p. 103626, Jan. 2021.
81 | doi: `10.1016/j.ijnonlinmec.2020.103626 `_.
82 |
83 | """
84 | I1 = det(C) ** (-1 / 3) * trace(C)
85 | return mu * N * ((I1 - 3) / (6 * N) - log((I1 - 3 * N) / (3 - 3 * N)))
86 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_blatz_ko.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from tensortrax.math import sqrt, trace
20 | from tensortrax.math.linalg import det
21 |
22 |
23 | def blatz_ko(C, mu):
24 | r"""Strain energy function of the Blatz-Ko isotropic hyperelastic
25 | `foam `_ material formulation [1]_.
26 |
27 | Parameters
28 | ----------
29 | C : tensortrax.Tensor or jax.Array
30 | Right Cauchy-Green deformation tensor.
31 | mu : float
32 | The shear modulus.
33 |
34 | Notes
35 | -----
36 | The Poisson ratio of the Blatz-Ko model formulation is :math:`\nu = 0.25`. The
37 | strain energy function is given in Eq. :eq:`psi-blatz-ko`
38 |
39 | .. math::
40 | :label: psi-blatz-ko
41 |
42 | \psi = \frac{\mu}{2} \left(\frac{I_2}{I_3} + 2 \sqrt{I_3} - 5 \right)
43 |
44 | The shear modulus :math:`\mu` is related to young's modulus as denoted in Eq.
45 | :eq:`shear-modulus-blatz-ko`.
46 |
47 | .. math::
48 | :label: shear-modulus-blatz-ko
49 |
50 | \mu = \frac{2 E}{5}
51 |
52 | Examples
53 | --------
54 | First, choose the desired automatic differentiation backend
55 |
56 | .. plot::
57 | :context: close-figs
58 |
59 | >>> # import felupe.constitution.jax as mat
60 | >>> import felupe.constitution.tensortrax as mat
61 |
62 | and create the hyperelastic material.
63 |
64 | .. plot::
65 | :context: close-figs
66 |
67 | >>> import felupe as fem
68 | >>>
69 | >>> umat = mat.Hyperelastic(mat.models.hyperelastic.blatz_ko, mu=1.0)
70 | >>> ax = umat.plot()
71 |
72 | References
73 | ----------
74 | .. [1] P. J. Blatz and W. L. Ko, "Application of Finite Elastic Theory to the
75 | Deformation of Rubbery Materials", Transactions of the Society of Rheology, vol.
76 | 6, no. 1. Society of Rheology, pp. 223–252, Mar. 01, 1962. doi: 10.1122/1.548937.
77 | """
78 |
79 | I1 = trace(C)
80 | I2 = (I1**2 - trace(C @ C)) / 2
81 | I3 = det(C)
82 |
83 | return mu * (I2 / I3 + 2 * sqrt(I3) - 5)
84 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_lopez_pamies.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from tensortrax.math import sum as tsum
19 | from tensortrax.math import trace
20 | from tensortrax.math.linalg import det
21 |
22 |
23 | def lopez_pamies(C, mu, alpha):
24 | r"""Strain energy function of the isotropic hyperelastic
25 | `Lopez-Pamies `_ material
26 | formulation [1]_.
27 |
28 | Parameters
29 | ----------
30 | C : tensortrax.Tensor
31 | Right Cauchy-Green deformation tensor.
32 | mu : list of float
33 | List of moduli.
34 | alpha : list of float
35 | List of invariant exponents.
36 |
37 | Notes
38 | -----
39 | The strain energy function is given in Eq. :eq:`psi-lp`
40 |
41 | .. math::
42 | :label: psi-lp
43 |
44 | \psi = \sum_{r=1}^M \frac{3^{1-\alpha_r}}{2 \alpha_r} \mu_r \left(
45 | \hat{I}_1^{\alpha_r} - 3^{\alpha_r}
46 | \right)
47 |
48 | with the first main invariant of the distortional part of the right
49 | Cauchy-Green deformation tensor, see Eq. :eq:`invariant-lp`.
50 |
51 | .. math::
52 | :label: invariant-lp
53 |
54 | \hat{I}_1 = J^{-2/3} \text{tr}\left( \boldsymbol{C} \right)
55 |
56 | The sum of the moduli :math:`\mu_r` is equal to the initial shear modulus
57 | :math:`\mu`, see Eq. :eq:`shear-modulus-lp`.
58 |
59 | .. math::
60 | :label: shear-modulus-lp
61 |
62 | \mu = \sum_r \mu_r
63 |
64 | Examples
65 | --------
66 |
67 | .. plot::
68 |
69 | >>> import felupe as fem
70 | >>>
71 | >>> umat = fem.Hyperelastic(
72 | ... fem.lopez_pamies, mu=[0.2699, 0.00001771], alpha=[1.08, 4.40]
73 | ... )
74 | >>>
75 | >>> ux = fem.math.linsteps([0.6, 7], num=50)
76 | >>> ps = fem.math.linsteps([1, 7], num=50)
77 | >>> bx = fem.math.linsteps([1, 5], num=50)
78 | >>>
79 | >>> ax = umat.plot(ux=ux, ps=ps, bx=bx, incompressible=True)
80 |
81 | References
82 | ----------
83 | .. [1] O. Lopez-Pamies, "A new I1-based hyperelastic model for rubber elastic
84 | materials", Comptes Rendus. Mécanique, vol. 338, no. 1. Cellule MathDoc/Centre
85 | Mersenne, pp. 3–11, Dec. 23, 2009. doi:
86 | `10.1016/j.crme.2009.12.007 `_.
87 |
88 | """
89 | I1 = det(C) ** (-1 / 3) * trace(C)
90 | ψr = lambda μr, αr, I1: 3 ** (1 - αr) / (2 * αr) * μr * (I1**αr - 3**αr)
91 |
92 | return tsum([ψr(μr, αr, I1) for μr, αr in zip(mu, alpha)])
93 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_miehe_goektepe_lulei.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from .microsphere import langevin, linear, nonaffine_stretch, nonaffine_tube
19 |
20 |
21 | def miehe_goektepe_lulei(C, mu, N, U, p, q):
22 | """Strain energy function of the isotropic hyperelastic
23 | `micro-sphere `_ model formulation [1]_.
24 |
25 | Parameters
26 | ----------
27 | C : tensortrax.Tensor or jax.Array
28 | Right Cauchy-Green deformation tensor.
29 | mu : float
30 | Shear modulus (ground state stifness).
31 | N : float
32 | Number of chain segments (chain locking response).
33 | U : float
34 | Tube geometry parameter (3D locking characteristics).
35 | p : float
36 | Non-affine stretch parameter (additional constraint stifness).
37 | q : float
38 | Non-affine tube parameter (shape of constraint stress).
39 |
40 | Examples
41 | --------
42 | First, choose the desired automatic differentiation backend
43 |
44 | .. plot::
45 | :context: close-figs
46 |
47 | >>> # import felupe.constitution.jax as mat
48 | >>> import felupe.constitution.tensortrax as mat
49 |
50 | and create the hyperelastic material.
51 |
52 | .. plot::
53 | :context: close-figs
54 |
55 | >>> import felupe as fem
56 | >>>
57 | >>> umat = mat.Hyperelastic(
58 | ... mat.models.hyperelastic.miehe_goektepe_lulei,
59 | ... mu=0.1475,
60 | ... N=3.273,
61 | ... p=9.31,
62 | ... U=9.94,
63 | ... q=0.567,
64 | ... )
65 | >>> ux = ps = fem.math.linsteps([1, 2], num=50)
66 | >>> bx = fem.math.linsteps([1, 1.5], num=50)
67 | >>> ax = umat.plot(ux=ux, ps=ps, bx=bx, incompressible=True)
68 |
69 | References
70 | ----------
71 | .. [1] C. Miehe, S. Göktepe and F. Lulei, "A micro-macro approach to rubber-like
72 | materials - Part I: the non-affine micro-sphere model of rubber elasticity",
73 | Journal of the Mechanics and Physics of Solids, vol. 52, no. 11. Elsevier BV, pp.
74 | 2617–2660, Nov. 2004. doi:
75 | `10.1016/j.jmps.2004.03.011 `_.
76 | """
77 |
78 | kwargs_stretch = {"mu": mu, "N": N}
79 | kwargs_tube = {"mu": mu * N * U}
80 |
81 | return nonaffine_stretch(
82 | C, p=p, f=langevin, kwargs=kwargs_stretch
83 | ) + nonaffine_tube(C, q=q, f=linear, kwargs=kwargs_tube)
84 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_mooney_rivlin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from tensortrax.math import trace
20 | from tensortrax.math.linalg import det
21 |
22 |
23 | def mooney_rivlin(C, C10, C01):
24 | r"""Strain energy function of the isotropic hyperelastic
25 | `Mooney-Rivlin `_ material
26 | formulation.
27 |
28 | Parameters
29 | ----------
30 | C : tensortrax.Tensor or jax.Array
31 | Right Cauchy-Green deformation tensor.
32 | C10 : float
33 | First material parameter associated to the first invariant.
34 | C01 : float
35 | Second material parameter associated to the second invariant.
36 |
37 | Notes
38 | -----
39 | The strain energy function is given in Eq. :eq:`psi-mr`
40 |
41 | .. math::
42 | :label: psi-mr
43 |
44 | \psi = C_{10} \left(\hat{I}_1 - 3 \right) + C_{01} \left(\hat{I}_2 - 3 \right)
45 |
46 | with the first and second main invariant of the distortional part of the right
47 | Cauchy-Green deformation tensor, see Eq. :eq:`invariants-mr`.
48 |
49 | .. math::
50 | :label: invariants-mr
51 |
52 | \hat{I}_1 &= J^{-2/3} \text{tr}\left( \boldsymbol{C} \right)
53 |
54 | \hat{I}_2 &= J^{-4/3} \frac{1}{2} \left(
55 | \text{tr}\left(\boldsymbol{C}\right)^2 -
56 | \text{tr}\left(\boldsymbol{C}^2\right)
57 | \right)
58 |
59 | The doubled sum of both material parameters is equal to the shear modulus
60 | :math:`\mu` as denoted in Eq. :eq:`shear-modulus-mr`.
61 |
62 | .. math::
63 | :label: shear-modulus-mr
64 |
65 | \mu = 2 \left( C_{10} + C_{01} \right)
66 |
67 | Examples
68 | --------
69 | First, choose the desired automatic differentiation backend
70 |
71 | .. plot::
72 | :context: close-figs
73 |
74 | >>> # import felupe.constitution.jax as mat
75 | >>> import felupe.constitution.tensortrax as mat
76 |
77 | and create the hyperelastic material.
78 |
79 | .. plot::
80 | :context: close-figs
81 |
82 | >>> umat = mat.Hyperelastic(
83 | ... mat.models.hyperelastic.mooney_rivlin, C10=0.3, C01=0.8
84 | ... )
85 | >>> ax = umat.plot(incompressible=True)
86 |
87 | """
88 | J3 = det(C) ** (-1 / 3)
89 | I1 = J3 * trace(C)
90 | I2 = (I1**2 - J3**2 * trace(C @ C)) / 2
91 | return C10 * (I1 - 3) + C01 * (I2 - 3)
92 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_neo_hooke.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from tensortrax.math import trace
19 | from tensortrax.math.linalg import det
20 |
21 |
22 | def neo_hooke(C, mu):
23 | r"""Strain energy function of the isotropic hyperelastic
24 | `Neo-Hookean `_ material
25 | formulation.
26 |
27 | Parameters
28 | ----------
29 | C : tensortrax.Tensor or jax.Array
30 | Right Cauchy-Green deformation tensor.
31 | mu : float
32 | Shear modulus.
33 |
34 | Notes
35 | -----
36 | The strain energy function is given in Eq. :eq:`psi-nh`.
37 |
38 | .. math::
39 | :label: psi-nh
40 |
41 | \psi = \frac{\mu}{2} \left(\text{tr}\left(\hat{\boldsymbol{C}}\right) - 3\right)
42 |
43 | Examples
44 | --------
45 | First, choose the desired automatic differentiation backend
46 |
47 | .. plot::
48 | :context: close-figs
49 |
50 | >>> # import felupe.constitution.jax as mat
51 | >>> import felupe.constitution.tensortrax as mat
52 |
53 | and create the hyperelastic material.
54 |
55 | .. plot::
56 | :context: close-figs
57 |
58 | >>> import felupe as fem
59 | >>>
60 | >>> umat = mat.Hyperelastic(mat.models.hyperelastic.neo_hooke, mu=1.0)
61 | >>> ax = umat.plot(incompressible=True)
62 |
63 | """
64 | return mu / 2 * (det(C) ** (-1 / 3) * trace(C) - 3)
65 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_ogden.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from tensortrax.math import sum as tsum
20 | from tensortrax.math.linalg import det, eigvalsh
21 |
22 |
23 | def ogden(C, mu, alpha):
24 | r"""Strain energy function of the isotropic hyperelastic
25 | `Ogden `_ material
26 | formulation.
27 |
28 | Parameters
29 | ----------
30 | C : tensortrax.Tensor
31 | Right Cauchy-Green deformation tensor.
32 | mu : list of float
33 | List of moduli.
34 | alpha : list of float
35 | List of stretch exponents.
36 |
37 | Notes
38 | -----
39 | The strain energy function is given in Eq. :eq:`psi-ogden`
40 |
41 | .. math::
42 | :label: psi-ogden
43 |
44 | \psi = \sum_i \frac{2 \mu_i}{\alpha^2_i} \left(
45 | \lambda_1^{\alpha_i} + \lambda_2^{\alpha_i} + \lambda_3^{\alpha_i} - 3
46 | \right)
47 |
48 | The sum of the moduli :math:`\mu_i` is equal to the initial shear modulus
49 | :math:`\mu`, see Eq. :eq:`shear-modulus-ogden`.
50 |
51 | .. math::
52 | :label: shear-modulus-ogden
53 |
54 | \mu = \sum_i \mu_i
55 |
56 | Examples
57 | --------
58 |
59 | .. plot::
60 |
61 | >>> import felupe as fem
62 | >>>
63 | >>> umat = fem.Hyperelastic(fem.ogden, mu=[1, 0.2], alpha=[1.7, -1.5])
64 | >>> ax = umat.plot(incompressible=True)
65 |
66 | """
67 |
68 | wC = det(C) ** (-1 / 3) * eigvalsh(C)
69 | return tsum([2 * m / a**2 * (tsum(wC ** (a / 2)) - 3) for m, a in zip(mu, alpha)])
70 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_saint_venant_kirchhoff.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from tensortrax.math import base, log
20 | from tensortrax.math import sum as tsum
21 | from tensortrax.math import trace
22 | from tensortrax.math.linalg import eigvalsh
23 |
24 |
25 | def saint_venant_kirchhoff(C, mu, lmbda, k=2):
26 | r"""Strain energy function of the isotropic hyperelastic
27 | `Saint-Venant Kirchhoff `_
28 | material formulation.
29 |
30 | Parameters
31 | ----------
32 | C : tensortrax.Tensor
33 | Right Cauchy-Green deformation tensor.
34 | mu : float
35 | Second Lamé constant (shear modulus).
36 | lmbda : float
37 | First Lamé constant (shear modulus).
38 | k : float, optional
39 | Strain exponent (default is 2). If 2, the Green-Lagrange strain measure is used.
40 | For any other value, the family of Seth-Hill strains is used.
41 |
42 | Notes
43 | -----
44 | The strain energy function is given in Eq. :eq:`psi-svk`
45 |
46 | .. math::
47 | :label: psi-svk
48 |
49 | \psi = \mu I_2 + \lambda \frac{I_1^2}{2}
50 |
51 | with the first and second invariant of the Green-Lagrange strain tensor
52 | :math:`\boldsymbol{E} = \frac{1}{2} (\boldsymbol{C} - \boldsymbol{1})`, see Eq.
53 | :eq:`invariants-svk`.
54 |
55 | .. math::
56 | :label: invariants-svk
57 |
58 | I_1 &= \text{tr}\left( \boldsymbol{E} \right)
59 |
60 | I_2 &= \boldsymbol{E} : \boldsymbol{E}
61 |
62 | Examples
63 | --------
64 | .. warning::
65 | The Saint-Venant Kirchhoff material formulation is unstable for large strains.
66 |
67 | .. plot::
68 |
69 | >>> import felupe as fem
70 | >>>
71 | >>> umat = fem.Hyperelastic(fem.saint_venant_kirchhoff, mu=1.0, lmbda=20.0)
72 | >>> ax = umat.plot(incompressible=False)
73 |
74 | """
75 | eye = base.eye
76 |
77 | if k == 2:
78 | E = (C - eye(C)) / 2
79 |
80 | I1 = trace(E)
81 | I2 = trace(E @ E)
82 |
83 | else:
84 | λ2 = eigvalsh(C)
85 | if k == 0:
86 | Ek = log(λ2) / 2
87 | else:
88 | Ek = (λ2 ** (k / 2) - 1) / k
89 |
90 | I1 = tsum(Ek)
91 | I2 = tsum(Ek**2)
92 |
93 | return mu * I2 + lmbda * I1**2 / 2
94 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_van_der_waals.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | import numpy as np
20 | from tensortrax.math import log, sqrt, trace
21 | from tensortrax.math.linalg import det
22 |
23 |
24 | def van_der_waals(C, mu, limit, a, beta):
25 | r"""Strain energy function of the
26 | `Van der Waals `_ [1]_ material
27 | formulation.
28 |
29 | Parameters
30 | ----------
31 | C : tensortrax.Tensor or jax.Array
32 | Right Cauchy-Green deformation tensor.
33 | mu : float
34 | Initial shear modulus.
35 | limit : float
36 | Limiting stretch :math:`\lambda_m` at which the polymer chain network becomes
37 | locked.
38 | a : float
39 | Attractive interactions between the quasi-particles.
40 | beta : float
41 | Mixed-Invariant factor: 0 for pure I1- and 1 for pure I2-contribution.
42 |
43 | Examples
44 | --------
45 | First, choose the desired automatic differentiation backend
46 |
47 | .. plot::
48 | :context: close-figs
49 |
50 | >>> # import felupe.constitution.jax as mat
51 | >>> import felupe.constitution.tensortrax as mat
52 |
53 | and create the hyperelastic material.
54 |
55 | .. plot::
56 | :context: close-figs
57 |
58 | >>> import felupe as fem
59 | >>>
60 | >>> umat = mat.Hyperelastic(
61 | ... mat.models.hyperelastic.van_der_waals,
62 | ... mu=1.0,
63 | ... beta=0.1,
64 | ... a=0.5,
65 | ... limit=5.0
66 | ... )
67 | >>> ax = umat.plot(incompressible=True)
68 |
69 | References
70 | ----------
71 | .. [1] H.-G. Kilian, "Equation of state of real networks", Polymer, vol. 22, no. 2.
72 | Elsevier BV, pp. 209–217, Feb. 1981. doi:
73 | `10.1016/0032-3861(81)90200-7 `_.
74 |
75 | """
76 | J3 = det(C) ** (-1 / 3)
77 | I1 = J3 * trace(C)
78 | I2 = (trace(C) ** 2 - J3**2 * trace(C @ C)) / 2
79 | Im = (1 - beta) * I1 + beta * I2
80 | Im += 1e-4
81 | eta = sqrt((Im - 3) / (limit**2 - 3))
82 | return mu * (
83 | -(limit**2 - 3) * (log(1 - eta) + eta) - 2 / 3 * a * ((Im - 3) / 2) ** (3 / 2)
84 | )
85 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/_yeoh.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from tensortrax.math import trace
20 | from tensortrax.math.linalg import det
21 |
22 |
23 | def yeoh(C, C10, C20, C30):
24 | r"""Strain energy function of the isotropic hyperelastic
25 | `Yeoh `_
26 | material formulation.
27 |
28 | Parameters
29 | ----------
30 | C : tensortrax.Tensor or jax.Array
31 | Right Cauchy-Green deformation tensor.
32 | C10 : float
33 | Material parameter associated to the linear term of the first invariant.
34 | C20 : float
35 | Material parameter associated to the quadratic term of the first invariant.
36 | C30 : float
37 | Material parameter associated to the cubic term of the first invariant.
38 |
39 | Notes
40 | -----
41 | The strain energy function is given in Eq. :eq:`psi-yeoh`
42 |
43 | .. math::
44 | :label: psi-yeoh
45 |
46 | \psi = C_{10} \left(\hat{I}_1 - 3 \right) + C_{20} \left(\hat{I}_1 - 3 \right)^2
47 | + C_{30} \left(\hat{I}_1 - 3 \right)^3
48 |
49 | with the first main invariant of the distortional part of the right
50 | Cauchy-Green deformation tensor, see Eq. :eq:`invariants-yeoh`.
51 |
52 | .. math::
53 | :label: invariants-yeoh
54 |
55 | \hat{I}_1 = J^{-2/3} \text{tr}\left( \boldsymbol{C} \right)
56 |
57 | The :math:`C_{10}` material parameter is equal to half the initial shear modulus
58 | :math:`\mu` as denoted in Eq. :eq:`shear-modulus-yeoh`.
59 |
60 | .. math::
61 | :label: shear-modulus-yeoh
62 |
63 | \mu = 2 C_{10}
64 |
65 | Examples
66 | --------
67 | First, choose the desired automatic differentiation backend
68 |
69 | .. plot::
70 | :context: close-figs
71 |
72 | >>> # import felupe.constitution.jax as mat
73 | >>> import felupe.constitution.tensortrax as mat
74 |
75 | and create the hyperelastic material.
76 |
77 | .. plot::
78 | :context: close-figs
79 |
80 | >>> umat = mat.Hyperelastic(
81 | ... mat.models.hyperelastic.yeoh, C10=0.5, C20=-0.1, C30=0.02
82 | ... )
83 | >>> ax = umat.plot(incompressible=True)
84 |
85 | """
86 |
87 | I1 = det(C) ** (-1 / 3) * trace(C)
88 | return C10 * (I1 - 3) + C20 * (I1 - 3) ** 2 + C30 * (I1 - 3) ** 3
89 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/microsphere/__init__.py:
--------------------------------------------------------------------------------
1 | from ._chain import langevin, linear
2 | from ._framework_affine import (
3 | affine_stretch,
4 | affine_stretch_statevars,
5 | affine_tube,
6 | affine_tube_statevars,
7 | )
8 | from ._framework_nonaffine import nonaffine_stretch, nonaffine_tube
9 |
10 | __all__ = [
11 | "affine_stretch",
12 | "affine_stretch_statevars",
13 | "affine_tube",
14 | "affine_tube_statevars",
15 | "linear",
16 | "langevin",
17 | "nonaffine_stretch",
18 | "nonaffine_tube",
19 | ]
20 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/microsphere/_chain.py:
--------------------------------------------------------------------------------
1 | from tensortrax.math import log, sinh, sqrt
2 |
3 |
4 | def langevin(stretch, mu, N):
5 | """Langevin model given by the free energy of a single chain as a function of the
6 | stretch (assuming a complex valued logarithm). The inverse Langevin function is
7 | defined by a Padé approximation.
8 | """
9 |
10 | x = stretch / sqrt(N)
11 | L = x * (3 - x**2) / (1 - x**2)
12 |
13 | return mu * N * (x * L + log(L / sinh(L)))
14 |
15 |
16 | def linear(stretch, mu):
17 | """Linear model given by the free energy
18 | of a single chain as a function of the stretch."""
19 |
20 | return mu * (stretch - 1)
21 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/microsphere/_framework_affine.py:
--------------------------------------------------------------------------------
1 | from tensortrax.math import einsum, sqrt
2 | from tensortrax.math.linalg import det, inv
3 |
4 | from ......quadrature import BazantOh
5 |
6 |
7 | def affine_stretch(C, f, kwargs, quadrature=BazantOh(n=21)):
8 | "Micro-sphere model: Affine stretch part."
9 |
10 | r = quadrature.points
11 | w = quadrature.weights
12 |
13 | # affine stretches (distortional part)
14 | λ = det(C) ** (-1 / 6) * sqrt(einsum("ai,ij...,aj->a...", r, C, r))
15 |
16 | return einsum("a...,a->...", f(λ, **kwargs), w)
17 |
18 |
19 | def affine_stretch_statevars(C, statevars, f, kwargs, quadrature=BazantOh(n=21)):
20 | "Micro-sphere model: Affine stretch part."
21 |
22 | r = quadrature.points
23 | w = quadrature.weights
24 |
25 | # affine stretches (distortional part)
26 | λ = det(C) ** (-1 / 6) * sqrt(einsum("ai,ij...,aj->a...", r, C, r))
27 | ψ, statevars_new = f(λ, statevars, **kwargs)
28 |
29 | return einsum("a...,a->...", ψ, w), statevars_new
30 |
31 |
32 | def affine_tube(C, f, kwargs, quadrature=BazantOh(n=21)):
33 | "Micro-sphere model: Affine area-stretch part."
34 |
35 | r = quadrature.points
36 | w = quadrature.weights
37 |
38 | # affine area-stretches (distortional part)
39 | λa = det(C) ** (1 / 6) * sqrt(einsum("ai,ij...,aj->a...", r, inv(C), r))
40 |
41 | return einsum("a...,a->...", f(λa, **kwargs), w)
42 |
43 |
44 | def affine_tube_statevars(C, statevars, f, kwargs, quadrature=BazantOh(n=21)):
45 | "Micro-sphere model: Affine area-stretch part."
46 |
47 | r = quadrature.points
48 | w = quadrature.weights
49 |
50 | # affine area-stretches (distortional part)
51 | λa = det(C) ** (1 / 6) * sqrt(einsum("ai,ij...,aj->a...", r, inv(C), r))
52 | ψa, statevars_new = f(λa, statevars, **kwargs)
53 |
54 | return einsum("a...,a->...", ψa, w), statevars_new
55 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/hyperelastic/microsphere/_framework_nonaffine.py:
--------------------------------------------------------------------------------
1 | from tensortrax.math import einsum, sqrt
2 | from tensortrax.math.linalg import det, inv
3 |
4 | from ......quadrature import BazantOh
5 |
6 |
7 | def nonaffine_stretch(C, p, f, kwargs, quadrature=BazantOh(n=21)):
8 | "Micro-sphere model: Non-affine stretch part."
9 |
10 | r = quadrature.points
11 | w = quadrature.weights
12 |
13 | # affine stretches
14 | λ = sqrt(einsum("ai,ij...,aj->a...", r, C, r))
15 |
16 | # non-affine stretch (distortional part)
17 | Λ = det(C) ** (-1 / 6) * einsum("a...,a->...", λ**p, w) ** (1 / p)
18 |
19 | return f(Λ, **kwargs)
20 |
21 |
22 | def nonaffine_tube(C, q, f, kwargs, quadrature=BazantOh(n=21)):
23 | "Micro-sphere model: Non-affine tube part."
24 |
25 | r = quadrature.points
26 | w = quadrature.weights
27 |
28 | # affine area-stretches
29 | λa = sqrt(einsum("ai,ij...,aj->a...", r, inv(C), r))
30 |
31 | # non-affine tube contraction (distortional part)
32 | Λt = det(C) ** (q / 6) * einsum("a...,a->...", λa**q, w)
33 |
34 | return f(Λt, **kwargs)
35 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/lagrange/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Strain-energy density functions for strain energy-gradient (stress) model formulations.
3 |
4 | This module contains material model formulations to be used as the ``fun``-argument in
5 | :func:`~felupe.constitution.tensortrax.Material`. The gradient as well as the hessian of
6 | the strain energy density function is carried out by automatic differentiation using
7 | :mod:`tensortrax`. Hence, all math-functions must be taken from :mod:`tensortrax.math`.
8 | """
9 |
10 | from ._morph import morph
11 | from ._morph_representative_directions import morph_representative_directions
12 | from ._morph_uniaxial import morph_uniaxial
13 |
14 | __all__ = [
15 | "morph",
16 | "morph_representative_directions",
17 | "morph_uniaxial",
18 | ]
19 |
20 | # default (stable) material parameters
21 | morph.kwargs = dict(p=[0, 0, 0, 0, 0, 1, 0, 0])
22 | morph_representative_directions.kwargs = dict(p=[0, 0, 0, 0, 0, 1, 0, 0])
23 | morph_uniaxial.kwargs = dict(p=[0, 0, 0, 0, 0, 1, 0, 0])
24 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/lagrange/_morph_uniaxial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 | from tensortrax.math import abs as tensor_abs
19 | from tensortrax.math import array, exp, maximum, sqrt
20 | from tensortrax.math.special import try_stack
21 |
22 |
23 | def morph_uniaxial(λ, statevars, p, ε=1e-6):
24 | """Return the force (per undeformed area) for a given longitudinal stretch in
25 | uniaxial incompressible tension or compression for the MORPH material
26 | formulation [1]_, [2]_.
27 |
28 | Parameters
29 | ----------
30 | λ : tensortrax.Tensor or jax.Array
31 | Longitudinal stretch of uniaxial incompressible deformation.
32 | statevars : array
33 | Vector of stacked state variables (CTS, λ - 1, SA1, SA2).
34 | p : list of float
35 | A list which contains the 8 material parameters.
36 | ε : float, optional
37 | A small stabilization parameter (default is 1e-6).
38 |
39 | References
40 | ----------
41 | .. [1] D. Besdo and J. Ihlemann, "A phenomenological constitutive model for
42 | rubberlike materials and its numerical applications", International Journal
43 | of Plasticity, vol. 19, no. 7. Elsevier BV, pp. 1019–1036, Jul. 2003. doi:
44 | `10.1016/s0749-6419(02)00091-8 `_.
45 |
46 | .. [2] M. Freund, "Verallgemeinerung eindimensionaler Materialmodelle für die
47 | Finite-Elemente-Methode", Dissertation, Technische Universität Chemnitz,
48 | Chemnitz, 2013.
49 |
50 | """
51 | CTSn = array(statevars[:21], like=λ, shape=(21,))
52 | λn = array(statevars[21:42], like=λ, shape=(21,)) + 1
53 | SA1n = array(statevars[42:63], like=λ, shape=(21,))
54 | SA2n = array(statevars[63:84], like=λ, shape=(21,))
55 |
56 | CT = tensor_abs(λ**2 - 1 / λ)
57 | CTS = maximum(CT, CTSn)
58 |
59 | L1 = 2 * (λ**3 / λn - λn**2) / 3
60 | L2 = (λn**2 / λ**3 - 1 / λn) / 3
61 | LT = tensor_abs(L1 - L2)
62 |
63 | sigmoid = lambda x: 1 / sqrt(1 + x**2)
64 | α = p[0] + p[1] * sigmoid(p[2] * CTS)
65 | β = p[3] * sigmoid(p[2] * CTS)
66 | γ = p[4] * CTS * (1 - sigmoid(CTS / p[5]))
67 |
68 | L1_LT = L1 / (ε + LT)
69 | L2_LT = L2 / (ε + LT)
70 | CT_CTS = CT / (ε + CTS)
71 |
72 | SL1 = (γ * exp(p[6] * L1_LT * CT_CTS) + p[7] * L1_LT) / λ**2
73 | SL2 = (γ * exp(p[6] * L2_LT * CT_CTS) + p[7] * L2_LT) * λ
74 |
75 | SA1 = (SA1n + β * LT * SL1) / (1 + β * LT)
76 | SA2 = (SA2n + β * LT * SL2) / (1 + β * LT)
77 |
78 | dψdλ = (2 * α + SA1) * λ - (2 * α + SA2) / λ**2
79 | statevars_new = try_stack([CTS, (λ - 1), SA1, SA2], fallback=statevars)
80 |
81 | return dψdλ, statevars_new
82 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/lagrange/microsphere/__init__.py:
--------------------------------------------------------------------------------
1 | from ._framework_affine import affine_force_statevars
2 |
3 | __all__ = [
4 | "affine_force_statevars",
5 | ]
6 |
--------------------------------------------------------------------------------
/src/felupe/constitution/tensortrax/models/lagrange/microsphere/_framework_affine.py:
--------------------------------------------------------------------------------
1 | from tensortrax.math import einsum, sqrt, trace
2 | from tensortrax.math.linalg import det, inv
3 |
4 | from ......quadrature import BazantOh
5 | from ...._total_lagrange import total_lagrange
6 |
7 |
8 | @total_lagrange
9 | def affine_force_statevars(F, statevars, f, kwargs, quadrature=BazantOh(n=21)):
10 | "Micro-sphere model: Affine force (stretch) part."
11 |
12 | r = quadrature.points
13 | M = einsum("ai,aj->aij", r, r)
14 | Mw = einsum("aij,a->aij", M, quadrature.weights)
15 |
16 | # affine stretches (unimodular part)
17 | J = det(F)
18 | C = F.T @ F
19 | λ = J ** (-1 / 3) * sqrt(einsum("ij...,aij->a...", C, M))
20 |
21 | dψdλ, statevars_new = f(λ, statevars, **kwargs)
22 | dψdE = einsum("a...,aij->ij...", dψdλ / λ, Mw)
23 |
24 | S = J ** (-2 / 3) * (dψdE - trace(dψdE @ C) / 3 * inv(C))
25 |
26 | return S, statevars_new
27 |
--------------------------------------------------------------------------------
/src/felupe/dof/__init__.py:
--------------------------------------------------------------------------------
1 | from ._boundary import Boundary
2 | from ._dict import BoundaryDict
3 | from ._loadcase import biaxial, shear, symmetry, uniaxial
4 | from ._tools import apply, get_dof0, get_dof1, partition
5 |
6 | __all__ = [
7 | "Boundary",
8 | "BoundaryDict",
9 | "biaxial",
10 | "shear",
11 | "symmetry",
12 | "uniaxial",
13 | "apply",
14 | "get_dof0",
15 | "get_dof1",
16 | "partition",
17 | ]
18 |
--------------------------------------------------------------------------------
/src/felupe/dof/_dict.py:
--------------------------------------------------------------------------------
1 | class BoundaryDict(dict):
2 | "A dict of boundary conditions."
3 |
4 | def plot(
5 | self,
6 | plotter=None,
7 | colors=None,
8 | size=(0.1, 0.1),
9 | show_points=True,
10 | show_lines=True,
11 | **kwargs,
12 | ):
13 | "Plot the boundary conditions."
14 |
15 | if colors is None:
16 | import matplotlib.colors as mcolors
17 |
18 | colors = list(mcolors.TABLEAU_COLORS.values())
19 |
20 | colors_list = []
21 | while len(colors_list) < len(self.keys()):
22 | colors_list = [*colors_list, *colors]
23 |
24 | for (key, boundary), color in zip(self.items(), colors_list):
25 | label = key
26 | if boundary.name != "default":
27 | label = boundary.name
28 |
29 | plotter = boundary.plot(
30 | label=label,
31 | color=color,
32 | plotter=plotter,
33 | size=size,
34 | show_points=show_points,
35 | show_lines=show_lines,
36 | **kwargs,
37 | )
38 |
39 | plotter.add_legend(size=size, bcolor="white")
40 |
41 | return plotter
42 |
43 | def screenshot(
44 | self,
45 | *args,
46 | filename="boundaries.png",
47 | transparent_background=None,
48 | scale=None,
49 | colors=None,
50 | plotter=None,
51 | **kwargs,
52 | ):
53 | "Take a screenshot of the boundary conditions."
54 |
55 | if plotter is None:
56 | mesh = self[list(self.keys())[0]].field.region.mesh
57 | plotter = mesh.plot(off_screen=True)
58 |
59 | plotter = self.plot(plotter=plotter, colors=colors, **kwargs)
60 |
61 | return plotter.screenshot(
62 | filename=filename,
63 | transparent_background=transparent_background,
64 | scale=scale,
65 | )
66 |
67 | def imshow(self, *args, ax=None, dpi=None, **kwargs):
68 | """Take a screenshot of the boundary conditions, show the image data in
69 | a figure and return the ax.
70 | """
71 |
72 | if ax is None:
73 | import matplotlib.pyplot as plt
74 |
75 | fig, ax = plt.subplots(dpi=dpi)
76 |
77 | ax.imshow(self.screenshot(*args, filename=None, **kwargs))
78 | ax.set_axis_off()
79 |
80 | return ax
81 |
--------------------------------------------------------------------------------
/src/felupe/element/__init__.py:
--------------------------------------------------------------------------------
1 | from ._base import Element
2 | from ._hexahedron import (
3 | ConstantHexahedron,
4 | Hexahedron,
5 | QuadraticHexahedron,
6 | TriQuadraticHexahedron,
7 | )
8 | from ._lagrange import (
9 | ArbitraryOrderLagrange,
10 | lagrange_hexahedron,
11 | lagrange_line,
12 | lagrange_quad,
13 | )
14 | from ._line import Line
15 | from ._quad import BiQuadraticQuad, ConstantQuad, Quad, QuadraticQuad
16 | from ._tetra import QuadraticTetra, Tetra, TetraMINI
17 | from ._triangle import QuadraticTriangle, Triangle, TriangleMINI
18 | from ._vertex import Vertex
19 |
20 | __all__ = [
21 | "Element",
22 | "ConstantHexahedron",
23 | "Hexahedron",
24 | "QuadraticHexahedron",
25 | "TriQuadraticHexahedron",
26 | "ArbitraryOrderLagrange",
27 | "Line",
28 | "BiQuadraticQuad",
29 | "ConstantQuad",
30 | "Quad",
31 | "QuadraticQuad",
32 | "QuadraticTetra",
33 | "Tetra",
34 | "TetraMINI",
35 | "QuadraticTriangle",
36 | "Triangle",
37 | "TriangleMINI",
38 | "lagrange_line",
39 | "lagrange_quad",
40 | "lagrange_hexahedron",
41 | "Vertex",
42 | ]
43 |
--------------------------------------------------------------------------------
/src/felupe/element/_line.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | import numpy as np
20 |
21 | from ._base import Element
22 |
23 |
24 | class Line(Element):
25 | r"""A 1D line element formulation with linear shape functions.
26 |
27 | Notes
28 | -----
29 | The linear line element is defined by two points (0-1). [1]
30 |
31 | The shape functions :math:`\boldsymbol{h}` are given in terms of the coordinates
32 | :math:`(r)`.
33 |
34 | .. math::
35 |
36 | \boldsymbol{h}(r) = \frac{1}{2} \begin{bmatrix}
37 | (1-r) \\
38 | (1+r)
39 | \end{bmatrix}
40 |
41 | References
42 | ----------
43 | .. [1] W. Schroeder, K. Martin and B. Lorensen. The Visualization
44 | Toolkit, 4th ed. Kitware, 2006. ISBN: 978-1-930934-19-1.
45 | """
46 |
47 | def __init__(self):
48 | self.points = np.array([-1, 1], dtype=float).reshape(-1, 1)
49 | self.cells = np.arange(len(self.points)).reshape(1, -1)
50 | self.cell_type = "line"
51 |
52 | def function(self, rv):
53 | "Return the shape functions at given coordinates (r,)."
54 | (r,) = rv
55 | return np.array([(1 - r), (1 + r)]) * 0.5
56 |
57 | def gradient(self, rv):
58 | "Return the gradient of shape functions at given coordinates (r,)."
59 | (r,) = rv
60 | return np.array([[-1], [1]]) * 0.5
61 |
62 | def hessian(self, rv):
63 | "Return the hessian of shape functions at given coordinates (r,)."
64 | return np.zeros((2, 1, 1))
65 |
--------------------------------------------------------------------------------
/src/felupe/element/_vertex.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | import numpy as np
20 |
21 | from ._base import Element
22 |
23 |
24 | class Vertex(Element):
25 | r"""A vertex element formulation with constant shape functions.
26 |
27 | Notes
28 | -----
29 | The vertex element is defined by one point.
30 | """
31 |
32 | def __init__(self):
33 | self.points = np.array([[0.0]])
34 | self.cells = np.arange(len(self.points)).reshape(1, -1)
35 | self.cell_type = "vertex"
36 |
37 | def function(self, r):
38 | "Return the shape functions at given coordinate (r)."
39 | return np.ones(1)
40 |
41 | def gradient(self, r):
42 | "Return the gradient of shape functions at given coordinate (r)."
43 | return np.zeros((1, 1))
44 |
45 | def hessian(self, rs):
46 | "Return the hessian of shape functions at given coordinate (r)."
47 | return np.zeros((1, 1, 1))
48 |
--------------------------------------------------------------------------------
/src/felupe/field/__init__.py:
--------------------------------------------------------------------------------
1 | from ._axi import FieldAxisymmetric
2 | from ._base import Field
3 | from ._container import FieldContainer
4 | from ._dual import FieldDual
5 | from ._evaluate import EvaluateFieldContainer
6 | from ._fields import FieldsMixed
7 | from ._planestrain import FieldPlaneStrain
8 |
9 | __all__ = [
10 | "FieldAxisymmetric",
11 | "Field",
12 | "FieldContainer",
13 | "FieldsMixed",
14 | "FieldPlaneStrain",
15 | "FieldDual",
16 | "EvaluateFieldContainer",
17 | ]
18 |
--------------------------------------------------------------------------------
/src/felupe/field/_indices.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | import numpy as np
20 |
21 |
22 | class Indices:
23 | def __init__(self, cai, ai, region, dim):
24 | """Indices for cell "c", point "a" and component "i"."""
25 |
26 | self.cai = cai
27 | self.ai = ai
28 | self.dof = np.arange(region.mesh.npoints * dim).reshape(-1, dim)
29 | self.shape = (region.mesh.npoints * dim, 1)
30 |
--------------------------------------------------------------------------------
/src/felupe/math/__init__.py:
--------------------------------------------------------------------------------
1 | from numpy import sqrt
2 |
3 | from ._field import (
4 | deformation_gradient,
5 | displacement,
6 | extract,
7 | grad,
8 | hess,
9 | interpolate,
10 | norm,
11 | right_cauchy_green_deformation,
12 | strain,
13 | strain_stretch_1d,
14 | values,
15 | )
16 | from ._math import linsteps
17 | from ._solve import solve_2d, solve_nd
18 | from ._spatial import rotation_matrix
19 | from ._tensor import (
20 | cdya,
21 | cdya_ik,
22 | cdya_il,
23 | cof,
24 | cross,
25 | dddot,
26 | ddot,
27 | det,
28 | dev,
29 | dot,
30 | dya,
31 | eig,
32 | eigh,
33 | eigvals,
34 | eigvalsh,
35 | equivalent_von_mises,
36 | identity,
37 | inplane,
38 | inv,
39 | majortranspose,
40 | ravel,
41 | reshape,
42 | sym,
43 | tovoigt,
44 | trace,
45 | transpose,
46 | )
47 |
48 | __all__ = [
49 | "sqrt",
50 | "extract",
51 | "grad",
52 | "hess",
53 | "interpolate",
54 | "norm",
55 | "strain",
56 | "strain_stretch_1d",
57 | "values",
58 | "linsteps",
59 | "rotation_matrix",
60 | "cdya",
61 | "cdya_ik",
62 | "cdya_il",
63 | "cof",
64 | "cross",
65 | "ddot",
66 | "dddot",
67 | "deformation_gradient",
68 | "det",
69 | "dev",
70 | "displacement",
71 | "dot",
72 | "dya",
73 | "eig",
74 | "eigh",
75 | "eigvals",
76 | "eigvalsh",
77 | "equivalent_von_mises",
78 | "identity",
79 | "inplane",
80 | "inv",
81 | "majortranspose",
82 | "ravel",
83 | "reshape",
84 | "right_cauchy_green_deformation",
85 | "sym",
86 | "tovoigt",
87 | "trace",
88 | "transpose",
89 | "solve_2d",
90 | "solve_nd",
91 | ]
92 |
--------------------------------------------------------------------------------
/src/felupe/math/_spatial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | import numpy as np
20 |
21 |
22 | def rotation_matrix(alpha_deg, dim=3, axis=0):
23 | r"""Rotation matrix with given rotation axis and dimension (2d or 3d).
24 |
25 | Parameters
26 | ----------
27 | alpha_deg : int
28 | Rotation angle in degree.
29 | dim : int, optional (default is 3)
30 | Dimension of the rotation matrix.
31 | axis : int, optional (default is 0)
32 | Rotation axis.
33 |
34 | Returns
35 | -------
36 | rotation_matrix : ndarray
37 | Rotation matrix of dim 2 or 3 with given rotation axis.
38 |
39 | Notes
40 | -----
41 | The two-dimensional rotation axis is denoted in Eq. :eq:`rotation-matrix-2d`.
42 |
43 | .. math::
44 | :label: rotation-matrix-2d
45 |
46 | \boldsymbol{R}(\alpha) = \begin{bmatrix}
47 | \cos(\alpha) & -\sin(\alpha) \\
48 | \sin(\alpha) & \cos(\alpha)
49 | \end{bmatrix}
50 |
51 | A three-dimensional rotation matrix is created by inserting zeros in the row and
52 | column at the given axis of rotation and one at the intersection, see
53 | Eq. :eq:`rotation-matrix-3d`. If the axis of rotation is the second axis, the two-
54 | dimensinal rotation matrix is transposed.
55 |
56 | .. math::
57 | :label: rotation-matrix-3d
58 |
59 | \boldsymbol{R}(\alpha) = \begin{bmatrix}
60 | \cos(\alpha) & -\sin(\alpha) & 0 \\
61 | \sin(\alpha) & \cos(\alpha) & 0 \\
62 | 0 & 0 & 1
63 | \end{bmatrix}
64 |
65 | Examples
66 | --------
67 | >>> import numpy as np
68 | >>> import felupe as fem
69 | >>>
70 | >>> R = fem.math.rotation_matrix(alpha_deg=45, dim=2)
71 | >>> x = np.array([1., 0.])
72 | >>> y = R @ x
73 | >>> y
74 | array([0.70710678, 0.70710678])
75 | """
76 |
77 | a = np.deg2rad(alpha_deg)
78 | rotation_matrix = np.array([[np.cos(a), -np.sin(a)], [np.sin(a), np.cos(a)]])
79 |
80 | if dim == 3:
81 | if axis == 1:
82 | rotation_matrix = rotation_matrix.T
83 | rotation_matrix = np.insert(rotation_matrix, [axis], np.zeros((1, 2)), axis=0)
84 | rotation_matrix = np.insert(rotation_matrix, [axis], np.zeros((3, 1)), axis=1)
85 | rotation_matrix[axis, axis] = 1
86 |
87 | return rotation_matrix
88 |
--------------------------------------------------------------------------------
/src/felupe/mechanics/__init__.py:
--------------------------------------------------------------------------------
1 | from ._curve import CharacteristicCurve
2 | from ._free_vibration import FreeVibration
3 | from ._helpers import Assemble, Evaluate, Results, StateNearlyIncompressible
4 | from ._item import FormItem
5 | from ._job import Job
6 | from ._multipoint import MultiPointConstraint, MultiPointContact
7 | from ._pointload import PointLoad
8 | from ._solidbody import SolidBody
9 | from ._solidbody_cauchy_stress import SolidBodyCauchyStress
10 | from ._solidbody_force import SolidBodyForce
11 | from ._solidbody_gravity import SolidBodyGravity
12 | from ._solidbody_incompressible import SolidBodyNearlyIncompressible
13 | from ._solidbody_pressure import SolidBodyPressure
14 | from ._step import Step
15 | from ._truss import TrussBody
16 |
17 | __all__ = [
18 | "Assemble",
19 | "CharacteristicCurve",
20 | "Evaluate",
21 | "FreeVibration",
22 | "FormItem",
23 | "StateNearlyIncompressible",
24 | "Job",
25 | "PointLoad",
26 | "Results",
27 | "SolidBody",
28 | "SolidBodyCauchyStress",
29 | "SolidBodyGravity",
30 | "SolidBodyForce",
31 | "SolidBodyNearlyIncompressible",
32 | "SolidBodyPressure",
33 | "Step",
34 | "MultiPointConstraint",
35 | "MultiPointContact",
36 | "TrussBody",
37 | ]
38 |
--------------------------------------------------------------------------------
/src/felupe/mesh/__init__.py:
--------------------------------------------------------------------------------
1 | from ._container import MeshContainer
2 | from ._convert import (
3 | add_midpoints_edges,
4 | add_midpoints_faces,
5 | add_midpoints_volumes,
6 | cell_types,
7 | collect_edges,
8 | collect_faces,
9 | collect_volumes,
10 | convert,
11 | )
12 | from ._dual import dual
13 | from ._geometry import (
14 | Circle,
15 | Cube,
16 | CubeArbitraryOrderHexahedron,
17 | Grid,
18 | Line,
19 | Point,
20 | Rectangle,
21 | RectangleArbitraryOrderQuad,
22 | Triangle,
23 | )
24 | from ._interpolate import interpolate_line
25 | from ._line_rectangle_cube import cube_hexa as _cube_hexa
26 | from ._line_rectangle_cube import line_line as _line_line
27 | from ._line_rectangle_cube import rectangle_quad as _rectangle_quad
28 | from ._mesh import Mesh
29 | from ._read import read
30 | from ._tools import concatenate, expand, fill_between, flip, merge_duplicate_cells
31 | from ._tools import merge_duplicate_points
32 | from ._tools import merge_duplicate_points as sweep
33 | from ._tools import mirror, revolve, rotate, runouts, stack, translate, triangulate
34 |
35 | __all__ = [
36 | "_cube_hexa",
37 | "_line_line",
38 | "_rectangle_quad",
39 | "MeshContainer",
40 | "add_midpoints_edges",
41 | "add_midpoints_faces",
42 | "add_midpoints_volumes",
43 | "cell_types",
44 | "collect_edges",
45 | "collect_faces",
46 | "collect_volumes",
47 | "convert",
48 | "dual",
49 | "Circle",
50 | "Cube",
51 | "CubeArbitraryOrderHexahedron",
52 | "Grid",
53 | "Line",
54 | "Point",
55 | "Rectangle",
56 | "RectangleArbitraryOrderQuad",
57 | "Triangle",
58 | "Mesh",
59 | "read",
60 | "concatenate",
61 | "expand",
62 | "flip",
63 | "fill_between",
64 | "interpolate_line",
65 | "mirror",
66 | "merge_duplicate_points",
67 | "merge_duplicate_cells",
68 | "revolve",
69 | "rotate",
70 | "runouts",
71 | "stack",
72 | "sweep",
73 | "translate",
74 | "triangulate",
75 | ]
76 |
--------------------------------------------------------------------------------
/src/felupe/mesh/_line_rectangle_cube.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | import numpy as np
20 |
21 | from ._tools import expand
22 |
23 |
24 | def line_line(a=0, b=1, n=2):
25 | "Line generator."
26 | points = np.linspace(a, b, n).reshape(-1, 1)
27 | cells = np.repeat(np.arange(n), 2)[1:-1].reshape(-1, 2)
28 | cell_type = "line"
29 |
30 | return points, cells, cell_type
31 |
32 |
33 | def rectangle_quad(a=(0, 0), b=(1, 1), n=(2, 2)):
34 | "Rectangle generator."
35 | dim = 2
36 | array_like = (tuple, list, np.ndarray)
37 |
38 | # check if number "n" is scalar or no. of points per axis (array-like)
39 | if not isinstance(n, array_like):
40 | n = np.full(dim, n, dtype=int)
41 |
42 | line = line_line(a=a[0], b=b[0], n=n[0])
43 |
44 | points, cells, cell_type = expand(*line, n=n[-1], z=b[-1] - a[-1])
45 | points[:, -1] += a[-1]
46 |
47 | return points, cells, cell_type
48 |
49 |
50 | def cube_hexa(a=(0, 0, 0), b=(1, 1, 1), n=(2, 2, 2)):
51 | "Cube generator."
52 | dim = 3
53 | array_like = (tuple, list, np.ndarray)
54 |
55 | # check if number "n" is scalar or no. of points per axis (array-like)
56 | if not isinstance(n, array_like):
57 | n = np.full(dim, n, dtype=int)
58 |
59 | rectangle = rectangle_quad(a=a[:-1], b=b[:-1], n=n[:-1])
60 |
61 | points, cells, cell_type = expand(*rectangle, n=n[-1], z=b[-1] - a[-1])
62 | points[:, -1] += a[-1]
63 |
64 | return points, cells, cell_type
65 |
--------------------------------------------------------------------------------
/src/felupe/quadrature/__init__.py:
--------------------------------------------------------------------------------
1 | from ._gauss_legendre import GaussLegendre, GaussLegendreBoundary
2 | from ._gauss_lobatto import GaussLobatto, GaussLobattoBoundary
3 | from ._scheme import Scheme
4 | from ._sphere import BazantOh
5 | from ._tetra import Tetrahedron
6 | from ._triangle import Triangle
7 |
8 | __all__ = [
9 | "Scheme",
10 | "GaussLegendre",
11 | "GaussLegendreBoundary",
12 | "GaussLobatto",
13 | "GaussLobattoBoundary",
14 | "Tetrahedron",
15 | "Triangle",
16 | "BazantOh",
17 | ]
18 |
--------------------------------------------------------------------------------
/src/felupe/quadrature/_scheme.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | import numpy as np
20 |
21 |
22 | class Scheme:
23 | r"""A quadrature scheme with integration points :math:`x_q` and weights :math:`w_q`.
24 | It approximates the integral of a function over a region :math:`V` by a weighted sum
25 | of function values :math:`f_q = f(x_q)`, evaluated on the quadrature-points.
26 |
27 | Notes
28 | -----
29 |
30 | The approximation is given by
31 |
32 | .. math::
33 |
34 | \int_V f(x) dV \approx \sum f(x_q) w_q
35 |
36 | with quadrature points :math:`x_q` and corresponding weights :math:`w_q`.
37 | """
38 |
39 | def __init__(self, points, weights):
40 | self.points = points
41 | self.weights = weights
42 |
43 | self.npoints, self.dim = self.points.shape
44 |
45 | def plot(self, plotter=None, point_size=20, weighted=False, **kwargs):
46 | """Plot the quadrature points, scaled by their weights, into a (optionally
47 | provided) PyVista plotter.
48 |
49 | See Also
50 | --------
51 | felupe.Scene.plot: Plot method of a scene.
52 | """
53 |
54 | if plotter is None:
55 | from ..mesh import Mesh
56 |
57 | mesh = Mesh(self.points, np.zeros((0, 2), dtype=int), "line")
58 | plotter = mesh.plot(**kwargs)
59 |
60 | for weight, point in zip(self.weights, self.points):
61 | # plotter requires 3d-point coordinates
62 | points = np.pad([point], ((0, 0), (0, 3 - self.dim)))
63 |
64 | if weighted:
65 | point_weight = weight / self.weights.max()
66 | else:
67 | point_weight = 1.0
68 |
69 | plotter.add_points(
70 | points=points,
71 | point_size=point_size * point_weight,
72 | color="grey",
73 | )
74 |
75 | return plotter
76 |
77 | def screenshot(
78 | self,
79 | *args,
80 | filename=None,
81 | transparent_background=None,
82 | scale=None,
83 | **kwargs,
84 | ):
85 | """Take a screenshot of the quadrature.
86 |
87 | See Also
88 | --------
89 | pyvista.Plotter.screenshot: Take a screenshot of a PyVista plotter.
90 | """
91 |
92 | if filename is None:
93 | filename = "quadrature.png"
94 |
95 | return self.plot(*args, off_screen=True, **kwargs).screenshot(
96 | filename=filename,
97 | transparent_background=transparent_background,
98 | scale=scale,
99 | )
100 |
--------------------------------------------------------------------------------
/src/felupe/region/__init__.py:
--------------------------------------------------------------------------------
1 | from ._boundary import RegionBoundary
2 | from ._region import Region
3 | from ._templates import (
4 | RegionBiQuadraticQuad,
5 | RegionBiQuadraticQuadBoundary,
6 | RegionConstantHexahedron,
7 | RegionConstantQuad,
8 | RegionHexahedron,
9 | RegionHexahedronBoundary,
10 | RegionLagrange,
11 | RegionQuad,
12 | RegionQuadBoundary,
13 | RegionQuadraticHexahedron,
14 | RegionQuadraticHexahedronBoundary,
15 | RegionQuadraticQuad,
16 | RegionQuadraticQuadBoundary,
17 | RegionQuadraticTetra,
18 | RegionQuadraticTriangle,
19 | RegionTetra,
20 | RegionTetraMINI,
21 | RegionTriangle,
22 | RegionTriangleMINI,
23 | RegionTriQuadraticHexahedron,
24 | RegionTriQuadraticHexahedronBoundary,
25 | RegionTruss,
26 | RegionVertex,
27 | )
28 |
29 | __all__ = [
30 | "RegionBoundary",
31 | "Region",
32 | "RegionBiQuadraticQuad",
33 | "RegionBiQuadraticQuadBoundary",
34 | "RegionConstantHexahedron",
35 | "RegionConstantQuad",
36 | "RegionHexahedron",
37 | "RegionHexahedronBoundary",
38 | "RegionLagrange",
39 | "RegionQuad",
40 | "RegionQuadBoundary",
41 | "RegionQuadraticHexahedron",
42 | "RegionQuadraticHexahedronBoundary",
43 | "RegionQuadraticQuad",
44 | "RegionQuadraticQuadBoundary",
45 | "RegionQuadraticTetra",
46 | "RegionQuadraticTriangle",
47 | "RegionTetra",
48 | "RegionTetraMINI",
49 | "RegionTriangle",
50 | "RegionTriangleMINI",
51 | "RegionTriQuadraticHexahedron",
52 | "RegionTriQuadraticHexahedronBoundary",
53 | "RegionTruss",
54 | "RegionVertex",
55 | ]
56 |
--------------------------------------------------------------------------------
/src/felupe/solve/__init__.py:
--------------------------------------------------------------------------------
1 | from ._solve import partition, solve
2 |
3 | __all__ = ["partition", "solve"]
4 |
--------------------------------------------------------------------------------
/src/felupe/tools/__init__.py:
--------------------------------------------------------------------------------
1 | from ._hello_world import hello_world
2 | from ._misc import logo, runs_on
3 | from ._newton import NewtonResult
4 | from ._newton import fun_items as fun
5 | from ._newton import jac_items as jac
6 | from ._newton import newtonrhapson
7 | from ._post import curve, force, moment
8 | from ._project import extrapolate, project, topoints
9 | from ._save import save
10 | from ._solve import solve
11 |
12 | __all__ = [
13 | "fun",
14 | "jac",
15 | "newtonrhapson",
16 | "curve",
17 | "force",
18 | "hello_world",
19 | "moment",
20 | "extrapolate",
21 | "project",
22 | "topoints",
23 | "logo",
24 | "runs_on",
25 | "save",
26 | "solve",
27 | "NewtonResult",
28 | ]
29 |
--------------------------------------------------------------------------------
/src/felupe/tools/_misc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from platform import architecture, machine, platform
20 |
21 | from ..__about__ import __version__ as version
22 |
23 |
24 | def logo():
25 | return "\n".join(
26 | [
27 | " _______ _______ ___ __ __ _______ _______",
28 | "| || || | | | | || || |",
29 | "| ___|| ___|| | | | | || _ || ___|",
30 | "| |___ | |___ | | | |_| || |_| || |___",
31 | "| ___|| ___|| |___ | || ___|| ___|",
32 | "| | | |___ | || || | | |___",
33 | "|___| |_______||_______||_______||___| |_______|",
34 | ]
35 | )
36 |
37 |
38 | def runs_on():
39 | return "\n".join(
40 | [
41 | f"FElupe Version {version}",
42 | f"{platform(terse=True)} {machine()} {architecture()[0]}",
43 | ]
44 | )
45 |
--------------------------------------------------------------------------------
/src/felupe/tools/_post.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | import numpy as np
20 | from scipy.interpolate import interp1d
21 | from scipy.sparse import issparse
22 |
23 | from ..math import cross
24 |
25 |
26 | def force(field, forces, boundary):
27 | "Evaluate the force vector sum on points of a boundary."
28 |
29 | if issparse(forces):
30 | forces = forces.toarray()
31 |
32 | forces_first_field = np.split(forces, field.offsets)[0]
33 | dim = field[0].dim
34 |
35 | return ((forces_first_field.reshape(-1, dim))[boundary.points]).sum(axis=0)
36 |
37 |
38 | def moment(field, forces, boundary, centerpoint=np.zeros(3)):
39 | "Evaluate the moment vector sum on points of a boundary at a given center point."
40 |
41 | if issparse(forces):
42 | forces = forces.toarray()
43 |
44 | dim = field[0].dim
45 | centerpoint = np.asarray(centerpoint).reshape(1, -1)[:, :dim]
46 |
47 | displacements = field[0].values
48 | force = (np.split(forces, field.offsets)[0]).reshape(-1, dim)
49 |
50 | moments = cross(
51 | (field.region.mesh.points + displacements - centerpoint)[boundary.points].T,
52 | force[boundary.points].T,
53 | ).T
54 |
55 | return moments.sum(axis=0)
56 |
57 |
58 | def curve(x, y, num=50):
59 | "Interpolate a curve from given (x, y) data."
60 |
61 | kind = [None, "linear", "quadratic", "cubic"][min(len(y), 4) - 1]
62 |
63 | f = interp1d(x[: len(y)], y, kind=kind)
64 |
65 | xt = x[: len(y)]
66 | xx = np.linspace(xt[0], xt[-1], num=num)
67 |
68 | return np.array([xt, y]), np.array([xx, f(xx)])
69 |
--------------------------------------------------------------------------------
/src/felupe/tools/_solve.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | import numpy as np
20 |
21 | from .. import solve as solvetools
22 |
23 |
24 | def solve(K, f, field, dof0, dof1, offsets, ext0):
25 | "Solve linear equation system K dx = b"
26 | system = solvetools.partition(field, K, dof1, dof0, -f)
27 | dfields = np.split(solvetools.solve(*system, ext0), offsets)
28 | return dfields
29 |
--------------------------------------------------------------------------------
/src/felupe/view/__init__.py:
--------------------------------------------------------------------------------
1 | from ._field import ViewField
2 | from ._mesh import ViewMesh
3 | from ._scene import Scene
4 | from ._solid import ViewSolid
5 | from ._xdmf import ViewXdmf
6 |
7 | __all__ = [
8 | "Scene",
9 | "ViewField",
10 | "ViewMesh",
11 | "ViewSolid",
12 | "ViewXdmf",
13 | ]
14 |
--------------------------------------------------------------------------------
/src/felupe/view/_mesh.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from ._scene import Scene
20 |
21 |
22 | class ViewMesh(Scene):
23 | r"""Provide Visualization methods for :class:`felupe.Mesh` with optional given
24 | dicts of point- and cell-data items.
25 |
26 | Parameters
27 | ----------
28 | mesh : felupe.Mesh
29 | The mesh object.
30 | point_data : dict or None, optional
31 | Additional point-data dict (default is None).
32 | cell_data : dict or None, optional
33 | Additional cell-data dict (default is None).
34 | cell_type : pyvista.CellType or None, optional
35 | Cell-type of PyVista (default is None).
36 |
37 | Attributes
38 | ----------
39 | mesh : pyvista.UnstructuredGrid
40 | A generalized Dataset with the mesh as well as point- and cell-data. This is
41 | not an instance of :class:`felupe.Mesh`.
42 |
43 | Examples
44 | --------
45 | .. pyvista-plot::
46 | :force_static:
47 |
48 | >>> import numpy as np
49 | >>> import felupe as fem
50 | >>>
51 | >>> mesh = fem.Cube(n=3)
52 | >>> displacement = np.arange(81).reshape(27, 3) / 300
53 | >>> view = fem.ViewMesh(mesh, point_data={"Displacement": displacement})
54 | >>>
55 | >>> view.plot("Displacement", component=None).show()
56 |
57 | See Also
58 | --------
59 | felupe.view.Scene : Base class for plotting a static scene.
60 | felupe.ViewField : Provide Visualization methods for a field container.
61 | felupe.ViewSolid : Provide Visualization methods for a field container or a
62 | solid body.
63 |
64 | """
65 |
66 | def __init__(self, mesh, point_data=None, cell_data=None, cell_type=None):
67 | self.mesh = mesh.as_pyvista(cell_type=cell_type)
68 |
69 | if point_data is None:
70 | point_data = {}
71 |
72 | if cell_data is None:
73 | cell_data = {}
74 |
75 | for label, data in point_data.items():
76 | self.mesh.point_data[label] = data
77 |
78 | for label, data in cell_data.items():
79 | self.mesh.cell_data[label] = data
80 |
81 | self.mesh.set_active_scalars(None)
82 | self.mesh.set_active_vectors(None)
83 | self.mesh.set_active_tensors(None)
84 |
--------------------------------------------------------------------------------
/src/felupe/view/_xdmf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | This file is part of FElupe.
4 |
5 | FElupe is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | FElupe is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with FElupe. If not, see .
17 | """
18 |
19 | from ._scene import Scene
20 |
21 |
22 | class ViewXdmf(Scene): # pragma: no cover
23 | """Provide Visualization methods for a XDMF file generated by
24 | :meth:`Job.evaluate(filename="result.xdmf")`. The warped (deformed) mesh is created
25 | from the values of the point-data "Displacement".
26 |
27 | Parameters
28 | ----------
29 | filename : str
30 | The filename of the XDMF file (including the extension).
31 | time : float, optional
32 | The time value at which the data is extracted (default is 0).
33 |
34 | Attributes
35 | ----------
36 | mesh : pyvista.UnstructuredGrid
37 | A generalized Dataset with the mesh as well as point- and cell-data. This is
38 | not an instance of :class:`felupe.Mesh`.
39 |
40 | """
41 |
42 | def __init__(
43 | self,
44 | filename,
45 | time=0,
46 | ):
47 | "XDMF Result file reader and plotter."
48 |
49 | self.filename = filename
50 | self.mesh = self._read(time)
51 |
52 | def _read(self, time):
53 | "Read the file and obtain the mesh."
54 |
55 | import pyvista as pv
56 |
57 | self.file = pv.XdmfReader(self.filename)
58 | self.file.set_active_time_value(time)
59 |
60 | mesh = self.file.read()[0]
61 |
62 | return mesh
63 |
64 | def set_active_time_value(self, time):
65 | "Set new active time value and re-read the mesh."
66 |
67 | self.mesh = self._read(time)
68 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/tests/__init__.py
--------------------------------------------------------------------------------
/tests/mesh_no-cells.bdf:
--------------------------------------------------------------------------------
1 | BEGIN BULK
2 | GRID* 1 06.2849498358E+011.9849655274E+02+
3 | * 0.0000000000E+00 0
4 | GRID* 2 05.6035997841E+011.8542236219E+02+
5 | * 0.0000000000E+00 0
6 | GRID* 3 04.8892020502E+011.7193153918E+02+
7 | * 0.0000000000E+00 0
8 | GRID* 4 04.1288698771E+011.5800564901E+02+
9 | * 0.0000000000E+00 0
10 | GRID* 5 03.2907983274E+011.4345387706E+02+
11 | * 0.0000000000E+00 0
12 | GRID* 6 02.2815822125E+011.2721952420E+02+
13 | * 0.0000000000E+00 0
14 | GRID* 7 02.2806927722E+011.1158166335E+02+
15 | * 0.0000000000E+00 0
16 | GRID* 8 01.8519289070E+011.0068947874E+02+
17 | * 0.0000000000E+00 0
18 | GRID* 9 01.2319316478E+019.0211148904E+01+
19 | * 0.0000000000E+00 0
20 | GRID* 10 02.4442105357E+007.9231495452E+01+
21 | * 0.0000000000E+00 0
22 | ENDDATA
--------------------------------------------------------------------------------
/tests/test_basis.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | _______ _______ ___ __ __ _______ _______
4 | | || || | | | | || || |
5 | | ___|| ___|| | | | | || _ || ___|
6 | | |___ | |___ | | | |_| || |_| || |___
7 | | ___|| ___|| |___ | || ___|| ___|
8 | | | | |___ | || || | | |___
9 | |___| |_______||_______||_______||___| |_______|
10 |
11 | This file is part of felupe.
12 |
13 | Felupe is free software: you can redistribute it and/or modify
14 | it under the terms of the GNU General Public License as published by
15 | the Free Software Foundation, either version 3 of the License, or
16 | (at your option) any later version.
17 |
18 | Felupe is distributed in the hope that it will be useful,
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | GNU General Public License for more details.
22 |
23 | You should have received a copy of the GNU General Public License
24 | along with Felupe. If not, see .
25 |
26 | """
27 |
28 | import numpy as np
29 | import pytest
30 |
31 | import felupe as fem
32 |
33 |
34 | def pre(dim):
35 | m = fem.Cube(n=3)
36 | r = fem.RegionHexahedron(m)
37 | u = fem.FieldContainer([fem.Field(r, dim=dim)])
38 | return r.reload(grad=True, hess=True), u
39 |
40 |
41 | def pre_constant(dim):
42 | m = fem.Cube(n=3)
43 | r = fem.RegionConstantHexahedron(m)
44 | u = fem.FieldContainer([fem.Field(r, dim=dim)])
45 | return r, u
46 |
47 |
48 | def test_basis():
49 | for parallel in [False, True]:
50 | r, u = pre(dim=3)
51 | b = fem.assembly.expression.Basis(u, parallel=parallel)
52 |
53 | assert not np.any(b[0].basis.grad == None)
54 |
55 | r, u = pre(dim=1)
56 | b = fem.assembly.expression.Basis(u, parallel=parallel)
57 |
58 | assert not np.any(b[0].basis.grad == None)
59 |
60 | r, u = pre(dim=1)
61 | b = fem.assembly.expression.Basis(u, parallel=parallel)
62 |
63 | assert not np.any(b[0].basis.hess == None)
64 |
65 | r, u = pre_constant(dim=3)
66 | b = fem.assembly.expression.Basis(u, parallel=parallel)
67 |
68 | assert np.all(b[0].basis.grad == None)
69 | assert np.all(b[0].basis.hess == None)
70 |
71 | r, u = pre_constant(dim=1)
72 | b = fem.assembly.expression.Basis(u, parallel=parallel)
73 |
74 | assert np.all(b[0].basis.grad == None)
75 | assert np.all(b[0].basis.hess == None)
76 |
77 |
78 | if __name__ == "__main__":
79 | test_basis()
80 |
--------------------------------------------------------------------------------
/tests/test_dtype.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | _______ _______ ___ __ __ _______ _______
4 | | || || | | | | || || |
5 | | ___|| ___|| | | | | || _ || ___|
6 | | |___ | |___ | | | |_| || |_| || |___
7 | | ___|| ___|| |___ | || ___|| ___|
8 | | | | |___ | || || | | |___
9 | |___| |_______||_______||_______||___| |_______|
10 |
11 | This file is part of felupe.
12 |
13 | Felupe is free software: you can redistribute it and/or modify
14 | it under the terms of the GNU General Public License as published by
15 | the Free Software Foundation, either version 3 of the License, or
16 | (at your option) any later version.
17 |
18 | Felupe is distributed in the hope that it will be useful,
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | GNU General Public License for more details.
22 |
23 | You should have received a copy of the GNU General Public License
24 | along with Felupe. If not, see .
25 |
26 | """
27 |
28 | import numpy as np
29 |
30 | import felupe as fem
31 |
32 |
33 | def test_dtype(dtype=np.float32, tol=1e-3):
34 | mesh = fem.Cube(n=3)
35 | region = fem.RegionHexahedron(mesh).astype(dtype, copy=False)
36 | displacement = fem.Field(region, dim=3, dtype=dtype)
37 | field = fem.FieldContainer([displacement])
38 |
39 | assert field.extract()[0].dtype == dtype
40 | assert field.extract(grad=False)[0].dtype == dtype
41 |
42 | boundaries, loadcase = fem.dof.uniaxial(field, clamped=True)
43 |
44 | umat = fem.LinearElastic(E=1, nu=0.3)
45 | solid = fem.SolidBody(umat, field)
46 | step = fem.Step([solid], boundaries=boundaries)
47 | job = fem.Job([step]).evaluate(tol=tol)
48 |
49 | assert np.allclose([norm[-1] for norm in job.fnorms], 0, atol=tol)
50 | assert displacement.values.dtype == dtype
51 |
52 |
53 | def test_dtype_axi():
54 | mesh = fem.Rectangle(n=3)
55 | region = fem.RegionQuad(mesh).astype(np.float32)
56 | displacement = fem.FieldAxisymmetric(region, dtype=np.float32)
57 | field = fem.FieldContainer([displacement])
58 |
59 | assert field.extract()[0].dtype == np.float32
60 | assert field.extract(grad=False)[0].dtype == np.float32
61 |
62 |
63 | def test_dtype_planestrain():
64 | mesh = fem.Rectangle(n=3)
65 | region = fem.RegionQuad(mesh, hess=True).astype(np.float32)
66 | displacement = fem.FieldPlaneStrain(region, dtype=np.float32)
67 | field = fem.FieldContainer([displacement])
68 |
69 | assert field.extract()[0].dtype == np.float32
70 | assert field.extract(grad=False)[0].dtype == np.float32
71 |
72 |
73 | if __name__ == "__main__":
74 | test_dtype()
75 | test_dtype_axi()
76 | test_dtype_planestrain()
77 |
--------------------------------------------------------------------------------
/tests/test_free_vibration.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | _______ _______ ___ __ __ _______ _______
4 | | || || | | | | || || |
5 | | ___|| ___|| | | | | || _ || ___|
6 | | |___ | |___ | | | |_| || |_| || |___
7 | | ___|| ___|| |___ | || ___|| ___|
8 | | | | |___ | || || | | |___
9 | |___| |_______||_______||_______||___| |_______|
10 |
11 | This file is part of felupe.
12 |
13 | Felupe is free software: you can redistribute it and/or modify
14 | it under the terms of the GNU General Public License as published by
15 | the Free Software Foundation, either version 3 of the License, or
16 | (at your option) any later version.
17 |
18 | Felupe is distributed in the hope that it will be useful,
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | GNU General Public License for more details.
22 |
23 | You should have received a copy of the GNU General Public License
24 | along with Felupe. If not, see .
25 |
26 | """
27 |
28 | import numpy as np
29 |
30 | import felupe as fem
31 |
32 |
33 | def test_free_vibration():
34 | mesh = fem.Cube(a=(0, 0, 5), b=(50, 100, 30), n=(3, 6, 4))
35 | region = fem.RegionHexahedron(mesh)
36 | field = fem.FieldContainer([fem.Field(region, dim=3)])
37 |
38 | umat = fem.NeoHooke(mu=1, bulk=2)
39 | solid = fem.SolidBody(umat=umat, field=field, density=1.5e-9)
40 |
41 | job = fem.FreeVibration([solid]).evaluate()
42 | new_field, frequency = job.extract(n=-1, inplace=False)
43 |
44 |
45 | def test_free_vibration_mixed():
46 | meshes = [
47 | fem.Cube(a=(0, 0, 30), b=(50, 100, 35), n=(3, 6, 2)),
48 | fem.Cube(a=(0, 0, 5), b=(50, 100, 30), n=(3, 6, 4)),
49 | fem.Cube(a=(0, 0, 0), b=(50, 100, 5), n=(3, 6, 2)),
50 | ]
51 | container = fem.MeshContainer(meshes, merge=True)
52 | mesh = container.stack()
53 |
54 | regions = [fem.RegionHexahedron(m) for m in container.meshes]
55 | fields = [
56 | fem.FieldsMixed(regions[0], n=1),
57 | fem.FieldsMixed(regions[1], n=3),
58 | fem.FieldsMixed(regions[2], n=1),
59 | ]
60 |
61 | region = fem.RegionHexahedron(mesh)
62 | field = fem.FieldContainer([fem.Field(region, dim=3), *fields[1][1:]])
63 |
64 | boundaries = dict(left=fem.Boundary(field[0], fx=0))
65 | rubber = fem.ThreeFieldVariation(fem.NeoHooke(mu=1, bulk=5000))
66 | steel = fem.LinearElasticLargeStrain(2.1e5, 0.3)
67 | solids = [
68 | fem.SolidBody(umat=steel, field=fields[0], density=7.85e-9),
69 | fem.SolidBody(umat=rubber, field=fields[1], density=1.5e-9),
70 | fem.SolidBody(umat=steel, field=fields[2], density=7.85e-9),
71 | ]
72 |
73 | job = fem.FreeVibration(solids, boundaries).evaluate(x0=field)
74 | new_field, frequency = job.extract(x0=field, n=-1, inplace=False)
75 |
76 |
77 | if __name__ == "__main__":
78 | test_free_vibration()
79 | test_free_vibration_mixed()
80 |
--------------------------------------------------------------------------------
/tests/test_import.py:
--------------------------------------------------------------------------------
1 | def test_import():
2 | import felupe as fem
3 |
4 | assert hasattr(fem, "constitution")
5 |
6 |
7 | if __name__ == "__main__":
8 | test_import()
9 |
--------------------------------------------------------------------------------
/tests/test_solve.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | _______ _______ ___ __ __ _______ _______
4 | | || || | | | | || || |
5 | | ___|| ___|| | | | | || _ || ___|
6 | | |___ | |___ | | | |_| || |_| || |___
7 | | ___|| ___|| |___ | || ___|| ___|
8 | | | | |___ | || || | | |___
9 | |___| |_______||_______||_______||___| |_______|
10 |
11 | This file is part of felupe.
12 |
13 | Felupe is free software: you can redistribute it and/or modify
14 | it under the terms of the GNU General Public License as published by
15 | the Free Software Foundation, either version 3 of the License, or
16 | (at your option) any later version.
17 |
18 | Felupe is distributed in the hope that it will be useful,
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | GNU General Public License for more details.
22 |
23 | You should have received a copy of the GNU General Public License
24 | along with Felupe. If not, see .
25 |
26 | """
27 |
28 | import numpy as np
29 |
30 | import felupe as fem
31 |
32 |
33 | def test_solve():
34 | m = fem.Cube(n=3)
35 | e = fem.Hexahedron()
36 | q = fem.GaussLegendre(1, 3)
37 | r = fem.Region(m, e, q)
38 | u = fem.Field(r, dim=3)
39 | v = fem.FieldContainer([u])
40 |
41 | W = fem.constitution.NeoHooke(1, 3)
42 |
43 | F = v.extract()
44 | P = W.gradient(F)[:-1]
45 | A = W.hessian(F)
46 |
47 | b = fem.dof.symmetry(u)
48 | dof0, dof1 = fem.dof.partition(v, b)
49 |
50 | ext0 = fem.dof.apply(v, b, dof0)
51 |
52 | L = fem.IntegralForm(P, v, r.dV)
53 | a = fem.IntegralForm(A, v, r.dV, v)
54 |
55 | b = L.assemble().toarray()[:, 0]
56 | A = a.assemble()
57 |
58 | system = fem.solve.partition(v, A, dof1, dof0)
59 |
60 | du = fem.solve.solve(*system)
61 | assert np.allclose(du, 0)
62 |
63 | du = fem.solve.solve(*system, ext0)
64 | assert np.allclose(du, 0)
65 |
66 | system = fem.solve.partition(v, A, dof1, dof0, b)
67 |
68 | du = fem.solve.solve(*system)
69 | assert np.allclose(du, 0)
70 |
71 | du = fem.solve.solve(*system, ext0)
72 | assert np.allclose(du, 0)
73 |
74 |
75 | if __name__ == "__main__":
76 | test_solve()
77 |
--------------------------------------------------------------------------------
/tests/umat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adtzlr/felupe/0f41d8eafabddbbe3a6f1f03df465b7eea0889d3/tests/umat.png
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = core, py3
3 | isolated_build = True
4 |
5 | [tool:pytest]
6 | addopts = --doctest-modules
7 |
8 | [testenv]
9 | deps =
10 | pytest
11 | pytest-cov
12 | extras = all
13 | commands =
14 | pytest tests {posargs}
15 |
16 | [testenv:core]
17 | commands =
18 | pytest tests/test_import.py {posargs}
19 |
--------------------------------------------------------------------------------