├── .gitignore ├── .pdm-python ├── .readthedocs.yaml ├── LICENSE ├── LICENSE.txt ├── MANIFEST.in ├── README.md ├── README.rst ├── archive ├── setup-org.py ├── setup-template.py └── setup.py ├── build-package.py ├── docs ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── calfem.logo.bw.svg │ ├── calfem_examples.rst │ ├── calfem_mesh_guide.rst │ ├── calfem_reference.rst │ ├── conf.py │ ├── developer.rst │ ├── examples │ ├── cfeditor.ui │ ├── exm1.ipynb │ ├── exm10.ipynb │ ├── exm13.ipynb │ ├── exm2.ipynb │ ├── exm3.ipynb │ ├── exm6.ipynb │ ├── exm7.ipynb │ ├── exmqt1.ui │ ├── exmqt11.ui │ ├── exmqt6.ui │ ├── exs2.ipynb │ ├── exs3.ipynb │ ├── exs4.ipynb │ └── exs7.ipynb │ ├── exs1.rst │ ├── images │ ├── SVG │ │ └── Rityta 1.svg │ ├── bars1.png │ ├── bars2.png │ ├── bars3.png │ ├── calfem.logo.ai │ ├── calfem.logo.png │ ├── calfem.logo.svg │ ├── calfem.logo.sw.svg │ ├── exm0_2.png │ ├── exs1-1-rev1.png │ ├── exs1-1.png │ ├── exs2.png │ ├── frame_and_bars.png │ ├── mesh1.png │ ├── mesh2.png │ ├── mesh3.png │ └── tut2-1.png │ ├── index.rst │ └── installation.rst ├── example_outputs.py ├── examples ├── example1.py ├── exd_beam2_b.py ├── exd_beam2_m.py ├── exd_beam2_t.py ├── exd_beam2_tr.py ├── exe_stress_2d_editor.py ├── exm_circle_bsplines.py ├── exm_flow_model.py ├── exm_geometry.py ├── exm_qt_app.py ├── exm_qt_app.ui ├── exm_qt_vis.py ├── exm_qt_vis.ui ├── exm_stress_2d.py ├── exm_stress_2d_export.py ├── exm_stress_2d_materials.py ├── exm_stress_2d_pyvtk.py ├── exm_stress_2d_qt.py ├── exm_stress_2d_qt.ui ├── exm_structured_mesh.py ├── exm_structured_mesh_3d.py ├── exm_structured_mesh_vtk.py ├── exm_temp_2d_markers.py ├── exm_temp_2d_splines_arcs.py ├── exm_tet_mesh.py ├── exm_tet_mesh_vtk.py ├── exm_tutorial_1.py ├── exm_tutorial_2.py ├── exn_bar2g.py ├── exn_bar2m.py ├── exn_beam2.py ├── exn_beam2_b.py ├── experimental │ ├── .vscode │ │ └── settings.json │ ├── exed1.py │ ├── exed1.ui │ ├── exint1.py │ ├── exm11.py │ ├── exm11_mpl.py │ ├── exm12.ipynb │ ├── exm12.py │ ├── exm12_mpl.py │ ├── exm14_vtk.py │ ├── exm1_mpl_edit.py │ ├── exs6.py │ ├── exui1.py │ ├── gmsh_api.py │ ├── gmsh_api2.py │ ├── path_int.py │ ├── plot_tst.py │ ├── point_in_geom.py │ ├── prim3d.py │ ├── qt1.py │ ├── qt2.py │ └── tri_mesh.py ├── exs_bar2.py ├── exs_bar2_la.py ├── exs_bar2_lb.py ├── exs_beam1.ipynb ├── exs_beam1.py ├── exs_beam2.ipynb ├── exs_beam2.py ├── exs_beambar2.py ├── exs_flw_diff2.py ├── exs_flw_temp1.py ├── exs_flw_temp2.py ├── exs_spring.py ├── exv1.py ├── exv2.py ├── exv3.py ├── exv4.m ├── exv4.mat ├── exv4.py ├── exv5.py ├── exvis_beam_soli8.py ├── gmsh-api │ ├── exgm1.py │ ├── exgm2.py │ ├── exgm3.py │ └── exgm4.py └── obsolete │ ├── extri1.py │ └── extri2.py ├── gen_output_dict.py ├── pyproject.toml ├── reports ├── manual-mesh-module.pdf └── manual.pdf ├── resources └── resources.qrc ├── src ├── __init__.py └── calfem │ ├── __init__.py │ ├── _export.py │ ├── classes_qt4.py │ ├── classes_wx.py │ ├── core.py │ ├── core_compat.py │ ├── editor.py │ ├── editor.ui │ ├── editor_resources.py │ ├── editor_scene.py │ ├── editor_ui.py │ ├── experimental.py │ ├── geometry.py │ ├── intvis.py │ ├── mesh.py │ ├── misc.py │ ├── qt5.py │ ├── shapes.py │ ├── solver.py │ ├── ui.py │ ├── utils.py │ ├── vedo_utils.py │ ├── vis.py │ ├── vis_mpl.py │ ├── vis_vedo.py │ ├── vis_vedo_utils.py │ └── vis_vtk.py ├── test_calfem.py └── tests └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.pyc 3 | 4 | *.msh 5 | 6 | *.geo 7 | 8 | *.bak 9 | 10 | docs/build 11 | docs/pycalfem 12 | 13 | venv-calfem 14 | 15 | .spyproject/ 16 | 17 | calfem/shapes - kopia.py 18 | 19 | calfem_python.egg-info/* 20 | calfem_python_small.egg-info/* 21 | 22 | .vscode/launch.json 23 | *.project 24 | .pydevproject 25 | *.prefs 26 | calfem-python.pyproj 27 | *.suo 28 | calfem-python.sln 29 | build/ 30 | calfem_python.egg-info/ 31 | dist/ 32 | *.xml 33 | *.iml 34 | .idea/ 35 | .vscode/settings.json 36 | examples/.ipynb_checkpoints/* 37 | # .vscode/settings.json 38 | calfem/.ipynb_checkpoints/* 39 | exm6.vtk 40 | 41 | # new notebook examples 42 | docs/source/examples/.ipynb_checkpoints/ 43 | .DS_Store 44 | *.lock 45 | *.log 46 | *.log 47 | *.log 48 | .pdm-python 49 | test_examples_output.log 50 | *.log 51 | test_examples.log 52 | -------------------------------------------------------------------------------- /.pdm-python: -------------------------------------------------------------------------------- 1 | C:/Users/jonas/miniconda3/envs/calfem-dev/python.EXE -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.12" 12 | # You can also specify other tool versions: 13 | # nodejs: "20" 14 | # rust: "1.70" 15 | # golang: "1.20" 16 | 17 | # Build documentation in the "docs/" directory with Sphinx 18 | sphinx: 19 | configuration: docs/source/conf.py 20 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs 21 | # builder: "dirhtml" 22 | # Fail on all warnings to avoid broken references 23 | # fail_on_warning: true 24 | 25 | # Optionally build your docs in additional formats such as PDF and ePub 26 | # formats: 27 | # - pdf 28 | # - epub 29 | 30 | # Optional but recommended, declare the Python requirements required 31 | # to build your documentation 32 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 33 | python: 34 | install: 35 | - requirements: docs/requirements.txt 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2021 Division of Structural Mechanics 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2021 Division of Structural Mechanics 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.md 2 | include *.rst 3 | recursive-include examples *.py 4 | graft examples 5 | global-exclude *.py[co] 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CALFEM for Python 2 | 3 | ## Documentation 4 | 5 | [https://calfem-for-python.readthedocs.io/en/latest/](https://calfem-for-python.readthedocs.io/en/latest/) 6 | 7 | ## Manuals 8 | 9 | Original manual: [manual.pdf](https://github.com/CALFEM/calfem-python/tree/master/reports/manual.pdf) 10 | 11 | Manual for with improved mesh: [manual-mesh-module.pdf](https://github.com/CALFEM/calfem-python/tree/master/reports/manual-mesh-module.pdf) 12 | 13 | ## Background 14 | 15 | The computer program CALFEM is written for the software MATLAB and is an interactive tool for learning the finite element method. CALFEM is an abbreviation 16 | of ”Computer Aided Learning of the Finite Element Method” and been developed by the Division of Structural Mechanics at Lund University since the late 70’s. 17 | 18 | ## Why CALFEM for Python? 19 | 20 | While both the MATLAB and Python versions of CALFEM are open-source (MIT Licensed), the key difference lies in the environments they operate in. MATLAB is not open-source and requires expensive licenses (for commercial use), which can be a barrier for many users. In contrast, Python is a free, open-source programming language, making CALFEM for Python more accessible and cost-effective for a broader audience, including those in academic, personal, or commercial settings. 21 | 22 | CALFEM for Python is released under the MIT license, which enables its use in open-source as well as commercial projects. 23 | 24 | ## Installation 25 | 26 | Install CALFEM for python using 27 | `pip install calfem-python` 28 | 29 | ## Dependencies 30 | 31 | Mesh Generation Software: GMSH. 32 | Install GMSH [here](http://gmsh.info/) and add to the PATH of your file or instead add contents of GMSH to the file folder. 33 | 34 | ## References 35 | 36 | * Forsman, K, 2017. VisCon: Ett visualiseringsverktyg för tvådimensionell konsolidering i undervisningssammanhang - http://www.byggmek.lth.se/fileadmin/byggnadsmekanik/publications/tvsm5000/web5225.pdf 37 | 38 | * Edholm, A., 2013. Meshing and visualisation routines in the Python version of CALFEM. - http://www.byggmek.lth.se/fileadmin/byggnadsmekanik/publications/tvsm5000/web5187.pdf 39 | 40 | * Ottosson, A., 2010. Implementation of CALFEM for Python - http://www.byggmek.lth.se/fileadmin/byggnadsmekanik/publications/tvsm5000/web5167.pdf 41 | 42 | * Eriksson, K, 2021. CALFEM Geometry Editor - An interactive geometry editor for CALFEM 43 | 44 | * Åmand, A, 2022. Development of visualisation functions for CALFEM for Python 45 | 46 | 47 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | The computer program CALFEM is written for the software MATLAB and is an interactive tool for learning the finite element method. CALFEM is an abbreviation 2 | of ”Computer Aided Learning of the Finite Element Method” and been developed by the Division of Structural Mechanics at Lund University since the late 70’s. 3 | 4 | Unlike MATLAB, which have expensive licenses, Python is free to use and distribute both for personal and commercial use. This is the python version of CALFEM for scientific purposes/research. 5 | -------------------------------------------------------------------------------- /archive/setup-org.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://github.com/CALFEM/calfem-python 5 | """ 6 | 7 | # Always prefer setuptools over distutils 8 | from setuptools import setup, find_packages 9 | # To use a consistent encoding 10 | from codecs import open 11 | from os import path 12 | import os, glob, sys 13 | 14 | here = path.abspath(path.dirname(__file__)) 15 | 16 | # Get the long description from the README file 17 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 18 | long_description = f.read() 19 | 20 | def gen_data_files(*dirs): 21 | results = [] 22 | 23 | for src_dir in dirs: 24 | for root,dirs,files in os.walk(src_dir): 25 | results.append((root, map(lambda f:root + "/" + f, files))) 26 | return results 27 | 28 | setup( 29 | name='calfem-python', 30 | 31 | # Versions should comply with PEP440. For a discussion on single-sourcing 32 | # the version across setup.py and the project code, see 33 | # https://packaging.python.org/en/latest/single_source_version.html 34 | 35 | version='3.6.4', 36 | 37 | description='CALFEM for Python', 38 | long_description='The computer program CALFEM is written for the software MATLAB and is an interactive tool for learning the finite element method. CALFEM is an abbreviation of "Computer Aided Learning of the Finite Element Method" and been developed by the Division of Structural Mechanics at Lund University since the late 70s.', 39 | 40 | # The project's main homepage. 41 | url='https://github.com/CALFEM/calfem-python', 42 | 43 | # Author details 44 | author='Jonas Lindemann, et al', 45 | author_email='jonas.lindemann@byggmek.lth.se', 46 | 47 | # Choose your license 48 | license='MIT', 49 | 50 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 51 | classifiers=[ 52 | # How mature is this project? Common values are 53 | # 3 - Alpha 54 | # 4 - Beta 55 | # 5 - Production/Stable 56 | 'Development Status :: 4 - Beta', 57 | 58 | # Indicate who your project is intended for 59 | 'Intended Audience :: Developers', 60 | 'Topic :: Software Development :: Build Tools', 61 | 62 | # Pick your license as you wish (should match "license" above) 63 | 'License :: OSI Approved :: MIT License', 64 | 65 | # Specify the Python versions you support here. In particular, ensure 66 | # that you indicate whether you support Python 2, Python 3 or both. 67 | 'Programming Language :: Python :: 3', 68 | 'Programming Language :: Python :: 3.7', 69 | 'Programming Language :: Python :: 3.8', 70 | 'Programming Language :: Python :: 3.9', 71 | 'Programming Language :: Python :: 3.10', 72 | 'Programming Language :: Python :: 3.11', 73 | ], 74 | 75 | # What does your project relate to? 76 | keywords='finite element, math, numerics', 77 | 78 | # You can just specify the packages manually here if your project is 79 | # simple. Or you can use find_packages(). 80 | #packages=find_packages(exclude=['contrib', 'docs', 'tests']), 81 | #packages=find_packages(exclude=['docs', 'old', 'examples', 'examplegeo']), 82 | packages=['calfem',], 83 | 84 | # Alternatively, if you want to distribute just a my_module.py, uncomment 85 | # this: 86 | # py_modules=["my_module"], 87 | 88 | # List run-time dependencies here. These will be installed by pip when 89 | # your project is installed. For an analysis of "install_requires" vs pip's 90 | # requirements files see: 91 | # https://packaging.python.org/en/latest/requirements.html 92 | install_requires=['numpy', 'visvis', 'pyvtk', 'matplotlib', 'scipy', 'gmsh', 'qtpy', 'vedo', 'tabulate'], 93 | include_package_data=True 94 | #package_data={'calfem': ['examples/*']} 95 | 96 | #data_files=gen_data_files("examples", "doc") 97 | 98 | #package_data={ 99 | # 'calfem': ['examples/*.py', 'examples/*.ui'] 100 | #} 101 | 102 | # List additional groups of dependencies here (e.g. development 103 | # dependencies). You can install these using the following syntax, 104 | # for example: 105 | # $ pip install -e .[dev,test] 106 | #extras_require={ 107 | # 'dev': ['check-manifest'], 108 | # 'test': ['coverage'], 109 | #}, 110 | 111 | # If there are data files included in your packages that need to be 112 | # installed, specify them here. If using Python 2.6 or less, then these 113 | # have to be included in MANIFEST.in as well. 114 | ) 115 | -------------------------------------------------------------------------------- /archive/setup-template.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://github.com/CALFEM/calfem-python 5 | """ 6 | 7 | # Always prefer setuptools over distutils 8 | from setuptools import setup, find_packages 9 | # To use a consistent encoding 10 | from codecs import open 11 | from os import path 12 | import os, glob, sys 13 | 14 | here = path.abspath(path.dirname(__file__)) 15 | 16 | # Get the long description from the README file 17 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 18 | long_description = f.read() 19 | 20 | def gen_data_files(*dirs): 21 | results = [] 22 | 23 | for src_dir in dirs: 24 | for root,dirs,files in os.walk(src_dir): 25 | results.append((root, map(lambda f:root + "/" + f, files))) 26 | return results 27 | 28 | setup( 29 | name='{package_name}', 30 | 31 | # Versions should comply with PEP440. For a discussion on single-sourcing 32 | # the version across setup.py and the project code, see 33 | # https://packaging.python.org/en/latest/single_source_version.html 34 | 35 | version='{package_version}', 36 | 37 | description='CALFEM for Python', 38 | long_description='The computer program CALFEM is written for the software MATLAB and is an interactive tool for learning the finite element method. CALFEM is an abbreviation of "Computer Aided Learning of the Finite Element Method" and been developed by the Division of Structural Mechanics at Lund University since the late 70s.', 39 | 40 | # The project's main homepage. 41 | url='https://github.com/CALFEM/calfem-python', 42 | 43 | # Author details 44 | author='Jonas Lindemann, et al', 45 | author_email='jonas.lindemann@lunarc.lu.se', 46 | 47 | # Choose your license 48 | license='MIT', 49 | 50 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 51 | classifiers=[ 52 | # How mature is this project? Common values are 53 | # 3 - Alpha 54 | # 4 - Beta 55 | # 5 - Production/Stable 56 | 'Development Status :: 4 - Beta', 57 | 58 | # Indicate who your project is intended for 59 | 'Intended Audience :: Developers', 60 | 'Topic :: Software Development :: Build Tools', 61 | 62 | # Pick your license as you wish (should match "license" above) 63 | 'License :: OSI Approved :: MIT License', 64 | 65 | # Specify the Python versions you support here. In particular, ensure 66 | # that you indicate whether you support Python 2, Python 3 or both. 67 | 'Programming Language :: Python :: 3', 68 | 'Programming Language :: Python :: 3.7', 69 | 'Programming Language :: Python :: 3.8', 70 | 'Programming Language :: Python :: 3.9', 71 | 'Programming Language :: Python :: 3.10', 72 | 'Programming Language :: Python :: 3.11', 73 | 'Programming Language :: Python :: 3.12', 74 | ], 75 | 76 | # What does your project relate to? 77 | keywords='finite element, math, numerics', 78 | 79 | # You can just specify the packages manually here if your project is 80 | # simple. Or you can use find_packages(). 81 | #packages=find_packages(exclude=['contrib', 'docs', 'tests']), 82 | #packages=find_packages(exclude=['docs', 'old', 'examples', 'examplegeo']), 83 | packages=['calfem',], 84 | 85 | # Alternatively, if you want to distribute just a my_module.py, uncomment 86 | # this: 87 | # py_modules=["my_module"], 88 | 89 | # List run-time dependencies here. These will be installed by pip when 90 | # your project is installed. For an analysis of "install_requires" vs pip's 91 | # requirements files see: 92 | # https://packaging.python.org/en/latest/requirements.html 93 | install_requires=[{package_depends}], 94 | include_package_data=True 95 | 96 | #data_files=gen_data_files("examples", "doc") 97 | 98 | ) 99 | -------------------------------------------------------------------------------- /archive/setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://github.com/CALFEM/calfem-python 5 | """ 6 | 7 | # Always prefer setuptools over distutils 8 | from setuptools import setup, find_packages 9 | # To use a consistent encoding 10 | from codecs import open 11 | from os import path 12 | import os, glob, sys 13 | 14 | here = path.abspath(path.dirname(__file__)) 15 | 16 | # Get the long description from the README file 17 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 18 | long_description = f.read() 19 | 20 | def gen_data_files(*dirs): 21 | results = [] 22 | 23 | for src_dir in dirs: 24 | for root,dirs,files in os.walk(src_dir): 25 | results.append((root, map(lambda f:root + "/" + f, files))) 26 | return results 27 | 28 | setup( 29 | name='calfem-python-small', 30 | 31 | # Versions should comply with PEP440. For a discussion on single-sourcing 32 | # the version across setup.py and the project code, see 33 | # https://packaging.python.org/en/latest/single_source_version.html 34 | 35 | version='3.6.6', 36 | 37 | description='CALFEM for Python', 38 | long_description='The computer program CALFEM is written for the software MATLAB and is an interactive tool for learning the finite element method. CALFEM is an abbreviation of "Computer Aided Learning of the Finite Element Method" and been developed by the Division of Structural Mechanics at Lund University since the late 70s.', 39 | 40 | # The project's main homepage. 41 | url='https://github.com/CALFEM/calfem-python', 42 | 43 | # Author details 44 | author='Jonas Lindemann, et al', 45 | author_email='jonas.lindemann@lunarc.lu.se', 46 | 47 | # Choose your license 48 | license='MIT', 49 | 50 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 51 | classifiers=[ 52 | # How mature is this project? Common values are 53 | # 3 - Alpha 54 | # 4 - Beta 55 | # 5 - Production/Stable 56 | 'Development Status :: 4 - Beta', 57 | 58 | # Indicate who your project is intended for 59 | 'Intended Audience :: Developers', 60 | 'Topic :: Software Development :: Build Tools', 61 | 62 | # Pick your license as you wish (should match "license" above) 63 | 'License :: OSI Approved :: MIT License', 64 | 65 | # Specify the Python versions you support here. In particular, ensure 66 | # that you indicate whether you support Python 2, Python 3 or both. 67 | 'Programming Language :: Python :: 3', 68 | 'Programming Language :: Python :: 3.7', 69 | 'Programming Language :: Python :: 3.8', 70 | 'Programming Language :: Python :: 3.9', 71 | 'Programming Language :: Python :: 3.10', 72 | 'Programming Language :: Python :: 3.11', 73 | 'Programming Language :: Python :: 3.12', 74 | ], 75 | 76 | # What does your project relate to? 77 | keywords='finite element, math, numerics', 78 | 79 | # You can just specify the packages manually here if your project is 80 | # simple. Or you can use find_packages(). 81 | #packages=find_packages(exclude=['contrib', 'docs', 'tests']), 82 | #packages=find_packages(exclude=['docs', 'old', 'examples', 'examplegeo']), 83 | packages=['calfem',], 84 | 85 | # Alternatively, if you want to distribute just a my_module.py, uncomment 86 | # this: 87 | # py_modules=["my_module"], 88 | 89 | # List run-time dependencies here. These will be installed by pip when 90 | # your project is installed. For an analysis of "install_requires" vs pip's 91 | # requirements files see: 92 | # https://packaging.python.org/en/latest/requirements.html 93 | install_requires=['numpy', 'visvis', 'matplotlib', 'scipy', 'gmsh', 'tabulate'], 94 | include_package_data=True 95 | 96 | #data_files=gen_data_files("examples", "doc") 97 | 98 | ) 99 | -------------------------------------------------------------------------------- /build-package.py: -------------------------------------------------------------------------------- 1 | 2 | import os, sys 3 | 4 | def update_setup(package_name, package_version, package_deps): 5 | 6 | with open("setup-template.py", "r") as f: 7 | setup_template = f.read() 8 | 9 | with open("setup.py", "w") as f: 10 | f.write(setup_template.format(package_name=package_name, package_version=package_version, package_depends=package_deps)) 11 | 12 | def build_package(): 13 | os.system("C:\Users\Miniconda3\envs\calfem-dev\python.exe -m build --wheel") 14 | 15 | if __name__ == "__main__": 16 | 17 | package_version = "3.6.6" 18 | 19 | update_setup("calfem-python", package_version, "'numpy', 'visvis', 'pyvtk', 'matplotlib', 'scipy', 'gmsh', 'qtpy', 'vedo', 'tabulate'") 20 | 21 | build_package() 22 | 23 | update_setup("calfem-python-small", package_version, "'numpy', 'visvis', 'matplotlib', 'scipy', 'gmsh', 'tabulate'") 24 | 25 | build_package() 26 | 27 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | rem if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | rem ) 10 | set SOURCEDIR=source 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.https://www.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/requirements.txt: -------------------------------------------------------------------------------- 1 | visvis 2 | PyQt5 3 | pyvtk 4 | calfem-python 5 | ipython_genutils==0.1.0 6 | sphinx==6.1 7 | nbsphinx==0.9.3 8 | sphinx-material 9 | -------------------------------------------------------------------------------- /docs/source/calfem.logo.bw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/source/calfem_examples.rst: -------------------------------------------------------------------------------- 1 | Using CALFEM for Python 2 | ======================= 3 | 4 | What is CALFEM? 5 | --------------- 6 | 7 | CALFEM is an interactive computer program for teaching the finite element method (FEM). The name CALFEM is an abbreviation of "Computer Aided Learning of the Finite Element Method". The program can be used for different types of structural mechanics problems and field problems. 8 | 9 | CALFEM, the program and its built-in philosophy, have been developed at the Division of Structural Mechanics, Lund University, starting in the late 70's. Many coworkers, former and present, have been engaged in the development at different stages. 10 | 11 | What is CALFEM for Python? 12 | -------------------------- 13 | * Subset of CALFEM routines implemented in Python 14 | * Using NumPy for matrices 15 | * Additional mesh generation routines supporting Triangle and GMSH 16 | * Plotting with Matplotlib and visvis 17 | 18 | CALFEM Python modules 19 | --------------------- 20 | 21 | * **calfem.core** 22 | 23 | * Element routines 24 | * System routines 25 | * **calfem.utils** 26 | 27 | * I/O routines 28 | * Misc. routines 29 | * **calfem.geometry** 30 | 31 | * Routines for defining problem geometry used for input in mesh generation 32 | * **calfem.mesh** 33 | 34 | * Mesh generation routines 35 | * **calfem.vis/calfem.vis_mpl** 36 | 37 | * Routines for visualising geometry, meshes and results. 38 | 39 | Examples 40 | -------- 41 | The example codes show what CALFEM can do for you. The examples are divided into two: 42 | 43 | - Numerical examples 44 | 45 | - Mesh examples 46 | 47 | The next is tutorial on using Calfem for Python for numerical finite element, i.e., solving FEM equation to obtain nodal displacements given loading forces and 48 | stiffness matrix. The example can be found in `examples` directories both on 49 | calfem-python root directory (for .py files) and docs directory (for .ipynb files). 50 | -------------------------------------------------------------------------------- /docs/source/calfem_reference.rst: -------------------------------------------------------------------------------- 1 | Function reference 2 | ================== 3 | 4 | Core functions 5 | -------------- 6 | 7 | .. automodule:: calfem.core 8 | :members: 9 | 10 | Geometry functions 11 | ------------------ 12 | 13 | .. automodule:: calfem.geometry 14 | :members: 15 | 16 | Mesh functions 17 | -------------- 18 | 19 | .. automodule:: calfem.mesh 20 | :members: 21 | 22 | User interface functions 23 | ------------------------ 24 | 25 | .. automodule:: calfem.ui 26 | :members: 27 | 28 | Utility functions 29 | ----------------- 30 | 31 | .. automodule:: calfem.utils 32 | :members: 33 | 34 | Visualisation functions (Matplotlib) 35 | ------------------------------------ 36 | 37 | .. automodule:: calfem.vis_mpl 38 | :members: 39 | 40 | Visualisation functions (VisVis) 41 | -------------------------------- 42 | 43 | .. automodule:: calfem.vis 44 | :members: 45 | 46 | Interactive Geometry Editor 47 | --------------------------- 48 | 49 | .. automodule:: calfem.editor 50 | :members: 51 | -------------------------------------------------------------------------------- /docs/source/developer.rst: -------------------------------------------------------------------------------- 1 | Developing CALFEM for Python 2 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | 4 | Creating an environment for development 5 | --------------------------------------- 6 | 7 | It could be benficial to create an dedicated environment for development. This can be easily created in the Anaconda distribution.:: 8 | 9 | conda create -n calfem-dev python=3.9 10 | conda activate calfem-dev 11 | 12 | Installing dependencies 13 | ----------------------- 14 | 15 | To develop for CALFEM for Python you will need to install the required dependencies first. The easiest way to do this is to install the pip version of CALFEM:: 16 | 17 | pip install calfem-python 18 | 19 | Creating a fork in GitHub 20 | ------------------------- 21 | 22 | To be able to submit code changes and addition it is a good idea to create a fork on GitHub. A fork is your own version of CALFEM for Python in which you can track changes. From the fork you can also easily create a pull request, that is a suggested change that you can submit to CALFEM for Python. 23 | 24 | Please see 25 | 26 | https://reflectoring.io/github-fork-and-pull/ 27 | 28 | for more information on how to create and manage forks. 29 | 30 | Checking out code from github 31 | ----------------------------- 32 | 33 | It is also possible to check out a local version of the code from the command line. The master or develop branches can be checkout with the following procedures: 34 | 35 | Cloning the master branch on your local computer.:: 36 | 37 | git clone https://github.com/CALFEM/calfem-python.git 38 | 39 | Cloning the develop branch on your local computer.:: 40 | 41 | git clone https://github.com/CALFEM/calfem-python.git 42 | git checkout develop 43 | 44 | It is also possible to use the command line tools to clone your github fork: 45 | 46 | git clone https://github.com/USERNAME/calfem-python.git 47 | 48 | 49 | Using GitHub Desktop to manage your code 50 | ---------------------------------------- 51 | 52 | GitHub Desktop is a graphical client for GitHub that makes the procedure working with git-repos much more easy. More information on how to use GitHub Desktop can be found here: 53 | 54 | https://desktop.github.com/ 55 | 56 | https://docs.github.com/en/desktop 57 | 58 | 59 | Modifying the Python search PATH 60 | -------------------------------- 61 | 62 | To work on the checked out source directory, set the PYTHONPATH environment variable to the root of the source directory. 63 | 64 | On Windows:: 65 | 66 | set PYTHONPATH=C:\[Path to source directory] 67 | 68 | On other platforms:: 69 | 70 | export PYTHONPATH=[Path to source directory] 71 | 72 | Guidelines 73 | ---------- 74 | 75 | If you want to develop standalone element routines for CALFEM it is probarbly a good idea to develop them standalone and then submit a change request for inclusion in the calfem.extension module. 76 | 77 | Element routines should be named according to the following rule: 78 | 79 | [name][1|2|3][e|s] 80 | 81 | Where 1,2 and 3 indicates element dimensions. e - denotes that the routine returns element stiffness matrix and or force vector. s - denotes that the routines returns element forces given element nodal values. 82 | 83 | Please look at existing routines to familiar yourself with how they are constructued. 84 | 85 | All routines should have documentation strings describing input and output parameters. Code comments describing the general flow should be added to the function at relevant positions. 86 | 87 | Submit a Pull request 88 | --------------------- 89 | 90 | If you want your changes to be included in future releases of CALFEM please create a pull request against GitHub. More information on this can be found here: 91 | 92 | https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /docs/source/examples/cfeditor.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 800 25 | 21 26 | 27 | 28 | 29 | 30 | File 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Open... 44 | 45 | 46 | 47 | 48 | Save 49 | 50 | 51 | 52 | 53 | Save as... 54 | 55 | 56 | 57 | 58 | Exit 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /docs/source/examples/exmqt1.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 806 10 | 559 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | 27 | 28 | 16777215 29 | 50 30 | 31 | 32 | 33 | QFrame::StyledPanel 34 | 35 | 36 | QFrame::Raised 37 | 38 | 39 | 40 | 41 | 42 | Execute 43 | 44 | 45 | 46 | 47 | 48 | 49 | Qt::Horizontal 50 | 51 | 52 | 53 | 40 54 | 20 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 0 71 | 0 72 | 806 73 | 21 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/source/examples/exmqt6.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 806 10 | 559 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | 27 | 28 | 16777215 29 | 50 30 | 31 | 32 | 33 | QFrame::StyledPanel 34 | 35 | 36 | QFrame::Raised 37 | 38 | 39 | 40 | 41 | 42 | Execute 43 | 44 | 45 | 46 | 47 | 48 | 49 | Qt::Horizontal 50 | 51 | 52 | 53 | 40 54 | 20 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 0 71 | 0 72 | 806 73 | 21 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /docs/source/exs1.rst: -------------------------------------------------------------------------------- 1 | Example: Connected springs 2 | ------------------------------------- 3 | 4 | This example is from the CALFEM manual (exs1.py). 5 | 6 | **Purpose:** 7 | 8 | Show the basic steps in a finite element calculation. 9 | 10 | **Description:** 11 | 12 | The general procedure in linear finite element calculations is carried out for a 13 | simple structure. The steps are: 14 | 15 | * define the model 16 | * generate element matrices 17 | * assemble element matrices into the global system of equations 18 | * solve the global system of equations 19 | * evaluate element forces 20 | 21 | Consider the system of three linear elastic springs, and the corresponding 22 | finite element model. The system of springs is fixed in its ends and loaded by a 23 | single load F. To make it convenience, we follow notation in "Fundamentals of Finite Element Analysis" by David Hutton, where square is symbol for nodes, circle is for element, and U is for (global) nodal displacement. Capital letter shows global variables while small letter follows local variables. 24 | 25 | .. image:: images/exs1-1-rev1.png 26 | 27 | We begin our FEM computation by importing required modules 28 | 29 | .. literalinclude:: ../../examples/exs_spring.py 30 | :lines: 16-17 31 | 32 | The computation is initialized by defining the topology matrix Edof, containing 33 | element numbers and global element degrees of freedom. All input to CALFEM is NumPy arrays. Topology is defined by index 1, i.e., the first row represents the first element bounded by node 1 and node 2. Hence we write 34 | 35 | .. literalinclude:: ../../examples/exs_spring.py 36 | :lines: 20-24 37 | 38 | the initial global stiffness matrix `K` (3x3) and load force `f` containing zeros, 39 | 40 | .. literalinclude:: ../../examples/exs_spring.py 41 | :lines: 27-28 42 | 43 | Element stiffness matrices are generated by the function spring1e. The element 44 | property `ep` for the springs contains the spring stiffnesses k and 2k 45 | respectively, where k = 1500. 46 | 47 | .. literalinclude:: ../../examples/exs_spring.py 48 | :lines: 30-43 49 | 50 | The output is printed as follows:: 51 | 52 | Stiffness matrix K: 53 | [[ 3000. -3000. 0.] 54 | [-3000. 7500. -4500.] 55 | [ 0. -4500. 4500.]] 56 | 57 | and the load/force vector f (3x1) with the load F = 100 in position 2 (Note that Python indexes from 0, hence f[1] corresponds to edof 2). 58 | 59 | .. literalinclude:: ../../examples/exs_spring.py 60 | :lines: 46 61 | 62 | The element stiffness matrices are assembled into the global stiffness matrix K 63 | according to the topology. `bc` is an array of prescribed degrees of freedom. Values to be specified are specified in a separate array. If all values are 0, they don't have to be specified. 64 | The global system of equations is solved considering the boundary conditions 65 | given in bc. 66 | 67 | .. literalinclude:: ../../examples/exs_spring.py 68 | :lines: 49-56 69 | 70 | output: :: 71 | 72 | Displacements a: 73 | [[0. ] 74 | [0.01333333] 75 | [0. ]] 76 | Reaction forces Q: 77 | [[-40.] 78 | [ 0.] 79 | [-60.]] 80 | 81 | Element forces are evaluated from the element displacements. These are obtained 82 | from the global displacements `a` using the function extract. 83 | 84 | .. literalinclude:: ../../examples/exs_spring.py 85 | :lines: 59-61 86 | 87 | The spring element forces at each element are evaluated using the function spring1s. 88 | 89 | .. literalinclude:: ../../examples/exs_spring.py 90 | :lines: 68-70 91 | 92 | Output: :: 93 | 94 | Element forces N: 95 | N1 = 40.0 96 | N2 = -20.0 97 | N3 = -40.0 98 | 99 | -------------------------------------------------------------------------------- /docs/source/images/SVG/Rityta 1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/source/images/bars1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/bars1.png -------------------------------------------------------------------------------- /docs/source/images/bars2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/bars2.png -------------------------------------------------------------------------------- /docs/source/images/bars3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/bars3.png -------------------------------------------------------------------------------- /docs/source/images/calfem.logo.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/calfem.logo.ai -------------------------------------------------------------------------------- /docs/source/images/calfem.logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/calfem.logo.png -------------------------------------------------------------------------------- /docs/source/images/calfem.logo.sw.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/source/images/exm0_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/exm0_2.png -------------------------------------------------------------------------------- /docs/source/images/exs1-1-rev1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/exs1-1-rev1.png -------------------------------------------------------------------------------- /docs/source/images/exs1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/exs1-1.png -------------------------------------------------------------------------------- /docs/source/images/exs2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/exs2.png -------------------------------------------------------------------------------- /docs/source/images/frame_and_bars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/frame_and_bars.png -------------------------------------------------------------------------------- /docs/source/images/mesh1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/mesh1.png -------------------------------------------------------------------------------- /docs/source/images/mesh2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/mesh2.png -------------------------------------------------------------------------------- /docs/source/images/mesh3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/mesh3.png -------------------------------------------------------------------------------- /docs/source/images/tut2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/docs/source/images/tut2-1.png -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. CALFEM for Python documentation master file, created by 2 | sphinx-quickstart on Mon May 30 23:34:38 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. image:: images/calfem.logo.png 7 | :scale: 20 % 8 | 9 | CALFEM for Python - Documentation 10 | ================================= 11 | 12 | Welcome to the documentation for CALFEM for Python. On this page you will find examples of how to use CALFEM for Python as well as reference documentation for the different modules contained in the CALFEM for Python distribution. This is not a replacement for the CALFEM Manual, but contain information on how to use CALFEM in a Python context. 13 | 14 | Contents: 15 | --------- 16 | 17 | .. toctree:: 18 | :maxdepth: 1 19 | :caption: Installation 20 | 21 | installation 22 | 23 | .. toctree:: 24 | :maxdepth: 2 25 | :caption: Tutorial 26 | 27 | calfem_examples 28 | exs1 29 | examples/exs2 30 | examples/exs3 31 | examples/exs4 32 | examples/exs7 33 | calfem_mesh_guide 34 | examples/exm1 35 | examples/exm2 36 | examples/exm3 37 | examples/exm6 38 | examples/exm10 39 | 40 | .. toctree:: 41 | :maxdepth: 1 42 | :caption: Developing 43 | 44 | developer 45 | 46 | .. toctree:: 47 | :maxdepth: 1 48 | :caption: Function Reference 49 | 50 | calfem_reference 51 | 52 | 53 | ================== 54 | Indices and tables 55 | ================== 56 | 57 | * :ref:`genindex` 58 | * :ref:`modindex` 59 | * :ref:`search` 60 | 61 | -------------------------------------------------------------------------------- /docs/source/installation.rst: -------------------------------------------------------------------------------- 1 | Installation instructions 2 | ^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | 4 | The simplest way to install CALFEM for Python is via pip. 5 | This procedure will ensure that all required dependencies are fulfilled. 6 | 7 | This can be achieved by executing the following command:: 8 | 9 | pip install calfem-python 10 | 11 | or:: 12 | 13 | sudo pip install calfem-python 14 | 15 | to install system-wide (not recommended if your system used a lot of python dependencies):: 16 | 17 | pip install -u calfem-python 18 | 19 | to install just for your own user. You can use the argument `--user` which is 20 | same as `-u`. If you want to specify your Python version, use the command like 21 | the following:: 22 | 23 | python3.9 -m pip install --user calfem-python 24 | 25 | where python3.9 is the Python version you want to install CALFEM for 26 | Python. Change this command with your preferable version. This last command is 27 | the preferred one according to the Python community. 28 | 29 | Installing in a Anaconda environment 30 | ------------------------------------ 31 | 32 | If you don't want to install all packages directly in the base Anaconda environment you could create a new enviroment for CALFEM:: 33 | 34 | conda create -n calfem-dev python=3.9 35 | conda activate calfem-dev 36 | 37 | Now we can install CALFEM for Python and its dependencies directly into this environment using Pip.:: 38 | 39 | pip install calfem-python 40 | 41 | 42 | -------------------------------------------------------------------------------- /examples/example1.py: -------------------------------------------------------------------------------- 1 | import calfem.geometry as cfg 2 | import calfem.mesh as cfm 3 | import calfem.vis_mpl as cfv 4 | 5 | g = cfg.Geometry() 6 | 7 | # Add points 8 | 9 | g.point([0, 0]) # 0 10 | g.point([1, 0]) # 1 11 | g.point([1, 1]) # 2 12 | g.point([0, 1]) # 3 13 | 14 | # Add points for circle 15 | 16 | r = 0.20 17 | 18 | g.point([0.5, 0.5]) # 4 19 | g.point([0.5, 0.5+r]) # 5 20 | g.point([0.5, 0.5-r]) # 6 21 | g.point([0.5+r, 0.5]) # 7 22 | g.point([0.5-r, 0.5]) # 8 23 | 24 | # Add lines 25 | 26 | g.spline([0, 1]) # 0 27 | g.spline([1, 2]) # 1 28 | g.spline([2, 3]) # 2 29 | g.spline([3, 0]) # 3 30 | 31 | # TODO: Add circles HERE 32 | 33 | g.circle([5, 4, 7]) # 4 34 | g.circle([7, 4, 6]) # 5 35 | g.circle([6, 4, 8]) # 6 36 | g.circle([8, 4, 5]) # 7 37 | 38 | # Add surface and hole UPDATE 39 | 40 | g.surface([0, 1, 2, 3], [[7, 6, 5, 4]]) 41 | 42 | #cfv.figure(fig_size=(10.0,10.0)) 43 | #cfv.draw_geometry(g) 44 | 45 | mesh = cfm.GmshMesh(g) 46 | 47 | # Mesh properties 48 | 49 | mesh.el_type = 3 50 | mesh.dofs_per_node = 1 # Degrees of freedom per node. 51 | mesh.el_size_factor = 0.040 # Factor that changes element sizes. 52 | 53 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 54 | 55 | 56 | cfv.figure(fig_size=(10,10)) 57 | cfv.draw_mesh( 58 | coords=coords, 59 | edof=edof, 60 | dofs_per_node=mesh.dofs_per_node, 61 | el_type=mesh.el_type, 62 | filled=True, 63 | title="Example 01" 64 | ) 65 | 66 | cfv.show_and_wait_mpl() 67 | -------------------------------------------------------------------------------- /examples/exd_beam2_b.py: -------------------------------------------------------------------------------- 1 | # example exd_beam2_b 2 | # ---------------------------------------------------------------- 3 | # PURPOSE 4 | # Structural Dynamics, time integration, time dependent 5 | # boundary conditions. 6 | # 7 | # Note: file exd_beam2_m.py must be in the same directory 8 | # ---------------------------------------------------------------- 9 | 10 | from exd_beam2_m import * 11 | 12 | # ----- Impact, center point, vertical beam ---------------------- 13 | 14 | dt = 0.002 15 | T = 1 16 | 17 | # ----- Boundary condition, initial condition -------------------- 18 | 19 | G = np.array([[0, 0], [0.1, 0.02], [0.2, -0.01], [0.3, 0], [T, 0]]) 20 | 21 | t, g = cfc.gfunc(G, dt) 22 | 23 | bc = np.zeros((4, 1 + len(g))) 24 | bc[0, :] = np.hstack((1, g)) 25 | bc[1, 0] = 2 26 | bc[2, 0] = 3 27 | bc[3, 0] = 14 28 | 29 | a0 = np.zeros((15, 1)) 30 | da0 = np.zeros((15, 1)) 31 | 32 | # ----- Output parameters ---------------------------------------- 33 | 34 | times = np.arange(0.1, 1.1, 0.1) 35 | dofs = np.array([1, 4, 11]) 36 | 37 | # ----- Time integration parameters ------------------------------ 38 | 39 | ip = np.array([dt, T, 0.25, 0.5]) 40 | 41 | # ----- Time integration ----------------------------------------- 42 | 43 | sol, dofhist = cfc.step2(K, [], M, [], a0, da0, bc, ip, times, dofs) 44 | 45 | # ----- Plot time history for two DOFs --------------------------- 46 | 47 | cfv.figure(1, fig_size=(7, 4)) 48 | cfv.plt.plot(t, dofhist["a"][0, :], "-") 49 | cfv.plt.plot(t, dofhist["a"][1, :], "--") 50 | cfv.plt.plot(t, dofhist["a"][2, :], "-.") 51 | cfv.plt.xlim([0, 1]) 52 | cfv.plt.ylim([-0.02, 0.03]) 53 | cfv.plt.xlabel("time (sec)") 54 | cfv.plt.ylabel("displacement (m)") 55 | cfv.plt.title("Displacement(time) at the 1st, 4th and 11th degree of freedom") 56 | cfv.text("solid line = bottom, vertical beam, x-direction", [0.2, 0.022]) 57 | cfv.text("dashed line = center, vertical beam, x-direction", [0.2, 0.017]) 58 | cfv.text("dashed-dotted line = center, horizontal beam, y-direction", [0.2, 0.012]) 59 | cfv.plt.grid() 60 | 61 | # ----- Plot displacement for some time increments ---------------- 62 | 63 | cfv.figure(2, fig_size=(7, 5)) 64 | for i in range(5): 65 | Edb = cfc.extract_ed(edof, sol["a"][:, i]) 66 | ext = ex + i * 3.5 67 | cfv.eldraw2(ext, ey, [2, 3, 1]) 68 | cfv.eldisp2(ext, ey, Edb, [1, 2, 2], sfac=20) 69 | cfv.text(f"{times[i]:.1f}", [3.5 * i + 0.5, 1.5]) 70 | eyt = ey - 4 71 | for i in range(5, 10): 72 | Edb = cfc.extract_ed(edof, sol["a"][:, i]) 73 | ext = ex + (i - 5) * 3.5 74 | cfv.eldraw2(ext, eyt, [2, 3, 1]) 75 | cfv.eldisp2(ext, eyt, Edb, [1, 2, 2], sfac=20) 76 | cfv.text(f"{times[i]:.1f}", [3.5 * (i - 5) + 0.5, -2.5]) 77 | cfv.title("Snapshots (sec), magnification = 20") 78 | ax = cfv.gca() 79 | ax.set_axis_off() 80 | cfv.show_and_wait() 81 | 82 | # ----- End ------------------------------------------------------- 83 | -------------------------------------------------------------------------------- /examples/exd_beam2_m.py: -------------------------------------------------------------------------------- 1 | # example exd_beam2_m 2 | # ---------------------------------------------------------------- 3 | # PURPOSE 4 | # Set up the fe-model and perform eigenvalue analysis 5 | # for a simple frame structure. 6 | # ---------------------------------------------------------------- 7 | 8 | import numpy as np 9 | import calfem.core as cfc 10 | import calfem.vis_mpl as cfv 11 | 12 | # ----- Generate the model --------------------------------------- 13 | # ----- Material data -------------------------------------------- 14 | 15 | E = 3e10 16 | Av = 0.1030e-2 17 | Ah = 0.0764e-2 18 | rho = 2500 19 | Iv = 0.0171e-4 20 | Ih = 0.00801e-4 21 | ep1 = [E, Av, Iv, rho * Av] # IPE100 22 | ep2 = [E, Ah, Ih, rho * Ah] # IPE80 23 | 24 | # ----- Topology ------------------------------------------------- 25 | 26 | edof = np.array( 27 | [ 28 | [1, 2, 3, 4, 5, 6], 29 | [4, 5, 6, 7, 8, 9], 30 | [7, 8, 9, 10, 11, 12], 31 | [10, 11, 12, 13, 14, 15], 32 | ] 33 | ) 34 | 35 | # ----- List of coordinates -------------------------------------- 36 | 37 | coord = np.array( 38 | [ 39 | [0.0, 0.0], 40 | [0.0, 1.5], 41 | [0.0, 3.0], 42 | [1.0, 3.0], 43 | [2.0, 3.0], 44 | ] 45 | ) 46 | 47 | # ----- List of degrees of freedom ------------------------------- 48 | 49 | dof = np.array( 50 | [ 51 | [1, 2, 3], 52 | [4, 5, 6], 53 | [7, 8, 9], 54 | [10, 11, 12], 55 | [13, 14, 15], 56 | ] 57 | ) 58 | 59 | # ----- Generate element matrices, assemble in global matrices --- 60 | 61 | K = np.zeros([15, 15]) 62 | M = np.zeros([15, 15]) 63 | 64 | ex, ey = cfc.coordxtr(edof, coord, dof) 65 | ep = np.array([ep1, ep1, ep2, ep2]) 66 | 67 | for elx, ely, eltopo, elprop in zip(ex, ey, edof, ep): 68 | Ke, Me = cfc.beam2de(elx, ely, elprop) 69 | cfc.assem(eltopo, K, Ke) 70 | cfc.assem(eltopo, M, Me) 71 | 72 | # ----- Eigenvalue analysis -------------------------------------- 73 | 74 | b = np.array([1, 2, 3, 14]) 75 | La, Egv = cfc.eigen(K, M, b) 76 | freq = np.sqrt(La) / (2 * np.pi) 77 | 78 | if __name__ == "__main__": 79 | # ----- Draw a plot of the element mesh -------------------------- 80 | 81 | cfv.figure(1, fig_size=(5.5, 4.5)) 82 | cfv.eldraw2(ex, ey, [1, 2, 1]) 83 | cfv.title("2-D Frame Structure") 84 | 85 | # ----- Plot one eigenmode --------------------------------------- 86 | 87 | cfv.figure(2, fig_size=(5.5, 4.5)) 88 | cfv.eldraw2(ex, ey, [2, 3, 1]) 89 | Edb = cfc.extract_ed(edof, Egv[:, 0]) 90 | cfv.eldisp2(ex, ey, Edb, [1, 2, 2]) 91 | cfv.title("The first eigenmode") 92 | cfv.text(f"{freq[0]:.2f}", [0.5, 1.75]) 93 | ax = cfv.gca() 94 | ax.grid() 95 | 96 | # ----- Plot eight eigenmodes ------------------------------------ 97 | 98 | cfv.figure(3, fig_size=(7, 5)) 99 | for i in range(4): 100 | Edb = cfc.extract_ed(edof, Egv[:, i]) 101 | ext = ex + i * 3 102 | cfv.eldraw2(ext, ey, [2, 3, 1]) 103 | cfv.eldisp2(ext, ey, Edb, [1, 2, 2], sfac=0.5) 104 | cfv.text(f"{freq[i]:.2f}", [3 * i + 0.5, 1.5]) 105 | eyt = ey - 4 106 | for i in range(4, 8): 107 | Edb = cfc.extract_ed(edof, Egv[:, i]) 108 | ext = ex + (i - 4) * 3 109 | cfv.eldraw2(ext, eyt, [2, 3, 1]) 110 | cfv.eldisp2(ext, eyt, Edb, [1, 2, 2], sfac=0.5) 111 | cfv.text(f"{freq[i]:.2f}", [3 * (i - 4) + 0.5, -2.5]) 112 | cfv.title("The first eight eigenmodes [Hz]") 113 | ax = cfv.gca() 114 | ax.set_axis_off() 115 | cfv.show_and_wait() 116 | 117 | # ----- End ------------------------------------------------------- 118 | -------------------------------------------------------------------------------- /examples/exd_beam2_t.py: -------------------------------------------------------------------------------- 1 | # example exd_beam2_t 2 | # ---------------------------------------------------------------- 3 | # PURPOSE 4 | # Structural Dynamics, time integration, full system. 5 | # 6 | # Note: file exd_beam2_m.py must be in the same directory 7 | # ---------------------------------------------------------------- 8 | 9 | from exd_beam2_m import * 10 | 11 | # ----- Impact, center point, vertical beam ---------------------- 12 | 13 | dt = 0.002 14 | T = 1 15 | 16 | # ----- The load ------------------------------------------------- 17 | 18 | G = np.array([[0, 0], [0.15, 1], [0.25, 0], [T, 0]]) 19 | 20 | t, g = cfc.gfunc(G, dt) 21 | f = np.zeros((15, len(g))) 22 | f[3, :] = 1000 * g 23 | 24 | # ----- Boundary condition, initial condition -------------------- 25 | 26 | bc = np.array([[1, 0], [2, 0], [3, 0], [14, 0]]) 27 | 28 | a0 = np.zeros((15, 1)) 29 | da0 = np.zeros((15, 1)) 30 | 31 | # ----- Output parameters ---------------------------------------- 32 | 33 | times = np.arange(0.1, 1.1, 0.1) 34 | dofs = np.array([4, 11]) 35 | 36 | # ----- Time integration parameters ------------------------------ 37 | 38 | ip = np.array([dt, T, 0.25, 0.5]) 39 | 40 | # ----- Time integration ----------------------------------------- 41 | 42 | sol, dofhist = cfc.step2(K, [], M, f, a0, da0, bc, ip, times, dofs) 43 | 44 | # ----- Plot time history for two DOFs --------------------------- 45 | 46 | cfv.figure(1, fig_size=(7, 4)) 47 | cfv.plt.plot(t, dofhist["a"][0, :], "-") 48 | cfv.plt.plot(t, dofhist["a"][1, :], "--") 49 | cfv.plt.xlim([0, 1]) 50 | cfv.plt.ylim([-0.01, 0.02]) 51 | cfv.plt.xlabel("time (sec)") 52 | cfv.plt.ylabel("displacement (m)") 53 | cfv.plt.title("Displacement(time) at the 4th and 11th degree of freedom") 54 | cfv.text("solid line = impact point, x-direction", [0.3, 0.017]) 55 | cfv.text("dashed line = center, horizontal beam, y-direction", [0.3, 0.012]) 56 | cfv.plt.grid() 57 | 58 | # ----- Plot displacement for some time increments ---------------- 59 | 60 | cfv.figure(2, fig_size=(7, 5)) 61 | for i in range(5): 62 | Edb = cfc.extract_ed(edof, sol["a"][:, i]) 63 | ext = ex + i * 3.5 64 | cfv.eldraw2(ext, ey, [2, 3, 1]) 65 | cfv.eldisp2(ext, ey, Edb, [1, 2, 2], sfac=25) 66 | cfv.text(f"{times[i]:.1f}", [3.5 * i + 0.5, 1.5]) 67 | eyt = ey - 4 68 | for i in range(5, 10): 69 | Edb = cfc.extract_ed(edof, sol["a"][:, i]) 70 | ext = ex + (i - 5) * 3.5 71 | cfv.eldraw2(ext, eyt, [2, 3, 1]) 72 | cfv.eldisp2(ext, eyt, Edb, [1, 2, 2], sfac=25) 73 | cfv.text(f"{times[i]:.1f}", [3.5 * (i - 5) + 0.5, -2.5]) 74 | cfv.title("Snapshots (sec), magnification = 25") 75 | ax = cfv.gca() 76 | ax.set_axis_off() 77 | cfv.show_and_wait() 78 | 79 | # ----- End ------------------------------------------------------- 80 | -------------------------------------------------------------------------------- /examples/exd_beam2_tr.py: -------------------------------------------------------------------------------- 1 | # example exd_beam2_tr 2 | # ---------------------------------------------------------------- 3 | # PURPOSE 4 | # Structural Dynamics, time integration, reduced system. 5 | # 6 | # Note: file exd_beam2_m.py must be in the same directory 7 | # ---------------------------------------------------------------- 8 | 9 | from exd_beam2_m import * 10 | 11 | # ----- Impact, center point, vertical beam ---------------------- 12 | 13 | dt = 0.002 14 | T = 1 15 | nev = 2 16 | 17 | # ----- The load ------------------------------------------------- 18 | 19 | G = np.array([[0, 0], [0.15, 1], [0.25, 0], [T, 0]]) 20 | 21 | t, g = cfc.gfunc(G, dt) 22 | f = np.zeros((15, len(g))) 23 | f[3, :] = 1000 * g 24 | fr = np.hstack((np.arange(1, nev + 1).reshape(-1, 1), Egv[:, :nev].T @ f)) 25 | 26 | # ----- Reduced system matrices ---------------------------------- 27 | 28 | kr = np.diag(np.diag(Egv[:, :nev].T @ K @ Egv[:, :nev])) 29 | mr = np.diag(np.diag(Egv[:, :nev].T @ M @ Egv[:, :nev])) 30 | 31 | # ----- Initial condition ---------------------------------------- 32 | 33 | ar0 = np.zeros((nev, 1)) 34 | dar0 = np.zeros((nev, 1)) 35 | 36 | # ----- Output parameters ---------------------------------------- 37 | 38 | times = np.arange(0.1, 1.1, 0.1) 39 | dofsr = np.arange(1, nev + 1) 40 | dofs = np.array([4, 11]) 41 | 42 | # ----- Time integration parameters ------------------------------ 43 | 44 | ip = np.array([dt, T, 0.25, 0.5]) 45 | 46 | # ----- Time integration ----------------------------------------- 47 | sol, dofhist = cfc.step2(kr, [], mr, fr, ar0, dar0, [], ip, times, dofsr) 48 | 49 | # ----- Mapping back to original coordinate system --------------- 50 | 51 | aR = Egv[:, :nev] @ sol["a"] 52 | aRhist = Egv[dofs - 1, :nev] @ dofhist["a"] 53 | 54 | # ----- Plot time history for two DOFs --------------------------- 55 | 56 | cfv.figure(1, fig_size=(7, 4)) 57 | cfv.plt.plot(t, aRhist[0, :], "-") 58 | cfv.plt.plot(t, aRhist[1, :], "--") 59 | cfv.plt.xlim([0, 1]) 60 | cfv.plt.ylim([-0.01, 0.02]) 61 | cfv.plt.xlabel("time (sec)") 62 | cfv.plt.ylabel("displacement (m)") 63 | cfv.plt.title("Displacement(time) at the 4th and 11th degree of freedom") 64 | cfv.text("solid line = impact point, x-direction", [0.3, 0.017]) 65 | cfv.text("dashed line = center, horizontal beam, y-direction", [0.3, 0.012]) 66 | cfv.text("TWO EIGENVECTORS ARE USED", [0.3, -0.007]) 67 | cfv.plt.grid() 68 | 69 | # ----- Plot displacement for some time increments ---------------- 70 | 71 | cfv.figure(2, fig_size=(7, 5)) 72 | 73 | for i in range(5): 74 | Edb = cfc.extract_ed(edof, aR[:, i]) 75 | ext = ex + i * 3.5 76 | cfv.eldraw2(ext, ey, [2, 3, 1]) 77 | cfv.eldisp2(ext, ey, Edb, [1, 2, 2], sfac=25) 78 | cfv.text(f"{times[i]:.1f}", [3.5 * i + 0.5, 1.5]) 79 | 80 | eyt = ey - 4 81 | 82 | for i in range(5, 10): 83 | Edb = cfc.extract_ed(edof, aR[:, i]) 84 | ext = ex + (i - 5) * 3.5 85 | cfv.eldraw2(ext, eyt, [2, 3, 1]) 86 | cfv.eldisp2(ext, eyt, Edb, [1, 2, 2], sfac=25) 87 | cfv.text(f"{times[i]:.1f}", [3.5 * (i - 5) + 0.5, -2.5]) 88 | 89 | cfv.title("Snapshots (sec), magnification = 25") 90 | ax = cfv.gca() 91 | ax.set_axis_off() 92 | cfv.show_and_wait() 93 | 94 | # ----- End ------------------------------------------------------- 95 | -------------------------------------------------------------------------------- /examples/exe_stress_2d_editor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | CALFEM Editor Example 5 | 6 | Written by Karl Eriksson 7 | """ 8 | 9 | import calfem.editor as cfe 10 | import calfem.geometry as cfg 11 | import calfem.mesh as cfm 12 | import calfem.vis_mpl as cfv 13 | import calfem.utils as cfu 14 | import calfem.core as cfc 15 | import numpy as np 16 | 17 | # --- Creating a square geometry with two markers 18 | 19 | g = cfg.Geometry() 20 | 21 | g.point([0.0, 0.0]) # point 0 22 | g.point([100.0, 0.0]) # point 1 23 | g.point([100, 100]) # point 2 24 | g.point([0, 100]) # point 3 25 | 26 | g.spline([0, 1]) # line 0 27 | g.spline([1, 2]) # line 1 28 | g.spline([2, 3]) # line 2 29 | g.spline([3, 0]) # line 3 30 | 31 | g.surface([0, 1, 2, 3]) # Connect lines to form surface 32 | g.setCurveMarker(0, 10) 33 | g.setCurveMarker(2, 20) 34 | 35 | # --- Open the geometry to allow changes in the CALFEM Geometry Editor 36 | 37 | new_geometry, marker_dict = cfe.edit_geometry(g) 38 | print(marker_dict) 39 | 40 | t = 0.2 41 | v = 0.35 42 | E = 2.1e9 43 | ptype = 1 44 | ep = [ptype, t] 45 | D = cfc.hooke(ptype, E, v) 46 | 47 | # --- Every border or point marked with 10 will recieve boundary 48 | # --- condition value of 0 49 | 50 | bcs_new = [[marker_dict[10], 0]] 51 | 52 | # --- Every border or point marked with 20 will recieve load 53 | # --- value of 10e5 54 | 55 | loads_new = [[marker_dict[20], 10e5]] 56 | 57 | # --- Every border or point marked with A will recieve boundary 58 | # --- condition value of 0 59 | 60 | bcs_old = [[10, 0]] 61 | 62 | # --- Every border or point marked with B will recieve load 63 | # --- value of 10e5 64 | 65 | loads_old = [[20, 10e5]] 66 | 67 | el_size_factor = 5 68 | el_type = 3 69 | dofs_per_node = 2 70 | 71 | 72 | def calc(geometry, bcs, loads, text): 73 | mesh = cfm.GmshMeshGenerator(geometry) 74 | mesh.el_size_factor = el_size_factor # Factor that changes element sizes. 75 | mesh.el_type = el_type 76 | mesh.dofs_per_node = dofs_per_node 77 | 78 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 79 | 80 | # --- Calculate element coordinates 81 | 82 | ex, ey = cfc.coordxtr(edof, coords, dofs) 83 | 84 | # --- Assemble system matrix 85 | 86 | nDofs = edof.max() 87 | 88 | K = np.zeros([nDofs, nDofs]) 89 | 90 | for eltopo, elx, ely in zip(edof, ex, ey): 91 | Ke = cfc.planqe(elx, ely, ep, D) 92 | cfc.assem(eltopo, K, Ke) 93 | 94 | # --- Solve equation system 95 | 96 | f = np.zeros([nDofs, 1]) 97 | bcPrescr = np.array([], int) 98 | bcVal = np.array([], float) 99 | 100 | for bc in bcs: 101 | bcPrescr, bcVal = cfu.applybc(bdofs, bcPrescr, bcVal, bc[0], bc[1]) 102 | 103 | for load in loads: 104 | cfu.applyforcetotal(bdofs, f, load[0], load[1]) 105 | 106 | a, r = cfc.solveq(K, f, bcPrescr, bcVal) 107 | 108 | # --- Calculate element forces 109 | 110 | ed = cfc.extractEldisp(edof, a) 111 | 112 | vonMises = [] 113 | 114 | # --- For each element: 115 | 116 | for i in range(edof.shape[0]): 117 | # --- Determine element stresses and strains in the element. 118 | 119 | es, et = cfc.planqs(ex[i, :], ey[i, :], ep, D, ed[i, :]) 120 | 121 | # --- Calc and append effective stress to list. 122 | vonMises.append( 123 | np.sqrt(np.power(es[0], 2) - es[0] * es[1] + np.power(es[1], 2) + 3 * es[2]) 124 | ) 125 | 126 | title = "Effective stress" + text 127 | cfv.draw_element_values( 128 | vonMises, 129 | coords, 130 | edof, 131 | mesh.dofs_per_node, 132 | mesh.el_type, 133 | None, 134 | draw_elements=False, 135 | draw_undisplaced_mesh=False, 136 | title=title, 137 | ) 138 | 139 | 140 | # --- Display results 141 | 142 | cfv.clf() 143 | calc(g, bcs_old, loads_old, " original") 144 | cfv.figure() 145 | calc(new_geometry, bcs_new, loads_new, " modified") 146 | cfv.show_and_wait() 147 | -------------------------------------------------------------------------------- /examples/exm_circle_bsplines.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Example 02 5 | Creating geometry from B-Splines and circle arcs. 6 | Also shows how to set ID numbers for geometry entities and how to specify element density. 7 | """ 8 | 9 | import matplotlib.pyplot as plt 10 | import matplotlib.collections 11 | import numpy as np 12 | 13 | import calfem.geometry as cfg 14 | import calfem.mesh as cfm 15 | import calfem.vis_mpl as cfv 16 | 17 | # ---- Define geometry ------------------------------------------------------ 18 | 19 | g = cfg.Geometry() 20 | 21 | # Add points: 22 | # In this example we set the IDs manually. 23 | 24 | g.point([-2, 0], ID=0) 25 | # el_size determines the size of the elements near this point. 26 | g.point([0, 1], ID=1, el_size=5) 27 | # el_size is 1 by default. Larger number means less dense mesh. 28 | g.point([1, 0], 2, el_size=5) 29 | g.point([0, -2], 3) # Size means the length of the sides of the elements. 30 | g.point([0, 0], 4, el_size=5) 31 | g.point([0.5, 0.2], 5) 32 | g.point([-0.5, 0.5], 6) 33 | g.point([-0.7, -0.5], 7) 34 | 35 | # Add curves: 36 | 37 | # The 3 points that define the circle arc are [start, center, end]. 38 | # The arc must be smaller than Pi. 39 | 40 | g.circle([1, 4, 2], 2) 41 | 42 | # BSplines are similar to Splines, but do not necessarily pass through the 43 | # control points. 44 | 45 | g.bspline([5, 6, 7, 5], 5) 46 | g.bspline([1, 0, 3, 2], 4) 47 | 48 | # Add surface: 49 | 50 | g.surface([4, 2], [[5]]) 51 | 52 | # Markers do not have to be set when the curve is created. It can be done afterwards. 53 | # Set marker=80 for curves 2 and 4: 54 | 55 | for curveID in [2, 4]: 56 | g.curveMarker(curveID, 80) 57 | 58 | # ---- Generate mesh -------------------------------------------------------- 59 | 60 | mesh = cfm.GmshMesh(g) 61 | 62 | # Element type 2 is triangle. (3 is quad. See user manual for more element types) 63 | 64 | mesh.el_type = 3 65 | 66 | # Degrees of freedom per node. 67 | 68 | mesh.dofs_per_node = 2 69 | mesh.el_size_factor = 0.05 70 | # mesh.gmsh_exec_path = "D:\\vsmn20-software\\gmsh\gmsh.exe" 71 | 72 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 73 | 74 | # ---- Visualise mesh ------------------------------------------------------- 75 | 76 | # Hold left mouse button to pan. 77 | # Hold right mouse button to zoom. 78 | 79 | # Draw the geometry. 80 | 81 | cfv.figure() 82 | cfv.draw_geometry(g, label_curves=True, title="Example 2 - Geometry") 83 | 84 | # Draws the mesh. 85 | 86 | cfv.figure() 87 | cfv.draw_mesh( 88 | coords=coords, 89 | edof=edof, 90 | dofs_per_node=mesh.dofs_per_node, 91 | el_type=mesh.el_type, 92 | filled=True, 93 | title="Example 2 - Mesh", 94 | ) 95 | 96 | # Enter main loop 97 | 98 | cfv.show_and_wait() 99 | -------------------------------------------------------------------------------- /examples/exm_flow_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # example exm0_mpl.py 4 | # ---------------------------------------------------------------- 5 | # PURPOSE 6 | # Setup a finite element flow model using the mesh functions 7 | # in CALFEM. 8 | # ---------------------------------------------------------------- 9 | # 10 | # REFERENCES 11 | # J Lindemann 2021-12-29 12 | # ---------------------------------------------------------------- 13 | 14 | # ----- Import needed modules ------------------------------------ 15 | 16 | import numpy as np 17 | import calfem.core as cfc 18 | import calfem.geometry as cfg 19 | import calfem.mesh as cfm 20 | import calfem.vis_mpl as cfv 21 | import calfem.utils as cfu 22 | 23 | # ----- Problem parameters --------------------------------------- 24 | 25 | w = 100.0 26 | h = 10.0 27 | t = 1.0 28 | d = h / 2 29 | 30 | D = np.identity(2, "float") 31 | ep = [1.0, 1] 32 | 33 | # ----- Create geometry object ----------------------------------- 34 | 35 | g = cfg.Geometry() 36 | 37 | g.point([0, 0]) # point 1 38 | g.point([w, 0]) # point 2 39 | g.point([w, h]) # point 3 40 | g.point([w - w / 2 + t / 2, h]) # point 4 41 | g.point([w - w / 2 + t / 2, h - d]) # point 5 42 | g.point([w - w / 2 - t / 2, h - d]) # point 6 43 | g.point([w - w / 2 - t / 2, h]) # point 7 44 | g.point([0, h]) # point 8 45 | 46 | # ----- Create lines between points ------------------------------ 47 | 48 | left_side = 80 49 | right_side = 90 50 | 51 | g.spline([0, 1]) 52 | g.spline([1, 2]) 53 | g.spline([2, 3], marker=left_side) # marker just to name 54 | g.spline([3, 4]) 55 | g.spline([4, 5]) 56 | g.spline([5, 6]) 57 | g.spline([6, 7], marker=right_side) 58 | g.spline([7, 0]) 59 | 60 | # ----- Make surface area ---------------------------------------- 61 | 62 | g.surface([0, 1, 2, 3, 4, 5, 6, 7]) 63 | 64 | # ----- Mesh generation ------------------------------------------ 65 | 66 | el_type = 3 # quadrature element 67 | dofs_per_node = 1 # 1 dof 68 | 69 | # ----- Set mesh paramters --------------------------------------- 70 | 71 | mesh = cfm.GmshMesh(g) 72 | mesh.el_size_factor = 1.0 73 | mesh.el_type = el_type 74 | mesh.dofs_per_node = dofs_per_node 75 | 76 | # ----- Create mesh ---------------------------------------------- 77 | 78 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 79 | 80 | # ----- Assemble elements ---------------------------------------- 81 | 82 | nDofs = np.size(dofs) 83 | ex, ey = cfc.coordxtr(edof, coords, dofs) 84 | K = np.zeros([nDofs, nDofs]) 85 | 86 | for eltopo, elx, ely in zip(edof, ex, ey): 87 | Ke = cfc.flw2i4e(elx, ely, ep, D) 88 | cfc.assem(eltopo, K, Ke) 89 | 90 | # ----- Force vector --------------------------------------------- 91 | 92 | f = np.zeros([nDofs, 1]) 93 | 94 | # ----- Boundary conditions -------------------------------------- 95 | 96 | bc = np.array([], int) 97 | bcVal = np.array([], int) 98 | 99 | bc, bcVal = cfu.applybc(bdofs, bc, bcVal, left_side, 0.0) 100 | bc, bcVal = cfu.applybc(bdofs, bc, bcVal, right_side, 10.0) 101 | 102 | # ----- Solve equation system ------------------------------------ 103 | 104 | a, r = cfc.solveq(K, f, bc, bcVal) 105 | ed = cfc.extractEldisp(edof, a) 106 | 107 | # ----- Calculating element forces ------------------------------- 108 | 109 | maxFlow = [] # empty list to store flow 110 | 111 | for i in range(edof.shape[0]): 112 | es, et, eci = cfc.flw2i4s(ex[i, :], ey[i, :], ep, D, ed[i, :]) 113 | maxFlow.append(np.sqrt(pow(es[0, 0], 2) + pow(es[0, 1], 2))) 114 | 115 | # ----- Visualize results ---------------------------------------- 116 | 117 | cfv.figure() 118 | cfv.draw_geometry(g, title="Geometry") 119 | 120 | cfv.figure() 121 | cfv.draw_element_values( 122 | maxFlow, coords, edof, dofs_per_node, el_type, None, title="Max flows" 123 | ) 124 | 125 | cfv.figure() 126 | cfv.draw_nodal_values(a, coords, edof, dofs_per_node=dofs_per_node, el_type=el_type) 127 | 128 | cfv.showAndWait() 129 | -------------------------------------------------------------------------------- /examples/exm_geometry.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Example 01 4 | 5 | Shows how to create simple geometry from splines and ellipse arcs, and how to mesh a quad mesh in GmshMesher. 6 | Also demonstrates drawGeometry(), drawMesh, and drawing texts and labels in a figure. 7 | """ 8 | 9 | import calfem.geometry as cfg 10 | import calfem.mesh as cfm 11 | import calfem.vis_mpl as cfv 12 | 13 | # ---- Define geometry ------------------------------------------------------ 14 | 15 | g = cfg.Geometry() # Create a GeoData object that holds the geometry. 16 | 17 | # Add points: 18 | # The first parameter is the coordinates. These can be in 2D or 3D. 19 | # The other parameters are not defined in this example. These parameters are 20 | # ID, marker, and elSize. 21 | # Since we do not specify an ID the points are automatically assigned IDs, 22 | # starting from 0. 23 | 24 | g.point([0, 0]) 25 | g.point([2, 0]) 26 | g.point([2, 1]) 27 | g.point([0, 1]) 28 | g.point([0.5, 0.3]) 29 | g.point([0.3, 0.7]) 30 | g.point([0.7, 0.7]) 31 | g.point([0.8, 0.5]) 32 | g.point([1.7, 0.5]) 33 | g.point([1.5, 0.5]) 34 | g.point([1.7, 0.7]) 35 | 36 | # Add curves: 37 | # There are four types of curves. In this example we create an ellipse arc 38 | # and some splines. The first parameter is a list of point IDs that define 39 | # the curve. Curves can have have IDs and markers. In this example the IDs 40 | # are undefined so the curves are automatically assigned IDs. The markers can 41 | # be used for identifying regions/boundaries in the model. 42 | 43 | 44 | # 0 - An ellipse arc. Read the function 45 | # doc for more information. The four 46 | # points are 47 | # [start, center, majorAxis, end] 48 | 49 | g.ellipse([7, 8, 9, 10], marker=50) 50 | 51 | g.spline([0, 1], marker=80) # 1 - A spline. Splines pass through the 52 | # points in the first parameter. 53 | g.spline([2, 1]) # 2 54 | g.spline([3, 2]) # 3 55 | g.spline([0, 3]) # 4 56 | g.spline([7, 9], marker=50) # 5 57 | g.spline([10, 9]) # 6 58 | g.spline([4, 5, 6, 4]) # 7 - This is a closed spline. 59 | # The start and end points are the same 60 | 61 | # Add a surface: 62 | # Surfaces are defined by its curve boundaries. 63 | # The first parameter is a list of curve IDs that specify the outer boundary 64 | # of the surface. The second parameter is a list of lists of curve IDs that 65 | # specify holes in the surface. In this example there are two holes. The 66 | # boundaries and holes must be closed paths. We can see that [7] is closed 67 | # because curve 7 is a closed spline. addSurface creates a flat surface, so 68 | # all curves must lie on the same plane. 69 | 70 | g.surface([4, 3, 2, 1], [[7], [5, 6, 0]]) 71 | 72 | # ---- Generate mesh -------------------------------------------------------- 73 | 74 | mesh = cfm.GmshMesh(g) 75 | 76 | # Element type 3 is quad. 77 | # (2 is triangle. See user manual for more element types) 78 | 79 | mesh.el_type = 3 80 | mesh.dofs_per_node = 1 # Degrees of freedom per node. 81 | mesh.el_size_factor = 0.05 # Factor that changes element sizes. 82 | # mesh.mesh_dir = "./mesh_files" 83 | # mesh.gmsh_exec_path = "D:\\vsmn20-software\\gmsh\gmsh.exe" 84 | 85 | # Mesh the geometry: 86 | # 87 | # The first four return values are the same as those that trimesh2d() returns. 88 | # coords is as list of node coordinates. edof is the element topology 89 | # (element degrees of freedom). dofs is a lists of all degrees of freedom 90 | # bdofs is a dictionary of boundary dofs (dofs of geometric entities with 91 | # markers). elementmarkers is a list of markers, and is used for finding the 92 | # marker of a given element (index). 93 | 94 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 95 | 96 | # ---- Visualise mesh ------------------------------------------------------- 97 | 98 | # Hold left mouse button to pan. 99 | # Hold right mouse button to zoom. 100 | 101 | # Draw the geometry. Note that surfaces and volumes are not drawn at all by 102 | # this function. 103 | 104 | cfv.figure() 105 | cfv.draw_geometry(g) 106 | 107 | # Draw the mesh. 108 | 109 | cfv.figure() 110 | cfv.draw_mesh( 111 | coords=coords, 112 | edof=edof, 113 | dofs_per_node=mesh.dofs_per_node, 114 | el_type=mesh.el_type, 115 | filled=True, 116 | title="Example 01", 117 | ) 118 | 119 | # Adds a text in world space 120 | 121 | cfv.text("This is a Text", pos=(1, -0.3), rotation=45) 122 | 123 | # Adds a label in the screen space 124 | 125 | our_label = cfv.label("This is a Label", pos=(1, 0.3), rotation=-45) 126 | 127 | # We can change the attributes of labels and texts, such as color, text, and position. 128 | 129 | our_label.set_text("Label, changed.") 130 | our_label.set_color("r") # Make it red. (1,0,0) would also have worked. 131 | our_label.set_position((1, 0.3)) 132 | 133 | # Enter main loop: 134 | 135 | cfv.show_and_wait() 136 | -------------------------------------------------------------------------------- /examples/exm_qt_vis.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Example illustrating how to integrate CALFEM in a PyQt application 4 | """ 5 | 6 | import sys 7 | import time 8 | 9 | from calfem.qt5 import * 10 | 11 | import calfem.geometry as cfg 12 | import calfem.mesh as cfm 13 | import calfem.vis as cfv 14 | 15 | class MainWindow(QMainWindow): 16 | def __init__(self): 17 | """Constructor""" 18 | super(MainWindow, self).__init__() 19 | 20 | # Load user interface from UI-file 21 | 22 | loadUi('exm_qt_vis.ui', self) 23 | 24 | Figure = cfv.figureClass() 25 | 26 | self.fig1 = Figure(self) 27 | self.fig2 = Figure(self) 28 | 29 | self.gridLayout.addWidget(self.fig1._widget, 0, 0) 30 | self.gridLayout.addWidget(self.fig2._widget, 0, 1) 31 | 32 | print(self.fig1._widget) 33 | 34 | 35 | @Slot() 36 | def on_executeButton_clicked(self): 37 | self.solveProblem() 38 | self.drawGeometry() 39 | self.drawMesh() 40 | 41 | 42 | def solveProblem(self): 43 | 44 | g = cfg.Geometry() #Create a GeoData object that holds the geometry. 45 | 46 | g.point([0, 0]) 47 | g.point([2, 0]) 48 | g.point([2, 1]) 49 | g.point([0, 1]) 50 | g.point([0.5, 0.3]) 51 | g.point([0.3, 0.7]) 52 | g.point([0.7, 0.7]) 53 | g.point([0.8, 0.5]) 54 | g.point([1.7, 0.5]) 55 | g.point([1.5, 0.5]) 56 | g.point([1.7, 0.7]) 57 | 58 | g.ellipse([7,8,9,10], marker=50) # 0 - An ellipse arc. Read the function 59 | g.spline([0, 1], marker=80) # 1 - A spline. Splines pass through the 60 | g.spline([2, 1]) # 2 61 | g.spline([3, 2]) # 3 62 | g.spline([0, 3]) # 4 63 | g.spline([7, 9], marker=50) # 5 64 | g.spline([10, 9]) # 6 65 | g.spline([4, 5, 6, 4]) # 7 - This is a closed spline. 66 | 67 | g.surface([4,3,2,1], [[7], [5,6,0]]) 68 | 69 | meshGen = cfm.GmshMeshGenerator(g) 70 | 71 | meshGen.elType = 3 # Degrees of freedom per node. 72 | meshGen.dofsPerNode = 1 # Factor that changes element sizes. 73 | meshGen.elSizeFactor = 0.05 74 | 75 | self.coords, self.edof, self.dofs, self.bdofs, self.elementmarkers = meshGen.create() 76 | self.meshGen = meshGen 77 | self.g = g 78 | 79 | def drawGeometry(self): 80 | cfv.figure(self.fig1.nr) 81 | cfv.clf() 82 | cfv.drawGeometry(self.g) 83 | 84 | def drawMesh(self): 85 | cfv.figure(self.fig2.nr) 86 | cfv.clf() 87 | cfv.draw_mesh( 88 | coords=self.coords, 89 | edof=self.edof, 90 | dofs_per_node=self.meshGen.dofsPerNode, 91 | el_type=self.meshGen.elType, 92 | filled=True, 93 | title="Example 01" 94 | ) 95 | 96 | cfv.addText("This is a Text", pos=(1, -0.3), angle=45) #Adds a text in world space 97 | 98 | ourLabel = cfv.label("This is a Label", pos=(100,200), angle=-45) #Adds a label in the screen space 99 | ourLabel.text = "Label, changed." #We can change the attributes of labels and texts, such as color, text, and position. 100 | ourLabel.textColor = 'r' #Make it red. (1,0,0) would also have worked. 101 | ourLabel.position = (20,30) 102 | 103 | 104 | if __name__ == "__main__": 105 | 106 | app = QApplication(sys.argv) 107 | widget = MainWindow() 108 | widget.show() 109 | sys.exit(app.exec_()) 110 | -------------------------------------------------------------------------------- /examples/exm_qt_vis.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 806 10 | 559 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | 27 | 28 | 16777215 29 | 50 30 | 31 | 32 | 33 | QFrame::StyledPanel 34 | 35 | 36 | QFrame::Raised 37 | 38 | 39 | 40 | 41 | 42 | Execute 43 | 44 | 45 | 46 | 47 | 48 | 49 | Qt::Horizontal 50 | 51 | 52 | 53 | 40 54 | 20 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 0 71 | 0 72 | 806 73 | 21 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /examples/exm_stress_2d_qt.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 806 10 | 559 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | 27 | 28 | 16777215 29 | 50 30 | 31 | 32 | 33 | QFrame::StyledPanel 34 | 35 | 36 | QFrame::Raised 37 | 38 | 39 | 40 | 41 | 42 | Execute 43 | 44 | 45 | 46 | 47 | 48 | 49 | Qt::Horizontal 50 | 51 | 52 | 53 | 40 54 | 20 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 0 71 | 0 72 | 806 73 | 21 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /examples/exm_structured_mesh.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Example 04. 4 | 5 | Structured 3D meshing. Adding texts and labels to figures. Altering axis properties. 6 | """ 7 | 8 | import calfem.geometry as cfg 9 | import calfem.mesh as cfm 10 | import calfem.vis_mpl as cfv 11 | 12 | # ---- Define geometry ------------------------------------------------------ 13 | 14 | g = cfg.geometry() 15 | 16 | # Add Points 17 | 18 | g.point([0, 0, 0], ID=0) 19 | g.point([0.5, -0.3, -0.3], 1) 20 | g.point([1, 0, 0], 2) 21 | g.point([1, 1, 0], 3) 22 | g.point([0, 1, 0], 4, marker=11) # Set some markers no reason. 23 | g.point([0, 0, 1], 5, marker=11) # (markers can be given to points as well 24 | # as curves and surfaces) 25 | g.point([1, 0, 1], 6, marker=11) 26 | g.point([1, 1, 1], 7) 27 | g.point([0, 1, 1], 8) 28 | 29 | # Add splines 30 | 31 | g.spline([0, 1, 2], 0, marker=33, el_on_curve=5) 32 | g.spline([2, 3], 1, marker=23, el_on_curve=5) 33 | g.spline([3, 4], 2, marker=23, el_on_curve=5) 34 | g.spline([4, 0], 3, el_on_curve=5) 35 | g.spline([0, 5], 4, el_on_curve=5) 36 | g.spline([2, 6], 5, el_on_curve=5) 37 | g.spline([3, 7], 6, el_on_curve=5) 38 | g.spline([4, 8], 7, el_on_curve=5) 39 | g.spline([5, 6], 8, el_on_curve=5) 40 | g.spline([6, 7], 9, el_on_curve=5) 41 | g.spline([7, 8], 10, el_on_curve=5) 42 | g.spline([8, 5], 11, el_on_curve=5) 43 | 44 | # Add surfaces 45 | 46 | g.structuredSurface([0, 1, 2, 3], 0, marker=45) 47 | g.structuredSurface([8, 9, 10, 11], 1) 48 | g.structuredSurface([0, 4, 8, 5], 2, marker=55) 49 | g.structuredSurface([1, 5, 9, 6], 3, marker=55) 50 | g.structuredSurface([2, 6, 10, 7], 4) 51 | g.structuredSurface([3, 4, 11, 7], 5) 52 | 53 | # Add Volume: 54 | # addStructuredVolume() takes three args. The first is a list of surface IDs 55 | # (structured surfaces). The surfaces should make a hexahedron 56 | # (i.e. 6 surfaces). Other kinds of structured volumes than hexahedra will 57 | # not work for hexahedral elements, which is the only type of 3D element that 58 | # CALFEM handles. The two optional parameters are the volume ID and 59 | # volume marker. 60 | 61 | g.structuredVolume([0, 1, 2, 3, 4, 5], 0, marker=90) 62 | 63 | # ---- Create mesh ---------------------------------------------------------- 64 | 65 | # Element type 5 is hexahedron. (See user manual for more element types) 66 | el_type = 5 # error here, element type not implemented 67 | 68 | # Degrees of freedom per node. 69 | dofs_per_node = 1 70 | 71 | # Create mesh 72 | coords, edof, dofs, bdofs, _ = cfm.mesh(g, el_type, dofs_per_node) 73 | 74 | # coords, edof, dofs, bdofs, _ = cfm.mesh( 75 | # g, el_type, dofs_per_node, 76 | # gmsh_exec_path="D:\\vsmn20-software\\gmsh\gmsh.exe") 77 | 78 | # ---- Visualise mesh ------------------------------------------------------- 79 | 80 | # Hold Left Mouse button to rotate. 81 | # Hold right mouse button to zoom. 82 | # Hold SHIFT and left mouse button to pan. 83 | # Hold SHIFT and right mouse button to change the field of view. 84 | # Hold Ctrl and left mouse button to roll the camera. 85 | 86 | # Draw geometry 87 | 88 | cfv.draw_geometry(g, draw_points=False) 89 | 90 | # Draw mesh 91 | 92 | cfv.figure() 93 | cfv.draw_mesh( 94 | coords=coords, edof=edof, dofs_per_node=dofs_per_node, el_type=el_type, filled=True 95 | ) 96 | 97 | # Add a text in world space 98 | 99 | # cfv.add_text("This is a Text", pos=(1, 0.5, 0.5), angle=45) 100 | 101 | # Add a label in the screen space 102 | 103 | # our_label = cfv.add_label("This is a Label", pos=(20,30), angle=-45) 104 | 105 | # We can change the attributes of labels and texts, such as color and position. 106 | 107 | # our_label.text = "Label, changed." 108 | 109 | # Make it red. (1,0,0) would also have worked. 110 | 111 | # our_label.textColor = 'r' 112 | 113 | # Matlab style axes (three axes in the background instead of a cube) 114 | 115 | # cfv.gca().axis.showBox = 0 116 | 117 | # Change the limits of the axes. 118 | 119 | # cfv.gca().SetLimits(rangeX=(0,2), rangeY=(-1,1.5), rangeZ=(-0.5,2), margin=0.02) 120 | 121 | # Enter main loop 122 | 123 | cfv.show_and_wait() 124 | -------------------------------------------------------------------------------- /examples/exm_structured_mesh_3d.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Example 04. 4 | 5 | Structured 3D meshing. Adding texts and labels to figures. Altering axis properties. 6 | """ 7 | 8 | import calfem.geometry as cfg 9 | import calfem.mesh as cfm 10 | import calfem.vis_vtk as cfv 11 | 12 | # ---- Define geometry ------------------------------------------------------ 13 | 14 | g = cfg.geometry() 15 | 16 | # Add Points 17 | 18 | g.point([0, 0, 0], ID=0) 19 | g.point([0.5, -0.3, -0.3], 1) 20 | g.point([1, 0, 0], 2) 21 | g.point([1, 1, 0], 3) 22 | g.point([0, 1, 0], 4, marker=11) # Set some markers no reason. 23 | g.point([0, 0, 1], 5, marker=11) # (markers can be given to points as well 24 | # as curves and surfaces) 25 | g.point([1, 0, 1], 6, marker=11) 26 | g.point([1, 1, 1], 7) 27 | g.point([0, 1, 1], 8) 28 | 29 | # Add splines 30 | 31 | g.spline([0, 1, 2], 0, marker=33, el_on_curve=5) 32 | g.spline([2, 3], 1, marker=23, el_on_curve=5) 33 | g.spline([3, 4], 2, marker=23, el_on_curve=5) 34 | g.spline([4, 0], 3, el_on_curve=5) 35 | g.spline([0, 5], 4, el_on_curve=5) 36 | g.spline([2, 6], 5, el_on_curve=5) 37 | g.spline([3, 7], 6, el_on_curve=5) 38 | g.spline([4, 8], 7, el_on_curve=5) 39 | g.spline([5, 6], 8, el_on_curve=5) 40 | g.spline([6, 7], 9, el_on_curve=5) 41 | g.spline([7, 8], 10, el_on_curve=5) 42 | g.spline([8, 5], 11, el_on_curve=5) 43 | 44 | # Add surfaces 45 | 46 | g.structuredSurface([0, 1, 2, 3], 0, marker=45) 47 | g.structuredSurface([8, 9, 10, 11], 1) 48 | g.structuredSurface([0, 4, 8, 5], 2, marker=55) 49 | g.structuredSurface([1, 5, 9, 6], 3, marker=55) 50 | g.structuredSurface([2, 6, 10, 7], 4) 51 | g.structuredSurface([3, 4, 11, 7], 5) 52 | 53 | # Add Volume: 54 | # addStructuredVolume() takes three args. The first is a list of surface IDs 55 | # (structured surfaces). The surfaces should make a hexahedron 56 | # (i.e. 6 surfaces). Other kinds of structured volumes than hexahedra will 57 | # not work for hexahedral elements, which is the only type of 3D element that 58 | # CALFEM handles. The two optional parameters are the volume ID and 59 | # volume marker. 60 | 61 | g.structuredVolume([0, 1, 2, 3, 4, 5], 0, marker=90) 62 | 63 | # ---- Create mesh ---------------------------------------------------------- 64 | 65 | # Element type 5 is hexahedron. (See user manual for more element types) 66 | 67 | el_type = 5 68 | 69 | # Degrees of freedom per node. 70 | 71 | dofs_per_node = 1 72 | 73 | # Create mesh 74 | 75 | coords, edof, dofs, bdofs, _ = cfm.mesh(g, el_type, 1, dofs_per_node) 76 | 77 | # coords, edof, dofs, bdofs, _ = cfm.mesh( 78 | # g, el_type, dofs_per_node, gmsh_exec_path="D:\\vsmn20-software\\gmsh\gmsh.exe") 79 | 80 | # ---- Visualise mesh ------------------------------------------------------- 81 | 82 | cfv.draw_mesh(coords, edof, el_type) 83 | -------------------------------------------------------------------------------- /examples/exm_structured_mesh_vtk.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Example 03 4 | 5 | Shows structured meshing in 2D. 6 | """ 7 | 8 | import calfem.geometry as cfg 9 | import calfem.mesh as cfm 10 | import calfem.vis_mpl as cfv 11 | 12 | # ---- Define geometry ------------------------------------------------------ 13 | 14 | g = cfg.Geometry() 15 | 16 | # Add Points: 17 | 18 | g.point([0, 0]) 19 | g.point([1.2, 0]) 20 | g.point([1, 1.3]) 21 | g.point([0, 1]) 22 | g.point([2, 0.5]) 23 | 24 | # Add Splines: 25 | # The first four curves are structured curves, i.e the number of nodes along 26 | # the curves is pre-determined. Parameter el_on_curve states how many elements 27 | # are placed along the curve. Parameters el_distrib_type and el_distrib_val are 28 | # optional parameters that specify how elements are distributed. 29 | # "bump" means elements are bunched up at the ends or the middle of the curve. 30 | # In this case el_distrib_val is smaller than 1, so elements crowd at the edges. 31 | # "progression" means each element along the curve is larger/smaller than the previous one. 32 | # A larger el_distrib_val makes the elements larger at the end of the curves. 33 | 34 | g.spline([0, 1], el_on_curve=10, el_distrib_type="bump", el_distrib_val=0.2) 35 | g.spline([1, 2], el_on_curve=20, el_distrib_type="progression", el_distrib_val=1.1) 36 | g.spline([2, 3], el_on_curve=10, el_distrib_type="bump", el_distrib_val=0.2) 37 | g.spline( 38 | [0, 3], el_on_curve=20, el_distrib_type="progression", el_distrib_val=1.1 39 | ) # Change order of points to reverse progression distribution 40 | g.spline([2, 4, 1]) 41 | 42 | # Add Surfaces: 43 | # A structured surface must contain 4 curves that have the parameter 'el_on_curve' 44 | # defined. The number of elements on two opposite curves must be the same 45 | # (In this case, curves 0 & 2 and 1 & 3). 46 | 47 | g.structuredSurface([0, 1, 2, 3]) 48 | g.surface([4, 1]) 49 | 50 | # ---- Create mesh ---------------------------------------------------------- 51 | 52 | mesh = cfm.GmshMesh(g) 53 | 54 | # Element type 3 is quad. (2 is triangle. See user manual for more element types) 55 | 56 | mesh.el_type = 3 57 | 58 | # Degrees of freedom per node. 59 | 60 | mesh.dofs_per_node = 1 61 | mesh.el_size_factor = 0.01 62 | 63 | # mesh.gmsh_exec_path = "D:\\vsmn20-software\\gmsh\gmsh.exe" 64 | 65 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 66 | 67 | # ---- Visualise mesh ------------------------------------------------------- 68 | 69 | # Draw geometry 70 | 71 | cfv.draw_geometry(g) 72 | 73 | # Draw mesh 74 | 75 | cfv.figure() 76 | cfv.draw_mesh( 77 | coords, edof, dofs_per_node=mesh.dofs_per_node, el_type=mesh.el_type, filled=True 78 | ) 79 | 80 | # Enter main loop 81 | 82 | cfv.show_and_wait() 83 | -------------------------------------------------------------------------------- /examples/exm_temp_2d_markers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Example 07 4 | 5 | Meshing 8-node-isoparametric elements (second order incomplete quads). 6 | Shows use of surfacemarkers/elementmarkers to apply different properties to 7 | elements in different regions. 8 | """ 9 | 10 | import calfem.geometry as cfg 11 | import calfem.mesh as cfm 12 | import calfem.vis_mpl as cfv 13 | import calfem.utils as cfu 14 | import calfem.core as cfc 15 | 16 | import matplotlib.pyplot as plt 17 | import matplotlib as mpl 18 | import matplotlib.tri as tri 19 | 20 | import numpy as np 21 | 22 | # ---- Problem constants ---------------------------------------------------- 23 | 24 | kx1 = 100 25 | ky1 = 100 26 | kx2 = 10 27 | ky2 = 10 28 | t = 1.0 29 | 30 | # Gauss points or integration points 31 | 32 | n = 2 33 | ep = [t, n] 34 | 35 | D1 = np.matrix([[kx1, 0.0], [0.0, ky1]]) 36 | D2 = np.matrix([[kx2, 0.0], [0.0, ky2]]) 37 | 38 | # markers 10 & 11 will be used to specify different regions with different 39 | # conductivity. 40 | 41 | Ddict = {10: D1, 11: D2} 42 | 43 | # ---- Create Geometry ------------------------------------------------------ 44 | 45 | g = cfg.geometry() 46 | 47 | # Add Points: 48 | 49 | points = [[0, 0], [0, 100], [0, 150], [100, 0], [150, 0], [100, -100], [150, -100]] 50 | 51 | for p in points: 52 | g.point(p) 53 | 54 | # Add Splines: 55 | 56 | g.spline([1, 2], marker=2, el_on_curve=4) 57 | g.spline([3, 4], el_on_curve=4) 58 | g.circle([1, 0, 3], el_on_curve=10) 59 | g.circle([2, 0, 4], el_on_curve=10) 60 | g.spline([3, 5], el_on_curve=6) 61 | g.spline([5, 6], marker=3, el_on_curve=4) 62 | g.spline([6, 4], el_on_curve=6) 63 | 64 | # Add Surfaces: 65 | # 66 | # When we set markers for surfaces, and have 2D elements, we can find which 67 | # region an element is in via the list 'elementmarkers', which is returned by 68 | # GmshMesher.create() 69 | 70 | g.structuredSurface([0, 2, 1, 3], marker=10) 71 | g.structuredSurface([1, 4, 5, 6], marker=11) 72 | 73 | # Element type 16 is 8-node-quad. (See gmsh manual for more element types) 74 | 75 | el_type = 16 76 | 77 | # Degrees of freedom per node. 78 | 79 | dofs_per_node = 1 80 | 81 | # ---- Generate mesh -------------------------------------------------------- 82 | 83 | # gmshExecPath = Path to gmsh.exe. 84 | # If None then the system PATH variable is queried. 85 | # Relative and absolute paths work. 86 | 87 | mesh = cfm.GmshMeshGenerator(g, el_type, dofs_per_node) 88 | 89 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 90 | 91 | # ---- Solve problem -------------------------------------------------------- 92 | 93 | print("Assembling system matrix...") 94 | 95 | n_dofs = np.size(dofs) 96 | ex, ey = cfc.coordxtr(edof, coords, dofs) 97 | 98 | K = np.zeros([n_dofs, n_dofs]) 99 | 100 | for eltopo, elx, ely, elMarker in zip(edof, ex, ey, elementmarkers): 101 | # Calc element stiffness matrix: Conductivity matrix D is taken 102 | # from Ddict and depends on which region (which marker) the element is in. 103 | 104 | Ke = cfc.flw2i8e(elx, ely, ep, Ddict[elMarker]) 105 | cfc.assem(eltopo, K, Ke) 106 | 107 | print("Solving equation system...") 108 | 109 | f = np.zeros([n_dofs, 1]) 110 | 111 | bc = np.array([], "i") 112 | bc_val = np.array([], "i") 113 | 114 | bc, bc_val = cfu.applybc(bdofs, bc, bc_val, 2, 30.0) 115 | bc, bc_val = cfu.applybc(bdofs, bc, bc_val, 3, 0.0) 116 | 117 | a, r = cfc.solveq(K, f, bc, bc_val) 118 | 119 | # ---- Compute element forces ----------------------------------------------- 120 | 121 | print("Computing element forces...") 122 | 123 | ed = cfc.extractEldisp(edof, a) 124 | 125 | for i in range(np.shape(ex)[0]): 126 | es, et, eci = cfc.flw2i8s( 127 | ex[i, :], ey[i, :], ep, Ddict[elementmarkers[i]], ed[i, :] 128 | ) 129 | 130 | # Do something with es, et, eci here. 131 | 132 | # ---- Visualise results ---------------------------------------------------- 133 | 134 | print("Visualising...") 135 | 136 | cfv.figure() 137 | cfv.draw_geometry(g, title="Geometry") 138 | 139 | # 8-node quads are drawn as simple quads. 140 | 141 | cfv.figure() 142 | cfv.draw_mesh(coords, edof, dofs_per_node, el_type, filled=False) 143 | 144 | cfv.figure() 145 | cfv.draw_nodal_values_shaded( 146 | a, 147 | coords, 148 | edof, 149 | title="Temperature", 150 | dofs_per_node=mesh.dofs_per_node, 151 | el_type=mesh.el_type, 152 | draw_elements=True, 153 | ) 154 | cbar = cfv.colorbar(orientation="vertical") 155 | cbar.set_label("Temperature") 156 | 157 | 158 | cfv.text("The bend has high conductivity", (75, 130)) 159 | cfv.text("This part has low conductivity", (20, -90)) 160 | 161 | # Enter main loop 162 | 163 | cfv.show_and_wait() 164 | 165 | print("Done.") 166 | -------------------------------------------------------------------------------- /examples/exm_tet_mesh.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Example 05 4 | 5 | This example shows how to make an unstructured 3D mesh (tetrahedron elements, which calfem cant actually use). 6 | It also demonstrates how to do subplots and create two axes that are viewed from the same camera. 7 | """ 8 | 9 | import calfem.geometry as cfg 10 | import calfem.mesh as cfm 11 | import calfem.vis as cfv 12 | 13 | # ---- Define geometry ------------------------------------------------------ 14 | 15 | g = cfg.geometry() 16 | 17 | g.point([0, 0, 0], 0) 18 | g.point([1, 0, 0], 1) 19 | g.point([0, 1, 0], 2) 20 | g.point([0, 1, 1], 3, el_size=0.1) 21 | g.point([0.5, -0.3, 0], 4) 22 | g.point([-0.3, 0.5, 0], 5) 23 | g.point([0.75, 0.75, 0], 6) 24 | 25 | g.spline([0, 4, 1]) 26 | g.spline([1, 6, 2]) 27 | g.spline([2, 5, 0]) 28 | g.spline([0, 3]) 29 | g.spline([3, 2]) 30 | g.spline([3, 1]) 31 | 32 | g.ruledSurface([0, 1, 2]) 33 | g.ruledSurface([0, 5, 3]) 34 | g.ruledSurface([1, 5, 4]) 35 | g.ruledSurface([2, 3, 4]) 36 | 37 | g.volume([0, 1, 2, 3]) 38 | 39 | # ---- Create mesh ---------------------------------------------------------- 40 | 41 | # Element type 4 is tetrahedron. (See user manual for more element types). 42 | 43 | el_type = 4 44 | 45 | # Degrees of freedom per node. 46 | 47 | dofs_per_node = 1 48 | 49 | # Create mesh 50 | 51 | coords, edof, dofs, bdofs, elementmarkers = cfm.mesh(g, el_type, 0.3, dofs_per_node) 52 | 53 | # coords, edof, dofs, bdofs, _ = cfm.mesh( 54 | # g, el_type, 0.3, dofs_per_node, gmsh_exec_path="D:\\vsmn20-software\\gmsh\gmsh.exe") 55 | 56 | 57 | # ---- Visualise mesh ------------------------------------------------------- 58 | 59 | # Create two axes that are viewed from the same camera: 60 | 61 | cfv.figure() 62 | a1 = cfv.subplot(121) 63 | a2 = cfv.subplot(122) 64 | cam = cfv.camera3d() 65 | a1.camera = a2.camera = cam 66 | 67 | # Draw geometry and mesh 68 | 69 | cfv.draw_geometry(g, axes=a1) 70 | cfv.draw_mesh( 71 | coords=coords, 72 | edof=edof, 73 | dofs_per_node=dofs_per_node, 74 | el_type=el_type, 75 | filled=False, 76 | axes=a2, 77 | ) 78 | 79 | # Enter main loop 80 | 81 | cfv.show_and_wait() 82 | -------------------------------------------------------------------------------- /examples/exm_tet_mesh_vtk.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """Example 05 4 | 5 | This example shows how to make an unstructured 3D mesh (tetrahedron elements, which calfem cant actually use). 6 | It also demonstrates how to do subplots and create two axes that are viewed from the same camera. 7 | """ 8 | 9 | import calfem.geometry as cfg 10 | import calfem.mesh as cfm 11 | import calfem.vis_vtk as cfv 12 | 13 | import vtk 14 | 15 | # ---- Define geometry ------------------------------------------------------ 16 | 17 | g = cfg.geometry() 18 | 19 | g.point([0, 0, 0], 0) 20 | g.point([1, 0, 0], 1) 21 | g.point([0, 1, 0], 2) 22 | g.point([0, 1, 1], 3, el_size=0.1) 23 | g.point([0.5, -0.3, 0], 4) 24 | g.point([-0.3, 0.5, 0], 5) 25 | g.point([0.75, 0.75, 0], 6) 26 | 27 | g.spline([0, 4, 1]) 28 | g.spline([1, 6, 2]) 29 | g.spline([2, 5, 0]) 30 | g.spline([0, 3]) 31 | g.spline([3, 2]) 32 | g.spline([3, 1]) 33 | 34 | g.ruled_surface([0, 1, 2]) 35 | g.ruled_surface([0, 5, 3]) 36 | g.ruled_surface([1, 5, 4]) 37 | g.ruled_surface([2, 3, 4]) 38 | 39 | g.volume([0, 1, 2, 3]) 40 | 41 | # ---- Create mesh ---------------------------------------------------------- 42 | 43 | # Element type 4 is tetrahedron. (See user manual for more element types). 44 | 45 | el_type = 4 46 | 47 | # Degrees of freedom per node. 48 | 49 | dofs_per_node = 1 50 | 51 | # Create mesh 52 | 53 | coords, edof, dofs, bdofs, elementmarkers = cfm.mesh(g, el_type, 0.3, dofs_per_node) 54 | 55 | # coords, edof, dofs, bdofs, _ = cfm.mesh( 56 | # g, el_type, 0.3, dofs_per_node, gmsh_exec_path="D:\\vsmn20-software\\gmsh\gmsh.exe") 57 | 58 | 59 | # ---- Visualise mesh ------------------------------------------------------- 60 | 61 | cfv.draw_mesh(coords, edof, el_type) 62 | -------------------------------------------------------------------------------- /examples/exm_tutorial_1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Mar 3 22:08:29 2018 4 | 5 | @author: Jonas Lindemann 6 | """ 7 | 8 | import calfem.geometry as cfg 9 | import calfem.mesh as cfm 10 | import calfem.vis_mpl as cfv 11 | 12 | # ----- Define geometry 13 | 14 | g = cfg.Geometry() 15 | 16 | g.point([0.0, 0.0]) # point 0 17 | g.point([5.0, 0.0], marker=20) # point 1 18 | g.point([2.5, 4.0]) # point 2 19 | 20 | g.spline([0, 1]) # line 0 21 | g.spline([1, 2]) # line 1 22 | g.spline([2, 0], marker=10) # line 2 23 | 24 | g.surface([0, 1, 2]) 25 | 26 | # ----- Create mesh 27 | 28 | mesh = cfm.GmshMesh(g) 29 | 30 | mesh.el_type = 2 # Degrees of freedom per node. 31 | mesh.dofs_per_node = 1 # Factor that changes element sizes. 32 | mesh.el_size_factor = 0.15 33 | 34 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 35 | 36 | print(bdofs) 37 | 38 | cfv.figure() 39 | cfv.draw_geometry(g) 40 | 41 | # ----- Draw the mesh. 42 | 43 | cfv.figure() 44 | cfv.draw_mesh( 45 | coords=coords, 46 | edof=edof, 47 | dofs_per_node=mesh.dofsPerNode, 48 | el_type=mesh.elType, 49 | filled=True, 50 | title="Example 01", 51 | ) 52 | 53 | cfv.showAndWait() 54 | -------------------------------------------------------------------------------- /examples/exm_tutorial_2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sat Mar 3 22:08:29 2018 4 | 5 | @author: Jonas Lindemann 6 | """ 7 | 8 | import calfem.core as cfc 9 | import calfem.geometry as cfg 10 | import calfem.mesh as cfm 11 | import calfem.vis_mpl as cfv 12 | import calfem.utils as cfu 13 | 14 | import numpy as np 15 | from math import * 16 | 17 | # ----- Problem parameters 18 | 19 | l = 5.0 20 | h = 1.0 21 | t = 0.2 22 | 23 | v = 0.35 24 | E = 2.1e9 25 | ptype = 1 26 | ep = [ptype, t] 27 | D = cfc.hooke(ptype, E, v) 28 | 29 | left_support = 10 30 | right_support = 20 31 | top_line = 30 32 | 33 | # ----- Define geometry 34 | 35 | g = cfg.Geometry() 36 | 37 | g.point([0.0, 0.0], marker=left_support) # point 0 38 | g.point([l, 0.0], marker=right_support) # point 1 39 | g.point([l, h]) # point 2 40 | g.point([0.0, h]) # point 2 41 | 42 | g.spline([0, 1]) # line 0 43 | g.spline([1, 2]) # line 1 44 | g.spline([2, 3], marker=top_line) # line 2 45 | g.spline([3, 0]) # line 2 46 | 47 | g.surface([0, 1, 2, 3]) 48 | 49 | # ----- Create mesh 50 | 51 | mesh = cfm.GmshMesh(g) 52 | 53 | mesh.el_type = 3 # Degrees of freedom per node. 54 | mesh.dofs_per_node = 2 # Factor that changes element sizes. 55 | mesh.el_size_factor = 0.10 56 | 57 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 58 | 59 | # ----- Solve problem 60 | 61 | nDofs = np.size(dofs) 62 | ex, ey = cfc.coordxtr(edof, coords, dofs) 63 | 64 | K = np.zeros([nDofs, nDofs]) 65 | 66 | for eltopo, elx, ely in zip(edof, ex, ey): 67 | Ke = cfc.planqe(elx, ely, ep, D) 68 | cfc.assem(eltopo, K, Ke) 69 | 70 | bc = np.array([], "i") 71 | bcVal = np.array([], "f") 72 | 73 | bc, bcVal = cfu.applybc(bdofs, bc, bcVal, left_support, 0.0, 0) 74 | bc, bcVal = cfu.applybc(bdofs, bc, bcVal, right_support, 0.0, 2) 75 | 76 | f = np.zeros([nDofs, 1]) 77 | 78 | cfu.applyforcetotal(bdofs, f, top_line, -10e5, 2) 79 | 80 | a, r = cfc.solveq(K, f, bc, bcVal) 81 | 82 | ed = cfc.extract_eldisp(edof, a) 83 | vonMises = [] 84 | 85 | for i in range(edof.shape[0]): 86 | es, et = cfc.planqs(ex[i, :], ey[i, :], ep, D, ed[i, :]) 87 | vonMises.append(sqrt(pow(es[0], 2) - es[0] * es[1] + pow(es[1], 2) + 3 * es[2])) 88 | 89 | # ----- Draw geometry 90 | 91 | cfv.figure() 92 | cfv.draw_geometry(g) 93 | 94 | # ----- Draw the mesh. 95 | 96 | cfv.figure() 97 | cfv.draw_mesh( 98 | coords=coords, 99 | edof=edof, 100 | dofs_per_node=mesh.dofs_per_node, 101 | el_type=mesh.el_type, 102 | filled=True, 103 | title="Example 01", 104 | ) 105 | 106 | # ----- Draw results 107 | 108 | cfv.figure() 109 | cfv.draw_element_values( 110 | vonMises, 111 | coords, 112 | edof, 113 | mesh.dofs_per_node, 114 | mesh.el_type, 115 | a, 116 | draw_elements=True, 117 | draw_undisplaced_mesh=False, 118 | title="Example 06 effective stress", 119 | ) 120 | 121 | cfv.figure() 122 | cfv.draw_displacements( 123 | a, 124 | coords, 125 | edof, 126 | mesh.dofs_per_node, 127 | mesh.el_type, 128 | draw_undisplaced_mesh=True, 129 | title="Example 06", 130 | magnfac=10.0, 131 | ) 132 | 133 | cfv.showAndWait() 134 | -------------------------------------------------------------------------------- /examples/exn_bar2g.py: -------------------------------------------------------------------------------- 1 | # example exn_bar2g 2 | # -------------------------------------------------------------------------- 3 | # PURPOSE 4 | # Analysis of a plane truss using second order theory. 5 | # -------------------------------------------------------------------------- 6 | 7 | import numpy as np 8 | import calfem.core as cfc 9 | import calfem.utils as cfu 10 | 11 | # ----- Topology ----- 12 | 13 | edof = np.array([[1, 2, 5, 6], [3, 4, 5, 6]]) 14 | 15 | # ----- Element properties and global coordinates ------------------------- 16 | 17 | E = 10e9 18 | A1 = 4e-2 19 | A2 = 1e-2 20 | ep1 = np.array([E, A1]) 21 | ep2 = np.array([E, A2]) 22 | 23 | ex1 = np.array([0.0, 1.6]) 24 | ey1 = np.array([0.0, 0.0]) 25 | ex2 = np.array([0.0, 1.6]) 26 | ey2 = np.array([1.2, 0]) 27 | 28 | # ----- Initial values for the iteration ---------------------------------- 29 | 30 | eps = 1e-6 # Error norm 31 | QX1 = 0.01 32 | QX2 = 0 33 | # Initial axial forces 34 | QX01 = 1 # Axial force of the initial former iteration 35 | n = 0 # Iteration counter 36 | 37 | # ----- Iteration procedure ----------------------------------------------- 38 | while abs((QX1 - QX01) / QX01) > eps: 39 | n += 1 40 | 41 | K = np.zeros((6, 6)) 42 | f = np.zeros((6, 1)) 43 | f[4] = -10e6 44 | f[5] = -0.2e6 45 | 46 | Ke1 = cfc.bar2ge(ex1, ey1, ep1, QX1) 47 | Ke2 = cfc.bar2ge(ex2, ey2, ep2, QX2) 48 | K = cfc.assem(edof[0, :], K, Ke1) 49 | K = cfc.assem(edof[1, :], K, Ke2) 50 | bc = np.array([1, 2, 3, 4]) 51 | a, r = cfc.solveq(K, f, bc) 52 | 53 | Ed = cfc.extract_ed(edof, a) 54 | 55 | QX01 = QX1 56 | es1, QX1 = cfc.bar2gs(ex1, ey1, ep1, Ed[0, :]) 57 | es2, QX2 = cfc.bar2gs(ex2, ey2, ep2, Ed[1, :]) 58 | 59 | if n > 20: 60 | print("The solution does not converge") 61 | break 62 | 63 | # ----- Results ----------------------------------------------- 64 | 65 | cfu.disp_h1("Displacements:") 66 | cfu.disp_array(a) 67 | cfu.disp_h1("Normal forces:") 68 | cfu.disp(QX1) 69 | cfu.disp(QX2) 70 | -------------------------------------------------------------------------------- /examples/exn_bar2m.py: -------------------------------------------------------------------------------- 1 | # example exn_bar2m 2 | # -------------------------------------------------------------------------- 3 | # PURPOSE 4 | # Analysis of a plane truss considering material nonlinearity. 5 | # -------------------------------------------------------------------------- 6 | 7 | import numpy as np 8 | import calfem.core as cfc 9 | import calfem.utils as cfu 10 | import calfem.vis_mpl as cfv 11 | 12 | edof = np.array([ 13 | [1, 2, 5, 6], 14 | [5, 6, 7, 8], 15 | [3, 4, 5, 6] 16 | ]) 17 | 18 | bc = np.array([1, 2, 3, 4, 7, 8]) 19 | 20 | ex = np.array([ 21 | [0.0, 1.6], 22 | [1.6, 1.6], 23 | [0.0, 1.6] 24 | ]) 25 | 26 | ey = np.array([[0.0, 0.0], [0.0, 1.2], [1.2, 0.0]]) 27 | 28 | E = np.array([200e9, 200e9, 200e9]) 29 | A = np.array([6.0e-4, 3.0e-4, 10.0e-4]) 30 | SY = 400e6 31 | Ns = (SY * A).reshape(-1, 1) 32 | 33 | dp = 4e3 34 | 35 | incr = 100 36 | 37 | a = np.zeros((8, 1)) 38 | r = np.zeros((8, 1)) 39 | es = np.zeros((3, 1)) 40 | 41 | plbar = 0 42 | pl = np.array([0.0, 0.0]) 43 | 44 | # Forward Euler increamental solution 45 | 46 | for i in range(incr): 47 | K = np.zeros((8, 8)) 48 | df = np.zeros((8, 1)) 49 | df[5] = -dp 50 | 51 | # Create and assemble element tangent stiffness matrix 52 | 53 | for j in range(3): 54 | ep = np.array([E[j], A[j]]) 55 | Ke = cfc.bar2e(ex[j, :], ey[j, :], ep) 56 | K = cfc.assem(edof[j, :], K, Ke) 57 | 58 | # Stop iteration if determinant det(Kr) <= 0 59 | 60 | fdof = np.setdiff1d(np.arange(1, 9), bc) - 1 61 | Kr = K[np.ix_(fdof, fdof)] 62 | if np.linalg.det(Kr) <= 0: 63 | print("Determinant zero after increment ", i) 64 | break 65 | 66 | # Solve for the displacement increment and determine total displacements 67 | 68 | da, dr = cfc.solveq(K, df, bc) 69 | a += da 70 | r += dr 71 | 72 | # Determine normal forces in elements 73 | 74 | ded = cfc.extract_ed(edof, da) 75 | des = np.zeros((3, 1)) 76 | 77 | for j in range(3): 78 | ep = np.array([E[j], A[j]]) 79 | desj = cfc.bar2s(ex[j, :], ey[j, :], ep, ded[j, :]) 80 | des[j, 0] = desj[0] 81 | 82 | es += des 83 | 84 | for j in range(3): 85 | if abs(es[j, 0]) >= Ns[j]: 86 | E[j] = 0 87 | 88 | # Determine if the stress in a bar has reached the yield stress 89 | 90 | newplbar = np.sum(abs(es) > Ns) 91 | 92 | if newplbar > plbar: 93 | plbar = newplbar 94 | print( 95 | plbar, "plastic elements for increment ", i + 1, " at load = ", (i + 1) * dp 96 | ) 97 | 98 | # Save variables for curve plotting 99 | 100 | pl = np.vstack((pl, np.array([-a[5, 0], (i + 1) * dp]))) 101 | 102 | # Plot force-displacement relation 103 | 104 | cfv.figure(1, fig_size=(7, 4)) 105 | cfv.plt.plot(pl[:, 0], pl[:, 1]) 106 | cfv.plt.xlabel("Displacement") 107 | cfv.plt.ylabel("Force") 108 | cfv.show_and_wait() 109 | -------------------------------------------------------------------------------- /examples/exn_beam2.py: -------------------------------------------------------------------------------- 1 | # example exn_beam2g 2 | # ---------------------------------------------------------------- 3 | # PURPOSE 4 | # Geometrically nonlinear analysis of a plane frame. 5 | # ---------------------------------------------------------------- 6 | 7 | import numpy as np 8 | import calfem.core as cfc 9 | import calfem.vis_mpl as cfv 10 | 11 | 12 | # ----- Topology ------------------------------------------------- 13 | 14 | edof = np.array([ 15 | [4, 5, 6, 1, 2, 3], 16 | [7, 8, 9, 10, 11, 12], 17 | [4, 5, 6, 7, 8, 9] 18 | ]) 19 | 20 | # ----- Element stiffness and element load matrices ------------- 21 | 22 | E = 200e9 23 | A1 = 2e-3 24 | A2 = 6e-3 25 | I1 = 1.6e-5 26 | I2 = 5.4e-5 27 | 28 | ep1 = np.array([E, A1, I1]) 29 | ep3 = np.array([E, A2, I2]) 30 | 31 | ex1 = np.array([0.0, 0.0]) 32 | ey1 = np.array([4.0, 0.0]) 33 | ex2 = np.array([6.0, 6.0]) 34 | ey2 = np.array([4.0, 0.0]) 35 | ex3 = np.array([0.0, 6.0]) 36 | ey3 = np.array([4.0, 4.0]) 37 | 38 | eq1 = np.array([0.0]) 39 | eq2 = np.array([0.0]) 40 | eq3 = np.array([-50e3]) 41 | 42 | # ----- Initial axial forces ---------------------------------------------- 43 | 44 | QX1 = 1e-4 45 | QX2 = 0 46 | QX3 = 0 47 | QX01 = 1 48 | 49 | # ----- Iteration for convergence ----------------------------------------- 50 | 51 | eps = 1e-6 52 | n = 0 53 | 54 | while abs((QX1 - QX01) / QX01) > eps: 55 | n += 1 56 | K = np.zeros([12, 12]) 57 | f = np.zeros([12, 1]) 58 | f[3, 0] = 10e3 59 | 60 | Ke1 = cfc.beam2ge(ex1, ey1, ep1, QX1) 61 | Ke2 = cfc.beam2ge(ex2, ey2, ep1, QX2) 62 | Ke3, fe3 = cfc.beam2ge(ex3, ey3, ep3, QX3, eq3) 63 | 64 | K = cfc.assem(edof[0, :], K, Ke1) 65 | K = cfc.assem(edof[1, :], K, Ke2) 66 | K, f = cfc.assem(edof[2, :], K, Ke3, f, fe3) 67 | 68 | bc = np.array([1, 2, 3, 10, 11]) 69 | a, r = cfc.solveq(K, f, bc) 70 | 71 | ed = cfc.extract_ed(edof, a) 72 | 73 | QX01 = QX1 74 | es1 = cfc.beam2gs(ex1, ey1, ep1, ed[0, :], QX1, eq1) 75 | es2 = cfc.beam2gs(ex2, ey2, ep1, ed[1, :], QX2, eq2) 76 | es3 = cfc.beam2gs(ex3, ey3, ep3, ed[2, :], QX3, eq3) 77 | QX1 = es1[1] 78 | QX2 = es2[1] 79 | QX3 = es3[1] 80 | 81 | if n == 1: 82 | ed0 = ed 83 | 84 | if n > 20: 85 | print("The solution does not converge") 86 | break 87 | 88 | 89 | # ----- Section forces --------------------------------------- 90 | 91 | eq1 = np.array([0.0, eq1.item()]) 92 | eq2 = np.array([0.0, eq2.item()]) 93 | eq3 = np.array([0.0, eq3.item()]) 94 | es1, edi1, eci1 = cfc.beam2s(ex1, ey1, ep1, ed[0, :], eq1, 21) 95 | es2, edi2, eci2 = cfc.beam2s(ex2, ey2, ep1, ed[1, :], eq2, 21) 96 | es3, edi3, eci3 = cfc.beam2s(ex3, ey3, ep3, ed[2, :], eq3, 21) 97 | 98 | 99 | # ----- Draw deformed frame --------------------------------------- 100 | 101 | cfv.figure(1, fig_size=(6, 4)) 102 | plotpar = [3, 1, 0] 103 | cfv.eldraw2(ex1, ey1, plotpar) 104 | cfv.eldraw2(ex2, ey2, plotpar) 105 | cfv.eldraw2(ex3, ey3, plotpar) 106 | sfac = cfv.scalfact2(ex3, ey3, edi3, 0.1) 107 | plotpar = [1, 2, 1] 108 | cfv.eldisp2(ex1, ey1, ed[0, :], plotpar, sfac) 109 | cfv.eldisp2(ex2, ey2, ed[1, :], plotpar, sfac) 110 | cfv.eldisp2(ex3, ey3, ed[2, :], plotpar, sfac) 111 | plotpar = [2, 4, 2] 112 | cfv.eldisp2(ex1, ey1, ed0[0, :], plotpar, sfac) 113 | cfv.eldisp2(ex2, ey2, ed0[1, :], plotpar, sfac) 114 | cfv.eldisp2(ex3, ey3, ed0[2, :], plotpar, sfac) 115 | cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) 116 | cfv.title("Displacements") 117 | 118 | 119 | # ----- Draw normal force diagram -------------------------------- 120 | cfv.figure(2, fig_size=(6, 4)) 121 | plotpar = [2, 1] 122 | sfac = cfv.scalfact2(ex1, ey1, es1[:, 0], 0.2) 123 | cfv.secforce2(ex1, ey1, es1[:, 0], plotpar, sfac) 124 | cfv.secforce2(ex2, ey2, es2[:, 0], plotpar, sfac) 125 | cfv.secforce2(ex3, ey3, es3[:, 0], plotpar, sfac) 126 | cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) 127 | cfv.title("Normal force") 128 | 129 | # ----- Draw shear force diagram --------------------------------- 130 | cfv.figure(3, fig_size=(6, 4)) 131 | plotpar = [2, 1] 132 | sfac = cfv.scalfact2(ex3, ey3, es3[:, 1], 0.2) 133 | cfv.secforce2(ex1, ey1, es1[:, 1], plotpar, sfac) 134 | cfv.secforce2(ex2, ey2, es2[:, 1], plotpar, sfac) 135 | cfv.secforce2(ex3, ey3, es3[:, 1], plotpar, sfac) 136 | cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) 137 | cfv.title("Shear force") 138 | 139 | # ----- Draw moment diagram -------------------------------------- 140 | cfv.figure(4, fig_size=(6, 4)) 141 | plotpar = [2, 1] 142 | sfac = cfv.scalfact2(ex3, ey3, es3[:, 2], 0.2) 143 | cfv.secforce2(ex1, ey1, es1[:, 2], plotpar, sfac) 144 | cfv.secforce2(ex2, ey2, es2[:, 2], plotpar, sfac) 145 | cfv.secforce2(ex3, ey3, es3[:, 2], plotpar, sfac) 146 | cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) 147 | cfv.title("Bending moment") 148 | cfv.show_and_wait() 149 | # ------------------------ end ----------------------------------- 150 | -------------------------------------------------------------------------------- /examples/exn_beam2_b.py: -------------------------------------------------------------------------------- 1 | # example exn_beam2g_b 2 | # ---------------------------------------------------------------- 3 | # PURPOSE 4 | # Buckling analysis of a plane frame. 5 | # ---------------------------------------------------------------- 6 | 7 | import numpy as np 8 | import calfem.core as cfc 9 | import calfem.vis_mpl as cfv 10 | 11 | 12 | # ----- Topology ------------------------------------------------- 13 | 14 | edof = np.array([[4, 5, 6, 1, 2, 3], [7, 8, 9, 10, 11, 12], [4, 5, 6, 7, 8, 9]]) 15 | 16 | # ----- Element stiffness and element load matrices ------------- 17 | 18 | E = 200e9 19 | A1 = 2e-3 20 | A2 = 6e-3 21 | I1 = 1.6e-5 22 | I2 = 5.4e-5 23 | 24 | ep1 = np.array([E, A1, I1]) 25 | ep3 = np.array([E, A2, I2]) 26 | 27 | ex1 = np.array([0.0, 0.0]) 28 | ey1 = np.array([4.0, 0.0]) 29 | ex2 = np.array([6.0, 6.0]) 30 | ey2 = np.array([4.0, 0.0]) 31 | ex3 = np.array([0.0, 6.0]) 32 | ey3 = np.array([4.0, 4.0]) 33 | 34 | eq1 = np.array([0.0]) 35 | eq2 = np.array([0.0]) 36 | eq3 = np.array([-50e3]) 37 | 38 | # ----- Initial axial forces ---------------------------------------------- 39 | 40 | QX1 = 1e-4 41 | QX2 = 0 42 | QX3 = 0 43 | QX01 = 1 44 | 45 | # ----- Iteration for convergence ----------------------------------------- 46 | 47 | eps = 1e-6 48 | n = 0 49 | 50 | while abs((QX1 - QX01) / QX01) > eps: 51 | n += 1 52 | K = np.zeros([12, 12]) 53 | f = np.zeros([12, 1]) 54 | f[3, 0] = 10e3 55 | 56 | Ke1 = cfc.beam2ge(ex1, ey1, ep1, QX1) 57 | Ke2 = cfc.beam2ge(ex2, ey2, ep1, QX2) 58 | Ke3, fe3 = cfc.beam2ge(ex3, ey3, ep3, QX3, eq3) 59 | 60 | K = cfc.assem(edof[0, :], K, Ke1) 61 | K = cfc.assem(edof[1, :], K, Ke2) 62 | K, f = cfc.assem(edof[2, :], K, Ke3, f, fe3) 63 | if n == 1: 64 | K0 = K 65 | 66 | bc = np.array([1, 2, 3, 10, 11]) 67 | a, r = cfc.solveq(K, f, bc) 68 | 69 | ed = cfc.extract_ed(edof, a) 70 | 71 | QX01 = QX1 72 | es1 = cfc.beam2gs(ex1, ey1, ep1, ed[0, :], QX1, eq1) 73 | es2 = cfc.beam2gs(ex2, ey2, ep1, ed[1, :], QX2, eq2) 74 | es3 = cfc.beam2gs(ex3, ey3, ep3, ed[2, :], QX3, eq3) 75 | 76 | QX1 = es1[1] 77 | QX2 = es2[1] 78 | QX3 = es3[1] 79 | 80 | if n > 20: 81 | print("The solution does not converge") 82 | break 83 | 84 | 85 | # ----- Buckling analysis ------------------------------------------------- 86 | 87 | lam, phi = cfc.eigen(K, K0, bc) 88 | one = np.ones(lam.shape) 89 | alpha = np.divide(one, one - lam) 90 | print(alpha[0]) 91 | 92 | # ----- Draw shape at instability ----------------------------------------- 93 | 94 | Ed = cfc.extract_ed(edof, -phi[:, 0]) 95 | cfv.figure(1, fig_size=(6, 4)) 96 | plotpar = [3, 1, 0] 97 | cfv.eldraw2(ex1, ey1, plotpar) 98 | cfv.eldraw2(ex2, ey2, plotpar) 99 | cfv.eldraw2(ex3, ey3, plotpar) 100 | sfac = cfv.scalfact2(ex3, ey3, Ed[2, :], 0.1) 101 | plotpar = [1, 2, 1] 102 | cfv.eldisp2(ex1, ey1, Ed[0, :], plotpar, sfac) 103 | cfv.eldisp2(ex2, ey2, Ed[1, :], plotpar, sfac) 104 | cfv.eldisp2(ex3, ey3, Ed[2, :], plotpar, sfac) 105 | cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) 106 | cfv.title("Shape at instability") 107 | cfv.show_and_wait() 108 | 109 | # ------------------------ end ----------------------------------- 110 | -------------------------------------------------------------------------------- /examples/experimental/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "e:\\anaconda3\\python.exe" 3 | } -------------------------------------------------------------------------------- /examples/experimental/exed1.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 0 27 | 0 28 | 800 29 | 22 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/experimental/exint1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import calfem.intvis as iv 4 | 5 | # --- Parametrar som kan ändras 6 | 7 | a = 1 8 | b_slider = 2.0 9 | c_list = [1, 2, 3] 10 | d_check = True 11 | f_param = 42.0 12 | g_float = 84.0 13 | g_int = 34 14 | 15 | # --- Redigera parametrar interaktivt 16 | 17 | iv.edit_params(vars()) 18 | 19 | def test(): 20 | c = 1 21 | d = 2 22 | iv.edit_params(vars()) 23 | 24 | test() 25 | 26 | # --- Redigera geometri 27 | 28 | #iv.edit_geometry(g) 29 | 30 | -------------------------------------------------------------------------------- /examples/experimental/exm11.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | '''Example 10 4 | 5 | The use case from the user manual. 6 | The example does not contain anything that is not covered in the previous examples. 7 | ''' 8 | 9 | import calfem.core as cfc 10 | import calfem.vis as cfv 11 | import calfem.utils as cfu 12 | import calfem.shapes as cfs 13 | import calfem.solver as cfslv 14 | 15 | cfu.enableLogging() 16 | 17 | # ---- General parameters --------------------------------------------------- 18 | 19 | # Define marker constants instead of using numbers in the code 20 | 21 | cfu.info("Creating rectangle") 22 | 23 | rect = cfs.Rectangle(5.0, 1.0, element_type=3, dofs_per_node=2, max_area=0.08) 24 | rect.t = 0.2 25 | rect.v = 0.35 26 | rect.E = 2e9 27 | rect.ptype = 1 28 | rect.ep = [rect.ptype, rect.t] 29 | rect.D = cfc.hooke(rect.ptype, rect.E, rect.v) 30 | 31 | cfu.info("Creating mesh...") 32 | 33 | mesh = cfs.ShapeMesh(rect) 34 | 35 | # ---- Solve problem -------------------------------------------------------- 36 | 37 | solver = cfslv.Plan2DSolver(mesh) 38 | 39 | solver.addBC(rect.left_id, 0.0) 40 | solver.addForceTotal(rect.top_id, -10e5, dimension=2) 41 | 42 | results = solver.execute() 43 | 44 | # ---- Visualise results ---------------------------------------------------- 45 | 46 | cfu.info("Drawing results...") 47 | 48 | cfv.figure() 49 | cfv.draw_geometry(rect.geometry(), title="Geometry") 50 | 51 | cfv.figure() 52 | cfv.draw_mesh(mesh.coords, mesh.edof, rect.dofs_per_node, rect.element_type, 53 | filled=True, title="Mesh") #Draws the mesh. 54 | 55 | cfv.figure() 56 | cfv.draw_displacements(results.a, mesh.coords, mesh.edof, rect.dofs_per_node, rect.element_type, 57 | draw_undisplaced_mesh=False, title="Displacements", 58 | magnfac=1) 59 | 60 | cfv.figure() 61 | cfv.draw_element_values(results.el_forces, mesh.coords, mesh.edof, rect.dofs_per_node, rect.element_type, results.a, 62 | draw_elements=True, draw_undisplaced_mesh=False, 63 | title="Effective Stress", magnfac=1) 64 | 65 | #cfv.colorBar().SetLabel("Effective stress") 66 | 67 | cfu.info("Done drawing...") 68 | 69 | cfv.show_and_wait() -------------------------------------------------------------------------------- /examples/experimental/exm11_mpl.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | '''Example 10 4 | 5 | The use case from the user manual. 6 | The example does not contain anything that is not covered in the previous examples. 7 | ''' 8 | 9 | import calfem.core as cfc 10 | import calfem.vis_mpl as cfv 11 | import calfem.utils as cfu 12 | import calfem.shapes as cfs 13 | import calfem.solver as cfslv 14 | 15 | cfu.enableLogging() 16 | 17 | # ---- General parameters --------------------------------------------------- 18 | 19 | # Define marker constants instead of using numbers in the code 20 | 21 | cfu.info("Creating rectangle") 22 | 23 | rect = cfs.Rectangle(5.0, 1.0, element_type=3, dofs_per_node=2, max_area=0.08) 24 | rect.t = 0.2 25 | rect.v = 0.35 26 | rect.E = 2e9 27 | rect.ptype = 1 28 | rect.ep = [rect.ptype, rect.t] 29 | rect.D = cfc.hooke(rect.ptype, rect.E, rect.v) 30 | 31 | cfu.info("Creating mesh...") 32 | 33 | mesh = cfs.ShapeMesh(rect) 34 | 35 | # ---- Solve problem -------------------------------------------------------- 36 | 37 | solver = cfslv.Plan2DSolver(mesh) 38 | 39 | solver.addBC(rect.left_id, 0.0) 40 | solver.addForceTotal(rect.top_id, -10e5, dimension=2) 41 | 42 | results = solver.execute() 43 | 44 | # ---- Visualise results ---------------------------------------------------- 45 | 46 | cfu.info("Drawing results...") 47 | 48 | cfv.figure() 49 | cfv.draw_geometry(rect.geometry(), title="Geometry") 50 | 51 | cfv.figure() 52 | cfv.draw_mesh(mesh.coords, mesh.edof, rect.dofs_per_node, rect.element_type, 53 | filled=True, title="Mesh") #Draws the mesh. 54 | 55 | cfv.figure() 56 | cfv.draw_displacements(results.a, mesh.coords, mesh.edof, rect.dofs_per_node, rect.element_type, 57 | draw_undisplaced_mesh=False, title="Displacements", 58 | magnfac=1) 59 | 60 | cfv.figure() 61 | cfv.draw_element_values(results.el_forces, mesh.coords, mesh.edof, rect.dofs_per_node, rect.element_type, results.a, 62 | draw_elements=True, draw_undisplaced_mesh=False, 63 | title="Effective Stress", magnfac=1) 64 | 65 | #cfv.colorBar().SetLabel("Effective stress") 66 | 67 | cfu.info("Done drawing...") 68 | 69 | cfv.show_and_wait() -------------------------------------------------------------------------------- /examples/experimental/exm12.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | '''Example 10 4 | 5 | The use case from the user manual. 6 | The example does not contain anything that is not covered in the previous examples. 7 | ''' 8 | 9 | import calfem.core as cfc 10 | import calfem.vis as cfv 11 | import calfem.utils as cfu 12 | import calfem.shapes as cfs 13 | import calfem.solver as cfslv 14 | 15 | import numpy as np 16 | 17 | cfu.enableLogging() 18 | 19 | # ---- General parameters --------------------------------------------------- 20 | 21 | # Define marker constants instead of using numbers in the code 22 | 23 | cfu.info("Creating rectangle") 24 | 25 | rect = cfs.Rectangle(5.0, 1.0, element_type=3, dofs_per_node=1, max_area=0.08) 26 | 27 | rect.t = 1 28 | rect.ep = [rect.t, 1] 29 | 30 | rect.D = np.diag([1.7, 1.7]) 31 | 32 | cfu.info("Creating mesh...") 33 | 34 | mesh = cfs.ShapeMesh(rect) 35 | 36 | # ---- Solve problem -------------------------------------------------------- 37 | 38 | solver = cfslv.Flow2DSolver(mesh) 39 | 40 | solver.addBC(rect.left_id, 0.0) 41 | solver.addBC(rect.right_id, 120.0) 42 | #solver.addForceTotal(rect.topId, -10e5, dimension=2) 43 | 44 | results = solver.execute() 45 | 46 | # ---- Visualise results ---------------------------------------------------- 47 | 48 | cfu.info("Drawing results...") 49 | 50 | cfv.figure() 51 | cfv.drawGeometry(rect.geometry(), title="Geometry") 52 | 53 | cfv.figure() 54 | cfv.drawMesh(mesh.coords, mesh.edof, rect.dofs_per_node, rect.element_type, 55 | filled=True, title="Mesh") #Draws the mesh. 56 | 57 | cfv.figure() 58 | cfv.drawNodalValues(results.a, mesh.coords, mesh.edof, rect.dofs_per_node, rect.element_type) 59 | 60 | cfv.showAndWait() -------------------------------------------------------------------------------- /examples/experimental/exm12_mpl.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | '''Example 10 4 | 5 | The use case from the user manual. 6 | The example does not contain anything that is not covered in the previous examples. 7 | ''' 8 | 9 | import calfem.core as cfc 10 | import calfem.vis_mpl as cfv 11 | import calfem.utils as cfu 12 | import calfem.shapes as cfs 13 | import calfem.solver as cfslv 14 | 15 | import numpy as np 16 | 17 | import matplotlib.pyplot as plt 18 | 19 | cfu.enableLogging() 20 | 21 | # ---- General parameters --------------------------------------------------- 22 | 23 | # Define marker constants instead of using numbers in the code 24 | 25 | cfu.info("Creating rectangle") 26 | 27 | rect = cfs.Rectangle(5.0, 1.0, element_type=2, dofs_per_node=1, max_area=0.08) 28 | 29 | rect.t = 1 30 | rect.ep = [rect.t, 1] 31 | 32 | rect.D = np.diag([1.7, 1.7]) 33 | 34 | cfu.info("Creating mesh...") 35 | 36 | mesh = cfs.ShapeMesh(rect) 37 | 38 | # ---- Solve problem -------------------------------------------------------- 39 | 40 | solver = cfslv.Flow2DSolver(mesh) 41 | 42 | solver.addBC(rect.left_id, 0.0) 43 | solver.addBC(rect.right_id, 120.0) 44 | #solver.addForceTotal(rect.topId, -10e5, dimension=2) 45 | 46 | results = solver.execute() 47 | 48 | # ---- Visualise results ---------------------------------------------------- 49 | 50 | cfu.info("Drawing results...") 51 | 52 | cfv.figure() 53 | cfv.draw_geometry(rect.geometry(), title="Geometry") 54 | 55 | cfv.figure() 56 | cfv.draw_mesh(mesh.coords, mesh.edof, rect.dofs_per_node, rect.element_type, 57 | filled=True, title="Mesh") #Draws the mesh. 58 | 59 | cfv.figure() 60 | cfv.draw_nodal_values_shaded(results.a, mesh.coords, mesh.edof) 61 | cfv.colorbar() 62 | 63 | cfv.figure() 64 | cfv.draw_nodal_values_contourf(results.a, mesh.coords, mesh.edof) 65 | cfv.colorbar() 66 | 67 | cfv.showAndWait() -------------------------------------------------------------------------------- /examples/experimental/exm14_vtk.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | '''Example 05 4 | 5 | This example shows how to make an unstructured 3D mesh (tetrahedron elements, which calfem cant actually use). 6 | It also demonstrates how to do subplots and create two axes that are viewed from the same camera. 7 | ''' 8 | 9 | import calfem.geometry as cfg 10 | import calfem.mesh as cfm 11 | import calfem.vis_vtk as cfv 12 | 13 | import prim3d as p3 14 | 15 | import vtk 16 | 17 | # ---- Define geometry ------------------------------------------------------ 18 | 19 | #box1 = p3.Box(0.0, 0.0, 0.0) 20 | #box2 = p3.Box(1.0, 0.0, 0.0) 21 | 22 | #model = p3.GeometryModel() 23 | #model.add_volume(box1.volume) 24 | #model.add_volume(box2.volume) 25 | 26 | g = cfg.Geometry() 27 | 28 | # ---- Create mesh ---------------------------------------------------------- 29 | 30 | # Element type 4 is tetrahedron. (See user manual for more element types). 31 | 32 | el_type = 5 33 | 34 | # Degrees of freedom per node. 35 | 36 | dofs_per_node = 1 37 | 38 | # Create mesh 39 | 40 | mesh_generator = cfm.GmshMesh("test.geo", el_type, 0.05, dofs_per_node) 41 | mesh_generator.mesh_dir = "mesh" 42 | 43 | mesh_generator.gmsh_options = {"Mesh.Algorithm":6, "Mesh.Algorithm3D":1, "Mesh.RecombinationAlgorithm":1, 44 | "Mesh.RecombineAll":1, "Mesh.Tetrahedra":1} 45 | 46 | coords, edof, dofs, bdofs, elementmarkers = mesh_generator.create(is3D=True) 47 | 48 | #coords, edof, dofs, bdofs, elementmarkers = cfm.mesh(model.geometry, el_type, 0.3, dofs_per_node) 49 | 50 | print(coords) 51 | print(edof) 52 | #print(bdofs) 53 | #print(elementmarkers) 54 | 55 | #print(bdofs[100]) 56 | #print(edof[0]) 57 | 58 | #coords, edof, dofs, bdofs, _ = cfm.mesh( 59 | # g, el_type, 0.3, dofs_per_node, gmsh_exec_path="D:\\vsmn20-software\\gmsh\gmsh.exe") 60 | 61 | 62 | # ---- Visualise mesh ------------------------------------------------------- 63 | 64 | cfv.draw_mesh(coords, edof, el_type) -------------------------------------------------------------------------------- /examples/experimental/exs6.py: -------------------------------------------------------------------------------- 1 | # example exs6 2 | #---------------------------------------------------------------- 3 | # PURPOSE 4 | # Analysis of a plane frame. 5 | #---------------------------------------------------------------- 6 | 7 | # REFERENCES 8 | # G"oran Sandberg 94-03-08 9 | # Karl-Gunnar Olsson 95-09-28 10 | # Anders Olsson 99-03-01 11 | # Ola Dahlblom 2004-09-14 12 | #---------------------------------------------------------------- 13 | 14 | import numpy as np 15 | import calfem.core as cfc 16 | import calfem.utils as cfu 17 | import calfem.vis_mpl as cfv 18 | 19 | # ----- Topology ------------------------------------------------- 20 | 21 | Edof = np.array([ 22 | [4, 5, 6, 1, 2, 3], 23 | [7, 8, 9, 10, 11, 12], 24 | [4, 5, 6, 7, 8, 9] 25 | ]) 26 | 27 | # ----- Stiffness matrix K and load vector f --------------------- 28 | 29 | K = np.matrix(np.zeros((12,12))) 30 | f = np.matrix(np.zeros((12,1))) 31 | f[3] = 2e+3 32 | 33 | # ----- Element stiffness and element load matrices ------------- 34 | 35 | E = 200e9 36 | A1 = 2e-3 37 | A2 = 6e-3 38 | I1 = 1.6e-5 39 | I2 = 5.4e-5 40 | 41 | ep1 = np.array([E, A1, I1]) 42 | ep3 = np.array([E, A2, I2]) 43 | ex1 = np.array([0, 0]) 44 | ex2 = np.array([6, 6]) 45 | ex3 = np.array([0, 6]) 46 | ey1 = np.array([4, 0]) 47 | ey2 = np.array([4, 0]) 48 | ey3 = np.array([4, 4]) 49 | eq1 = np.array([0, 0]) 50 | eq2 = np.array([0, 0]) 51 | eq3 = np.array([0, -10e+3]) 52 | 53 | Ke1 = cfc.beam2e(ex1, ey1, ep1) 54 | Ke2 = cfc.beam2e(ex2, ey2, ep1) 55 | Ke3, fe3 = cfc.beam2e(ex3, ey3, ep3, eq3) 56 | 57 | # ----- Assemble Ke into K --------------------------------------- 58 | 59 | cfc.assem(Edof[0,:], K, Ke1); 60 | cfc.assem(Edof[1,:], K, Ke2); 61 | cfc.assem(Edof[2,:], K, Ke3, f, fe3); 62 | 63 | # ----- Solve the system of equations and compute reactions ------ 64 | 65 | bc = np.array([1,2,3,10,11]) 66 | a, r = cfc.solveq(K,f,bc) 67 | 68 | print("a = ") 69 | print(a) 70 | print("r = ") 71 | print(r) 72 | 73 | # ----- Section forces ------------------------------------------- 74 | 75 | Ed = cfc.extractEldisp(Edof,a); 76 | 77 | es1, ed1, ec1 = cfc.beam2s(ex1, ey1, ep1, Ed[0,:], eq1, nep=21) 78 | es2, ed2, ec2 = cfc.beam2s(ex2, ey2, ep1, Ed[1,:], eq2, nep=21) 79 | es3, ed3, ec3 = cfc.beam2s(ex3, ey3, ep3, Ed[2,:], eq3, nep=21) 80 | 81 | print("es1 = ") 82 | print(es1) 83 | print("es2 = ") 84 | print(es2) 85 | print("es3 = ") 86 | print(es3) 87 | 88 | # ----- Draw deformed frame --------------------------------------- 89 | 90 | ex = np.array([ 91 | ex1, ex2, ex3 92 | ]) 93 | print(ex) 94 | 95 | ey = np.array([ 96 | ey1, ey2, ey3 97 | ]) 98 | print(ey) 99 | 100 | plotpar = [2, 2, 1] 101 | cfv.eldraw2(ex, ey, plotpar=plotpar) 102 | cfv.showAndWait() 103 | 104 | 105 | # 106 | #cfv.eldraw2(ex, ey, plotpar=plotpar) 107 | ##cfv.eldisp2(ex, ey, Ed) 108 | #cfv.showAndWait() 109 | 110 | #figure(1) 111 | #plotpar=[2 1 0]; 112 | #eldraw2(ex1,ey1,plotpar); 113 | #eldraw2(ex2,ey2,plotpar); 114 | #eldraw2(ex3,ey3,plotpar); 115 | #sfac=scalfact2(ex3,ey3,Ed(3,:),0.1); 116 | #plotpar=[1 2 1]; 117 | #eldisp2(ex1,ey1,Ed(1,:),plotpar,sfac); 118 | #eldisp2(ex2,ey2,Ed(2,:),plotpar,sfac); 119 | #eldisp2(ex3,ey3,Ed(3,:),plotpar,sfac); 120 | #axis([-1.5 7.5 -0.5 5.5]); 121 | #pltscalb2(sfac,[1e-2 0.5 0]); 122 | #axis([-1.5 7.5 -0.5 5.5]); 123 | #title('displacements') 124 | 125 | #----- Draw normal force diagram -------------------------------- 126 | 127 | #figure(2) 128 | #plotpar=[2 1]; 129 | #sfac=scalfact2(ex1,ey1,es1(:,1),0.2); 130 | #eldia2(ex1,ey1,es1(:,1),plotpar,sfac); 131 | #eldia2(ex2,ey2,es2(:,1),plotpar,sfac); 132 | #eldia2(ex3,ey3,es3(:,1),plotpar,sfac); 133 | #axis([-1.5 7.5 -0.5 5.5]); 134 | #pltscalb2(sfac,[3e4 1.5 0]); 135 | #title('normal force') 136 | 137 | #----- Draw shear force diagram --------------------------------- 138 | 139 | #figure(3) 140 | #plotpar=[2 1]; 141 | #sfac=scalfact2(ex3,ey3,es3(:,2),0.2); 142 | #eldia2(ex1,ey1,es1(:,2),plotpar,sfac); 143 | #eldia2(ex2,ey2,es2(:,2),plotpar,sfac); 144 | #eldia2(ex3,ey3,es3(:,2),plotpar,sfac); 145 | #axis([-1.5 7.5 -0.5 5.5]); 146 | #pltscalb2(sfac,[3e4 0.5 0]); 147 | #title('shear force') 148 | 149 | #----- Draw moment diagram -------------------------------------- 150 | 151 | #figure(4) 152 | #plotpar=[2 1]; 153 | #sfac=scalfact2(ex3,ey3,es3(:,3),0.2); 154 | #eldia2(ex1,ey1,es1(:,3),plotpar,sfac); 155 | #eldia2(ex2,ey2,es2(:,3),plotpar,sfac); 156 | #eldia2(ex3,ey3,es3(:,3),plotpar,sfac); 157 | #axis([-1.5 7.5 -0.5 5.5]); 158 | #pltscalb2(sfac,[3e4 0.5 0]); 159 | #title('moment') 160 | 161 | -------------------------------------------------------------------------------- /examples/experimental/exui1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Apr 11 09:44:29 2016 4 | 5 | @author: lindemann 6 | """ 7 | 8 | import sys 9 | 10 | from qtpy.QtCore import Slot, Signal, QMetaObject 11 | from qtpy.QtWidgets import * 12 | from qtpy.QtGui import QPixmap 13 | from qtpy.uic import loadUi 14 | 15 | import calfem.vis_mpl as cfv 16 | 17 | class MainWindow(QMainWindow): 18 | """Main window class of our UI""" 19 | def __init__(self): 20 | """Constructor""" 21 | super(MainWindow, self).__init__() 22 | 23 | self.resize(640,480) 24 | self.move(50,50) 25 | self.setWindowTitle("MyWindow") 26 | 27 | self.executeButton = QPushButton("Tryck", self) 28 | self.executeButton.setObjectName("executeButton") 29 | self.executeButton.move(50,50) 30 | self.executeButton.resize(100,50) 31 | 32 | QMetaObject.connectSlotsByName(self) 33 | 34 | @Slot() 35 | def on_executeButton_clicked(self): 36 | print("Button pressed") 37 | 38 | def init_app(): 39 | app = QApplication.instance() 40 | 41 | if app is None: 42 | print("No QApplication instance found. Creating one.") 43 | # if it does not exist then a QApplication is created 44 | app = QApplication(sys.argv) 45 | else: 46 | print("QApplication instance found.") 47 | 48 | return app 49 | 50 | def main_loop(): 51 | 52 | app = QApplication.instance() 53 | 54 | if app is None: 55 | print("No QApplication instance found. Creating one.") 56 | # if it does not exist then a QApplication is created 57 | app = QApplication(sys.argv) 58 | else: 59 | print("QApplication instance found.") 60 | 61 | # För matplotlib kompatibilitet 62 | 63 | # plt.show(block=False) 64 | 65 | app.exec_() 66 | 67 | 68 | def show_window(): 69 | app = init_app() 70 | widget = MainWindow() 71 | widget.show() 72 | app.exec_() 73 | 74 | if __name__ == '__main__': 75 | 76 | show_window() 77 | print("Hello") 78 | show_window() 79 | print("Hello after...") -------------------------------------------------------------------------------- /examples/experimental/gmsh_api.py: -------------------------------------------------------------------------------- 1 | import gmsh 2 | import sys 3 | 4 | if __name__ == "__main__": 5 | 6 | gmsh.initialize(sys.argv) 7 | print(sys.argv) 8 | gmsh.finalize() 9 | 10 | -------------------------------------------------------------------------------- /examples/experimental/gmsh_api2.py: -------------------------------------------------------------------------------- 1 | import gmsh 2 | import sys 3 | import numpy as np 4 | import calfem.mesh as cfm 5 | import calfem.vis_mpl as cfv 6 | 7 | if __name__ == "__main__": 8 | 9 | gmsh.initialize(sys.argv) 10 | 11 | gmsh.model.add("t1") 12 | gmsh.model.geo.add_point(0.0, 0.0, 0.0) 13 | gmsh.model.geo.add_point(1.0, 0.0, 0.0) 14 | gmsh.model.geo.add_point(1.0, 1.0, 0.0) 15 | gmsh.model.geo.add_point(0.0, 1.0, 0.0) 16 | 17 | gmsh.model.geo.add_line(1, 2) 18 | gmsh.model.geo.add_line(2, 3) 19 | gmsh.model.geo.add_line(3, 4) 20 | gmsh.model.geo.add_line(4, 1) 21 | 22 | gmsh.model.geo.add_curve_loop([1, 2, 3, 4], 1) 23 | gmsh.model.geo.add_plane_surface([1], 1) 24 | 25 | #gmsh.model.geo.add_surface_loop([1, 2, 3, 4]) 26 | 27 | gmsh.model.geo.synchronize() 28 | 29 | #gmsh.option.setNumber("Mesh.ElementOrder", 5) 30 | # gmsh.option.setNumber("Mesh.HighOrderOptimize", 2) 31 | gmsh.option.setNumber("Mesh.RecombineAll", 1) 32 | #gmsh.option.setNumber('Mesh.MeshSizeMin', 0.025) 33 | #gmsh.option.setNumber('Mesh.MeshSizeMax', 0.025) 34 | 35 | 36 | gmsh.model.mesh.generate(2) 37 | 38 | print_entities() 39 | 40 | #gmsh.write("t1.msh") 41 | 42 | gmsh.fltk.run() 43 | 44 | gmsh.finalize() 45 | 46 | -------------------------------------------------------------------------------- /examples/experimental/plot_tst.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ''' 4 | Example 02 5 | Creating geometry from B-Splines and circle arcs. 6 | Also shows how to set ID numbers for geometry entities and how to specify element density. 7 | ''' 8 | 9 | import matplotlib.pyplot as plt 10 | import matplotlib.collections 11 | import numpy as np 12 | 13 | import calfem.geometry as cfg 14 | import calfem.mesh as cfm 15 | import calfem.vis_mpl as cfv 16 | 17 | # ---- Define geometry ------------------------------------------------------ 18 | 19 | g = cfg.Geometry() 20 | 21 | # Add points: 22 | # In this example we set the IDs manually. 23 | 24 | g.point([ -2, 0], ID=0) 25 | g.point([ 0, 1], ID=1, elSize=5) # elSize determines the size of the elements near this point. 26 | g.point([ 1, 0], 2, elSize=5) # elSize is 1 by default. Larger number means less dense mesh. 27 | g.point([ 0, -2], 3) # Size means the length of the sides of the elements. 28 | g.point([ 0, 0], 4, elSize=5) 29 | g.point([ .5, .2], 5) 30 | g.point([-.5, .5], 6) 31 | g.point([-.7,-.5], 7) 32 | 33 | # Add curves: 34 | 35 | # The 3 points that define the circle arc are [start, center, end]. 36 | # The arc must be smaller than Pi. 37 | 38 | g.circle([1, 4, 2], 2) 39 | 40 | # BSplines are similar to Splines, but do not necessarily pass through the 41 | # control points. 42 | 43 | g.bspline([5,6,7,5], 5) 44 | g.bspline([1,0,3,2], 4) 45 | 46 | # Add surface: 47 | 48 | g.surface([4,2], [[5]]) 49 | 50 | # Markers do not have to be set when the curve is created. It can be done afterwards. 51 | # Set marker=80 for curves 2 and 4: 52 | 53 | for curveID in [2, 4]: 54 | g.curveMarker(curveID, 80) 55 | 56 | # ---- Generate mesh -------------------------------------------------------- 57 | 58 | mesh = cfm.GmshMesh(g) 59 | 60 | # Element type 2 is triangle. (3 is quad. See user manual for more element types) 61 | 62 | mesh.el_type = 3 63 | 64 | # Degrees of freedom per node. 65 | 66 | mesh.dofs_per_node = 2 67 | mesh.el_size_factor = 0.05 68 | # mesh.gmsh_exec_path = "D:\\vsmn20-software\\gmsh\gmsh.exe" 69 | 70 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 71 | 72 | # ---- Visualise mesh ------------------------------------------------------- 73 | 74 | # Hold left mouse button to pan. 75 | # Hold right mouse button to zoom. 76 | 77 | # Draw the geometry. 78 | 79 | #cfv.draw_geometry(g, labelCurves=True) 80 | 81 | # New figure window 82 | 83 | cfv.figure() 84 | 85 | # Draws the mesh. 86 | 87 | cfv.draw_mesh( 88 | coords=coords, 89 | edof=edof, 90 | dofs_per_node = mesh.dofs_per_node, 91 | el_type=mesh.el_type, 92 | filled=True, 93 | title="Example 02" 94 | ) 95 | 96 | # Show grid 97 | 98 | #cfv.show_grid() 99 | 100 | # Enter main loop 101 | 102 | cfv.show_and_wait() 103 | -------------------------------------------------------------------------------- /examples/experimental/point_in_geom.py: -------------------------------------------------------------------------------- 1 | import calfem.geometry as cfg 2 | import calfem.mesh as cfm 3 | import calfem.vis_mpl as cfv 4 | import calfem.utils as cfu 5 | import calfem.core as cfc 6 | 7 | import matplotlib.pyplot as plt 8 | import matplotlib as mpl 9 | import matplotlib.tri as tri 10 | 11 | import numpy as np 12 | 13 | # ---- Create Geometry ------------------------------------------------------ 14 | 15 | g = cfg.geometry() 16 | 17 | # Add Points: 18 | 19 | points = [ 20 | [0,0], 21 | [0,100], 22 | [0,150], 23 | [100,0], 24 | [150,0], 25 | [100,-100], 26 | [150,-100] 27 | ] 28 | 29 | for p in points: 30 | g.point(p) 31 | 32 | # Add Splines: 33 | 34 | g.spline([1,2], marker=2, elOnCurve=4) 35 | g.spline([3,4], elOnCurve=4) 36 | g.circle([1,0,3], elOnCurve = 10) 37 | g.circle([2,0,4], elOnCurve = 10) 38 | g.spline([3,5], elOnCurve = 6) 39 | g.spline([5,6], marker=3, elOnCurve = 4) 40 | g.spline([6,4], elOnCurve = 6) 41 | 42 | # Add Surfaces: 43 | # 44 | # When we set markers for surfaces, and have 2D elements, we can find which 45 | # region an element is in via the list 'elementmarkers', which is returned by 46 | # GmshMesher.create() 47 | 48 | g.structuredSurface([0,2,1,3], marker = 10) 49 | g.structuredSurface([1,4,5,6], marker = 11) 50 | 51 | el_type = 16 52 | dofs_per_node = 1 53 | 54 | mesh = cfm.GmshMeshGenerator(g, el_type, dofs_per_node) 55 | coords, edof, dofs, bdofs, elementmarkers = mesh.create() 56 | 57 | 58 | # ---- Visualise results ---------------------------------------------------- 59 | 60 | print("Visualising...") 61 | 62 | mpl.rcParams['figure.dpi'] = 160 63 | 64 | cfv.figure() 65 | 66 | cfv.draw_geometry(g, title="Geometry") 67 | 68 | cfv.point_in_geometry(g, [0.0, 0.0]) 69 | 70 | cfv.show_and_wait() 71 | 72 | print("Done.") 73 | -------------------------------------------------------------------------------- /examples/experimental/qt1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Mar 1 16:23:37 2017 4 | 5 | @author: Jonas Lindemann 6 | """ 7 | 8 | import sys 9 | import time 10 | 11 | from calfem.qt5 import * 12 | 13 | import calfem.geometry as cfg 14 | import calfem.mesh as cfm 15 | import calfem.vis as cfv 16 | 17 | class MainWindow(QMainWindow): 18 | def __init__(self): 19 | """Constructor""" 20 | super(MainWindow, self).__init__() 21 | 22 | if __name__ == "__main__": 23 | 24 | app = QApplication(sys.argv) 25 | widget = MainWindow() 26 | widget.show() 27 | sys.exit(app.exec_()) 28 | -------------------------------------------------------------------------------- /examples/experimental/qt2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Mar 9 17:14:04 2018 4 | 5 | @author: Jonas Lindemann 6 | """ 7 | 8 | # -*- coding: utf-8 -*- 9 | """ 10 | Created on Mon Apr 11 09:44:29 2016 11 | 12 | @author: lindemann 13 | """ 14 | 15 | import sys 16 | 17 | from PyQt5.QtWidgets import * 18 | 19 | class MyWindow(QWidget): 20 | """Main Window class for our application""" 21 | 22 | def __init__(self): 23 | """Class constructor""" 24 | super().__init__() 25 | 26 | self.init_ui() 27 | 28 | def init_ui(self): 29 | 30 | self.resize(200,200) 31 | self.move(50,50) 32 | self.setWindowTitle("MyWindow") 33 | 34 | self.main_widget = QWidget(self) 35 | 36 | self.button1 = QPushButton('Button1') 37 | self.button2 = QPushButton('Button2') 38 | self.button3 = QPushButton('Button3') 39 | self.button4 = QPushButton('Button4') 40 | 41 | self.button5 = QPushButton('Button5') 42 | self.button6 = QPushButton('Button6') 43 | self.button7 = QPushButton('Button7') 44 | self.button8 = QPushButton('Button8') 45 | 46 | self.vbox = QVBoxLayout(self) 47 | self.vbox.addWidget(self.button1) 48 | self.vbox.addWidget(self.button2) 49 | self.vbox.addWidget(self.button3) 50 | self.vbox.addWidget(self.button4) 51 | 52 | self.hbox = QHBoxLayout(self) 53 | self.hbox.addWidget(self.button5) 54 | self.hbox.addWidget(self.button6) 55 | self.hbox.addWidget(self.button7) 56 | self.hbox.addWidget(self.button8) 57 | 58 | self.vbox.addLayout(self.hbox) 59 | 60 | self.main_widget.setLayout(self.vbox) 61 | self.setCentralWidget(self.main_widget) 62 | 63 | 64 | if __name__ == '__main__': 65 | 66 | app = QApplication(sys.argv) 67 | 68 | window = MyWindow() 69 | window.show() 70 | 71 | sys.exit(app.exec_()) 72 | -------------------------------------------------------------------------------- /examples/experimental/tri_mesh.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import matplotlib.pyplot as plt 4 | import matplotlib as mpl 5 | import matplotlib.tri as tri 6 | 7 | import calfem.geometry as cfg 8 | import calfem.mesh as cfm 9 | import calfem.vis_mpl as cfv 10 | import calfem.utils as cfu 11 | import calfem.core as cfc 12 | 13 | import numpy as np 14 | 15 | coords = np.array([ 16 | [0.000, 0.000], 17 | [1.000, 0.000], 18 | [2.000, 0.500], 19 | [0.000, 1.000], 20 | [1.000, 1.000], 21 | [1.750, 1.300], 22 | [1.000, 1.700]]) 23 | 24 | edof = np.array([ 25 | [1, 2, 5], 26 | [5, 4, 1], 27 | [2, 3, 6], 28 | [6, 5, 2], 29 | [4, 5, 7], 30 | [5, 6, 7]]) 31 | 32 | values = [1, 2, 1, 2, 7, 4, 5] 33 | 34 | plt.figure() 35 | cfv.draw_nodal_values_contours(values, coords, edof) 36 | plt.colorbar() 37 | 38 | plt.figure() 39 | cfv.draw_nodal_values_shaded(values, coords, edof) 40 | plt.colorbar() 41 | 42 | plt.show() -------------------------------------------------------------------------------- /examples/exs_bar2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # example exs3 4 | # ---------------------------------------------------------------- 5 | # PURPOSE 6 | # Analysis of a plane truss. 7 | # ---------------------------------------------------------------- 8 | 9 | # REFERENCES 10 | # Ola Dahlblom 2004-09-07 11 | # Jonas Lindemann 2009-01-25 12 | # Ola Dahlblom 2023-02-02 13 | # ---------------------------------------------------------------- 14 | 15 | import numpy as np 16 | import calfem.core as cfc 17 | import calfem.utils as cfu 18 | import calfem.vis_mpl as cfv 19 | 20 | cfu.disp_h1("Analysis of a plane truss.") 21 | 22 | # ----- Topology matrix Edof ------------------------------------- 23 | 24 | edof = np.array([ 25 | [1, 2, 5, 6], 26 | [5, 6, 7, 8], 27 | [3, 4, 5, 6] 28 | ]) 29 | 30 | # ----- Stiffness matrix K and load vector f --------------------- 31 | 32 | K = np.array(np.zeros((8, 8))) 33 | f = np.array(np.zeros((8, 1))) 34 | 35 | # ----- Element properties --------------------------------------- 36 | 37 | E = 2.0e11 38 | A1 = 6.0e-4 39 | A2 = 3.0e-4 40 | A3 = 10.0e-4 41 | ep1 = [E, A1] 42 | ep2 = [E, A2] 43 | ep3 = [E, A3] 44 | 45 | # ----- Element coordinates -------------------------------------- 46 | 47 | ex1 = np.array([0.0, 1.6]) 48 | ex2 = np.array([1.6, 1.6]) 49 | ex3 = np.array([0.0, 1.6]) 50 | 51 | ey1 = np.array([0.0, 0.0]) 52 | ey2 = np.array([0.0, 1.2]) 53 | ey3 = np.array([1.2, 0.0]) 54 | 55 | # ----- Element stiffness matrices ------------------------------ 56 | 57 | Ke1 = cfc.bar2e(ex1, ey1, ep1) 58 | Ke2 = cfc.bar2e(ex2, ey2, ep2) 59 | Ke3 = cfc.bar2e(ex3, ey3, ep3) 60 | 61 | # ----- Assemble Ke into K --------------------------------------- 62 | 63 | K = cfc.assem(edof[0, :], K, Ke1) 64 | K = cfc.assem(edof[1, :], K, Ke2) 65 | K = cfc.assem(edof[2, :], K, Ke3) 66 | 67 | cfu.disp_h2("Stiffness matrix K:") 68 | cfu.disp_array(K) 69 | 70 | # ----- Solve the system of equations ---------------------------- 71 | 72 | bc = np.array([1, 2, 3, 4, 7, 8]) 73 | f[5] = -80e3 74 | a, r = cfc.solveq(K, f, bc) 75 | 76 | cfu.disp_h2("Displacements a:") 77 | cfu.disp_array(a) 78 | 79 | cfu.disp_h2("Reaction forces r:") 80 | cfu.disp_array(r) 81 | 82 | # ----- Element forces ------------------------------------------- 83 | 84 | ed1 = cfc.extract_ed(edof[0, :], a) 85 | N1 = cfc.bar2s(ex1, ey1, ep1, ed1) 86 | ed2 = cfc.extract_ed(edof[1, :], a) 87 | N2 = cfc.bar2s(ex2, ey2, ep2, ed2) 88 | ed3 = cfc.extract_ed(edof[2, :], a) 89 | N3 = cfc.bar2s(ex3, ey3, ep3, ed3) 90 | 91 | cfu.disp_h2("Element forces r:") 92 | 93 | print("N1 = ") 94 | print(N1) 95 | print("N2 = ") 96 | print(N2) 97 | print("N3 = ") 98 | print(N3) 99 | 100 | # ----- Draw deformed frame --------------------------------------- 101 | 102 | plotpar = [2, 1, 0] 103 | sfac = cfv.scalfact2(ex3, ey3, ed1, 0.1) 104 | print("sfac=") 105 | print(sfac) 106 | 107 | cfv.figure(1) 108 | cfv.eldraw2(ex1, ey1, plotpar) 109 | cfv.eldraw2(ex2, ey2, plotpar) 110 | cfv.eldraw2(ex3, ey3, plotpar) 111 | 112 | plotpar = [1, 2, 1] 113 | cfv.eldisp2(ex1, ey1, ed1, plotpar, sfac) 114 | cfv.eldisp2(ex2, ey2, ed2, plotpar, sfac) 115 | cfv.eldisp2(ex3, ey3, ed3, plotpar, sfac) 116 | cfv.axis([-0.4, 2.0, -0.4, 1.4]) 117 | plotpar1 = 2 118 | cfv.scalgraph2(sfac, [1e-3, 0, -0.3], plotpar1) 119 | cfv.title("Displacements") 120 | 121 | # ----- Draw normal force diagram -------------------------------- 122 | 123 | plotpar = [2, 1] 124 | sfac = cfv.scalfact2(ex1, ey1, N2[:, 0], 0.1) 125 | cfv.figure(2) 126 | cfv.secforce2(ex1, ey1, N1[:, 0], plotpar, sfac) 127 | cfv.secforce2(ex2, ey2, N2[:, 0], plotpar, sfac) 128 | cfv.secforce2(ex3, ey3, N3[:, 0], plotpar, sfac) 129 | cfv.axis([-0.4, 2.0, -0.4, 1.4]) 130 | cfv.scalgraph2(sfac, [5e4, 0, -0.3], plotpar1) 131 | cfv.title("Normal force") 132 | 133 | cfv.show_and_wait() 134 | -------------------------------------------------------------------------------- /examples/exs_bar2_la.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # example exs_bar2_la 4 | # ---------------------------------------------------------------- 5 | # PURPOSE 6 | # Analysis of a plane truss using loops. 7 | # ---------------------------------------------------------------- 8 | 9 | # REFERENCES 10 | # P-E Austrell 1994-03-08 11 | # K-G Olsson 1995-09-28 12 | # O Dahlblom 2004-08-31 13 | # J Lindemann 2009-01-25 14 | # O Dahlblom 2023-02-02 15 | # ---------------------------------------------------------------- 16 | 17 | import numpy as np 18 | import calfem.core as cfc 19 | import calfem.utils as cfu 20 | 21 | cfu.disp_h1("Analysis of a plane truss using loops") 22 | 23 | # ----- Topology matrix Edof ------------------------------------- 24 | 25 | edof = np.array([ 26 | [1, 2, 5, 6], 27 | [3, 4, 7, 8], 28 | [5, 6, 9, 10], 29 | [7, 8, 11, 12], 30 | [7, 8, 5, 6], 31 | [11, 12, 9, 10], 32 | [3, 4, 5, 6], 33 | [7, 8, 9, 10], 34 | [1, 2, 7, 8], 35 | [5, 6, 11, 12], 36 | ]) 37 | 38 | # ----- Stiffness matrix K and load vector f --------------------- 39 | 40 | K = np.zeros([12, 12]) 41 | f = np.zeros([12, 1]) 42 | f[10] = 0.5e6 * np.sin(np.pi / 6) 43 | f[11] = -0.5e6 * np.cos(np.pi / 6) 44 | 45 | # ----- Element properties --------------------------------------- 46 | 47 | A = 25.0e-4 48 | E = 2.1e11 49 | ep = [E, A] 50 | 51 | # ----- Element coordinates -------------------------------------- 52 | 53 | ex = np.array([ 54 | [0.0, 2.0], 55 | [0.0, 2.0], 56 | [2.0, 4.0], 57 | [2.0, 4.0], 58 | [2.0, 2.0], 59 | [4.0, 4.0], 60 | [0.0, 2.0], 61 | [2.0, 4.0], 62 | [0.0, 2.0], 63 | [2.0, 4.0], 64 | ]) 65 | 66 | ey = np.array([ 67 | [2.0, 2.0], 68 | [0.0, 0.0], 69 | [2.0, 2.0], 70 | [0.0, 0.0], 71 | [0.0, 2.0], 72 | [0.0, 2.0], 73 | [0.0, 2.0], 74 | [0.0, 2.0], 75 | [2.0, 0.0], 76 | [2.0, 0.0], 77 | ]) 78 | 79 | # ----- Create element stiffness matrices Ke and assemble into K - 80 | 81 | for elx, ely, eltopo in zip(ex, ey, edof): 82 | Ke = cfc.bar2e(elx, ely, ep) 83 | cfc.assem(eltopo, K, Ke) 84 | 85 | cfu.disp_h2("Stiffness matrix K:") 86 | cfu.disp_array(K) 87 | 88 | # ----- Solve the system of equations ---------------------------- 89 | 90 | bc = np.array([1, 2, 3, 4]) 91 | a, r = cfc.solveq(K, f, bc) 92 | 93 | cfu.disp_h2("Displacements a:") 94 | cfu.disp_array(a) 95 | 96 | cfu.disp_h2("Reaction forces r:") 97 | cfu.disp_array(r) 98 | 99 | # ----- Element forces ------------------------------------------- 100 | 101 | ed = cfc.extract_ed(edof, a) 102 | N = np.zeros([edof.shape[0]]) 103 | 104 | cfu.disp_h2("Element forces:") 105 | 106 | i = 0 107 | for elx, ely, eld in zip(ex, ey, ed): 108 | es = cfc.bar2s(elx, ely, ep, eld) 109 | N[i] = es[0][0] 110 | print("N%d = %g" % (i + 1, N[i])) 111 | i += 1 112 | -------------------------------------------------------------------------------- /examples/exs_bar2_lb.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # example exs_bar2_la 4 | # ---------------------------------------------------------------- 5 | # PURPOSE 6 | # Analysis of a plane truss using loops and extraction of 7 | # element coordinates from a global coordinate matrix. 8 | # ---------------------------------------------------------------- 9 | 10 | # REFERENCES 11 | # P-E Austrell 1994-03-08 12 | # K-G Olsson 1995-09-28 13 | # O Dahlblom 2004-08-31 14 | # J Lindemann 2009-01-25 15 | # O Dahlblom 2019-12-16 16 | # O Dahlblom 2023-02-02 17 | # ---------------------------------------------------------------- 18 | 19 | import numpy as np 20 | import calfem.core as cfc 21 | import calfem.utils as cfu 22 | 23 | cfu.disp_h1("Analysis of a plane truss using loops and extraction of element coordinates from a global coordinate matrix.") 24 | 25 | # ----- Topology matrix Edof ------------------------------------- 26 | 27 | edof = np.array([ 28 | [1, 2, 5, 6], 29 | [3, 4, 7, 8], 30 | [5, 6, 9, 10], 31 | [7, 8, 11, 12], 32 | [7, 8, 5, 6], 33 | [11, 12, 9, 10], 34 | [3, 4, 5, 6], 35 | [7, 8, 9, 10], 36 | [1, 2, 7, 8], 37 | [5, 6, 11, 12], 38 | ]) 39 | 40 | # ----- Stiffness matrix K and load vector f --------------------- 41 | 42 | K = np.zeros([12, 12]) 43 | f = np.zeros([12, 1]) 44 | f[10] = 0.5e6 * np.sin(np.pi / 6) 45 | f[11] = -0.5e6 * np.cos(np.pi / 6) 46 | 47 | # ----- Element properties --------------------------------------- 48 | 49 | A = 25.0e-4 50 | E = 2.1e11 51 | ep = [E, A] 52 | 53 | # ----- Global coordinates and topology -------------------------- 54 | 55 | coord = np.array([ 56 | [0, 2], 57 | [0, 0], 58 | [2, 2], 59 | [2, 0], 60 | [4, 2], 61 | [4, 0] 62 | ]) 63 | 64 | dof = np.array([ 65 | [1, 2], 66 | [3, 4], 67 | [5, 6], 68 | [7, 8], 69 | [9, 10], 70 | [11, 12] 71 | ]) 72 | 73 | # ----- Element coordinates -------------------------------------- 74 | 75 | ex, ey = cfc.coordxtr(edof, coord, dof, 2) 76 | 77 | # ----- Create element stiffness matrices Ke and assemble into K - 78 | 79 | for elx, ely, eltopo in zip(ex, ey, edof): 80 | Ke = cfc.bar2e(elx, ely, ep) 81 | cfc.assem(eltopo, K, Ke) 82 | 83 | cfu.disp_h2("Stiffness matrix K:") 84 | cfu.disp_array(K) 85 | 86 | # ----- Solve the system of equations ---------------------------- 87 | 88 | bc = np.array([1, 2, 3, 4]) 89 | a, r = cfc.solveq(K, f, bc) 90 | 91 | cfu.disp_h2("Displacements a:") 92 | cfu.disp_array(a) 93 | 94 | cfu.disp_h2("Reaction forces r:") 95 | cfu.disp_array(r) 96 | 97 | # ----- Element forces ------------------------------------------- 98 | 99 | ed = cfc.extract_ed(edof, a) 100 | N = np.zeros([edof.shape[0]]) 101 | 102 | cfu.disp_h2("Element forces:") 103 | 104 | i = 0 105 | for elx, ely, eld in zip(ex, ey, ed): 106 | es = cfc.bar2s(elx, ely, ep, eld) 107 | N[i] = es[0][0] 108 | print("N%d = %g" % (i + 1, N[i])) 109 | i += 1 110 | -------------------------------------------------------------------------------- /examples/exs_beam1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # example exs_beam1 4 | # ---------------------------------------------------------------- 5 | # PURPOSE 6 | # Analysis of a simply supported beam. 7 | # ---------------------------------------------------------------- 8 | 9 | # REFERENCES 10 | # Ola Dahlblom 2015-11-13 11 | # Ola Dahlblom 2019-12-11 12 | # Ola Dahlblom 2022-07-11 13 | # ---------------------------------------------------------------- 14 | 15 | import numpy as np 16 | import matplotlib.pyplot as plt 17 | import calfem.core as cfc 18 | import calfem.utils as cfu 19 | import calfem.vis_mpl as cfv 20 | 21 | # ----- Topology ------------------------------------------------- 22 | 23 | edof = np.array([ 24 | [1, 2, 3, 4], 25 | [3, 4, 5, 6] 26 | ]) 27 | 28 | # ----- Stiffness matrix K and load vector f --------------------- 29 | 30 | K = np.array(np.zeros((6, 6))) 31 | f = np.array(np.zeros((6, 1))) 32 | f[2] = -10e3 33 | 34 | # ----- Element stiffness and element load matrices ------------- 35 | 36 | E = 210e9 37 | I = 2510e-8 38 | 39 | ep = np.array([E, I]) 40 | ex1 = np.array([0, 3]) 41 | ex2 = np.array([3, 9]) 42 | eq1 = np.array([0]) 43 | eq2 = np.array([0]) 44 | 45 | Ke1 = cfc.beam1e(ex1, ep) 46 | Ke2 = cfc.beam1e(ex2, ep) 47 | 48 | # ----- Assemble Ke into K --------------------------------------- 49 | 50 | cfc.assem(edof[0, :], K, Ke1) 51 | cfc.assem(edof[1, :], K, Ke2) 52 | 53 | # ----- Solve the system of equations and compute reactions ------ 54 | 55 | bc = np.array([1, 5]) 56 | a, r = cfc.solveq(K, f, bc) 57 | 58 | cfu.disp_array(a, ["a"]) 59 | cfu.disp_array(r, ["r"]) 60 | 61 | # ----- Section forces ------------------------------------------- 62 | 63 | ed = cfc.extract_ed(edof, a) 64 | 65 | es1, ed1, ec1 = cfc.beam1s(ex1, ep, ed[0, :], eq1, nep=4) 66 | es2, ed2, ec2 = cfc.beam1s(ex2, ep, ed[1, :], eq2, nep=7) 67 | 68 | cfu.disp_h2("es1") 69 | cfu.disp_array(es1, ["V1", "M1"]) 70 | cfu.disp_h2("ed1") 71 | cfu.disp_array(ed1, ["v1"]) 72 | cfu.disp_h2("ec1") 73 | cfu.disp_array(ec1, ["x1"]) 74 | cfu.disp_h2("es2") 75 | cfu.disp_array(es2, ["V2", "M2"]) 76 | cfu.disp_h2("ed2") 77 | cfu.disp_array(ed2, ["v2"]) 78 | cfu.disp_h2("ec2") 79 | cfu.disp_array(ec2, ["x2"]) 80 | 81 | # ----- Draw deformed beam --------------------------------------- 82 | 83 | cfv.figure(1) 84 | plt.plot([0, 9], [0, 0], color=(0.8, 0.8, 0.8)) 85 | plt.plot( 86 | np.concatenate(([0], ec1[:, 0], 3 + ec2[:, 0], [9]), 0), 87 | np.concatenate(([0], ed1[:, 0], ed2[:, 0], [0]), 0), 88 | color=(0.0, 0.0, 0.0), 89 | ) 90 | cfv.title("displacements") 91 | 92 | # ----- Draw shear force diagram---------------------------------- 93 | 94 | cfv.figure(2) 95 | plt.plot([0, 9], [0, 0], color=(0.8, 0.8, 0.8)) 96 | plt.plot( 97 | np.concatenate(([0], ec1[:, 0], 3 + ec2[:, 0], [9]), 0), 98 | -np.concatenate(([0], es1[:, 0], es2[:, 0], [0]), 0) / 1000, 99 | color=(0.0, 0.0, 0.0), 100 | ) 101 | cfv.title("shear force") 102 | 103 | # ----- Draw moment diagram---------------------------------- 104 | 105 | cfv.figure(3) 106 | plt.plot([0, 9], [0, 0], color=(0.8, 0.8, 0.8)) 107 | plt.plot( 108 | np.concatenate(([0], ec1[:, 0], 3 + ec2[:, 0], [9]), 0), 109 | -np.concatenate(([0], es1[:, 1], es2[:, 1], [0]), 0) / 1000, 110 | color=(0.0, 0.0, 0.0), 111 | ) 112 | cfv.title("bending moment") 113 | 114 | cfv.show_and_wait() 115 | -------------------------------------------------------------------------------- /examples/exs_beambar2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # example exs_beam2 4 | # ---------------------------------------------------------------- 5 | # PURPOSE 6 | # Analysis of a combined beam and bar structure. 7 | # ---------------------------------------------------------------- 8 | 9 | # REFERENCES 10 | # Ola Dahlblom 2015-11-16 11 | # Ola Dahlblom 2019-12-19 12 | # Ola Dahlblom 2023-02-02 13 | # Copyright (c) Division of Structural Mechanics and 14 | # Division of Solid Mechanics. 15 | # Lund University 16 | # ---------------------------------------------------------------- 17 | 18 | import numpy as np 19 | import calfem.core as cfc 20 | import calfem.utils as cfu 21 | import calfem.vis_mpl as cfv 22 | 23 | #np.set_printoptions(precision=3, suppress=True) 24 | 25 | # ----- Topology ------------------------------------------------- 26 | 27 | edof1 = np.array([ 28 | [1, 2, 3, 4, 5, 6], 29 | [4, 5, 6, 7, 8, 9], 30 | [7, 8, 9, 10, 11, 12] 31 | ]) 32 | 33 | edof2 = np.array([ 34 | [13, 14, 4, 5], 35 | [13, 14, 7, 8] 36 | ]) 37 | 38 | # ----- Stiffness matrix K and load vector f --------------------- 39 | 40 | K = np.array(np.zeros((14, 14))) 41 | f = np.array(np.zeros((14, 1))) 42 | 43 | # ----- Element stiffness and element load matrices ------------- 44 | 45 | E = 200.e9 46 | A1 = 4.e-3 47 | I1 = 5.4e-5 48 | A2 = 1.e-3 49 | 50 | ep1 = np.array([E, A1, I1]) 51 | ep4 = np.array([E, A2]) 52 | 53 | eq1 = np.array([0, 0]) 54 | eq2 = np.array([0, -10e+3]) 55 | 56 | ex1 = np.array([0, 2]) 57 | ex2 = np.array([2, 4]) 58 | ex3 = np.array([4, 6]) 59 | ex4 = np.array([0, 2]) 60 | ex5 = np.array([0, 4]) 61 | ey1 = np.array([2, 2]) 62 | ey2 = np.array([2, 2]) 63 | ey3 = np.array([2, 2]) 64 | ey4 = np.array([0, 2]) 65 | ey5 = np.array([0, 2]) 66 | 67 | Ke1 = cfc.beam2e(ex1, ey1, ep1) 68 | Ke2, fe2 = cfc.beam2e(ex2, ey2, ep1, eq2) 69 | Ke3, fe3 = cfc.beam2e(ex3, ey3, ep1, eq2) 70 | Ke4 = cfc.bar2e(ex4, ey4, ep4) 71 | Ke5 = cfc.bar2e(ex5, ey5, ep4) 72 | 73 | # ----- Assemble Ke into K --------------------------------------- 74 | 75 | K = cfc.assem(edof1[0, :], K, Ke1) 76 | K, f = cfc.assem(edof1[1, :], K, Ke2, f, fe2) 77 | K, f = cfc.assem(edof1[2, :], K, Ke3, f, fe3) 78 | K = cfc.assem(edof2[0, :], K, Ke4) 79 | K = cfc.assem(edof2[1, :], K, Ke5) 80 | 81 | # ----- Solve the system of equations and compute reactions ------ 82 | 83 | bc = np.array([1, 2, 3, 13, 14]) 84 | a, r = cfc.solveq(K, f, bc) 85 | 86 | cfu.disp_h2("Displacements a:") 87 | cfu.disp_array(a) 88 | 89 | cfu.disp_h2("Reaction forces r:") 90 | cfu.disp_array(r) 91 | 92 | # ----- Section forces ------------------------------------------- 93 | 94 | ed1 = cfc.extract_ed(edof1, a) 95 | ed2 = cfc.extract_ed(edof2, a) 96 | 97 | es1, _, _ = cfc.beam2s(ex1, ey1, ep1, ed1[0, :], eq1, nep=11) 98 | es2, _, _ = cfc.beam2s(ex2, ey2, ep1, ed1[1, :], eq2, nep=11) 99 | es3, _, _ = cfc.beam2s(ex3, ey3, ep1, ed1[2, :], eq2, nep=11) 100 | es4 = cfc.bar2s(ex4, ey4, ep4, ed2[0, :]) 101 | es5 = cfc.bar2s(ex5, ey5, ep4, ed2[1, :]) 102 | 103 | cfu.disp_h2("es1 = ") 104 | cfu.disp_array(es1, headers=["N", "Q", "M"]) 105 | cfu.disp_h2("es2 = ") 106 | cfu.disp_array(es2, headers=["N", "Q", "M"]) 107 | cfu.disp_h2("es3 = ") 108 | cfu.disp_array(es3, headers=["N", "Q", "M"]) 109 | cfu.disp_h2("es4 = ") 110 | cfu.disp_array(es4, headers=["N"]) 111 | cfu.disp_h2("es5 = ") 112 | cfu.disp_array(es5, headers=["N"]) 113 | 114 | -------------------------------------------------------------------------------- /examples/exs_flw_diff2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # example exs8 4 | # ---------------------------------------------------------------- 5 | # PURPOSE 6 | # Analysis of two dimensional diffusion 7 | # ---------------------------------------------------------------- 8 | 9 | # REFERENCES 10 | # Karl-Gunnar Olsson 1995-10-08 11 | # Ola Dahlblom 2004-09-14 12 | # ---------------------------------------------------------------- 13 | 14 | import numpy as np 15 | import calfem.vis_mpl as cfv 16 | import calfem.core as cfc 17 | import calfem.utils as cfu 18 | 19 | # ----- System matrices ----- 20 | 21 | K = np.zeros((15, 15)) 22 | f = np.zeros((15, 1)) 23 | Coord = np.array( 24 | [ 25 | [0, 0], 26 | [0.025, 0], 27 | [0.05, 0], 28 | [0, 0.025], 29 | [0.025, 0.025], 30 | [0.05, 0.025], 31 | [0, 0.05], 32 | [0.025, 0.05], 33 | [0.05, 0.05], 34 | [0, 0.075], 35 | [0.025, 0.075], 36 | [0.05, 0.075], 37 | [0, 0.1], 38 | [0.025, 0.1], 39 | [0.05, 0.1], 40 | ] 41 | ) 42 | 43 | Dof = np.array( 44 | [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15]] 45 | ) 46 | 47 | # ----- Element properties, topology and coordinates ----- 48 | 49 | ep = np.array([1]) 50 | D = np.array([[1, 0], [0, 1]]) 51 | Edof = np.array( 52 | [ 53 | [1, 2, 5, 4], 54 | [2, 3, 6, 5], 55 | [4, 5, 8, 7], 56 | [5, 6, 9, 8], 57 | [7, 8, 11, 10], 58 | [8, 9, 12, 11], 59 | [10, 11, 14, 13], 60 | [11, 12, 15, 14], 61 | ] 62 | ) 63 | Ex, Ey = cfc.coordxtr(Edof, Coord, Dof) 64 | 65 | # ----- Generate FE-mesh ----- 66 | 67 | # clf; eldraw2(Ex,Ey,[1 3 0],Edof(:,1)); 68 | # disp('PRESS ENTER TO CONTINUE'); pause; clf; 69 | 70 | # ----- Create and assemble element matrices ----- 71 | 72 | for i in range(8): 73 | Ke = cfc.flw2qe(Ex[i], Ey[i], ep, D) 74 | K = cfc.assem(Edof[i], K, Ke) 75 | 76 | # ----- Solve equation system ----- 77 | 78 | bcPrescr = np.array([1, 2, 3, 4, 7, 10, 13, 14, 15]) 79 | bcVal = np.array([0, 0, 0, 0, 0, 0, 0.5e-3, 1e-3, 1e-3]) 80 | a, r = cfc.solveq(K, f, bcPrescr, bcVal) 81 | 82 | # ----- Compute element flux vector ----- 83 | 84 | Ed = cfc.extractEldisp(Edof, a) 85 | Es = np.zeros((8, 2)) 86 | for i in range(8): 87 | Es[i], Et = cfc.flw2qs(Ex[i], Ey[i], ep, D, Ed[i]) 88 | 89 | 90 | # ----- Draw flux vectors and contourlines ----- 91 | 92 | cfu.disp_h2("Ex") 93 | cfu.disp_array(Ex, headers=["x0", "x1", "x2", "x3"]) 94 | cfu.disp_h2("Ey") 95 | cfu.disp_array(Ey, headers=["x0", "x1", "x2", "x3"]) 96 | cfu.disp_h2("a") 97 | cfu.disp_array(a) 98 | cfu.disp_h2("Ed") 99 | cfu.disp_array(Ed, headers=["ed0", "ed1", "ed2", "ed3"]) 100 | 101 | cfv.eldraw2(Ex, Ey, [1, 2, 1], range(1, Ex.shape[0] + 1)) 102 | cfv.eliso2_mpl(Ex, Ey, Ed) 103 | cfv.show_and_wait() 104 | -------------------------------------------------------------------------------- /examples/exs_flw_temp1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # example exs_flw_temp1 4 | #---------------------------------------------------------------- 5 | # PURPOSE 6 | # Analysis of one dimensional heat flow. 7 | #---------------------------------------------------------------- 8 | 9 | # REFERENCES 10 | # P-E Austrell 1994-03-08 11 | # K-G Olsson 1995-09-28 12 | # O Dahlblom 2004-09-07 13 | # O Dahlblom 2023-02-02 14 | # ---------------------------------------------------------------- 15 | 16 | import numpy as np 17 | import calfem.core as cfc 18 | import calfem.utils as cfu 19 | 20 | # ----- Topology ------------------------------------------------- 21 | 22 | edof = np.array([ 23 | [1, 2], 24 | [2, 3], 25 | [3, 4], 26 | [4, 5], 27 | [5, 6] 28 | ]) 29 | 30 | # ----- Stiffness matrix K and load vector f --------------------- 31 | 32 | K = np.array(np.zeros((6, 6))) 33 | f = np.array(np.zeros((6, 1))) 34 | f[3] = 10 35 | 36 | # ----- Element stiffness and element load matrices ------------- 37 | 38 | ep1 = 25 39 | ep2 = 24.3 40 | ep3 = 0.4 41 | ep4 = 17 42 | ep5 = 7.7 43 | 44 | Ke1 = cfc.spring1e(ep1) 45 | Ke2 = cfc.spring1e(ep2) 46 | Ke3 = cfc.spring1e(ep3) 47 | Ke4 = cfc.spring1e(ep4) 48 | Ke5 = cfc.spring1e(ep5) 49 | 50 | # ----- Assemble Ke into K --------------------------------------- 51 | 52 | cfc.assem(edof[0, :], K, Ke1) 53 | cfc.assem(edof[1, :], K, Ke2) 54 | cfc.assem(edof[2, :], K, Ke3) 55 | cfc.assem(edof[3, :], K, Ke4) 56 | cfc.assem(edof[4, :], K, Ke5) 57 | 58 | # ----- Solve the system of equations ---------------------------- 59 | 60 | bc = np.array([1, 6]) 61 | bcVal = np.array([-17, 20]) 62 | a, r = cfc.solveq(K, f, bc, bcVal) 63 | 64 | cfu.disp_h2("Temperatures a:") 65 | cfu.disp_array(a) 66 | 67 | cfu.disp_h2("Reaction flows r:") 68 | cfu.disp_array(r) 69 | 70 | # ----- Section forces ------------------------------------------- 71 | 72 | ed1 = cfc.extract_ed(edof[0, :], a) 73 | ed2 = cfc.extract_ed(edof[1, :], a) 74 | ed3 = cfc.extract_ed(edof[2, :], a) 75 | ed4 = cfc.extract_ed(edof[3, :], a) 76 | ed5 = cfc.extract_ed(edof[4, :], a) 77 | 78 | q1 = cfc.spring1s(ep1, ed1) 79 | q2 = cfc.spring1s(ep2, ed2) 80 | q3 = cfc.spring1s(ep3, ed3) 81 | q4 = cfc.spring1s(ep4, ed4) 82 | q5 = cfc.spring1s(ep5, ed5) 83 | 84 | cfu.disp_h2("Element flows:") 85 | 86 | print("q1 = ") 87 | print(q1) 88 | print("q2 = ") 89 | print(q2) 90 | print("q3 = ") 91 | print(q3) 92 | print("q4 = ") 93 | print(q4) 94 | print("q5 = ") 95 | print(q5) 96 | 97 | -------------------------------------------------------------------------------- /examples/exs_flw_temp2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # example exs2 4 | # ---------------------------------------------------------------- 5 | # PURPOSE 6 | # Analysis of one dimensional heat flow. 7 | # ---------------------------------------------------------------- 8 | 9 | # REFERENCES 10 | # P-E Austrell 1994-03-08 11 | # K-G Olsson 1995-09-28 12 | # O Dahlblom 2004-09-07 13 | # J Lindemann 2009-01-25 14 | # ---------------------------------------------------------------- 15 | 16 | import numpy as np 17 | import calfem.core as cfc 18 | import calfem.utils as cfu 19 | 20 | # ----- Topology matrix Edof ------------------------------------- 21 | 22 | edof = np.array([ 23 | [1, 2], 24 | [2, 3], 25 | [3, 4], 26 | [4, 5], 27 | [5, 6] 28 | ]) 29 | 30 | # ----- Stiffness matrix K and load vector f --------------------- 31 | 32 | K = np.matrix(np.zeros((6, 6))) 33 | f = np.matrix(np.zeros((6, 1))) 34 | f[3] = 10.0 35 | 36 | # ----- Element properties --------------------------------------- 37 | 38 | ep1 = 25.0 39 | ep2 = 24.3 40 | ep3 = 0.4 41 | ep4 = 17.0 42 | ep5 = 7.7 43 | 44 | # ----- Element stiffness matrices ------------------------------ 45 | 46 | Ke1 = cfc.spring1e(ep1) 47 | Ke2 = cfc.spring1e(ep2) 48 | Ke3 = cfc.spring1e(ep3) 49 | Ke4 = cfc.spring1e(ep4) 50 | Ke5 = cfc.spring1e(ep5) 51 | 52 | # ---- Assemble Ke into K --------------------------------------- 53 | 54 | cfc.assem(edof[0, :], K, Ke1) 55 | cfc.assem(edof[1, :], K, Ke2) 56 | cfc.assem(edof[2, :], K, Ke3) 57 | cfc.assem(edof[3, :], K, Ke4) 58 | cfc.assem(edof[4, :], K, Ke5) 59 | 60 | cfu.disp_h2("Stiffness matrix K:") 61 | cfu.disp_array(K) 62 | 63 | # ----- Solve the system of equations ---------------------------- 64 | 65 | bc = np.array([1, 6]) 66 | bcVal = np.array([-17.0, 20.0]) 67 | a, r = cfc.solveq(K, f, bc, bcVal) 68 | 69 | cfu.disp_h2("Temperatures a:") 70 | cfu.disp_array(a) 71 | 72 | cfu.disp_h2("Reaction flows r:") 73 | cfu.disp_array(r) 74 | 75 | # ----- Element flows ------------------------------------------- 76 | 77 | ed1 = cfc.extract_ed(edof[0, :], a) 78 | ed2 = cfc.extract_ed(edof[1, :], a) 79 | ed3 = cfc.extract_ed(edof[2, :], a) 80 | ed4 = cfc.extract_ed(edof[3, :], a) 81 | ed5 = cfc.extract_ed(edof[4, :], a) 82 | 83 | q1 = cfc.spring1s(ep1, ed1) 84 | q2 = cfc.spring1s(ep2, ed2) 85 | q3 = cfc.spring1s(ep3, ed3) 86 | q4 = cfc.spring1s(ep4, ed4) 87 | q5 = cfc.spring1s(ep5, ed5) 88 | 89 | cfu.disp_h2("Element flows r:") 90 | 91 | print("q1 = "+str(q1)) 92 | print("q2 = "+str(q2)) 93 | print("q3 = "+str(q3)) 94 | print("q4 = "+str(q4)) 95 | print("q5 = "+str(q5)) 96 | -------------------------------------------------------------------------------- /examples/exs_spring.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # example exs1 4 | # ---------------------------------------------------------------- 5 | # PURPOSE 6 | # Linear elastic spring analysis. Introduction to the basic 7 | # steps in the finite element method. 8 | # ---------------------------------------------------------------- 9 | 10 | # REFERENCES 11 | # P-E Austrell 1994-03-08 12 | # K-G Olsson 1995-09-28 13 | # O Dahlblom 2004-09-06 14 | # J Lindemann 2009-01-25 15 | # ---------------------------------------------------------------- 16 | 17 | # ----- import necesarry mooules 18 | 19 | import numpy as np 20 | import calfem.core as cfc 21 | import calfem.utils as cfu 22 | 23 | # ----- Topology matrix Edof 24 | 25 | edof = np.array([ 26 | [1, 2], # element 1 between node 1 and 2 27 | [2, 3], # element 2 between node 2 and 3 28 | [2, 3] # element 3 between node 2 and 3 29 | ]) 30 | 31 | # ----- Stiffness matrix K and load vector f 32 | 33 | K = np.zeros((3, 3)) 34 | f = np.zeros((3, 1)) 35 | 36 | # ----- Element stiffness matrices 37 | 38 | k = 1500. 39 | ep1 = k 40 | ep2 = 2.*k 41 | Ke1 = cfc.spring1e(ep1) 42 | Ke2 = cfc.spring1e(ep2) 43 | 44 | # ----- Assemble Ke into K 45 | 46 | cfc.assem(edof[0, :], K, Ke2) 47 | cfc.assem(edof[1, :], K, Ke1) 48 | cfc.assem(edof[2, :], K, Ke2) 49 | 50 | cfu.disp_h2("Stiffness matrix K:") 51 | cfu.disp_array(K) 52 | 53 | # f[1] corresponds to edof 2 54 | 55 | f[1] = 100.0 56 | 57 | # ----- Solve the system of equations 58 | 59 | bc = np.array([1, 3]) 60 | a, r = cfc.solveq(K, f, bc) 61 | 62 | cfu.disp_h2("Displacements a:") 63 | cfu.disp_array(a) 64 | 65 | cfu.disp_h2("Reaction forces r:") 66 | cfu.disp_array(r) 67 | 68 | # ----- Caculate element forces 69 | 70 | ed1 = cfc.extract_ed(edof[0, :], a) 71 | ed2 = cfc.extract_ed(edof[1, :], a) 72 | ed3 = cfc.extract_ed(edof[2, :], a) 73 | 74 | es1 = cfc.spring1s(ep2, ed1) 75 | es2 = cfc.spring1s(ep1, ed2) 76 | es3 = cfc.spring1s(ep2, ed3) 77 | 78 | cfu.disp_h2("Element forces N:") 79 | print("N1 = "+str(es1)) 80 | print("N2 = "+str(es2)) 81 | print("N3 = "+str(es3)) 82 | -------------------------------------------------------------------------------- /examples/exv1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Example using Vedo, spring elements 4 | 5 | @author: Andreas Åmand 6 | """ 7 | 8 | import numpy as np 9 | import calfem.core as cfc 10 | import calfem.vis_vedo as cfv 11 | 12 | coord = np.array([ 13 | [0], 14 | [0.5], 15 | [1], 16 | [1.5] 17 | ]) 18 | 19 | dof = np.array([ 20 | [1], 21 | [2], 22 | [3], 23 | [4] 24 | ]) 25 | 26 | edof = np.array([ 27 | [1, 2], 28 | [2, 3], 29 | [3, 4] 30 | ]) 31 | 32 | k = 1000 33 | ep = [3*k, k, 8*k] 34 | 35 | ndof = dof.shape[0]*dof.shape[1] 36 | nel = edof.shape[0] 37 | K = np.zeros([ndof,ndof]) 38 | for i in range(nel): 39 | Ke = cfc.spring1e(ep[i]) 40 | K = cfc.assem(edof[i],K,Ke) 41 | 42 | f = np.zeros([ndof,1]) 43 | f[3,0] = 500 #Newton 44 | 45 | bcPrescr = np.array([1]) 46 | a,r = cfc.solveq(K, f, bcPrescr) 47 | 48 | cfv.figure(1,flat=True) 49 | cfv.draw_mesh(edof,coord,dof,1) 50 | mesh = cfv.draw_displaced_mesh(edof,coord,dof,1,a,offset=[0,0.2,0],render_nodes=True) 51 | cfv.add_text_3D('k=3 kN/m',[0.15,-0.1,0],size=0.03) 52 | cfv.add_text_3D('k=1 kN/m',[0.65,-0.1,0],size=0.03) 53 | cfv.add_text_3D('k=8 kN/m',[1.15,-0.1,0],size=0.03) 54 | cfv.add_text_3D('F_x =500 N',[1.55,-0.02,0],size=0.03) 55 | 56 | # For exporting mesh 57 | cfv.export_vtk('export/exv1/exv1', mesh) 58 | 59 | cfv.figure(2) 60 | steps = 20 61 | cfv.add_text(f'Looping bewteen undef. & def. state w/ {steps} steps',pos='top-middle') 62 | cfv.animation(edof,coord,dof,1,a,loop=True,steps=20,dt=0,export=True,file='export/exv1/anim/exv1') 63 | 64 | #Start Calfem-vedo visualization 65 | cfv.show_and_wait() 66 | 67 | # For not exporting animation 68 | #cfv.animation(edof,coord,dof,1,a,loop=True,steps=20,dt=0) 69 | 70 | -------------------------------------------------------------------------------- /examples/exv4.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/examples/exv4.mat -------------------------------------------------------------------------------- /examples/gmsh-api/exgm1.py: -------------------------------------------------------------------------------- 1 | import gmsh 2 | import sys 3 | 4 | lc = 0 5 | 6 | gmsh.initialize() 7 | gmsh.model.occ.addBox(0, 0, 0, 1, 1, 1, 1) 8 | gmsh.model.occ.synchronize() 9 | 10 | #gmsh.model.add_physical_group(1, [1, 2, 4], 5) 11 | #ps = gmsh.model.add_physical_group(2, [1]) 12 | #gmsh.model.set_physical_name(2, ps, "My surface") 13 | 14 | #gmsh.option.setNumber("Mesh.MeshSizeFactor", 0.2) 15 | #gmsh.option.setNumber("Mesh.Algorithm", 6) # Frontal-Delaunay for 2D meshes 16 | #gmsh.option.setNumber("Mesh.Algorithm", 8) # Frontal-Delaunay for quads 17 | #gmsh.model.mesh.setAlgorithm(2, 33, 1) 18 | #gmsh.option.setNumber("Mesh.Smoothing", 100) 19 | #gmsh.option.setNumber("Mesh.RecombineAll", 1) 20 | #gmsh.option.setNumber("Mesh.RecombinationAlgorithm", 2) # or 3 21 | 22 | gmsh.model.mesh.generate(3) 23 | 24 | entities = gmsh.model.get_entities() 25 | 26 | tag = 1 27 | dim = 3 28 | 29 | node_tags, node_coords, node_params = gmsh.model.mesh.get_nodes(dim, tag) 30 | elem_types, elem_tags, elem_node_tags = gmsh.model.mesh.get_elements(dim, tag) 31 | type = gmsh.model.get_type(dim, tag) 32 | name = gmsh.model.getEntityName(dim, tag) 33 | 34 | print("type =", type) 35 | print("tag =", tag) 36 | 37 | print("node_tags:", len(node_tags)) 38 | print(node_tags) 39 | print("node_coords:", int(node_coords.shape[0]/3)) 40 | print(node_coords.reshape((int(node_coords.shape[0]/3), 3))) 41 | print("node_params:", len(node_params)) 42 | print(node_params) 43 | print("elem_types:", len(elem_types)) 44 | print(elem_types) 45 | print("elem_tags:", len(elem_tags)) 46 | print(elem_tags[0]) 47 | print("elem_node_tags:", len(elem_node_tags)) 48 | print(elem_node_tags[0]) 49 | 50 | # for e in entities: 51 | # dim = e[0] 52 | # tag = e[1] 53 | # print(dim, tag) 54 | # node_tags, node_coords, node_params = gmsh.model.mesh.get_nodes(dim, tag) 55 | # elem_types, elem_tags, elem_node_tags = gmsh.model.mesh.get_elements(dim, tag) 56 | 57 | # type = gmsh.model.getType(e[0], e[1]) 58 | # name = gmsh.model.getEntityName(e[0], e[1]) 59 | # #if len(name): name += ' ' 60 | # #print("Entity " + name + str(e) + " of type " + type) 61 | 62 | # num_elem = sum(len(i) for i in elem_tags) 63 | # #print(" - Mesh has " + str(len(node_tags)) + " nodes and " + str(num_elem) + 64 | # # " elements") 65 | 66 | # for i in elem_node_tags: 67 | # print(i) 68 | 69 | 70 | 71 | # # * Upward and downward adjacencies: 72 | # up, down = gmsh.model.get_adjacencies(e[0], e[1]) 73 | # if len(up): 74 | # print(" - Upward adjacencies: " + str(up)) 75 | # if len(down): 76 | # print(" - Downward adjacencies: " + str(down)) 77 | 78 | # physicalTags = gmsh.model.getPhysicalGroupsForEntity(dim, tag) 79 | # if len(physicalTags): 80 | # s = '' 81 | # for p in physicalTags: 82 | # n = gmsh.model.getPhysicalName(dim, p) 83 | # if n: n += ' ' 84 | # s += n + '(' + str(dim) + ', ' + str(p) + ') ' 85 | # print(" - Physical groups: " + s) 86 | 87 | # partitions = gmsh.model.getPartitions(e[0], e[1]) 88 | # if len(partitions): 89 | # print(" - Partition tags: " + str(partitions) + " - parent entity " + 90 | # str(gmsh.model.getParent(e[0], e[1]))) 91 | 92 | # # * List all types of elements making up the mesh of the entity: 93 | # for t in elem_types: 94 | # name, dim, order, numv, parv, _ = gmsh.model.mesh.getElementProperties(t) 95 | # print(" - Element type: " + name + ", order " + str(order) + " (" + 96 | # str(numv) + " nodes in param coord: " + str(parv) + ")") 97 | 98 | gmsh.write("exgmsh1.msh") 99 | 100 | #if '-nopopup' not in sys.argv: 101 | #gmsh.fltk.run() 102 | 103 | gmsh.finalize() -------------------------------------------------------------------------------- /examples/gmsh-api/exgm2.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # 3 | # Gmsh Python tutorial 16 4 | # 5 | # Constructive Solid Geometry, OpenCASCADE geometry kernel 6 | # 7 | # ------------------------------------------------------------------------------ 8 | 9 | # Instead of constructing a model in a bottom-up fashion with Gmsh's built-in 10 | # geometry kernel, starting with version 3 Gmsh allows you to directly use 11 | # alternative geometry kernels. Here we will use the OpenCASCADE kernel. 12 | 13 | import gmsh 14 | import math 15 | import sys 16 | 17 | gmsh.initialize() 18 | 19 | gmsh.model.add("t16") 20 | 21 | # Let's build the same model as in `t5.py', but using constructive solid 22 | # geometry. 23 | 24 | # We can log all messages for further processing with: 25 | gmsh.logger.start() 26 | 27 | # We first create two cubes: 28 | gmsh.model.occ.addBox(0, 0, 0, 1, 1, 1, 1) 29 | gmsh.model.occ.addBox(0, 0, 0, 0.5, 0.5, 0.5, 2) 30 | 31 | # We apply a boolean difference to create the "cube minus one eigth" shape: 32 | gmsh.model.occ.cut([(3, 1)], [(3, 2)], 3) 33 | 34 | # Boolean operations with OpenCASCADE always create new entities. By default the 35 | # extra arguments `removeObject' and `removeTool' in `cut()' are set to `True', 36 | # which will delete the original entities. 37 | 38 | # We then create the five spheres: 39 | x = 0 40 | y = 0.75 41 | z = 0 42 | r = 0.09 43 | holes = [] 44 | 45 | # If we had wanted five empty holes we would have used `cut()' again. Here we 46 | # want five spherical inclusions, whose mesh should be conformal with the mesh 47 | # of the cube: we thus use `fragment()', which intersects all volumes in a 48 | # conformal manner (without creating duplicate interfaces): 49 | 50 | # ov, ovv = gmsh.model.occ.fragment([(3, 3)], holes) 51 | 52 | # ov contains all the generated entities of the same dimension as the input 53 | # entities: 54 | #print("fragment produced volumes:") 55 | #for e in ov: 56 | # print(e) 57 | 58 | # ovv contains the parent-child relationships for all the input entities: 59 | #print("before/after fragment relations:") 60 | #for e in zip([(3, 3)] + holes, ovv): 61 | # print("parent " + str(e[0]) + " -> child " + str(e[1])) 62 | 63 | gmsh.model.occ.synchronize() 64 | 65 | # When the boolean operation leads to simple modifications of entities, and if 66 | # one deletes the original entities, Gmsh tries to assign the same tag to the 67 | # new entities. (This behavior is governed by the 68 | # `Geometry.OCCBooleanPreserveNumbering' option.) 69 | 70 | # Here the `Physical Volume' definitions can thus be made for the 5 spheres 71 | # directly, as the five spheres (volumes 4, 5, 6, 7 and 8), which will be 72 | # deleted by the fragment operations, will be recreated identically (albeit with 73 | # new surfaces) with the same tags: 74 | #for i in range(1, 6): 75 | # gmsh.model.addPhysicalGroup(3, [3 + i], i) 76 | 77 | # The tag of the cube will change though, so we need to access it 78 | # programmatically: 79 | #gmsh.model.addPhysicalGroup(3, [ov[-1][1]], 10) 80 | 81 | # Creating entities using constructive solid geometry is very powerful, but can 82 | # lead to practical issues for e.g. setting mesh sizes at points, or identifying 83 | # boundaries. 84 | 85 | # To identify points or other bounding entities you can take advantage of the 86 | # `getEntities()', `getBoundary()' and `getEntitiesInBoundingBox()' functions: 87 | 88 | lcar1 = .1 89 | lcar2 = .0005 90 | lcar3 = .055 91 | 92 | # Assign a mesh size to all the points: 93 | gmsh.model.mesh.setSize(gmsh.model.getEntities(0), lcar1) 94 | 95 | # Override this constraint on the points of the five spheres: 96 | #gmsh.model.mesh.setSize(gmsh.model.getBoundary(holes, False, False, True), 97 | # lcar3) 98 | 99 | # Select the corner point by searching for it geometrically: 100 | eps = 1e-3 101 | #ov = gmsh.model.getEntitiesInBoundingBox(0.5 - eps, 0.5 - eps, 0.5 - eps, 102 | # 0.5 + eps, 0.5 + eps, 0.5 + eps, 0) 103 | #gmsh.model.mesh.setSize(ov, lcar2) 104 | 105 | gmsh.model.mesh.generate(3) 106 | 107 | gmsh.write("t16.msh") 108 | 109 | # Additional examples created with the OpenCASCADE geometry kernel are available 110 | # in `t18.py', `t19.py' and `t20.py', as well as in the `demos/api' directory. 111 | 112 | # Inspect the log: 113 | log = gmsh.logger.get() 114 | print("Logger has recorded " + str(len(log)) + " lines") 115 | gmsh.logger.stop() 116 | 117 | # Launch the GUI to see the results: 118 | if '-nopopup' not in sys.argv: 119 | gmsh.fltk.run() 120 | 121 | gmsh.finalize() 122 | -------------------------------------------------------------------------------- /examples/gmsh-api/exgm3.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # 3 | # Gmsh Python tutorial 17 4 | # 5 | # Anisotropic background mesh 6 | # 7 | # ------------------------------------------------------------------------------ 8 | 9 | # As seen in `t7.py', mesh sizes can be specified very accurately by providing a 10 | # background mesh, i.e., a post-processing view that contains the target mesh 11 | # sizes. 12 | 13 | # Here, the background mesh is represented as a metric tensor field defined on a 14 | # square. One should use bamg as 2d mesh generator to enable anisotropic meshes 15 | # in 2D. 16 | 17 | import gmsh 18 | import math 19 | import os 20 | import sys 21 | 22 | gmsh.initialize() 23 | 24 | gmsh.model.add("t17") 25 | 26 | # Create a square 27 | gmsh.model.occ.addRectangle(-1, -1, 0, 2, 2) 28 | gmsh.model.occ.synchronize() 29 | 30 | # Merge a post-processing view containing the target anisotropic mesh sizes 31 | path = os.path.dirname(os.path.abspath(__file__)) 32 | gmsh.merge(os.path.join(path, os.pardir, 't17_bgmesh.pos')) 33 | 34 | # Apply the view as the current background mesh 35 | bg_field = gmsh.model.mesh.field.add("PostView") 36 | gmsh.model.mesh.field.setNumber(bg_field, "ViewIndex", 0) 37 | gmsh.model.mesh.field.setAsBackgroundMesh(bg_field) 38 | 39 | # Use bamg 40 | gmsh.option.setNumber("Mesh.SmoothRatio", 3) 41 | gmsh.option.setNumber("Mesh.AnisoMax", 1000) 42 | gmsh.option.setNumber("Mesh.Algorithm", 7) 43 | 44 | gmsh.model.mesh.generate(2) 45 | gmsh.write("t17.msh") 46 | 47 | # Launch the GUI to see the results: 48 | if '-nopopup' not in sys.argv: 49 | gmsh.fltk.run() 50 | 51 | gmsh.finalize() 52 | -------------------------------------------------------------------------------- /examples/obsolete/extri1.py: -------------------------------------------------------------------------------- 1 | #!/bin/env python 2 | 3 | import numpy as np 4 | import calfem.core as cfc 5 | import calfem.utils as cfu 6 | import calfem.vis as cfv 7 | import calfem.mesh as cfm 8 | 9 | 10 | # ---- Problem constants 11 | 12 | kx = 50 13 | ky = 50 14 | t = 1.0 15 | ep = [t] 16 | 17 | D = np.matrix([ 18 | [kx, 0.], 19 | [0., ky] 20 | ]) 21 | 22 | # ---- Problem geometry 23 | 24 | vertices = np.array([ 25 | [0.0, 0.0], 26 | [200., 0.0], 27 | [200., 70.0], 28 | [120.0, 70.0], 29 | [120.0, 20.0], 30 | [80.0, 20.0], 31 | [80.0, 70.0], 32 | [0.0, 70.0] 33 | ]) 34 | 35 | segments = np.array([ 36 | [0,1,1], 37 | [1,2,1], 38 | [2,3,2], 39 | [3,4,1], 40 | [4,5,1], 41 | [5,6,1], 42 | [6,7,3], 43 | [7,0,1] 44 | ]) 45 | 46 | # ---- Create element mesh 47 | 48 | print("Creating element mesh...") 49 | 50 | coords, edof, dofs, bdofs = cfm.trimesh2d(vertices, segments, maxArea=20.0, dofs_per_node=1) 51 | 52 | # ---- Assemble system matrix 53 | 54 | print("Assemblig system matrix...") 55 | 56 | nDofs = np.size(dofs) 57 | ex, ey = cfc.coordxtr(edof, coords, dofs) 58 | 59 | K = np.zeros([nDofs,nDofs]) 60 | 61 | for eltopo, elx, ely in zip(edof, ex, ey): 62 | Ke = cfc.flw2te(elx, ely, ep, D) 63 | cfc.assem(eltopo, K, Ke) 64 | 65 | # ---- Solving equation system 66 | 67 | print("Solving equation system...") 68 | 69 | f = np.zeros([nDofs,1]) 70 | 71 | bc = np.array([],'i') 72 | bcVal = np.array([],'i') 73 | 74 | bc, bcVal = cfu.applybc(bdofs,bc,bcVal,2,30.0) 75 | bc, bcVal = cfu.applybc(bdofs,bc,bcVal,3,0.0) 76 | 77 | a, r = cfc.solveq(K,f,bc,bcVal) 78 | 79 | # ---- Compute element forces 80 | 81 | print("Computing element forces...") 82 | 83 | ed = cfc.extractEldisp(edof,a) 84 | qs, qt = cfc.flw2ts(ex, ey, D, ed) 85 | 86 | # ---- Visualise results 87 | 88 | print("Drawing element mesh...") 89 | 90 | cfv.eliso2(ex,ey,ed) 91 | cfv.eldraw2(ex,ey) 92 | cfv.showAndWait() 93 | 94 | print("Done.") 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /examples/obsolete/extri2.py: -------------------------------------------------------------------------------- 1 | #!/bin/env python 2 | 3 | from calfem.core import * 4 | from calfem.utils import * 5 | 6 | def drawCustom(self, width, height): 7 | glPushMatrix() 8 | glBegin(GL_LINES) 9 | glColor(1.0, 0.0, 0.0, 1.0) 10 | glVertex(50,50,0) 11 | glVertex(100,100,0) 12 | glPopMatrix() 13 | 14 | # ---- Problem constants 15 | 16 | t = 0.1 17 | v = 0.35 18 | E = 2.1e9 19 | ptype = 1 20 | ep = [ptype,t] 21 | 22 | D=hooke(ptype, E, v) 23 | 24 | # ---- Problem geometry 25 | 26 | l = 0.2 27 | w = 0.05 28 | h = 0.1 29 | 30 | vertices = array([ 31 | [0.0, h], 32 | [l, h], 33 | [l, 0.0], 34 | [l-w, 0.0], 35 | [l-w, h-w], 36 | [0.0, h-w] 37 | ]) 38 | 39 | segments = array([ 40 | [0,1,1], 41 | [1,2,1], 42 | [2,3,3], 43 | [3,4,1], 44 | [4,5,1], 45 | [5,0,2] 46 | ]) 47 | 48 | # ---- Create element mesh 49 | 50 | print("Creating element mesh...") 51 | 52 | coords, edof, dofs, bdofs = trimesh2d(vertices, segments, maxArea=0.00005, dofsPerNode=2) 53 | 54 | # ---- Assemble system matrix 55 | 56 | print("Assemblig system matrix...") 57 | 58 | nDofs = size(dofs) 59 | ex, ey = coordxtr(edof, coords, dofs) 60 | 61 | #eldraw2(ex,ey) 62 | 63 | K = zeros([nDofs,nDofs]) 64 | 65 | for eltopo, elx, ely in zip(edof, ex, ey): 66 | Ke = plante(elx, ely, ep, D) 67 | assem(eltopo, K, Ke) 68 | 69 | # ---- Solving equation system 70 | 71 | print("Solving equation system...") 72 | 73 | f = zeros([nDofs,1]) 74 | 75 | bc = array([],'i') 76 | bcVal = array([],'i') 77 | 78 | bc, bcVal = applybc(bdofs,bc,bcVal,2,0.0) 79 | bc, bcVal = applybcnode(0, dofs, bc, bcVal, 0.0, 1) 80 | bc, bcVal = applybcnode(0, dofs, bc, bcVal, 0.0, 2) 81 | bc, bcVal = applybcnode(5, dofs, bc, bcVal, 0.0, 1) 82 | bc, bcVal = applybcnode(5, dofs, bc, bcVal, 0.0, 2) 83 | 84 | applyforce(bdofs,f,3,-10e3,2) 85 | 86 | a,r = solveq(K,f,bc,bcVal) 87 | 88 | # ---- Compute element forces 89 | 90 | print("Computing element forces...") 91 | 92 | ed = extractEldisp(edof,a) 93 | es, et = plants(ex, ey, ep, D, ed) 94 | ev = effmises(es, ptype) 95 | esnv = stress2nodal(ev, edof) 96 | 97 | # ---- Visualise results 98 | 99 | print("Drawing element mesh...") 100 | 101 | eldisp2(ex, ey, ed) 102 | elval2(ex, ey, ev) 103 | eliso2(ex, ey, esnv) 104 | 105 | elementView = ElementView(None, -1, "") 106 | elementView.ex = ex 107 | elementView.ey = ey 108 | elementView.ev = ev 109 | elementView.showMesh = False 110 | elementView.showElementValues = True 111 | elementView.showNodalValues = False 112 | elementView.drawCustom = drawCustom 113 | elementView.Show() 114 | 115 | waitDisplay() 116 | 117 | print("Done.") 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /gen_output_dict.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This script generates a dictionary of example outputs. 4 | """ 5 | 6 | import os, sys, re, subprocess 7 | from pprint import pprint 8 | 9 | def extract_numeric_values(output_text): 10 | """Extract numeric values from output text using regex.""" 11 | import re 12 | pattern = r'[-+]?\d*\.\d+(?:[eE][-+]?\d+)?' 13 | return [float(x) for x in re.findall(pattern, output_text)] 14 | 15 | def compare_outputs(output1, output2, rtol=1e-5, atol=1e-8): 16 | """Compare outputs with tolerance.""" 17 | import numpy as np 18 | values1 = extract_numeric_values(output1) 19 | values2 = extract_numeric_values(output2) 20 | 21 | if len(values1) != len(values2): 22 | return False 23 | 24 | return np.allclose(values1, values2, rtol=rtol, atol=atol) 25 | 26 | def gen_output_examples(): 27 | 28 | examples_dir = "examples" 29 | 30 | examples = [ 31 | "exs_bar2.py", 32 | "exs_bar2_la.py", 33 | "exs_bar2_lb.py", 34 | "exs_beam1.py", 35 | "exs_beam2.py", 36 | "exs_beambar2.py", 37 | "exs_flw_diff2.py", 38 | "exs_flw_temp1.py", 39 | "exs_flw_temp2.py", 40 | "exs_spring.py", 41 | "exm_stress_2d_materials.py", 42 | "exm_stress_2d.py", 43 | "exm_flow_model.py", 44 | ] 45 | 46 | # Set environment variable to avoid blocking of plots 47 | 48 | 49 | os.environ["CFV_NO_BLOCK"] = "YES" 50 | env = os.environ.copy() 51 | 52 | # Assume 0 return codes 53 | 54 | return_codes = 0 55 | 56 | example_dict = {} 57 | 58 | for example in examples: 59 | print(f"Running: {example}") 60 | 61 | proc = subprocess.run( 62 | [sys.executable, f"examples/{example}"], 63 | env=env, 64 | capture_output=True, 65 | text=True 66 | ) 67 | 68 | # Check return code 69 | assert proc.returncode == 0, f"Example {example} failed with output: {proc.stderr}" 70 | 71 | actual_values = extract_numeric_values(proc.stdout) 72 | 73 | example_dict[example] = actual_values 74 | 75 | 76 | # Save the example dictionary to a file 77 | 78 | with open("example_outputs.py", "w") as f: 79 | f.write("# Example outputs\n") 80 | f.write("examples = {\n") 81 | for example, values in example_dict.items(): 82 | f.write(f" '{example}': {values},\n") 83 | f.write("}\n") 84 | 85 | if __name__ == "__main__": 86 | gen_output_examples() -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "calfem-python" 3 | version = "3.6.11" 4 | description = "CALFEM for Python" 5 | authors = [ 6 | {name = "Jonas Lindemann", email = "jonas.lindemann@lunarc.lu.se"}, 7 | {name = "Jonas Lindemann", email = "jonas.lindemann@gmail.com"}, 8 | ] 9 | dependencies = [ 10 | "gmsh", 11 | "matplotlib", 12 | "numpy < 2", 13 | "scipy", 14 | "tabulate", 15 | ] 16 | 17 | requires-python = ">=3.8" 18 | readme = "README.md" 19 | license = {text = "MIT"} 20 | keywords = [ 21 | "finite element", 22 | "math", 23 | "numerics", 24 | ] 25 | classifiers = [ 26 | "Development Status :: 4 - Beta", 27 | "Intended Audience :: Developers", 28 | "License :: OSI Approved :: MIT License", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.10", 31 | "Programming Language :: Python :: 3.11", 32 | "Programming Language :: Python :: 3.12", 33 | "Programming Language :: Python :: 3.7", 34 | "Programming Language :: Python :: 3.8", 35 | "Programming Language :: Python :: 3.9", 36 | "Topic :: Software Development :: Build Tools", 37 | ] 38 | 39 | [project.urls] 40 | Homepage = "https://github.com/CALFEM/calfem-python" 41 | [build-system] 42 | requires = ["pdm-backend"] 43 | build-backend = "pdm.backend" 44 | 45 | [tool.pdm] 46 | distribution = true 47 | 48 | [project.optional-dependencies] 49 | visvis = [ "visvis" ] 50 | vedo = [ "vedo" ] 51 | pyvtk = [ "pyvtk" ] 52 | qtpy = [ "qtpy" ] 53 | -------------------------------------------------------------------------------- /reports/manual-mesh-module.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/reports/manual-mesh-module.pdf -------------------------------------------------------------------------------- /reports/manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/reports/manual.pdf -------------------------------------------------------------------------------- /resources/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | blank.svg 4 | plus.svg 5 | minus.svg 6 | erase.png 7 | add_marker.svg 8 | merge.svg 9 | split_edge.svg 10 | polygon.svg 11 | polygon_hole.svg 12 | rectangle.svg 13 | rectangle_hole.svg 14 | rectangle.svg 15 | polygon_hole.svg 16 | rectangle_hole.svg 17 | polygon.svg 18 | geometry.png 19 | grid.png 20 | grid_settings.png 21 | grid_snap.png 22 | line.png 23 | line_number.png 24 | move.png 25 | move_node.png 26 | node.png 27 | node_number.png 28 | save.png 29 | zoom_in.png 30 | zoom_out.png 31 | pan.png 32 | open.png 33 | polygon_hole.svg 34 | select.png 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/src/__init__.py -------------------------------------------------------------------------------- /src/calfem/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '3.6.1' 2 | VERSION = __version__ 3 | -------------------------------------------------------------------------------- /src/calfem/_export.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import scipy.io 3 | import numpy as np 4 | 5 | ''' 6 | Handle reading and writing of geometry and generated mesh from the program 7 | ''' 8 | 9 | 10 | def loadGeometry(name): 11 | with open(name, 'rb') as file: 12 | test = pickle.load(file) 13 | return test 14 | 15 | 16 | def saveGeometry(g, name="Untitled"): 17 | if not name.endswith(".cfg"): 18 | name = name + ".cfg" 19 | with open(name, 'wb') as file: 20 | pickle.dump(g, file) 21 | 22 | 23 | def loadMesh(name): 24 | with open(name, 'rb') as file: 25 | mesh = pickle.load(file) 26 | return mesh 27 | 28 | 29 | def saveMesh(mesh, name="Untitled"): 30 | if not name.endswith(".cfm"): 31 | name = name + ".cfm" 32 | with open(name, 'wb') as file: 33 | pickle.dump(mesh, file) 34 | 35 | 36 | def saveArrays(coords, edof, dofs, bdofs, elementmarkers, boundaryElements, markerDict ,name="Untitled"): 37 | if not name.endswith(".cfma"): 38 | name = name + ".cfma" 39 | with open(name, 'wb') as file: 40 | pickle.dump(coords, file) 41 | pickle.dump(edof, file) 42 | pickle.dump(dofs, file) 43 | #for key in bdofs.items(): 44 | # print(key, markerDict[key]) 45 | pickle.dump(bdofs, file) 46 | pickle.dump(elementmarkers, file) 47 | pickle.dump(boundaryElements, file) 48 | pickle.dump(markerDict, file) 49 | 50 | 51 | def loadArrays(name): 52 | with open(name, 'rb') as file: 53 | coords = pickle.load(file) 54 | edof= pickle.load(file) 55 | dofs = pickle.load(file) 56 | bdofs = pickle.load(file) 57 | elementmarkers = pickle.load(file) 58 | boundaryElements = pickle.load(file) 59 | markerDict = pickle.load(file) 60 | 61 | return coords, edof, dofs, bdofs, elementmarkers, boundaryElements, markerDict 62 | 63 | 64 | def saveMatlabArrays(coords, edof, dofs, bdofs, elementmarkers, boundaryElements, markerDict, name="Untitled"): 65 | if not name.endswith(".mat"): 66 | name = name + ".mat" 67 | saveDict = {} 68 | saveDict["coords"] = coords.astype('double') 69 | # Convert to CALFEM Edof definition with element number as first index 70 | new_column = np.arange(1, np.size(edof, 0) + 1)[:, np.newaxis] 71 | edof = np.append(new_column, edof, axis=1) 72 | 73 | saveDict["edof"] = edof.astype('double') 74 | saveDict["dofs"] = dofs.astype('double') 75 | # bdofs = {str(k): v for k, v in bdofs.items()} # MATLAB struct needs keys as strings 76 | #print(markerDict) 77 | newBdof = {} 78 | for name, index in bdofs.items(): 79 | print(name, index) 80 | if index == 0: 81 | newBdof["None"] = 0 82 | else: 83 | newBdof[markerDict[index]] = name 84 | 85 | saveDict["bdofs"] = newBdof 86 | elementmarkers = np.asarray(elementmarkers) 87 | elementmarkers = elementmarkers + 1 # To avoid problems with one indexing in MATLAB 88 | saveDict["elementmarkers"] = elementmarkers 89 | scipy.io.savemat(name, saveDict) 90 | 91 | -------------------------------------------------------------------------------- /src/calfem/intvis.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | 5 | from qtpy.QtWidgets import * 6 | from qtpy.QtGui import * 7 | 8 | import calfem.ui as cfui 9 | 10 | class GuiWindow(QWidget): 11 | def __init__(self, var_dict): 12 | """MyWindow constructor""" 13 | 14 | super().__init__() 15 | 16 | # Skapa gränssnittskontroller 17 | 18 | self.var_dict = var_dict 19 | 20 | self.init_gui() 21 | 22 | def __parse_variables(self, g): 23 | 24 | # a_edit = 1 25 | # b_slider = 2.0 26 | # c_list = [1, 2, 3] 27 | # d_check = True 28 | # f_param = 42.0 29 | # g_float = 84.0 30 | # g_int = 34 31 | 32 | row = 0 33 | 34 | for key, value in self.var_dict.items(): 35 | if '_edit' in key: 36 | var_label = QLabel(key) 37 | var_edit = QLineEdit(str(value)) 38 | 39 | g.addWidget(var_label, row, 0) 40 | g.addWidget(var_edit, row, 1) 41 | elif '_slider' in key: 42 | var_label = QLabel(key.split("_")[0]) 43 | var_edit = QSlider() 44 | 45 | 46 | def init_gui(self): 47 | """Initiera gränssnitt""" 48 | 49 | self.setGeometry(300, 300, 600, 600) 50 | self.setWindowTitle("Parameter window") 51 | 52 | self.grid = QGridLayout(self) 53 | 54 | row = 0 55 | 56 | for key, value in self.var_dict.items(): 57 | var_label = QLabel(key) 58 | var_edit = QLineEdit(str(value)) 59 | 60 | self.grid.addWidget(var_label, row, 0) 61 | self.grid.addWidget(var_edit, row, 1) 62 | 63 | row += 1 64 | 65 | buttons = QHBoxLayout() 66 | 67 | ok_button = QPushButton("OK") 68 | cancel_button = QPushButton("Cancel") 69 | 70 | buttons.addStretch() 71 | buttons.addWidget(ok_button) 72 | buttons.addWidget(cancel_button) 73 | buttons.addStretch() 74 | 75 | self.grid.setRowStretch(row, 10) 76 | 77 | row += 1 78 | 79 | self.grid.addLayout(buttons, row, 0, 1, 2) 80 | 81 | # Visa fönster 82 | 83 | self.show() 84 | 85 | def create_window(var_dict): 86 | w = GuiWindow(var_dict) 87 | 88 | return w 89 | 90 | def parse_variables(var_dict): 91 | """Parse variables in current context""" 92 | valid_vars = {} 93 | 94 | for key, value in var_dict.items(): 95 | if type(value) is int: 96 | valid_vars[key] = value 97 | if type(value) is float: 98 | valid_vars[key] = value 99 | if type(value) is list: 100 | valid_vars[key] = value 101 | if type(value) is bool: 102 | valid_vars[key] = value 103 | 104 | return valid_vars 105 | 106 | def edit_params(var_dict): 107 | """Run Qt event loop""" 108 | 109 | valid_vars = parse_variables(var_dict) 110 | print(valid_vars) 111 | 112 | app = cfui.init_qt_app() 113 | 114 | # Skapa vårt MyWindow objekt 115 | 116 | w = create_window(valid_vars) 117 | w.show() 118 | 119 | # Starta händelseloop 120 | 121 | app.exec_() 122 | 123 | def edit_geometry(geometry): 124 | pass -------------------------------------------------------------------------------- /src/calfem/misc.py: -------------------------------------------------------------------------------- 1 | def mlscalar2d(coords, edof, a): 2 | if not haveMlab: 3 | return 4 | 5 | x = reshape(coords[:,0],[size(coords[:,0])]) 6 | y = reshape(coords[:,1],[size(coords[:,1])]) 7 | z = zeros([size(coords[:,0])]) 8 | ascalar = reshape(asarray(a),[size(a)]) 9 | 10 | mlab.triangular_mesh(x, y, z, edof-1, scalars=ascalar, representation="surface") 11 | 12 | def mlflux2d(coords, vf, scalefactor=None, displaymode="2darrow"): 13 | if not haveMlab: 14 | return 15 | 16 | x = reshape(coords[:,0],[size(coords[:,0])]) 17 | y = reshape(coords[:,1],[size(coords[:,1])]) 18 | z = zeros([size(coords[:,0])]) 19 | u = reshape(vf[:,0],[size(vf[:,0])]) 20 | v = reshape(vf[:,1],[size(vf[:,1])]) 21 | w = zeros([size(vf[:,0])]) 22 | 23 | if scalefactor == None: 24 | mlab.quiver3d(x, y, z, u, v, w, mode=displaymode) 25 | else: 26 | mlab.quiver3d(x, y, z, u, v, w, mode=displaymode, scale_factor=scalefactor) 27 | 28 | 29 | def mlwireframe2d(coords, edof): 30 | if not haveMlab: 31 | return 32 | 33 | x = reshape(coords[:,0],[size(coords[:,0])]) 34 | y = reshape(coords[:,1],[size(coords[:,1])]) 35 | z = zeros([size(coords[:,0])])+1 36 | scalars = ones([size(coords[:,0])]) 37 | 38 | mlab.triangular_mesh(x, y, z, edof-1, scalars=scalars, representation="mesh", colormap="bone", line_width=20.0) 39 | 40 | 41 | def eldisp2(ex,ey,ed,rat=0.2): 42 | nen = -1 43 | if ex.shape != ey.shape: 44 | print("ex and ey shapes do not match.") 45 | return 1.0 46 | 47 | dlmax = 0. 48 | edmax = 1. 49 | 50 | # print(rank(ex)) 51 | 52 | if np.linalg.matrix_rank(ex)==1: 53 | nen = ex.shape[0] 54 | nel = 1 55 | dxmax = max(ex.T.max(0)-ex.T.min(0)) 56 | dymax = max(ey.T.max(0)-ey.T.min(0)) 57 | dlmax = max(dxmax,dymax) 58 | edmax = abs(ed).max() 59 | else: 60 | nen = ex.shape[1] 61 | nel = ex.shape[0] 62 | dxmax = max(ex.T.max(0)-ex.T.min(0)) 63 | dymax = max(ey.T.max(0)-ey.T.min(0)) 64 | dlmax = max(dxmax,dymax) 65 | edmax = abs(ed).max() 66 | 67 | k = rat 68 | return k*dlmax/edmax 69 | -------------------------------------------------------------------------------- /src/calfem/qt5.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Apr 12 23:17:26 2017 4 | 5 | @author: jonas_000 6 | """ 7 | 8 | from qtpy.QtCore import Slot, Signal, QMetaObject 9 | from qtpy.QtWidgets import * 10 | from qtpy.QtGui import QPixmap 11 | from qtpy.uic import loadUi 12 | -------------------------------------------------------------------------------- /src/calfem/shapes.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import calfem.core as cfc 3 | import calfem.geometry as cfg 4 | import calfem.mesh as cfm 5 | import calfem.vis as cfv 6 | 7 | import logging as cflog 8 | 9 | def error(msg): 10 | cflog.error("calfem.shapes: "+msg) 11 | 12 | def info(msg): 13 | cflog.info("calfem.shapes: "+msg) 14 | 15 | 16 | class Shape: 17 | """Base class for shapes""" 18 | 19 | def __init__(self, element_type = 3, dofs_per_node = 1, max_area = 1.0): 20 | self.max_area = max_area 21 | self.element_type = element_type 22 | self.dofs_per_node = dofs_per_node 23 | 24 | def geometry(self): 25 | """Return geometry of shape""" 26 | return None 27 | 28 | 29 | 30 | class Rectangle(Shape): 31 | """Rectangle geometry""" 32 | 33 | def __init__(self, width=1.0, height=1.0, element_type = 3, dofs_per_node = 1, max_area = -1): 34 | Shape.__init__(self, element_type, dofs_per_node, max_area) 35 | self.width = width 36 | self.height = height 37 | 38 | if (max_area<0): 39 | self.max_area = self.width * self.height * 0.05 40 | else: 41 | self.max_area = max_area 42 | 43 | self.left_id = 101 44 | self.right_id = 102 45 | self.top_id = 103 46 | self.bottom_id = 104 47 | 48 | def geometry(self): 49 | """Return geometry of shape""" 50 | self.g = cfg.Geometry() 51 | 52 | w = self.width 53 | h = self.height 54 | 55 | self.g.point([0, 0]) 56 | self.g.point([w, 0]) 57 | self.g.point([w, h]) 58 | self.g.point([0, h]) 59 | 60 | self.g.spline([0, 1], marker=self.bottom_id) 61 | self.g.spline([1, 2], marker=self.right_id) 62 | self.g.spline([2, 3], marker=self.top_id) 63 | self.g.spline([3, 0], marker=self.left_id) 64 | 65 | self.g.surface([0,1,2,3]) 66 | 67 | return self.g 68 | 69 | class RectangleWithHole(Rectangle): 70 | def __init__(self, width=1.0, height=1.0, element_type = 3, dofs_per_node = 1, max_area = -1): 71 | super().__init__(self, width, height, element_type, dofs_per_node, max_area) 72 | 73 | class ShapeMesh: 74 | """Mesh generator for shapes""" 75 | def __init__(self, shape): 76 | """Initialise mesh generator""" 77 | self.shape = shape 78 | 79 | self.create() 80 | 81 | def create(self): 82 | meshGen = cfm.GmshMeshGenerator(self.shape.geometry()) 83 | meshGen.el_type = self.shape.element_type 84 | meshGen.el_size_factor = self.shape.max_area 85 | meshGen.dofs_per_node = self.shape.dofs_per_node 86 | 87 | self.coords, self.edof, self.dofs, self.bdofs, self.markers = meshGen.create() 88 | 89 | # --- Ber├ñkna element koordinater 90 | 91 | self.ex, self.ey = cfc.coordxtr(self.edof, self.coords, self.dofs) 92 | self.pointDofs = self.dofs[list(self.shape.g.points.keys()),:] 93 | 94 | if __name__ == "__main__": 95 | 96 | 97 | print("Creating rectangle") 98 | rect = Rectangle(5.0, 1.0, element_type=3, dofs_per_node=2, max_area=0.05) 99 | 100 | print("Creating mesh...") 101 | 102 | mesh = ShapeMesh(rect) 103 | 104 | print(mesh.edof) 105 | print(mesh.dofs) 106 | print(mesh.bdofs[rect.left_id]) 107 | print(mesh.bdofs[rect.right_id]) 108 | print(mesh.bdofs[rect.top_id]) 109 | print(mesh.bdofs[rect.bottom_id]) 110 | print(mesh.pointDofs) 111 | -------------------------------------------------------------------------------- /src/calfem/ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | CALFEM UI module 4 | 5 | Routines for interfacing wirt user interface toolkits. 6 | """ 7 | 8 | import os, sys 9 | 10 | print("------------------------------------") 11 | print("CALFEM/Python ui module initialising") 12 | print("------------------------------------") 13 | print() 14 | 15 | from qtpy.QtCore import Slot, Signal, QThread 16 | from qtpy.QtWidgets import QApplication, QDialog, QWidget, QMainWindow 17 | from qtpy.QtGui import QPixmap 18 | from qtpy.uic import loadUi 19 | 20 | g_inSpyder = False 21 | 22 | if any('SPYDER' in name for name in os.environ): 23 | print('Running in Spyder...') 24 | g_inSpyder = True 25 | 26 | g_haveVisVis = True 27 | 28 | try: 29 | import visvis as vv 30 | except: 31 | g_haveVisVis = False 32 | 33 | if g_haveVisVis: 34 | print("VisVis installed...") 35 | else: 36 | print("VisVis not installed...") 37 | 38 | def init_qt_app(): 39 | app = QApplication.instance() 40 | 41 | if app is None: 42 | print("No QApplication instance found. Creating one.") 43 | # if it does not exist then a QApplication is created 44 | app = QApplication(sys.argv) 45 | else: 46 | print("QApplication instance found. Reusing.") 47 | 48 | return app 49 | 50 | def loadUiWidget(uifilename, parent=None): 51 | """Load user interface file and return object model""" 52 | ui = loadUi(uifilename, parent) 53 | return ui 54 | 55 | load_ui_widget = loadUiWidget 56 | 57 | def appInstance(useVisVis=True): 58 | """Create a suitable application instance""" 59 | print("Creating application instance...") 60 | 61 | global g_haveVisVis 62 | 63 | app = None 64 | 65 | if g_haveVisVis and useVisVis: 66 | print("Using VisVis application instance...") 67 | app = vv.use() 68 | app.Create() 69 | else: 70 | print("Trying Qt application instance...") 71 | app = QtGui.QApplication.instance() 72 | if app is None: 73 | print("Creating new Qt application instance...") 74 | app = QtGui.QApplication(sys.argv) 75 | else: 76 | print("Reusing existing Qt application instance...") 77 | 78 | if app!=None: 79 | app.Run = app.exec_ 80 | 81 | if app is None: 82 | print("No application instance found. Exiting...") 83 | sys.exit(-1) 84 | 85 | return app 86 | 87 | app_instance = appInstance -------------------------------------------------------------------------------- /src/calfem/vis_vtk.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | CALFEM Visualisation module (matplotlib) 4 | 5 | Contains all the functions implementing visualisation routines. 6 | """ 7 | 8 | import vtk 9 | 10 | def draw_mesh(coords, edof, el_type): 11 | 12 | colors = vtk.vtkNamedColors() 13 | points = vtk.vtkPoints() 14 | 15 | for i, coord in enumerate(coords): 16 | points.InsertPoint(i, coord) 17 | 18 | ugrid = vtk.vtkUnstructuredGrid() 19 | ugrid.Allocate(edof.shape[0]) 20 | 21 | for dofs in edof: 22 | if (el_type == 4): 23 | ugrid.InsertNextCell(vtk.VTK_TETRA, 4, dofs-1) 24 | elif (el_type == 5): 25 | ugrid.InsertNextCell(vtk.VTK_HEXAHEDRON, 8, dofs-1) 26 | else: 27 | print("Unsupported element type.") 28 | 29 | ugrid.SetPoints(points) 30 | 31 | ugridMapper = vtk.vtkDataSetMapper() 32 | ugridMapper.SetInputData(ugrid) 33 | 34 | ugridActor = vtk.vtkActor() 35 | ugridActor.SetMapper(ugridMapper) 36 | ugridActor.GetProperty().SetColor(colors.GetColor3d('Peacock')) 37 | ugridActor.GetProperty().EdgeVisibilityOn() 38 | 39 | renderer = vtk.vtkRenderer() 40 | 41 | renWin = vtk.vtkRenderWindow() 42 | renWin.AddRenderer(renderer) 43 | iren = vtk.vtkRenderWindowInteractor() 44 | iren.SetRenderWindow(renWin) 45 | 46 | renderer.AddActor(ugridActor) 47 | renderer.SetBackground(colors.GetColor3d('Beige')) 48 | 49 | renderer.ResetCamera() 50 | renderer.GetActiveCamera().Elevation(60.0) 51 | renderer.GetActiveCamera().Azimuth(30.0) 52 | renderer.GetActiveCamera().Dolly(1.0) 53 | 54 | renWin.SetSize(640, 480) 55 | renWin.SetWindowName('UGrid') 56 | 57 | # Interact with the data. 58 | renWin.Render() 59 | 60 | iren.Start() 61 | 62 | 63 | -------------------------------------------------------------------------------- /test_calfem.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This is very simple test of the calfem package. 4 | 5 | Make sure all examples run without errors. 6 | """ 7 | 8 | import os, sys, re, subprocess 9 | import example_outputs as eo 10 | import numpy as np 11 | 12 | from pprint import pprint 13 | 14 | def extract_numeric_values(output_text): 15 | """Extract numeric values from output text using regex.""" 16 | import re 17 | pattern = r'[-+]?\d*\.\d+(?:[eE][-+]?\d+)?' 18 | return [float(x) for x in re.findall(pattern, output_text)] 19 | 20 | def compare_outputs(output1, output2, rtol=1e-5, atol=1e-8): 21 | """Compare outputs with tolerance.""" 22 | import numpy as np 23 | values1 = extract_numeric_values(output1) 24 | values2 = extract_numeric_values(output2) 25 | 26 | if len(values1) != len(values2): 27 | return False 28 | 29 | return np.allclose(values1, values2, rtol=rtol, atol=atol) 30 | 31 | def test_examples(): 32 | 33 | examples_dir = "examples" 34 | 35 | examples = [ 36 | "exs_bar2.py", 37 | "exs_bar2_la.py", 38 | "exs_bar2_lb.py", 39 | "exs_beam1.py", 40 | "exs_beam2.py", 41 | "exs_beambar2.py", 42 | "exs_flw_diff2.py", 43 | "exs_flw_temp1.py", 44 | "exs_flw_temp2.py", 45 | "exs_spring.py", 46 | "exm_stress_2d.py", 47 | "exm_stress_2d_materials.py", 48 | "exm_flow_model.py" 49 | ] 50 | 51 | # Set environment variable to avoid blocking of plots 52 | 53 | os.environ["CFV_NO_BLOCK"] = "YES" 54 | 55 | # Assume 0 return codes 56 | 57 | for example in examples: 58 | print(f"Running: {example} ", end="") 59 | 60 | env = os.environ.copy() 61 | env["CFV_NO_BLOCK"] = "YES" 62 | 63 | proc = subprocess.run( 64 | [sys.executable, f"examples/{example}"], 65 | env=env, 66 | capture_output=True, 67 | text=True 68 | ) 69 | 70 | # Check return code 71 | assert proc.returncode == 0, f"Example {example} failed with output: {proc.stderr}" 72 | 73 | # Compare numeric values within tolerance 74 | actual_values = extract_numeric_values(proc.stdout) 75 | expected_values = eo.examples[example] 76 | 77 | assert len(actual_values) == len(expected_values), \ 78 | f"Expected {len(expected_values)} values, got {len(actual_values)}" 79 | 80 | assert np.allclose(actual_values, expected_values, rtol=1e-5, atol=1e-8), \ 81 | "Numeric values differ significantly" 82 | 83 | print(f"PASSED.") 84 | 85 | if __name__ == "__main__": 86 | test_examples() 87 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CALFEM/calfem-python/a6a71e4e031bd6f15922089d993245ca3726d155/tests/__init__.py --------------------------------------------------------------------------------