├── .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 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 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 | --------------------------------------------------------------------------------