From 66181465380654b53bfd06988e336124acb9fb3d Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Mon, 22 Aug 2022 14:17:18 +0200 Subject: [PATCH 01/17] Added support for building 2 packages std/small. --- build-package.py | 26 ++++ calfem_python_small.egg-info/PKG-INFO | 22 ++++ calfem_python_small.egg-info/SOURCES.txt | 107 +++++++++++++++++ .../dependency_links.txt | 1 + calfem_python_small.egg-info/requires.txt | 6 + calfem_python_small.egg-info/top_level.txt | 1 + setup-org.py | 113 ++++++++++++++++++ setup-template.py | 96 +++++++++++++++ setup.py | 24 +--- 9 files changed, 376 insertions(+), 20 deletions(-) create mode 100644 build-package.py create mode 100644 calfem_python_small.egg-info/PKG-INFO create mode 100644 calfem_python_small.egg-info/SOURCES.txt create mode 100644 calfem_python_small.egg-info/dependency_links.txt create mode 100644 calfem_python_small.egg-info/requires.txt create mode 100644 calfem_python_small.egg-info/top_level.txt create mode 100644 setup-org.py create mode 100644 setup-template.py diff --git a/build-package.py b/build-package.py new file mode 100644 index 0000000..02c2df4 --- /dev/null +++ b/build-package.py @@ -0,0 +1,26 @@ + +import os, sys + +def update_setup(package_name, package_version, package_deps): + + with open("setup-template.py", "r") as f: + setup_template = f.read() + + with open("setup.py", "w") as f: + f.write(setup_template.format(package_name=package_name, package_version=package_version, package_depends=package_deps)) + +def build_package(): + os.system("python -m build --wheel") + +if __name__ == "__main__": + + package_version = "3.6.3" + + update_setup("calfem-python", package_version, "'numpy', 'visvis', 'pyvtk', 'matplotlib', 'scipy', 'gmsh', 'qtpy', 'vedo', 'tabulate'") + + build_package() + + update_setup("calfem-python-small", package_version, "'numpy', 'visvis', 'matplotlib', 'scipy', 'gmsh', 'tabulate'") + + build_package() + diff --git a/calfem_python_small.egg-info/PKG-INFO b/calfem_python_small.egg-info/PKG-INFO new file mode 100644 index 0000000..073c99c --- /dev/null +++ b/calfem_python_small.egg-info/PKG-INFO @@ -0,0 +1,22 @@ +Metadata-Version: 2.1 +Name: calfem-python-small +Version: 3.6.3 +Summary: CALFEM for Python +Home-page: https://github.com/CALFEM/calfem-python +Author: Jonas Lindemann, et al +Author-email: jonas.lindemann@byggmek.lth.se +License: MIT +Keywords: finite element,math,numerics +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: Topic :: Software Development :: Build Tools +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.9 +License-File: LICENSE +License-File: LICENSE.txt + +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. diff --git a/calfem_python_small.egg-info/SOURCES.txt b/calfem_python_small.egg-info/SOURCES.txt new file mode 100644 index 0000000..9c30548 --- /dev/null +++ b/calfem_python_small.egg-info/SOURCES.txt @@ -0,0 +1,107 @@ +LICENSE +LICENSE.txt +MANIFEST.in +README.md +README.rst +setup.py +calfem/__init__.py +calfem/_export.py +calfem/classes_qt4.py +calfem/classes_wx.py +calfem/core.py +calfem/editor.py +calfem/editor_resources.py +calfem/editor_scene.py +calfem/experimental.py +calfem/geometry.py +calfem/intvis.py +calfem/mesh.py +calfem/misc.py +calfem/qt5.py +calfem/shapes.py +calfem/solver.py +calfem/ui.py +calfem/utils.py +calfem/vedo_utils.py +calfem/vis.py +calfem/vis_mpl.py +calfem/vis_vedo.py +calfem/vis_vedo_utils.py +calfem/vis_vtk.py +calfem_python_small.egg-info/PKG-INFO +calfem_python_small.egg-info/SOURCES.txt +calfem_python_small.egg-info/dependency_links.txt +calfem_python_small.egg-info/requires.txt +calfem_python_small.egg-info/top_level.txt +examples/ex_beam2.py +examples/ex_tutorial_1.py +examples/ex_tutorial_2.py +examples/exe_stress_2d_editor.py +examples/exm_circle_bsplines.py +examples/exm_flow_model.py +examples/exm_geometry.py +examples/exm_qt_app.py +examples/exm_qt_app.ui +examples/exm_qt_vis.py +examples/exm_qt_vis.ui +examples/exm_stress_2d.py +examples/exm_stress_2d_export.py +examples/exm_stress_2d_materials.py +examples/exm_stress_2d_pyvtk.py +examples/exm_stress_2d_qt.py +examples/exm_stress_2d_qt.ui +examples/exm_structured_mesh.py +examples/exm_structured_mesh_3d.py +examples/exm_structured_mesh_vtk.py +examples/exm_temp_2d_markers.py +examples/exm_temp_2d_splines_arcs.py +examples/exm_tet_mesh.py +examples/exm_tet_mesh_vtk.py +examples/exs1.py +examples/exs_bar2.py +examples/exs_bar2_la.py +examples/exs_beam1.py +examples/exs_beambar2.py +examples/exs_flw_diff2.py +examples/exs_flw_temp2.py +examples/exs_spring.py +examples/exv1.py +examples/exv2.py +examples/exv3.py +examples/exv4.m +examples/exv4.mat +examples/exv4.py +examples/exv5.py +examples/exvis_beam_soli8.py +examples/.ipynb_checkpoints/Untitled-checkpoint.ipynb +examples/.ipynb_checkpoints/exs1-checkpoint.ipynb +examples/.ipynb_checkpoints/exs2-checkpoint.ipynb +examples/.ipynb_checkpoints/exs3-checkpoint.ipynb +examples/experimental/exed1.py +examples/experimental/exed1.ui +examples/experimental/exint1.py +examples/experimental/exm11.py +examples/experimental/exm11_mpl.py +examples/experimental/exm12.ipynb +examples/experimental/exm12.py +examples/experimental/exm12_mpl.py +examples/experimental/exm14_vtk.py +examples/experimental/exm1_mpl_edit.py +examples/experimental/exs6_test.py +examples/experimental/exui1.py +examples/experimental/gmsh_api_test.py +examples/experimental/gmsh_api_test_2.py +examples/experimental/path_int.py +examples/experimental/plot_test.py +examples/experimental/prim3d.py +examples/experimental/qt1.py +examples/experimental/qt2.py +examples/experimental/test_point_in_geom.py +examples/experimental/test_tri_mesh.py +examples/experimental/.vscode/settings.json +examples/gmsh-api/exgm1.py +examples/gmsh-api/exgm2.py +examples/gmsh-api/exgm3.py +examples/gmsh-api/exgm4.py +examples/obsolete/extri1.py +examples/obsolete/extri2.py \ No newline at end of file diff --git a/calfem_python_small.egg-info/dependency_links.txt b/calfem_python_small.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/calfem_python_small.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/calfem_python_small.egg-info/requires.txt b/calfem_python_small.egg-info/requires.txt new file mode 100644 index 0000000..8b8cb09 --- /dev/null +++ b/calfem_python_small.egg-info/requires.txt @@ -0,0 +1,6 @@ +numpy +visvis +matplotlib +scipy +gmsh +tabulate diff --git a/calfem_python_small.egg-info/top_level.txt b/calfem_python_small.egg-info/top_level.txt new file mode 100644 index 0000000..5fdf479 --- /dev/null +++ b/calfem_python_small.egg-info/top_level.txt @@ -0,0 +1 @@ +calfem diff --git a/setup-org.py b/setup-org.py new file mode 100644 index 0000000..2e0f809 --- /dev/null +++ b/setup-org.py @@ -0,0 +1,113 @@ +"""A setuptools based setup module. + +See: +https://github.com/CALFEM/calfem-python +""" + +# Always prefer setuptools over distutils +from setuptools import setup, find_packages +# To use a consistent encoding +from codecs import open +from os import path +import os, glob, sys + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the README file +with open(path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +def gen_data_files(*dirs): + results = [] + + for src_dir in dirs: + for root,dirs,files in os.walk(src_dir): + results.append((root, map(lambda f:root + "/" + f, files))) + return results + +setup( + name='calfem-python', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + + version='3.6.3', + + description='CALFEM for Python', + 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.', + + # The project's main homepage. + url='https://github.com/CALFEM/calfem-python', + + # Author details + author='Jonas Lindemann, et al', + author_email='jonas.lindemann@byggmek.lth.se', + + # Choose your license + license='MIT', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 4 - Beta', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Build Tools', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: MIT License', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.9', + ], + + # What does your project relate to? + keywords='finite element, math, numerics', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + #packages=find_packages(exclude=['contrib', 'docs', 'tests']), + #packages=find_packages(exclude=['docs', 'old', 'examples', 'examplegeo']), + packages=['calfem',], + + # Alternatively, if you want to distribute just a my_module.py, uncomment + # this: + # py_modules=["my_module"], + + # List run-time dependencies here. These will be installed by pip when + # your project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=['numpy', 'visvis', 'pyvtk', 'matplotlib', 'scipy', 'gmsh', 'qtpy', 'vedo', 'tabulate'], + include_package_data=True + #package_data={'calfem': ['examples/*']} + + #data_files=gen_data_files("examples", "doc") + + #package_data={ + # 'calfem': ['examples/*.py', 'examples/*.ui'] + #} + + # List additional groups of dependencies here (e.g. development + # dependencies). You can install these using the following syntax, + # for example: + # $ pip install -e .[dev,test] + #extras_require={ + # 'dev': ['check-manifest'], + # 'test': ['coverage'], + #}, + + # If there are data files included in your packages that need to be + # installed, specify them here. If using Python 2.6 or less, then these + # have to be included in MANIFEST.in as well. +) diff --git a/setup-template.py b/setup-template.py new file mode 100644 index 0000000..f1418ec --- /dev/null +++ b/setup-template.py @@ -0,0 +1,96 @@ +"""A setuptools based setup module. + +See: +https://github.com/CALFEM/calfem-python +""" + +# Always prefer setuptools over distutils +from setuptools import setup, find_packages +# To use a consistent encoding +from codecs import open +from os import path +import os, glob, sys + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the README file +with open(path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +def gen_data_files(*dirs): + results = [] + + for src_dir in dirs: + for root,dirs,files in os.walk(src_dir): + results.append((root, map(lambda f:root + "/" + f, files))) + return results + +setup( + name='{package_name}', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + + version='{package_version}', + + description='CALFEM for Python', + 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.', + + # The project's main homepage. + url='https://github.com/CALFEM/calfem-python', + + # Author details + author='Jonas Lindemann, et al', + author_email='jonas.lindemann@byggmek.lth.se', + + # Choose your license + license='MIT', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 4 - Beta', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Build Tools', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: MIT License', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.9', + ], + + # What does your project relate to? + keywords='finite element, math, numerics', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + #packages=find_packages(exclude=['contrib', 'docs', 'tests']), + #packages=find_packages(exclude=['docs', 'old', 'examples', 'examplegeo']), + packages=['calfem',], + + # Alternatively, if you want to distribute just a my_module.py, uncomment + # this: + # py_modules=["my_module"], + + # List run-time dependencies here. These will be installed by pip when + # your project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=[{package_depends}], + include_package_data=True + + #data_files=gen_data_files("examples", "doc") + +) diff --git a/setup.py b/setup.py index 6d42204..02102e5 100644 --- a/setup.py +++ b/setup.py @@ -26,13 +26,13 @@ def gen_data_files(*dirs): return results setup( - name='calfem-python', + name='calfem-python-small', # Versions should comply with PEP440. For a discussion on single-sourcing # the version across setup.py and the project code, see # https://packaging.python.org/en/latest/single_source_version.html - version='3.6.2', + version='3.6.3', description='CALFEM for Python', 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.', @@ -68,6 +68,7 @@ def gen_data_files(*dirs): 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.9', ], # What does your project relate to? @@ -87,26 +88,9 @@ def gen_data_files(*dirs): # your project is installed. For an analysis of "install_requires" vs pip's # requirements files see: # https://packaging.python.org/en/latest/requirements.html - install_requires=['numpy', 'visvis', 'pyvtk', 'matplotlib', 'scipy', 'gmsh', 'qtpy', 'vedo', 'tabulate'], + install_requires=['numpy', 'visvis', 'matplotlib', 'scipy', 'gmsh', 'tabulate'], include_package_data=True - #package_data={'calfem': ['examples/*']} #data_files=gen_data_files("examples", "doc") - #package_data={ - # 'calfem': ['examples/*.py', 'examples/*.ui'] - #} - - # List additional groups of dependencies here (e.g. development - # dependencies). You can install these using the following syntax, - # for example: - # $ pip install -e .[dev,test] - #extras_require={ - # 'dev': ['check-manifest'], - # 'test': ['coverage'], - #}, - - # If there are data files included in your packages that need to be - # installed, specify them here. If using Python 2.6 or less, then these - # have to be included in MANIFEST.in as well. ) From 895562a4ca8f552388f9ce04de74a396b0708005 Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Wed, 2 Nov 2022 13:30:46 +0100 Subject: [PATCH 02/17] Embedding ui of CALFEM Geometry editor in source code. --- calfem/editor.py | 8 +- calfem/editor_ui.py | 1208 +++++++++++++++++++++++++++++++++++++++++++ setup-template.py | 2 +- 3 files changed, 1215 insertions(+), 3 deletions(-) create mode 100644 calfem/editor_ui.py diff --git a/calfem/editor.py b/calfem/editor.py index 4b270e5..7bf4ab5 100644 --- a/calfem/editor.py +++ b/calfem/editor.py @@ -20,6 +20,7 @@ import calfem.geometry as cfg import calfem.vis_mpl as cfv import calfem.editor_scene as editor_scene +import calfem.editor_ui as editor_ui app = None @@ -31,8 +32,11 @@ def __init__(self): super(QMainWindow, self).__init__() self.app = app - root = os.path.dirname(os.path.realpath(__file__)) - loadUi(os.path.join(root, 'editor.ui'), self) + #root = os.path.dirname(os.path.realpath(__file__)) + #loadUi(os.path.join(root, 'editor.ui'), self) + + ui = editor_ui.Ui_MainWindow() + ui.setupUi(self) # loadUi('editor.ui', self) loadUI kan ladd ui-fil och lägga till objekt direkt i klassen. self.setWindowTitle("CALFEM Geometry Editor") diff --git a/calfem/editor_ui.py b/calfem/editor_ui.py new file mode 100644 index 0000000..a8293bc --- /dev/null +++ b/calfem/editor_ui.py @@ -0,0 +1,1208 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'editor.ui' +# +# Created by: PyQt5 UI code generator 5.9.2 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(1493, 785) + MainWindow.setStyleSheet("") + MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.centralwidget = QtWidgets.QWidget(MainWindow) + MainWindow.centralwidget.setStyleSheet("QWidget{\n" +"background: rgb(220, 220, 220);\n" +"}") + MainWindow.centralwidget.setObjectName("centralwidget") + MainWindow.verticalLayout_2 = QtWidgets.QVBoxLayout(MainWindow.centralwidget) + MainWindow.verticalLayout_2.setObjectName("verticalLayout_2") + MainWindow.tabWidget = QtWidgets.QTabWidget(MainWindow.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.tabWidget.sizePolicy().hasHeightForWidth()) + MainWindow.tabWidget.setSizePolicy(sizePolicy) + MainWindow.tabWidget.setMinimumSize(QtCore.QSize(0, 120)) + MainWindow.tabWidget.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) + MainWindow.tabWidget.setStyleSheet("QTabWidget::pane { /* The tab widget frame */\n" +" border-bottom: 6px solid;\n" +" border-bottom-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgb(200, 200, 200), stop:1 rgba(220,220,220));\n" +" border-top: 8px solid rgb(0,0,128);\n" +" /*border-radius: 4px;*/\n" +"}\n" +"\n" +"\n" +"QTabWidget::tab-bar {\n" +" left: 20px; /* move to the right by 5px */\n" +" bottom: -8px;\n" +"}\n" +"\n" +"QTabBar::tab {\n" +" /*border-bottom-color: transparent;\n" +" border-top-left-radius: 4px;*/\n" +" min-width: 18ex;\n" +" padding: 4px;\n" +"}\n" +"\n" +"QTabBar::tab:selected {\n" +" background: rgb(240,240,240);\n" +" border: 2px solid rgb(200,200,200);\n" +" border-bottom: 0 px solid;\n" +" border-top-left-radius: 6px;\n" +" border-top-right-radius: 6px;\n" +"}\n" +"\n" +"QTabBar::tab:!selected {\n" +" border: 2px solid rgb(200,200,200);\n" +" margin-top: 4px; /* make non-selected tabs look smaller */\n" +" border-top-left-radius: 6px;\n" +" border-top-right-radius: 6px;\n" +"}") + MainWindow.tabWidget.setObjectName("tabWidget") + MainWindow.tab_2 = QtWidgets.QWidget() + MainWindow.tab_2.setStyleSheet("QWidget{\n" +" background-color: rgb(240, 240, 240);\n" +"} ") + MainWindow.tab_2.setObjectName("tab_2") + MainWindow.layoutWidget = QtWidgets.QWidget(MainWindow.tab_2) + MainWindow.layoutWidget.setGeometry(QtCore.QRect(0, 0, 1100, 81)) + MainWindow.layoutWidget.setObjectName("layoutWidget") + MainWindow.horizontalLayout_2 = QtWidgets.QHBoxLayout(MainWindow.layoutWidget) + MainWindow.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + MainWindow.horizontalLayout_2.setObjectName("horizontalLayout_2") + spacerItem = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_2.addItem(spacerItem) + MainWindow.gridLayout = QtWidgets.QGridLayout() + MainWindow.gridLayout.setObjectName("gridLayout") + MainWindow.zoomOutButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.zoomOutButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/Images/zoom_out.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.zoomOutButtonSurface.setIcon(icon) + MainWindow.zoomOutButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.zoomOutButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.zoomOutButtonSurface.setObjectName("zoomOutButtonSurface") + MainWindow.gridLayout.addWidget(MainWindow.zoomOutButtonSurface, 0, 1, 1, 1) + MainWindow.arrowButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.arrowButtonSurface.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) + MainWindow.arrowButtonSurface.setFocusPolicy(QtCore.Qt.TabFocus) + MainWindow.arrowButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/Images/select.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.arrowButtonSurface.setIcon(icon1) + MainWindow.arrowButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.arrowButtonSurface.setCheckable(False) + MainWindow.arrowButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.arrowButtonSurface.setObjectName("arrowButtonSurface") + MainWindow.gridLayout.addWidget(MainWindow.arrowButtonSurface, 0, 0, 1, 1) + MainWindow.panningButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.panningButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/Images/pan.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.panningButtonSurface.setIcon(icon2) + MainWindow.panningButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.panningButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.panningButtonSurface.setObjectName("panningButtonSurface") + MainWindow.gridLayout.addWidget(MainWindow.panningButtonSurface, 1, 0, 1, 1) + MainWindow.zoomInButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.zoomInButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap(":/Images/zoom_in.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.zoomInButtonSurface.setIcon(icon3) + MainWindow.zoomInButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.zoomInButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.zoomInButtonSurface.setObjectName("zoomInButtonSurface") + MainWindow.gridLayout.addWidget(MainWindow.zoomInButtonSurface, 1, 1, 1, 1) + MainWindow.horizontalLayout_2.addLayout(MainWindow.gridLayout) + MainWindow.line_2 = QtWidgets.QFrame(MainWindow.layoutWidget) + MainWindow.line_2.setMinimumSize(QtCore.QSize(15, 0)) + MainWindow.line_2.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line_2.setLineWidth(1) + MainWindow.line_2.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_2.setObjectName("line_2") + MainWindow.horizontalLayout_2.addWidget(MainWindow.line_2) + MainWindow.verticalLayout_7 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_7.setObjectName("verticalLayout_7") + MainWindow.polyButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.polyButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon4 = QtGui.QIcon() + icon4.addPixmap(QtGui.QPixmap(":/Images/polygon.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.polyButton.setIcon(icon4) + MainWindow.polyButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.polyButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.polyButton.setObjectName("polyButton") + MainWindow.verticalLayout_7.addWidget(MainWindow.polyButton) + MainWindow.rectButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.rectButton.setEnabled(True) + MainWindow.rectButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon5 = QtGui.QIcon() + icon5.addPixmap(QtGui.QPixmap(":/Images/rectangle.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.rectButton.setIcon(icon5) + MainWindow.rectButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.rectButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.rectButton.setObjectName("rectButton") + MainWindow.verticalLayout_7.addWidget(MainWindow.rectButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_7) + MainWindow.verticalLayout_10 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_10.setObjectName("verticalLayout_10") + MainWindow.addPolyHoleButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.addPolyHoleButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon6 = QtGui.QIcon() + icon6.addPixmap(QtGui.QPixmap(":/Images/polygon_hole.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.addPolyHoleButton.setIcon(icon6) + MainWindow.addPolyHoleButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.addPolyHoleButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.addPolyHoleButton.setObjectName("addPolyHoleButton") + MainWindow.verticalLayout_10.addWidget(MainWindow.addPolyHoleButton) + MainWindow.addRectHoleButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.addRectHoleButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon7 = QtGui.QIcon() + icon7.addPixmap(QtGui.QPixmap(":/Images/rectangle_hole.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.addRectHoleButton.setIcon(icon7) + MainWindow.addRectHoleButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.addRectHoleButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.addRectHoleButton.setObjectName("addRectHoleButton") + MainWindow.verticalLayout_10.addWidget(MainWindow.addRectHoleButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_10) + MainWindow.verticalLayout_12 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_12.setObjectName("verticalLayout_12") + MainWindow.mergeButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.mergeButton.sizePolicy().hasHeightForWidth()) + MainWindow.mergeButton.setSizePolicy(sizePolicy) + MainWindow.mergeButton.setLayoutDirection(QtCore.Qt.LeftToRight) + MainWindow.mergeButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon8 = QtGui.QIcon() + icon8.addPixmap(QtGui.QPixmap(":/Images/merge.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.mergeButton.setIcon(icon8) + MainWindow.mergeButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.mergeButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.mergeButton.setAutoRaise(False) + MainWindow.mergeButton.setObjectName("mergeButton") + MainWindow.verticalLayout_12.addWidget(MainWindow.mergeButton) + MainWindow.deleteButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.deleteButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon9 = QtGui.QIcon() + icon9.addPixmap(QtGui.QPixmap(":/Images/erase.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.deleteButton.setIcon(icon9) + MainWindow.deleteButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.deleteButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.deleteButton.setObjectName("deleteButton") + MainWindow.verticalLayout_12.addWidget(MainWindow.deleteButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_12) + MainWindow.line_5 = QtWidgets.QFrame(MainWindow.layoutWidget) + MainWindow.line_5.setMinimumSize(QtCore.QSize(15, 0)) + MainWindow.line_5.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line_5.setLineWidth(1) + MainWindow.line_5.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_5.setObjectName("line_5") + MainWindow.horizontalLayout_2.addWidget(MainWindow.line_5) + MainWindow.verticalLayout_9 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_9.setObjectName("verticalLayout_9") + MainWindow.gridSnapButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.gridSnapButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:checked {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + icon10 = QtGui.QIcon() + icon10.addPixmap(QtGui.QPixmap(":/Images/grid_snap.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.gridSnapButtonSurface.setIcon(icon10) + MainWindow.gridSnapButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridSnapButtonSurface.setCheckable(True) + MainWindow.gridSnapButtonSurface.setChecked(True) + MainWindow.gridSnapButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridSnapButtonSurface.setObjectName("gridSnapButtonSurface") + MainWindow.verticalLayout_9.addWidget(MainWindow.gridSnapButtonSurface) + MainWindow.gridButtonSurface = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.gridButtonSurface.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:checked {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + icon11 = QtGui.QIcon() + icon11.addPixmap(QtGui.QPixmap(":/Images/grid.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.gridButtonSurface.setIcon(icon11) + MainWindow.gridButtonSurface.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridButtonSurface.setCheckable(True) + MainWindow.gridButtonSurface.setChecked(True) + MainWindow.gridButtonSurface.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridButtonSurface.setObjectName("gridButtonSurface") + MainWindow.verticalLayout_9.addWidget(MainWindow.gridButtonSurface) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_9) + MainWindow.verticalLayout_8 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_8.setObjectName("verticalLayout_8") + MainWindow.gridSpacingSpinBox = QtWidgets.QSpinBox(MainWindow.layoutWidget) + MainWindow.gridSpacingSpinBox.setMinimum(5) + MainWindow.gridSpacingSpinBox.setMaximum(1000) + MainWindow.gridSpacingSpinBox.setSingleStep(10) + MainWindow.gridSpacingSpinBox.setProperty("value", 20) + MainWindow.gridSpacingSpinBox.setObjectName("gridSpacingSpinBox") + MainWindow.verticalLayout_8.addWidget(MainWindow.gridSpacingSpinBox) + MainWindow.gridSpacingButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.gridSpacingButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + icon12 = QtGui.QIcon() + icon12.addPixmap(QtGui.QPixmap(":/Images/grid_settings.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.gridSpacingButton.setIcon(icon12) + MainWindow.gridSpacingButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridSpacingButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridSpacingButton.setObjectName("gridSpacingButton") + MainWindow.verticalLayout_8.addWidget(MainWindow.gridSpacingButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_8) + MainWindow.line_6 = QtWidgets.QFrame(MainWindow.layoutWidget) + MainWindow.line_6.setMinimumSize(QtCore.QSize(15, 0)) + MainWindow.line_6.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line_6.setLineWidth(1) + MainWindow.line_6.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_6.setObjectName("line_6") + MainWindow.horizontalLayout_2.addWidget(MainWindow.line_6) + MainWindow.verticalLayout_11 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_11.setObjectName("verticalLayout_11") + MainWindow.loadGeometryButton = QtWidgets.QToolButton(MainWindow.layoutWidget) + MainWindow.loadGeometryButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon13 = QtGui.QIcon() + icon13.addPixmap(QtGui.QPixmap(":/Images/open.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.loadGeometryButton.setIcon(icon13) + MainWindow.loadGeometryButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.loadGeometryButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.loadGeometryButton.setObjectName("loadGeometryButton") + MainWindow.verticalLayout_11.addWidget(MainWindow.loadGeometryButton) + MainWindow.horizontalLayout_2.addLayout(MainWindow.verticalLayout_11) + MainWindow.tabWidget.addTab(MainWindow.tab_2, "") + MainWindow.tab = QtWidgets.QWidget() + MainWindow.tab.setStyleSheet("QWidget{\n" +" background-color: rgb(240, 240, 240);\n" +"} ") + MainWindow.tab.setObjectName("tab") + MainWindow.horizontalLayoutWidget_2 = QtWidgets.QWidget(MainWindow.tab) + MainWindow.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(0, 0, 464, 81)) + MainWindow.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2") + MainWindow.horizontalLayout_3 = QtWidgets.QHBoxLayout(MainWindow.horizontalLayoutWidget_2) + MainWindow.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) + MainWindow.horizontalLayout_3.setObjectName("horizontalLayout_3") + spacerItem1 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_3.addItem(spacerItem1) + MainWindow.gridLayout_2 = QtWidgets.QGridLayout() + MainWindow.gridLayout_2.setObjectName("gridLayout_2") + MainWindow.arrowButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.arrowButtonBorder.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) + MainWindow.arrowButtonBorder.setFocusPolicy(QtCore.Qt.TabFocus) + MainWindow.arrowButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.arrowButtonBorder.setIcon(icon1) + MainWindow.arrowButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.arrowButtonBorder.setCheckable(True) + MainWindow.arrowButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.arrowButtonBorder.setObjectName("arrowButtonBorder") + MainWindow.gridLayout_2.addWidget(MainWindow.arrowButtonBorder, 0, 0, 1, 1) + MainWindow.zoomOutButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.zoomOutButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.zoomOutButtonBorder.setIcon(icon) + MainWindow.zoomOutButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.zoomOutButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.zoomOutButtonBorder.setObjectName("zoomOutButtonBorder") + MainWindow.gridLayout_2.addWidget(MainWindow.zoomOutButtonBorder, 0, 1, 1, 1) + MainWindow.zoomInButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.zoomInButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.zoomInButtonBorder.setIcon(icon3) + MainWindow.zoomInButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.zoomInButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.zoomInButtonBorder.setObjectName("zoomInButtonBorder") + MainWindow.gridLayout_2.addWidget(MainWindow.zoomInButtonBorder, 1, 1, 1, 1) + MainWindow.panningButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.panningButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.panningButtonBorder.setIcon(icon2) + MainWindow.panningButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.panningButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.panningButtonBorder.setObjectName("panningButtonBorder") + MainWindow.gridLayout_2.addWidget(MainWindow.panningButtonBorder, 1, 0, 1, 1) + MainWindow.horizontalLayout_3.addLayout(MainWindow.gridLayout_2) + MainWindow.line = QtWidgets.QFrame(MainWindow.horizontalLayoutWidget_2) + MainWindow.line.setMinimumSize(QtCore.QSize(15, 0)) + MainWindow.line.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line.setObjectName("line") + MainWindow.horizontalLayout_3.addWidget(MainWindow.line) + MainWindow.verticalLayout_6 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_6.setObjectName("verticalLayout_6") + MainWindow.setMarkerButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.setMarkerButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon14 = QtGui.QIcon() + icon14.addPixmap(QtGui.QPixmap(":/Images/add_marker.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.setMarkerButton.setIcon(icon14) + MainWindow.setMarkerButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.setMarkerButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.setMarkerButton.setObjectName("setMarkerButton") + MainWindow.verticalLayout_6.addWidget(MainWindow.setMarkerButton) + MainWindow.splitEdgeButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.splitEdgeButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon15 = QtGui.QIcon() + icon15.addPixmap(QtGui.QPixmap(":/Images/split_edge.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.splitEdgeButton.setIcon(icon15) + MainWindow.splitEdgeButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.splitEdgeButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.splitEdgeButton.setObjectName("splitEdgeButton") + MainWindow.verticalLayout_6.addWidget(MainWindow.splitEdgeButton) + MainWindow.horizontalLayout_3.addLayout(MainWindow.verticalLayout_6) + MainWindow.line_3 = QtWidgets.QFrame(MainWindow.horizontalLayoutWidget_2) + MainWindow.line_3.setFrameShadow(QtWidgets.QFrame.Plain) + MainWindow.line_3.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_3.setObjectName("line_3") + MainWindow.horizontalLayout_3.addWidget(MainWindow.line_3) + MainWindow.verticalLayout_13 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_13.setObjectName("verticalLayout_13") + MainWindow.gridSnapButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.gridSnapButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:checked {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + MainWindow.gridSnapButtonBorder.setIcon(icon10) + MainWindow.gridSnapButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridSnapButtonBorder.setCheckable(True) + MainWindow.gridSnapButtonBorder.setChecked(True) + MainWindow.gridSnapButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridSnapButtonBorder.setObjectName("gridSnapButtonBorder") + MainWindow.verticalLayout_13.addWidget(MainWindow.gridSnapButtonBorder) + MainWindow.gridButtonBorder = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget_2) + MainWindow.gridButtonBorder.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:checked {\n" +" background-color: rgb(191, 184, 175);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgb(223, 219, 215);\n" +"}\n" +"") + MainWindow.gridButtonBorder.setIcon(icon11) + MainWindow.gridButtonBorder.setIconSize(QtCore.QSize(24, 24)) + MainWindow.gridButtonBorder.setCheckable(True) + MainWindow.gridButtonBorder.setChecked(True) + MainWindow.gridButtonBorder.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.gridButtonBorder.setObjectName("gridButtonBorder") + MainWindow.verticalLayout_13.addWidget(MainWindow.gridButtonBorder) + MainWindow.horizontalLayout_3.addLayout(MainWindow.verticalLayout_13) + MainWindow.tabWidget.addTab(MainWindow.tab, "") + MainWindow.tab_4 = QtWidgets.QWidget() + MainWindow.tab_4.setStyleSheet("QWidget{\n" +" background-color: rgb(240, 240, 240);\n" +"} ") + MainWindow.tab_4.setObjectName("tab_4") + MainWindow.saveGeomButton = QtWidgets.QToolButton(MainWindow.tab_4) + MainWindow.saveGeomButton.setGeometry(QtCore.QRect(10, 30, 141, 21)) + MainWindow.saveGeomButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon16 = QtGui.QIcon() + icon16.addPixmap(QtGui.QPixmap(":/Images/save.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.saveGeomButton.setIcon(icon16) + MainWindow.saveGeomButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.saveGeomButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.saveGeomButton.setObjectName("saveGeomButton") + MainWindow.tabWidget.addTab(MainWindow.tab_4, "") + MainWindow.tab_3 = QtWidgets.QWidget() + MainWindow.tab_3.setStyleSheet("QWidget{\n" +" background-color: rgb(240, 240, 240);\n" +"} ") + MainWindow.tab_3.setObjectName("tab_3") + MainWindow.horizontalLayoutWidget = QtWidgets.QWidget(MainWindow.tab_3) + MainWindow.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 0, 351, 71)) + MainWindow.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget") + MainWindow.horizontalLayout_5 = QtWidgets.QHBoxLayout(MainWindow.horizontalLayoutWidget) + MainWindow.horizontalLayout_5.setContentsMargins(0, 0, 0, 0) + MainWindow.horizontalLayout_5.setSpacing(0) + MainWindow.horizontalLayout_5.setObjectName("horizontalLayout_5") + MainWindow.label_9 = QtWidgets.QLabel(MainWindow.horizontalLayoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.label_9.sizePolicy().hasHeightForWidth()) + MainWindow.label_9.setSizePolicy(sizePolicy) + MainWindow.label_9.setText("") + MainWindow.label_9.setPixmap(QtGui.QPixmap(":/Images/save.png")) + MainWindow.label_9.setObjectName("label_9") + MainWindow.horizontalLayout_5.addWidget(MainWindow.label_9) + MainWindow.line_4 = QtWidgets.QFrame(MainWindow.horizontalLayoutWidget) + MainWindow.line_4.setFrameShape(QtWidgets.QFrame.VLine) + MainWindow.line_4.setFrameShadow(QtWidgets.QFrame.Sunken) + MainWindow.line_4.setObjectName("line_4") + MainWindow.horizontalLayout_5.addWidget(MainWindow.line_4) + MainWindow.verticalLayout_19 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_19.setSpacing(0) + MainWindow.verticalLayout_19.setObjectName("verticalLayout_19") + MainWindow.saveMeshButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget) + MainWindow.saveMeshButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + icon17 = QtGui.QIcon() + icon17.addPixmap(QtGui.QPixmap(":/Images/blank.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.saveMeshButton.setIcon(icon17) + MainWindow.saveMeshButton.setIconSize(QtCore.QSize(12, 12)) + MainWindow.saveMeshButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.saveMeshButton.setObjectName("saveMeshButton") + MainWindow.verticalLayout_19.addWidget(MainWindow.saveMeshButton) + MainWindow.saveArraysButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget) + MainWindow.saveArraysButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.saveArraysButton.setIcon(icon17) + MainWindow.saveArraysButton.setIconSize(QtCore.QSize(12, 12)) + MainWindow.saveArraysButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.saveArraysButton.setObjectName("saveArraysButton") + MainWindow.verticalLayout_19.addWidget(MainWindow.saveArraysButton) + MainWindow.saveArraysMatlabButton = QtWidgets.QToolButton(MainWindow.horizontalLayoutWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.saveArraysMatlabButton.sizePolicy().hasHeightForWidth()) + MainWindow.saveArraysMatlabButton.setSizePolicy(sizePolicy) + MainWindow.saveArraysMatlabButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.saveArraysMatlabButton.setIcon(icon17) + MainWindow.saveArraysMatlabButton.setIconSize(QtCore.QSize(12, 12)) + MainWindow.saveArraysMatlabButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) + MainWindow.saveArraysMatlabButton.setObjectName("saveArraysMatlabButton") + MainWindow.verticalLayout_19.addWidget(MainWindow.saveArraysMatlabButton) + MainWindow.horizontalLayout_5.addLayout(MainWindow.verticalLayout_19) + MainWindow.tabWidget.addTab(MainWindow.tab_3, "") + MainWindow.verticalLayout_2.addWidget(MainWindow.tabWidget) + MainWindow.horizontalLayout_4 = QtWidgets.QHBoxLayout() + MainWindow.horizontalLayout_4.setObjectName("horizontalLayout_4") + spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_4.addItem(spacerItem2) + MainWindow.labelTooltip = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.labelTooltip.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.labelTooltip.setText("") + MainWindow.labelTooltip.setObjectName("labelTooltip") + MainWindow.horizontalLayout_4.addWidget(MainWindow.labelTooltip) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_4.addItem(spacerItem3) + MainWindow.label = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.label.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.label.setObjectName("label") + MainWindow.horizontalLayout_4.addWidget(MainWindow.label) + MainWindow.labelX = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.labelX.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.labelX.setObjectName("labelX") + MainWindow.horizontalLayout_4.addWidget(MainWindow.labelX) + MainWindow.label_3 = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.label_3.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.label_3.setObjectName("label_3") + MainWindow.horizontalLayout_4.addWidget(MainWindow.label_3) + MainWindow.labelY = QtWidgets.QLabel(MainWindow.centralwidget) + MainWindow.labelY.setStyleSheet("QLabel{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.labelY.setObjectName("labelY") + MainWindow.horizontalLayout_4.addWidget(MainWindow.labelY) + spacerItem4 = QtWidgets.QSpacerItem(220, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_4.addItem(spacerItem4) + MainWindow.verticalLayout_2.addLayout(MainWindow.horizontalLayout_4) + MainWindow.horizontalLayout = QtWidgets.QHBoxLayout() + MainWindow.horizontalLayout.setSpacing(0) + MainWindow.horizontalLayout.setObjectName("horizontalLayout") + MainWindow.stackedWidget = QtWidgets.QStackedWidget(MainWindow.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.stackedWidget.sizePolicy().hasHeightForWidth()) + MainWindow.stackedWidget.setSizePolicy(sizePolicy) + MainWindow.stackedWidget.setMinimumSize(QtCore.QSize(661, 420)) + MainWindow.stackedWidget.setStyleSheet("QStackedWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.stackedWidget.setObjectName("stackedWidget") + MainWindow.page = QtWidgets.QWidget() + MainWindow.page.setStyleSheet("QWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.page.setObjectName("page") + MainWindow.verticalLayout_4 = QtWidgets.QVBoxLayout(MainWindow.page) + MainWindow.verticalLayout_4.setObjectName("verticalLayout_4") + MainWindow.verticalLayout = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout.setObjectName("verticalLayout") + MainWindow.verticalLayout_4.addLayout(MainWindow.verticalLayout) + MainWindow.stackedWidget.addWidget(MainWindow.page) + MainWindow.page_2 = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.page_2.sizePolicy().hasHeightForWidth()) + MainWindow.page_2.setSizePolicy(sizePolicy) + MainWindow.page_2.setStyleSheet("QWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.page_2.setObjectName("page_2") + MainWindow.verticalLayout_3 = QtWidgets.QVBoxLayout(MainWindow.page_2) + MainWindow.verticalLayout_3.setObjectName("verticalLayout_3") + MainWindow.graphicsView = QtWidgets.QGraphicsView(MainWindow.page_2) + MainWindow.graphicsView.setMinimumSize(QtCore.QSize(661, 401)) + MainWindow.graphicsView.viewport().setProperty("cursor", QtGui.QCursor(QtCore.Qt.ArrowCursor)) + MainWindow.graphicsView.setMouseTracking(True) + MainWindow.graphicsView.setStyleSheet("QGraphicsView{\n" +" background: rgb(255,255,255);\n" +" border: 2px solid rgb(0,0,128);\n" +"}") + MainWindow.graphicsView.setObjectName("graphicsView") + MainWindow.verticalLayout_3.addWidget(MainWindow.graphicsView) + MainWindow.stackedWidget.addWidget(MainWindow.page_2) + MainWindow.horizontalLayout.addWidget(MainWindow.stackedWidget) + MainWindow.stackedWidgetRight = QtWidgets.QStackedWidget(MainWindow.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.stackedWidgetRight.sizePolicy().hasHeightForWidth()) + MainWindow.stackedWidgetRight.setSizePolicy(sizePolicy) + MainWindow.stackedWidgetRight.setMinimumSize(QtCore.QSize(200, 401)) + MainWindow.stackedWidgetRight.setStyleSheet("QStackedWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.stackedWidgetRight.setObjectName("stackedWidgetRight") + MainWindow.page_5 = QtWidgets.QWidget() + MainWindow.page_5.setStyleSheet("QWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.page_5.setObjectName("page_5") + MainWindow.verticalLayout_14 = QtWidgets.QVBoxLayout(MainWindow.page_5) + MainWindow.verticalLayout_14.setObjectName("verticalLayout_14") + MainWindow.verticalLayout_15 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_15.setObjectName("verticalLayout_15") + MainWindow.widget = QtWidgets.QWidget(MainWindow.page_5) + MainWindow.widget.setStyleSheet("QWidget{\n" +" background: rgb(255,255,255);\n" +" border: 2px solid rgb(0,0,128);\n" +"}") + MainWindow.widget.setObjectName("widget") + MainWindow.gridLayout_3 = QtWidgets.QGridLayout(MainWindow.widget) + MainWindow.gridLayout_3.setObjectName("gridLayout_3") + MainWindow.label_4 = QtWidgets.QLabel(MainWindow.widget) + MainWindow.label_4.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_4.setObjectName("label_4") + MainWindow.gridLayout_3.addWidget(MainWindow.label_4, 5, 0, 1, 1) + MainWindow.elSizeSpinBox = QtWidgets.QDoubleSpinBox(MainWindow.widget) + MainWindow.elSizeSpinBox.setStyleSheet("QDoubleSpinBox{\n" +" background: rgb(255,255,255);\n" +" border: 1px solid rgb(0,0,128);\n" +"}") + MainWindow.elSizeSpinBox.setDecimals(1) + MainWindow.elSizeSpinBox.setMinimum(0.0) + MainWindow.elSizeSpinBox.setMaximum(1000.0) + MainWindow.elSizeSpinBox.setSingleStep(5.0) + MainWindow.elSizeSpinBox.setProperty("value", 25.0) + MainWindow.elSizeSpinBox.setObjectName("elSizeSpinBox") + MainWindow.gridLayout_3.addWidget(MainWindow.elSizeSpinBox, 5, 1, 1, 1) + MainWindow.radioButtonQuadrangle = QtWidgets.QRadioButton(MainWindow.widget) + MainWindow.radioButtonQuadrangle.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonQuadrangle.setChecked(False) + MainWindow.radioButtonQuadrangle.setObjectName("radioButtonQuadrangle") + MainWindow.gridLayout_3.addWidget(MainWindow.radioButtonQuadrangle, 2, 1, 1, 1) + spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + MainWindow.gridLayout_3.addItem(spacerItem5, 10, 0, 1, 1) + MainWindow.label_5 = QtWidgets.QLabel(MainWindow.widget) + MainWindow.label_5.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_5.setObjectName("label_5") + MainWindow.gridLayout_3.addWidget(MainWindow.label_5, 7, 0, 1, 1) + MainWindow.DOFSpinBox = QtWidgets.QSpinBox(MainWindow.widget) + MainWindow.DOFSpinBox.setStyleSheet("QSpinBox{\n" +" background: rgb(255,255,255);\n" +" border: 1px solid rgb(0,0,128);\n" +"}") + MainWindow.DOFSpinBox.setMinimum(1) + MainWindow.DOFSpinBox.setObjectName("DOFSpinBox") + MainWindow.gridLayout_3.addWidget(MainWindow.DOFSpinBox, 7, 1, 1, 1) + MainWindow.radioButtonTriangle = QtWidgets.QRadioButton(MainWindow.widget) + MainWindow.radioButtonTriangle.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonTriangle.setChecked(True) + MainWindow.radioButtonTriangle.setObjectName("radioButtonTriangle") + MainWindow.gridLayout_3.addWidget(MainWindow.radioButtonTriangle, 0, 1, 1, 1) + spacerItem6 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_3.addItem(spacerItem6, 4, 1, 1, 1) + spacerItem7 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_3.addItem(spacerItem7, 6, 1, 1, 1) + MainWindow.label_2 = QtWidgets.QLabel(MainWindow.widget) + MainWindow.label_2.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_2.setObjectName("label_2") + MainWindow.gridLayout_3.addWidget(MainWindow.label_2, 0, 0, 1, 1) + spacerItem8 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_3.addItem(spacerItem8, 8, 1, 1, 1) + MainWindow.refreshMeshButton = QtWidgets.QPushButton(MainWindow.widget) + MainWindow.refreshMeshButton.setObjectName("refreshMeshButton") + MainWindow.gridLayout_3.addWidget(MainWindow.refreshMeshButton, 9, 1, 1, 1) + MainWindow.verticalLayout_15.addWidget(MainWindow.widget) + MainWindow.verticalLayout_14.addLayout(MainWindow.verticalLayout_15) + MainWindow.stackedWidgetRight.addWidget(MainWindow.page_5) + MainWindow.page_6 = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.page_6.sizePolicy().hasHeightForWidth()) + MainWindow.page_6.setSizePolicy(sizePolicy) + MainWindow.page_6.setStyleSheet("QWidget{\n" +" background: rgba(255,255,255,0);\n" +"}") + MainWindow.page_6.setObjectName("page_6") + MainWindow.verticalLayout_16 = QtWidgets.QVBoxLayout(MainWindow.page_6) + MainWindow.verticalLayout_16.setObjectName("verticalLayout_16") + MainWindow.scrollArea = QtWidgets.QScrollArea(MainWindow.page_6) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.scrollArea.sizePolicy().hasHeightForWidth()) + MainWindow.scrollArea.setSizePolicy(sizePolicy) + MainWindow.scrollArea.setMinimumSize(QtCore.QSize(200, 300)) + MainWindow.scrollArea.setStyleSheet("QScrollArea{\n" +" background: rgb(255,255,255);\n" +" border: 2px solid rgb(0,0,128);\n" +"}") + MainWindow.scrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) + MainWindow.scrollArea.setWidgetResizable(True) + MainWindow.scrollArea.setObjectName("scrollArea") + MainWindow.scrollAreaWidgetContents_2 = QtWidgets.QWidget() + MainWindow.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 196, 296)) + MainWindow.scrollAreaWidgetContents_2.setStyleSheet("QWidget{\n" +" background: rgb(255,255,255);\n" +"}") + MainWindow.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") + MainWindow.scrollArea.setWidget(MainWindow.scrollAreaWidgetContents_2) + MainWindow.verticalLayout_16.addWidget(MainWindow.scrollArea) + spacerItem9 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + MainWindow.verticalLayout_16.addItem(spacerItem9) + MainWindow.stackedWidgetRight.addWidget(MainWindow.page_6) + MainWindow.page_7 = QtWidgets.QWidget() + MainWindow.page_7.setObjectName("page_7") + MainWindow.verticalLayout_5 = QtWidgets.QVBoxLayout(MainWindow.page_7) + MainWindow.verticalLayout_5.setObjectName("verticalLayout_5") + MainWindow.widget_2 = QtWidgets.QWidget(MainWindow.page_7) + MainWindow.widget_2.setStyleSheet("QWidget{\n" +" background: rgb(255,255,255);\n" +" border: 2px solid rgb(0,0,128);\n" +"}") + MainWindow.widget_2.setObjectName("widget_2") + MainWindow.gridLayout_4 = QtWidgets.QGridLayout(MainWindow.widget_2) + MainWindow.gridLayout_4.setObjectName("gridLayout_4") + spacerItem10 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_4.addItem(spacerItem10, 2, 1, 1, 1) + MainWindow.radioButtonDisplayPointLabelsTrue = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDisplayPointLabelsTrue.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDisplayPointLabelsTrue.setChecked(True) + MainWindow.radioButtonDisplayPointLabelsTrue.setObjectName("radioButtonDisplayPointLabelsTrue") + MainWindow.buttonGroupDisplayPointLabels = QtWidgets.QButtonGroup(MainWindow) + MainWindow.buttonGroupDisplayPointLabels.setObjectName("buttonGroupDisplayPointLabels") + MainWindow.buttonGroupDisplayPointLabels.addButton(MainWindow.radioButtonDisplayPointLabelsTrue) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDisplayPointLabelsTrue, 3, 1, 1, 1) + MainWindow.radioButtonDisplayEdgeLabelsTrue = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDisplayEdgeLabelsTrue.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDisplayEdgeLabelsTrue.setChecked(True) + MainWindow.radioButtonDisplayEdgeLabelsTrue.setObjectName("radioButtonDisplayEdgeLabelsTrue") + MainWindow.buttonGroupDOFsPerNode = QtWidgets.QButtonGroup(MainWindow) + MainWindow.buttonGroupDOFsPerNode.setObjectName("buttonGroupDOFsPerNode") + MainWindow.buttonGroupDOFsPerNode.addButton(MainWindow.radioButtonDisplayEdgeLabelsTrue) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDisplayEdgeLabelsTrue, 6, 1, 1, 1) + MainWindow.radioButtonDisplayPointLabelsFalse = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDisplayPointLabelsFalse.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDisplayPointLabelsFalse.setObjectName("radioButtonDisplayPointLabelsFalse") + MainWindow.buttonGroupDisplayPointLabels.addButton(MainWindow.radioButtonDisplayPointLabelsFalse) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDisplayPointLabelsFalse, 4, 1, 1, 1) + MainWindow.radioButtonDrawPointFalse = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDrawPointFalse.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDrawPointFalse.setObjectName("radioButtonDrawPointFalse") + MainWindow.buttonGroupDrawPoints = QtWidgets.QButtonGroup(MainWindow) + MainWindow.buttonGroupDrawPoints.setObjectName("buttonGroupDrawPoints") + MainWindow.buttonGroupDrawPoints.addButton(MainWindow.radioButtonDrawPointFalse) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDrawPointFalse, 1, 1, 1, 1) + MainWindow.radioButtonDrawPointTrue = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDrawPointTrue.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDrawPointTrue.setChecked(True) + MainWindow.radioButtonDrawPointTrue.setObjectName("radioButtonDrawPointTrue") + MainWindow.buttonGroupDrawPoints.addButton(MainWindow.radioButtonDrawPointTrue) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDrawPointTrue, 0, 1, 1, 1) + MainWindow.label_8 = QtWidgets.QLabel(MainWindow.widget_2) + MainWindow.label_8.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_8.setObjectName("label_8") + MainWindow.gridLayout_4.addWidget(MainWindow.label_8, 3, 0, 1, 1) + MainWindow.label_6 = QtWidgets.QLabel(MainWindow.widget_2) + MainWindow.label_6.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_6.setObjectName("label_6") + MainWindow.gridLayout_4.addWidget(MainWindow.label_6, 0, 0, 1, 1) + MainWindow.label_7 = QtWidgets.QLabel(MainWindow.widget_2) + MainWindow.label_7.setStyleSheet("QLabel{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.label_7.setObjectName("label_7") + MainWindow.gridLayout_4.addWidget(MainWindow.label_7, 6, 0, 1, 1) + spacerItem11 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + MainWindow.gridLayout_4.addItem(spacerItem11, 8, 0, 1, 1) + MainWindow.radioButtonDisplayEdgeLabelsFalse = QtWidgets.QRadioButton(MainWindow.widget_2) + MainWindow.radioButtonDisplayEdgeLabelsFalse.setStyleSheet("QRadioButton{\n" +" background: rgb(255,255,255);\n" +" border: 0px solid rgb(0,0,128);\n" +"}") + MainWindow.radioButtonDisplayEdgeLabelsFalse.setObjectName("radioButtonDisplayEdgeLabelsFalse") + MainWindow.buttonGroupDOFsPerNode.addButton(MainWindow.radioButtonDisplayEdgeLabelsFalse) + MainWindow.gridLayout_4.addWidget(MainWindow.radioButtonDisplayEdgeLabelsFalse, 7, 1, 1, 1) + spacerItem12 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + MainWindow.gridLayout_4.addItem(spacerItem12, 5, 1, 1, 1) + MainWindow.verticalLayout_5.addWidget(MainWindow.widget_2) + MainWindow.stackedWidgetRight.addWidget(MainWindow.page_7) + MainWindow.horizontalLayout.addWidget(MainWindow.stackedWidgetRight) + MainWindow.verticalLayout_2.addLayout(MainWindow.horizontalLayout) + MainWindow.horizontalLayout_7 = QtWidgets.QHBoxLayout() + MainWindow.horizontalLayout_7.setObjectName("horizontalLayout_7") + spacerItem13 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + MainWindow.horizontalLayout_7.addItem(spacerItem13) + MainWindow.verticalLayout_17 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_17.setObjectName("verticalLayout_17") + MainWindow.textBrowser = QtWidgets.QTextBrowser(MainWindow.centralwidget) + MainWindow.textBrowser.setMaximumSize(QtCore.QSize(16777215, 150)) + MainWindow.textBrowser.setStyleSheet("QTextBrowser{\n" +"border: 2px solid rgb(0,0,128);\n" +"background: rgb(255,255,255);\n" +"}") + MainWindow.textBrowser.setObjectName("textBrowser") + MainWindow.verticalLayout_17.addWidget(MainWindow.textBrowser) + MainWindow.horizontalLayout_7.addLayout(MainWindow.verticalLayout_17) + MainWindow.verticalLayout_18 = QtWidgets.QVBoxLayout() + MainWindow.verticalLayout_18.setObjectName("verticalLayout_18") + MainWindow.hideTextBrowserButton = QtWidgets.QToolButton(MainWindow.centralwidget) + MainWindow.hideTextBrowserButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}") + MainWindow.hideTextBrowserButton.setText("") + icon18 = QtGui.QIcon() + icon18.addPixmap(QtGui.QPixmap(":/Images/minus.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.hideTextBrowserButton.setIcon(icon18) + MainWindow.hideTextBrowserButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.hideTextBrowserButton.setObjectName("hideTextBrowserButton") + MainWindow.verticalLayout_18.addWidget(MainWindow.hideTextBrowserButton) + MainWindow.showTextBrowserButton = QtWidgets.QToolButton(MainWindow.centralwidget) + MainWindow.showTextBrowserButton.setEnabled(True) + MainWindow.showTextBrowserButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}") + MainWindow.showTextBrowserButton.setText("") + icon19 = QtGui.QIcon() + icon19.addPixmap(QtGui.QPixmap(":/Images/plus.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + MainWindow.showTextBrowserButton.setIcon(icon19) + MainWindow.showTextBrowserButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.showTextBrowserButton.setObjectName("showTextBrowserButton") + MainWindow.verticalLayout_18.addWidget(MainWindow.showTextBrowserButton) + MainWindow.clearTextBrowserButton = QtWidgets.QToolButton(MainWindow.centralwidget) + MainWindow.clearTextBrowserButton.setStyleSheet("QToolButton{\n" +" border: 0px;\n" +"}\n" +"\n" +"QToolButton:pressed {\n" +" background-color: rgb(185, 211, 220);\n" +"}\n" +"\n" +"QToolButton:hover {\n" +" background-color: rgba(185, 211, 220,100);\n" +"}\n" +"") + MainWindow.clearTextBrowserButton.setText("") + MainWindow.clearTextBrowserButton.setIcon(icon9) + MainWindow.clearTextBrowserButton.setIconSize(QtCore.QSize(24, 24)) + MainWindow.clearTextBrowserButton.setObjectName("clearTextBrowserButton") + MainWindow.verticalLayout_18.addWidget(MainWindow.clearTextBrowserButton) + MainWindow.horizontalLayout_7.addLayout(MainWindow.verticalLayout_18) + MainWindow.verticalLayout_2.addLayout(MainWindow.horizontalLayout_7) + MainWindow.setCentralWidget(MainWindow.centralwidget) + MainWindow.menubar = QtWidgets.QMenuBar(MainWindow) + MainWindow.menubar.setGeometry(QtCore.QRect(0, 0, 1493, 21)) + MainWindow.menubar.setObjectName("menubar") + MainWindow.setMenuBar(MainWindow.menubar) + MainWindow.statusbar = QtWidgets.QStatusBar(MainWindow) + MainWindow.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(MainWindow.statusbar) + + self.retranslateUi(MainWindow) + MainWindow.tabWidget.setCurrentIndex(0) + MainWindow.stackedWidget.setCurrentIndex(1) + MainWindow.stackedWidgetRight.setCurrentIndex(1) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + MainWindow.zoomOutButtonSurface.setText(_translate("MainWindow", "Zoom Out")) + MainWindow.arrowButtonSurface.setText(_translate("MainWindow", "Arrow")) + MainWindow.panningButtonSurface.setText(_translate("MainWindow", "Panning")) + MainWindow.zoomInButtonSurface.setText(_translate("MainWindow", "Zoom In")) + MainWindow.polyButton.setText(_translate("MainWindow", "Draw Polygon")) + MainWindow.rectButton.setText(_translate("MainWindow", "Draw Rectangle")) + MainWindow.addPolyHoleButton.setText(_translate("MainWindow", "Draw Polygon Hole")) + MainWindow.addRectHoleButton.setText(_translate("MainWindow", "Draw Rectangle Hole")) + MainWindow.mergeButton.setText(_translate("MainWindow", "Merge Overlapping Geometries")) + MainWindow.deleteButton.setText(_translate("MainWindow", "Delete Item")) + MainWindow.gridSnapButtonSurface.setText(_translate("MainWindow", "Toggle Gridsnap")) + MainWindow.gridButtonSurface.setText(_translate("MainWindow", "Toggle Grid")) + MainWindow.gridSpacingButton.setText(_translate("MainWindow", "Set Grid Spacing")) + MainWindow.loadGeometryButton.setText(_translate("MainWindow", "Load Geometry")) + MainWindow.tabWidget.setTabText(MainWindow.tabWidget.indexOf(MainWindow.tab_2), _translate("MainWindow", "Page")) + MainWindow.arrowButtonBorder.setText(_translate("MainWindow", "Arrow")) + MainWindow.zoomOutButtonBorder.setText(_translate("MainWindow", "Zoom Out")) + MainWindow.zoomInButtonBorder.setText(_translate("MainWindow", "Zoom In")) + MainWindow.panningButtonBorder.setText(_translate("MainWindow", "Panning")) + MainWindow.setMarkerButton.setText(_translate("MainWindow", "Set Marker")) + MainWindow.splitEdgeButton.setText(_translate("MainWindow", "Split Edge")) + MainWindow.gridSnapButtonBorder.setText(_translate("MainWindow", "Toggle Gridsnap")) + MainWindow.gridButtonBorder.setText(_translate("MainWindow", "Toggle Grid")) + MainWindow.tabWidget.setTabText(MainWindow.tabWidget.indexOf(MainWindow.tab), _translate("MainWindow", "Tab 1")) + MainWindow.saveGeomButton.setText(_translate("MainWindow", "Save Geometry")) + MainWindow.tabWidget.setTabText(MainWindow.tabWidget.indexOf(MainWindow.tab_4), _translate("MainWindow", "Page")) + MainWindow.saveMeshButton.setText(_translate("MainWindow", "Save Mesh")) + MainWindow.saveArraysButton.setText(_translate("MainWindow", "Save Mesh Arrays")) + MainWindow.saveArraysMatlabButton.setText(_translate("MainWindow", "Save Mesh Arrays to Matlab")) + MainWindow.tabWidget.setTabText(MainWindow.tabWidget.indexOf(MainWindow.tab_3), _translate("MainWindow", "Page")) + MainWindow.label.setText(_translate("MainWindow", "x: ")) + MainWindow.labelX.setText(_translate("MainWindow", "TextLabel")) + MainWindow.label_3.setText(_translate("MainWindow", "y:")) + MainWindow.labelY.setText(_translate("MainWindow", "TextLabel")) + MainWindow.label_4.setText(_translate("MainWindow", "Element Size:")) + MainWindow.radioButtonQuadrangle.setText(_translate("MainWindow", "Quadrangle")) + MainWindow.label_5.setText(_translate("MainWindow", "DOFs per Node:")) + MainWindow.radioButtonTriangle.setText(_translate("MainWindow", "Triangle")) + MainWindow.label_2.setText(_translate("MainWindow", "Element Type:")) + MainWindow.refreshMeshButton.setText(_translate("MainWindow", "Refresh Mesh")) + MainWindow.radioButtonDisplayPointLabelsTrue.setText(_translate("MainWindow", "True")) + MainWindow.radioButtonDisplayEdgeLabelsTrue.setText(_translate("MainWindow", "True")) + MainWindow.radioButtonDisplayPointLabelsFalse.setText(_translate("MainWindow", "False")) + MainWindow.radioButtonDrawPointFalse.setText(_translate("MainWindow", "False")) + MainWindow.radioButtonDrawPointTrue.setText(_translate("MainWindow", "True")) + MainWindow.label_8.setText(_translate("MainWindow", "Display Point Labels:")) + MainWindow.label_6.setText(_translate("MainWindow", "Draw Points:")) + MainWindow.label_7.setText(_translate("MainWindow", "Display Edge Labels")) + MainWindow.radioButtonDisplayEdgeLabelsFalse.setText(_translate("MainWindow", "False")) + MainWindow.textBrowser.setHtml(_translate("MainWindow", "\n" +"\n" +"


")) + +#import resources_rc diff --git a/setup-template.py b/setup-template.py index f1418ec..1176426 100644 --- a/setup-template.py +++ b/setup-template.py @@ -42,7 +42,7 @@ def gen_data_files(*dirs): # Author details author='Jonas Lindemann, et al', - author_email='jonas.lindemann@byggmek.lth.se', + author_email='jonas.lindemann@lunarc.lu.se', # Choose your license license='MIT', From 796587f85d1aa0f5962039da06171b8e7f82da5c Mon Sep 17 00:00:00 2001 From: Adam Sciegaj Date: Thu, 15 Dec 2022 12:49:07 +0100 Subject: [PATCH 03/17] Recreated example exd_beam2_m --- examples/exd_beam2_m.py | 104 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 examples/exd_beam2_m.py diff --git a/examples/exd_beam2_m.py b/examples/exd_beam2_m.py new file mode 100644 index 0000000..266fccd --- /dev/null +++ b/examples/exd_beam2_m.py @@ -0,0 +1,104 @@ +# example exd_beam2_m +# ---------------------------------------------------------------- +# PURPOSE +# Set up the fe-model and perform eigenvalue analysis +# for a simple frame structure. +# ---------------------------------------------------------------- + + +import numpy as np +import calfem.core as cfc +import calfem.vis_mpl as cfv + +# ----- Generate the model --------------------------------------- +# ----- Material data --------------------------------------------- +E = 3e10 +Av=0.1030e-2 +Ah=0.0764e-2 +rho=2500 +Iv = 0.0171e-4 +Ih=0.00801e-4 +ep1 = [E, Av, Iv, rho*Av] #IPE100 +ep2 = [E, Ah, Ih, rho*Ah] #IPE80 + +# ----- Topology ------------------------------------------------- +edof = np.array([ + [1,2,3,4,5,6], + [4,5,6,7,8,9], + [7,8,9,10,11,12], + [10,11,12,13,14,15] +]) + +# ----- List of coordinates -------------------------------------- +coord = np.array([ + [0.0, 0.0], + [0.0, 1.5], + [0.0, 3.0], + [1.0, 3.0], + [2.0, 3.0], +]) + +# ----- List of degrees of freedom ------------------------------- +dof = np.array([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + [10, 11, 12], + [13, 14, 15], +]) + +# ----- Generate element matrices, assemble in global matrices --- +K = np.zeros([15,15]) +M = np.zeros([15,15]) + +ex, ey = cfc.coordxtr(edof, coord, dof); +ep = np.array([ep1, ep1, ep2, ep2]) + +for elx, ely, eltopo, elprop in zip(ex, ey, edof, ep): + Ke, Me = cfc.beam2d(elx, ely, elprop) + cfc.assem(eltopo, K, Ke) + cfc.assem(eltopo, M, Me) + +# ----- Draw a plot of the element mesh -------------------------- +cfv.figure(1,fig_size=(5.5, 4.5)) +cfv.eldraw2(ex,ey,[1, 2, 1]) +cfv.title('2-D Frame Structure') + +# ----- Eigenvalue analysis -------------------------------------- +b = np.array([1, 2, 3, 14]) +La, Egv = cfc.eigen(K,M,b) +freq = np.sqrt(La)/(2*np.pi) + +# ----- Plot one eigenmode --------------------------------------- +cfv.figure(2,fig_size=(5.5, 4.5)) +cfv.eldraw2(ex,ey,[2, 3, 1]) +Edb = cfc.extract_ed(edof, Egv[:,0]) +cfv.eldisp2(ex,ey,Edb,[1, 2, 2]) +cfv.title('The first eigenmode') +cfv.text(f"{freq[0]:.2f}", [0.5,1.75]) +ax = cfv.gca() +ax.grid() + + +# ----- Plot eight eigenmodes ------------------------------------ +cfv.figure(3,fig_size=(7,5)) +for i in range(4): + Edb = cfc.extract_ed(edof,Egv[:,i]) + ext = ex+i*3 + cfv.eldraw2(ext,ey,[2,3,1]) + cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=0.5) + cfv.text(f"{freq[i]:.2f}", [3*i+0.5,1.5]) +eyt = ey-4 +for i in range(4,8): + Edb = cfc.extract_ed(edof,Egv[:,i]) + ext = ex+(i-4)*3 + cfv.eldraw2(ext,eyt,[2,3,1]) + cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=0.5) + cfv.text(f"{freq[i]:.2f}", [3*(i-4)+0.5,-2.5]) +cfv.title("The first eight eigenmodes [Hz]") +ax = cfv.gca() +ax.set_axis_off() +cfv.showAndWait() + +# ----- End ------------------------------------------------------- + From 16c72f92e174d2ab2c24343edc7ae7ffb4c54243 Mon Sep 17 00:00:00 2001 From: Adam Sciegaj Date: Fri, 16 Dec 2022 15:53:51 +0100 Subject: [PATCH 04/17] step2 and gfunc functions --- calfem/core.py | 228 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 227 insertions(+), 1 deletion(-) diff --git a/calfem/core.py b/calfem/core.py index b4e58c0..ff70733 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -6,7 +6,7 @@ """ from scipy.sparse.linalg import dsolve -from scipy.linalg import eig +from scipy.linalg import eig, lu import numpy as np import logging as cflog @@ -3936,6 +3936,232 @@ def eigen(K,M,b=None): return L, X +def gfunc(G,dt): + """ + Form vector with function values at equally spaced + points by linear interpolation + + Parameters: + + G = [t_i, g_i] t_i: time i, g_i: g(t_i) + dim(G) = np x 2, np = number of points + dt time step + + Returns: + + t 1-D vector with equally spaced time points + g 1-D vector with corresponding function values + """ + ti = np.arange(G[0,0],G[-1,0]+dt,dt) + g1 = np.interp(ti,G[:,0],G[:,1]) + return ti, g1 + + +def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): + """ + Algorithm for dynamic solution of second-order + FE equations considering boundary conditions. + + Parameters: + + K global stiffness matrix, dim(K) = ndof x ndof + C global damping matrix, dim(C) = ndof x ndof + If there is no damping in the system, simply set C=[] + M global mass matrix, dim(M) = ndof x ndof + f global load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial displacement vector a(0), dim(a0) = ndof x 1 + da0 initial velocity vector v(0), dim(da0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip list [dt, tottime, alpha, delta], where + dt is the size of the time increment, + tottime is the total time, + alpha and delta are time integration constants for the Newmark family of methods. + Frequently used values of alpha and delta: + alpha=1/4, delta=1/2: average acceleration (trapezoidal) rule, + alpha=1/6, delta=1/2: linear acceleration + alpha=0, delta=1/2: central difference + times array [t(i) ...] of times at which output should be written to a, da and d2a + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist, dahist and d2ahist + + Returns: + + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains displacement values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains velocity values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['d2a'] constains acceleration values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['d2a']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the selected 'dofs': + dofhist['a'] constains displacement time history at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains velocity time history at the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + dofhist['d2a'] constains acceleration time history at the dofs specified in 'dofs' + dim(dofhist['d2ahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + if not C: + C = np.zeros((ndof,ndof)) + dt, tottime, alpha, delta = ip + b1 = dt*dt*0.5*(1-2*alpha) + b2 = (1-delta)*dt + b3 = delta*dt + b4 = alpha*dt*dt + + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 + + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 + + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns + + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + + modelhist = {} + sa=0 + if not times.any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + modelhist['d2a'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + modelhist['d2a'] = np.zeros((ndof,ntimes)) + + dofhist = {} + if dofs.all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + dofhist['d2a'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 + + itime = 0 + + # Calculate initial second time derivative d2a0 + d2a0 = np.linalg.solve(M,tf[:,0].reshape(-1,1) - C@da0 - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + modelhist['d2a'][:,0] = d2a0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + modelhist['d2a'][:,itime] = d2a0.ravel() + itime += 1 + + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,0] = d2a0[np.ix_(dofs-1)].ravel() + + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + tempd2a = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = M[np.ix_(fdof,fdof)] + b3*C[np.ix_(fdof,fdof)] +b4*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = M + b3*C + b4*K + + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + d2anew = d2a0[np.ix_(fdof)] + + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + d2aold = np.copy(d2anew) + apred = aold + dt*daold + b1*d2aold + dapred = daold + b2*d2aold + if not bound: + reff = tf[:,j].reshape(-1,1) - C@dapred - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - C[np.ix_(fdof,fdof)]@dapred - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + d2anew = np.linalg.solve(U,y) + anew = apred + b4*d2anew + danew = dapred + b3*d2anew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + tempd2a[np.ix_(fdof)] = d2anew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + modelhist['d2a'][:,j] = tempd2a.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + modelhist['d2a'][:,itime] = tempd2a.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,j] = tempd2a[np.ix_(dofs-1)].ravel() + + return modelhist, dofhist + def extract_eldisp(edof, a): """ Extract element displacements from the global displacement From b2761b7997bb68ed9bf93f60707a66b0f03567ae Mon Sep 17 00:00:00 2001 From: Adam Sciegaj Date: Fri, 16 Dec 2022 15:54:45 +0100 Subject: [PATCH 05/17] Added examples exd_beam2_t, exd_beam2_tr, and exd_beam2_b --- examples/exd_beam2_b.py | 80 +++++++++++++++++++++++++++++++++++++ examples/exd_beam2_m.py | 72 +++++++++++++++++----------------- examples/exd_beam2_t.py | 80 +++++++++++++++++++++++++++++++++++++ examples/exd_beam2_tr.py | 85 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 281 insertions(+), 36 deletions(-) create mode 100644 examples/exd_beam2_b.py create mode 100644 examples/exd_beam2_t.py create mode 100644 examples/exd_beam2_tr.py diff --git a/examples/exd_beam2_b.py b/examples/exd_beam2_b.py new file mode 100644 index 0000000..71dac27 --- /dev/null +++ b/examples/exd_beam2_b.py @@ -0,0 +1,80 @@ +# example exd_beam2_b +# ---------------------------------------------------------------- +# PURPOSE +# Structural Dynamics, time integration, time dependent +# boundary conditions. +# +# Note: file exd_beam2_m.py must be in the same directory +# ---------------------------------------------------------------- +from exd_beam2_m import * + +# ----- Impact, center point, vertical beam ---------------------- +dt = 0.002 +T = 1 + +# ----- Boundary condition, initial condition -------------------- +G = np.array([ + [0, 0], + [0.1, 0.02], + [0.2, -0.01], + [0.3, 0], + [T, 0] +]) + +t,g = cfc.gfunc(G,dt) + +bc = np.zeros((4, 1+len(g))) +bc[0,:] = np.hstack((1,g)) +bc[1,0] = 2 +bc[2,0] = 3 +bc[3,0] = 14 + +a0 = np.zeros((15,1)) +da0 = np.zeros((15,1)) + +# ----- Output parameters ---------------------------------------- +times = np.arange(0.1,1.1,0.1) +dofs = np.array([1,4,11]) + +# ----- Time integration parameters ------------------------------ +ip = np.array([dt, T, 0.25, 0.5]) + +# ----- Time integration ----------------------------------------- +sol, dofhist = cfc.step2(K,[],M,[],a0,da0,bc,ip,times,dofs) + +# ----- Plot time history for two DOFs --------------------------- +cfv.figure(1,fig_size=(7,4)) +cfv.plt.plot(t,dofhist['a'][0,:], '-') +cfv.plt.plot(t,dofhist['a'][1,:],'--') +cfv.plt.plot(t,dofhist['a'][2,:],'-.') +cfv.plt.xlim([0,1]) +cfv.plt.ylim([-0.02,0.03]) +cfv.plt.xlabel("time (sec)") +cfv.plt.ylabel("displacement (m)") +cfv.plt.title("Displacement(time) at the 1st, 4th and 11th degree of freedom") +cfv.text("solid line = bottom, vertical beam, x-direction", [0.2,0.022]) +cfv.text("dashed line = center, vertical beam, x-direction", [0.2,0.017]) +cfv.text("dashed-dotted line = center, horizontal beam, y-direction", [0.2,0.012]) +cfv.plt.grid() + +# ----- Plot displacement for some time increments ---------------- +cfv.figure(2,fig_size=(7,5)) +for i in range(5): + Edb = cfc.extract_ed(edof,sol['a'][:,i]) + ext = ex+i*3.5 + cfv.eldraw2(ext,ey,[2,3,1]) + cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=20) + cfv.text(f"{times[i]:.1f}", [3.5*i+0.5,1.5]) +eyt = ey-4 +for i in range(5,10): + Edb = cfc.extract_ed(edof,sol['a'][:,i]) + ext = ex+(i-5)*3.5 + cfv.eldraw2(ext,eyt,[2,3,1]) + cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=20) + cfv.text(f"{times[i]:.1f}", [3.5*(i-5)+0.5,-2.5]) +cfv.title("Snapshots (sec), magnification = 20") +ax = cfv.gca() +ax.set_axis_off() +cfv.showAndWait() + +# ----- End ------------------------------------------------------- \ No newline at end of file diff --git a/examples/exd_beam2_m.py b/examples/exd_beam2_m.py index 266fccd..99be247 100644 --- a/examples/exd_beam2_m.py +++ b/examples/exd_beam2_m.py @@ -11,7 +11,7 @@ import calfem.vis_mpl as cfv # ----- Generate the model --------------------------------------- -# ----- Material data --------------------------------------------- +# ----- Material data -------------------------------------------- E = 3e10 Av=0.1030e-2 Ah=0.0764e-2 @@ -59,46 +59,46 @@ cfc.assem(eltopo, K, Ke) cfc.assem(eltopo, M, Me) -# ----- Draw a plot of the element mesh -------------------------- -cfv.figure(1,fig_size=(5.5, 4.5)) -cfv.eldraw2(ex,ey,[1, 2, 1]) -cfv.title('2-D Frame Structure') - # ----- Eigenvalue analysis -------------------------------------- b = np.array([1, 2, 3, 14]) La, Egv = cfc.eigen(K,M,b) freq = np.sqrt(La)/(2*np.pi) -# ----- Plot one eigenmode --------------------------------------- -cfv.figure(2,fig_size=(5.5, 4.5)) -cfv.eldraw2(ex,ey,[2, 3, 1]) -Edb = cfc.extract_ed(edof, Egv[:,0]) -cfv.eldisp2(ex,ey,Edb,[1, 2, 2]) -cfv.title('The first eigenmode') -cfv.text(f"{freq[0]:.2f}", [0.5,1.75]) -ax = cfv.gca() -ax.grid() - - -# ----- Plot eight eigenmodes ------------------------------------ -cfv.figure(3,fig_size=(7,5)) -for i in range(4): - Edb = cfc.extract_ed(edof,Egv[:,i]) - ext = ex+i*3 - cfv.eldraw2(ext,ey,[2,3,1]) - cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=0.5) - cfv.text(f"{freq[i]:.2f}", [3*i+0.5,1.5]) -eyt = ey-4 -for i in range(4,8): - Edb = cfc.extract_ed(edof,Egv[:,i]) - ext = ex+(i-4)*3 - cfv.eldraw2(ext,eyt,[2,3,1]) - cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=0.5) - cfv.text(f"{freq[i]:.2f}", [3*(i-4)+0.5,-2.5]) -cfv.title("The first eight eigenmodes [Hz]") -ax = cfv.gca() -ax.set_axis_off() -cfv.showAndWait() +if __name__=='__main__': + # ----- Draw a plot of the element mesh -------------------------- + cfv.figure(1,fig_size=(5.5, 4.5)) + cfv.eldraw2(ex,ey,[1, 2, 1]) + cfv.title('2-D Frame Structure') + + # ----- Plot one eigenmode --------------------------------------- + cfv.figure(2,fig_size=(5.5, 4.5)) + cfv.eldraw2(ex,ey,[2, 3, 1]) + Edb = cfc.extract_ed(edof, Egv[:,0]) + cfv.eldisp2(ex,ey,Edb,[1, 2, 2]) + cfv.title('The first eigenmode') + cfv.text(f"{freq[0]:.2f}", [0.5,1.75]) + ax = cfv.gca() + ax.grid() + + # ----- Plot eight eigenmodes ------------------------------------ + cfv.figure(3,fig_size=(7,5)) + for i in range(4): + Edb = cfc.extract_ed(edof,Egv[:,i]) + ext = ex+i*3 + cfv.eldraw2(ext,ey,[2,3,1]) + cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=0.5) + cfv.text(f"{freq[i]:.2f}", [3*i+0.5,1.5]) + eyt = ey-4 + for i in range(4,8): + Edb = cfc.extract_ed(edof,Egv[:,i]) + ext = ex+(i-4)*3 + cfv.eldraw2(ext,eyt,[2,3,1]) + cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=0.5) + cfv.text(f"{freq[i]:.2f}", [3*(i-4)+0.5,-2.5]) + cfv.title("The first eight eigenmodes [Hz]") + ax = cfv.gca() + ax.set_axis_off() + cfv.showAndWait() # ----- End ------------------------------------------------------- diff --git a/examples/exd_beam2_t.py b/examples/exd_beam2_t.py new file mode 100644 index 0000000..6bac640 --- /dev/null +++ b/examples/exd_beam2_t.py @@ -0,0 +1,80 @@ +# example exd_beam2_t +# ---------------------------------------------------------------- +# PURPOSE +# Structural Dynamics, time integration, full system. +# +# Note: file exd_beam2_m.py must be in the same directory +# ---------------------------------------------------------------- +from exd_beam2_m import * + +# ----- Impact, center point, vertical beam ---------------------- +dt = 0.002 +T = 1 + +# ----- The load ------------------------------------------------- +G = np.array([ + [0, 0], + [0.15, 1], + [0.25, 0], + [T, 0] +]) + +t,g = cfc.gfunc(G,dt) +f = np.zeros((15, len(g))) +f[3,:] = 1000*g + +# ----- Boundary condition, initial condition -------------------- +bc = np.array([ + [1, 0], + [2, 0], + [3, 0], + [14, 0] +]) + +a0 = np.zeros((15,1)) +da0 = np.zeros((15,1)) + +# ----- Output parameters ---------------------------------------- +times = np.arange(0.1,1.1,0.1) +dofs = np.array([4,11]) + +# ----- Time integration parameters ------------------------------ +ip = np.array([dt, T, 0.25, 0.5]) + +# ----- Time integration ----------------------------------------- +sol, dofhist = cfc.step2(K,[],M,f,a0,da0,bc,ip,times,dofs) + +# ----- Plot time history for two DOFs --------------------------- +cfv.figure(1,fig_size=(7,4)) +cfv.plt.plot(t,dofhist['a'][0,:], '-') +cfv.plt.plot(t,dofhist['a'][1,:],'--') +cfv.plt.xlim([0,1]) +cfv.plt.ylim([-0.01,0.02]) +cfv.plt.xlabel("time (sec)") +cfv.plt.ylabel("displacement (m)") +cfv.plt.title("Displacement(time) at the 4th and 11th degree of freedom") +cfv.text("solid line = impact point, x-direction", [0.3,0.017]) +cfv.text("dashed line = center, horizontal beam, y-direction", [0.3,0.012]) +cfv.plt.grid() + +# ----- Plot displacement for some time increments ---------------- +cfv.figure(2,fig_size=(7,5)) +for i in range(5): + Edb = cfc.extract_ed(edof,sol['a'][:,i]) + ext = ex+i*3.5 + cfv.eldraw2(ext,ey,[2,3,1]) + cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=25) + cfv.text(f"{times[i]:.1f}", [3.5*i+0.5,1.5]) +eyt = ey-4 +for i in range(5,10): + Edb = cfc.extract_ed(edof,sol['a'][:,i]) + ext = ex+(i-5)*3.5 + cfv.eldraw2(ext,eyt,[2,3,1]) + cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=25) + cfv.text(f"{times[i]:.1f}", [3.5*(i-5)+0.5,-2.5]) +cfv.title("Snapshots (sec), magnification = 25") +ax = cfv.gca() +ax.set_axis_off() +cfv.showAndWait() + +# ----- End ------------------------------------------------------- \ No newline at end of file diff --git a/examples/exd_beam2_tr.py b/examples/exd_beam2_tr.py new file mode 100644 index 0000000..0dd929f --- /dev/null +++ b/examples/exd_beam2_tr.py @@ -0,0 +1,85 @@ +# example exd_beam2_tr +# ---------------------------------------------------------------- +# PURPOSE +# Structural Dynamics, time integration, reduced system. +# +# Note: file exd_beam2_m.py must be in the same directory +# ---------------------------------------------------------------- +from exd_beam2_m import * + +# ----- Impact, center point, vertical beam ---------------------- +dt = 0.002 +T = 1 +nev = 2 + +# ----- The load ------------------------------------------------- +G = np.array([ + [0, 0], + [0.15, 1], + [0.25, 0], + [T, 0] +]) + +t,g = cfc.gfunc(G,dt) +f = np.zeros((15, len(g))) +f[3,:] = 1000*g +fr = np.hstack((np.arange(1,nev+1).reshape(-1,1),Egv[:,:nev].T@f)) + +# ----- Reduced system matrices ---------------------------------- +kr = np.diag(np.diag(Egv[:,:nev].T@K@Egv[:,:nev])) +mr = np.diag(np.diag(Egv[:,:nev].T@M@Egv[:,:nev])) + +# ----- Initial condition ---------------------------------------- +ar0 = np.zeros((nev,1)) +dar0 = np.zeros((nev,1)) + +# ----- Output parameters ---------------------------------------- +times = np.arange(0.1,1.1,0.1) +dofsr = np.arange(1,nev+1) +dofs = np.array([4,11]) + +# ----- Time integration parameters ------------------------------ +ip = np.array([dt, T, 0.25, 0.5]) + +# ----- Time integration ----------------------------------------- +sol, dofhist = cfc.step2(kr,[],mr,fr,ar0,dar0,[],ip,times,dofsr) + +# ----- Mapping back to original coordinate system --------------- +aR = Egv[:,:nev]@sol['a'] +aRhist = Egv[dofs-1,:nev]@dofhist['a'] + +# ----- Plot time history for two DOFs --------------------------- +cfv.figure(1,fig_size=(7,4)) +cfv.plt.plot(t,aRhist[0,:], '-') +cfv.plt.plot(t,aRhist[1,:],'--') +cfv.plt.xlim([0,1]) +cfv.plt.ylim([-0.01,0.02]) +cfv.plt.xlabel("time (sec)") +cfv.plt.ylabel("displacement (m)") +cfv.plt.title("Displacement(time) at the 4th and 11th degree of freedom") +cfv.text("solid line = impact point, x-direction", [0.3,0.017]) +cfv.text("dashed line = center, horizontal beam, y-direction", [0.3,0.012]) +cfv.text("TWO EIGENVECTORS ARE USED", [0.3,-0.007]) +cfv.plt.grid() + +# ----- Plot displacement for some time increments ---------------- +cfv.figure(2,fig_size=(7,5)) +for i in range(5): + Edb = cfc.extract_ed(edof,aR[:,i]) + ext = ex+i*3.5 + cfv.eldraw2(ext,ey,[2,3,1]) + cfv.eldisp2(ext,ey,Edb,[1,2,2],sfac=25) + cfv.text(f"{times[i]:.1f}", [3.5*i+0.5,1.5]) +eyt = ey-4 +for i in range(5,10): + Edb = cfc.extract_ed(edof,aR[:,i]) + ext = ex+(i-5)*3.5 + cfv.eldraw2(ext,eyt,[2,3,1]) + cfv.eldisp2(ext,eyt,Edb,[1,2,2],sfac=25) + cfv.text(f"{times[i]:.1f}", [3.5*(i-5)+0.5,-2.5]) +cfv.title("Snapshots (sec), magnification = 25") +ax = cfv.gca() +ax.set_axis_off() +cfv.showAndWait() + +# ----- End ------------------------------------------------------- \ No newline at end of file From f9fc27f9ebf09bdd5bd6c6824f1a333f3c953767 Mon Sep 17 00:00:00 2001 From: Adam Sciegaj Date: Sat, 17 Dec 2022 18:25:02 +0100 Subject: [PATCH 06/17] Fixed a bug in beam1s. Added example exs_beam2 and plots in exs_bar2 and exs_beam1 --- calfem/core.py | 12 ++--- examples/exs_bar2.py | 26 ++++++++++ examples/exs_beam1.py | 85 ++++++++++++++++--------------- examples/exs_beam2.py | 114 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 45 deletions(-) create mode 100644 examples/exs_beam2.py diff --git a/calfem/core.py b/calfem/core.py index ff70733..ffa56c7 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -307,7 +307,7 @@ def beam1e(ex, ep, eq=None): :param list ep: element properties [E, I], E - Young's modulus, I - Moment of inertia :param float eq: distributed load [qy] :return mat Ke: element stiffness matrix [4 x 4] - :return mat fe: element stiffness matrix [4 x 1] (if eq!=None) + :return mat fe: element load vector [4 x 1] (if eq!=None) """ L = ex[1]-ex[0] @@ -315,7 +315,7 @@ def beam1e(ex, ep, eq=None): I = ep[1] qy = 0. - if not eq is None: + if eq: qy = eq Ke = E*I/(L**3) * np.mat([ @@ -370,7 +370,7 @@ def beam1s(ex, ep, ed, eq=None, nep=None): qy = 0. - if not eq is None: + if eq: qy = eq ne = 2 @@ -387,15 +387,15 @@ def beam1s(ex, ep, ed, eq=None, nep=None): Ca = (Cinv@ed).T - x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T + x = np.asmatrix(np.linspace(0., L, nep)).T zero = np.asmatrix(np.zeros([len(x)])).T one = np.asmatrix(np.ones([len(x)])).T v = np.concatenate((one, x, np.power(x, 2), np.power(x, 3)), 1)@Ca \ + qy/(24*EI)*(np.power(x,4) - 2*L*np.power(x,3) + (L**2)*np.power(x,2)) d2v = np.concatenate((zero, zero, 2*one, 6*x), 1)@Ca \ - + qy/(2*EI)*(np.power(x,2) - L*x + L**2/12) - d3v = np.concatenate((zero, zero, zero, 6*one), 1)@Ca - qy*(x - L/2) + + qy/(12*EI)*(6*np.power(x,2) - 6*L*x + L**2) + d3v = np.concatenate((zero, zero, zero, 6*one), 1)@Ca + qy/(2*EI)*(2*x - L) M = EI*d2v V = -EI*d3v diff --git a/examples/exs_bar2.py b/examples/exs_bar2.py index e332348..dbf9cbd 100644 --- a/examples/exs_bar2.py +++ b/examples/exs_bar2.py @@ -13,6 +13,7 @@ import numpy as np import calfem.core as cfc +import calfem.vis_mpl as cfv # ----- Topology matrix Edof ------------------------------------- @@ -86,3 +87,28 @@ print("N1 = "+str(N1)) print("N2 = "+str(N2)) print("N3 = "+str(N3)) + +# ----- Draw deformed truss -------------------------------------- +cfv.figure(1,fig_size=(6,4)) +plotpar = [2,1,0] +cfv.eldraw2(ex1,ey1,plotpar) +cfv.eldraw2(ex2,ey2,plotpar) +cfv.eldraw2(ex3,ey3,plotpar) +sfac = cfv.scalfact2(ex1,ey1,ed1,0.1) +plotpar = [1,2,1] +cfv.eldisp2(ex1,ey1,ed1,plotpar,sfac) +cfv.eldisp2(ex2,ey2,ed2,plotpar,sfac) +cfv.eldisp2(ex3,ey3,ed3,plotpar,sfac) +cfv.plt.axis([-0.4, 2.0, -0.4, 1.4]) +cfv.title("Displacements") + +# ----- Draw normal force diagram --------------------------------- +cfv.figure(2,fig_size=(6,4)) +plotpar = [2,1] +sfac = cfv.scalfact2(ex1,ey1,N2,0.1) +cfv.secforce2(ex1,ey1,N1,plotpar,sfac) +cfv.secforce2(ex2,ey2,N2,plotpar,sfac) +cfv.secforce2(ex3,ey3,N3,plotpar,sfac) +cfv.plt.axis([-0.4, 2.0, -0.4, 1.4]) +cfv.title("Normal force") +cfv.showAndWait() \ No newline at end of file diff --git a/examples/exs_beam1.py b/examples/exs_beam1.py index 2c557b1..fafe72d 100644 --- a/examples/exs_beam1.py +++ b/examples/exs_beam1.py @@ -14,67 +14,74 @@ import numpy as np import calfem.core as cfc +import calfem.vis_mpl as cfv # ----- Topology ------------------------------------------------- edof = np.array([ - [1, 2, 3, 4, 5, 6], - [4, 5, 6, 7, 8, 9], - [7, 8, 9, 10, 11, 12] + [1, 2, 3, 4], + [3, 4, 5, 6], ]) # ----- Stiffness matrix K and load vector f --------------------- -K = np.mat(np.zeros((12, 12))) -f = np.mat(np.zeros((12, 1))) -f[4] = -10000. +K = np.mat(np.zeros((6, 6))) +f = np.mat(np.zeros((6, 1))) +f[2] = -10000. # ----- Element stiffness matrices ------------------------------ E = 2.1e11 -A = 45.3e-4 I = 2510e-8 -ep = np.array([E, A, I]) -ex = np.array([0., 3.]) -ey = np.array([0., 0.]) - -Ke = cfc.beam2e(ex, ey, ep) - -print(Ke) +ep = np.array([E, I]) +ex1 = np.array([0., 3.]) +ex2 = np.array([3., 9.]) +Ke1 = cfc.beam1e(ex1, ep) +Ke2 = cfc.beam1e(ex2, ep) # ----- Assemble Ke into K --------------------------------------- -K = cfc.assem(edof, K, Ke) +K = cfc.assem(edof[0,:], K, Ke1) +K = cfc.assem(edof[1,:], K, Ke2) # ----- Solve the system of equations and compute support forces - -bc = np.array([1, 2, 11]) +bc = np.array([1, 5]) (a, r) = cfc.solveq(K, f, bc) # ----- Section forces ------------------------------------------- ed = cfc.extract_ed(edof, a) -es1, ed1, ec1 = cfc.beam2s(ex, ey, ep, ed[0, :], nep=10) -es2, ed2, ec2 = cfc.beam2s(ex, ey, ep, ed[1, :], nep=10) -es3, ed3, ec3 = cfc.beam2s(ex, ey, ep, ed[2, :], nep=10) - -# ----- Results -------------------------------------------------- - -print("a=") -print(a) -print("r=") -print(r) -print("es1=") -print(es1) -print("es2=") -print(es2) -print("es3=") -print(es3) - -print("ed1=") -print(ed1) -print("ed2=") -print(ed2) -print("ed3=") -print(ed3) +es1, ed1, ec1 = cfc.beam1s(ex1, ep, ed[0, :], nep=10) +es2, ed2, ec2 = cfc.beam1s(ex2, ep, ed[1, :], nep=10) + +es = np.vstack(([0,0],es1,es2,[0,0])) +eD = np.vstack((0,ed1,ed2,0)) +ec = np.vstack((ex1[0],ec1+ex1[0],ec2+ex2[0],ex2[1])) + +# ----- Draw deformed beam ---------------------------------------- +cfv.figure(1,fig_size=(6,2.5)) +cfv.plt.plot([0, 9],[0,0],'b',linewidth=0.5) +cfv.plt.plot(ec,eD,'b') +cfv.plt.axis([-1,10,-0.03, 0.01]) +cfv.title("Displacements") + +# ----- Draw shear force diagram ---------------------------------- +cfv.figure(2,fig_size=(6,2.5)) +cfv.plt.plot([0, 9],[0,0],'b',linewidth=0.5) +cfv.plt.plot(ec,es[:,0],'b') +cfv.plt.axis([-1,10,-8000, 5000]) +cfv.title("Shear force") +cfv.gca().invert_yaxis() + +# ----- Draw bending moment diagram ------------------------------- +cfv.figure(3,fig_size=(6,2.5)) +cfv.plt.plot([0, 9],[0,0],'b',linewidth=0.5) +cfv.plt.plot(ec,es[:,1],'b') +cfv.plt.axis([-1,10,-5000, 25000]) +cfv.title("Bending moment") +cfv.gca().invert_yaxis() +cfv.showAndWait() + +#------------------------ end ----------------------------------- \ No newline at end of file diff --git a/examples/exs_beam2.py b/examples/exs_beam2.py new file mode 100644 index 0000000..98869ac --- /dev/null +++ b/examples/exs_beam2.py @@ -0,0 +1,114 @@ +# example exs6 +# ---------------------------------------------------------------- +# PURPOSE +# Analysis of a plane frame. +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc +import calfem.vis_mpl as cfv + + +#----- Topology ------------------------------------------------- + +edof = np.array([ + [4, 5, 6, 1, 2, 3], + [7, 8, 9, 10, 11, 12], + [4, 5, 6, 7, 8, 9] +]) + +#----- Stiffness matrix K and load vector f --------------------- + +K = np.zeros([12,12]) +f = np.zeros([12,1]) +f[3,0] = 2e3 + +#----- Element stiffness and element load matrices ------------- + +E=200e9 +A1=2e-3 +A2=6e-3 +I1=1.6e-5 +I2=5.4e-5 + +ep1 = np.array([E, A1, I1]) +ep3 = np.array([E, A2, I2]) + +ex1 = np.array([0.,0.]) +ey1 = np.array([4.,0.]) +ex2 = np.array([6.,6.]) +ey2 = np.array([4.,0.]) +ex3 = np.array([0.,6.]) +ey3 = np.array([4.,4.]) + +eq1 = np.array([0.,0.]) +eq2 = np.array([0.,0.]) +eq3 = np.array([0.,-10e3]) + +Ke1 = cfc.beam2e(ex1,ey1,ep1) +Ke2 = cfc.beam2e(ex2,ey2,ep1) +Ke3, fe3 = cfc.beam2e(ex3,ey3,ep3,eq3) + +#----- Assemble Ke into K --------------------------------------- + +K = cfc.assem(edof[0,:],K,Ke1) +K = cfc.assem(edof[1,:],K,Ke2) +K, f = cfc.assem(edof[2,:],K,Ke3,f,fe3) + +#----- Solve the system of equations and compute reactions ------ +bc = np.array([1, 2, 3, 10, 11]) +a, r = cfc.solveq(K, f, bc) + +#----- Section forces ------------------------------------------- +ed = cfc.extract_ed(edof, a) + +es1, edi1, eci1 = cfc.beam2s(ex1,ey1,ep1,ed[0,:],eq1,21) +es2, edi2, eci2 = cfc.beam2s(ex2,ey2,ep1,ed[1,:],eq2,21) +es3, edi3, eci3 = cfc.beam2s(ex3,ey3,ep3,ed[2,:],eq3,21) + +#----- Draw deformed frame --------------------------------------- +cfv.figure(1,fig_size=(6,4)) +plotpar=[2,1,0] +cfv.eldraw2(ex1,ey1,plotpar) +cfv.eldraw2(ex2,ey2,plotpar) +cfv.eldraw2(ex3,ey3,plotpar) +sfac=cfv.scalfact2(ex3,ey3,edi3,0.1) +plotpar=[1,2,1] +cfv.eldisp2(ex1,ey1,ed[0,:],plotpar,sfac) +cfv.eldisp2(ex2,ey2,ed[1,:],plotpar,sfac) +cfv.eldisp2(ex3,ey3,ed[2,:],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Displacements") + + +#----- Draw normal force diagram -------------------------------- +cfv.figure(2,fig_size=(6,4)) +plotpar=[2,1] +sfac=cfv.scalfact2(ex1,ey1,es1[:,0],0.2) +cfv.secforce2(ex1,ey1,es1[:,0],plotpar,sfac) +cfv.secforce2(ex2,ey2,es2[:,0],plotpar,sfac) +cfv.secforce2(ex3,ey3,es3[:,0],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Normal force") + +#----- Draw shear force diagram --------------------------------- +cfv.figure(3,fig_size=(6,4)) +plotpar=[2,1] +sfac=cfv.scalfact2(ex3,ey3,es3[:,1],0.2) +cfv.secforce2(ex1,ey1,es1[:,1],plotpar,sfac) +cfv.secforce2(ex2,ey2,es2[:,1],plotpar,sfac) +cfv.secforce2(ex3,ey3,es3[:,1],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Shear force") + +#----- Draw moment diagram -------------------------------------- +cfv.figure(4,fig_size=(6,4)) +plotpar=[2,1] +sfac=cfv.scalfact2(ex3,ey3,es3[:,2],0.2) +cfv.secforce2(ex1,ey1,es1[:,2],plotpar,sfac) +cfv.secforce2(ex2,ey2,es2[:,2],plotpar,sfac) +cfv.secforce2(ex3,ey3,es3[:,2],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Bending moment") +cfv.showAndWait() +#------------------------ end ----------------------------------- \ No newline at end of file From 164b3af6a5100300e53629d778c0e07e8be3055a Mon Sep 17 00:00:00 2001 From: Adam Sciegaj Date: Sun, 18 Dec 2022 17:55:29 +0100 Subject: [PATCH 07/17] Added bar2gs function and examples exn_bar2g, exn_beam2, exn_beam2_b, enx_bar2m --- calfem/core.py | 61 +++++++++++++++++ examples/exn_bar2g.py | 67 ++++++++++++++++++ examples/exn_bar2m.py | 98 ++++++++++++++++++++++++++ examples/exn_beam2.py | 148 ++++++++++++++++++++++++++++++++++++++++ examples/exn_beam2_b.py | 112 ++++++++++++++++++++++++++++++ 5 files changed, 486 insertions(+) create mode 100644 examples/exn_bar2g.py create mode 100644 examples/exn_bar2m.py create mode 100644 examples/exn_beam2.py create mode 100644 examples/exn_beam2_b.py diff --git a/calfem/core.py b/calfem/core.py index ffa56c7..ac16b25 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -226,6 +226,67 @@ def bar2s(ex, ey, ep, ed): return N.item() +def bar2gs(ex, ey, ep, ed): + """ + Calculate section forces in a two dimensional geometric + nonlinear bar element (bar2g). + Parameters: + ex = [x1 x2] element node coordinates + ey = [y1 y2] + + ep = [E A] element properties; + E: Young's modulus + A: cross section area + + ed = [u1 ... u4] element displacement vector + + Returns: + es = [N1; + N2 ] section forces, local directions + + QX: axial force + + edi = [ u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(es)= n x 1 + ...] + + eci = [ x1 ; local x-coordinates of the evaluation + x2 ; points, (x1=0 and xn=L) + ...] + """ + EA = ep[0]*ep[1] + ne = 2 + + dx = ex[1] - ex[0] + dy = ey[1] - ey[0] + L = np.sqrt(dx**2 + dy**2) + + n = [dx/L, dy/L, -dy/L, dx/L] + G = np.array([ + [n[0], n[1], 0., 0.], + [n[2], n[3], 0., 0.], + [0., 0., n[0], n[1]], + [0., 0., n[2], n[3]] + ]) + + edl = G@ed.reshape(-1,1) + a1 = np.array([edl[0], edl[2]]).reshape(-1,1) + + C1 = np.array([[1., 0.,], + [-1/L, 1/L]]) + C1a = C1@a1 + + x = np.linspace(0,L,ne).reshape(-1,1) + zero = np.zeros(x.shape) + one = np.ones(x.shape) + + u = np.concatenate((one, x),axis=1)@C1a + du = np.concatenate((zero, one),axis=1)@C1a + + N = EA*du + return N, N[0].item(), u, x + + def bar3e(ex, ey, ez, ep): """ Compute element stiffness matrix for three dimensional bar element. diff --git a/examples/exn_bar2g.py b/examples/exn_bar2g.py new file mode 100644 index 0000000..d0ab094 --- /dev/null +++ b/examples/exn_bar2g.py @@ -0,0 +1,67 @@ +# example exn_bar2g +#-------------------------------------------------------------------------- +# PURPOSE +# Analysis of a plane truss using second order theory. +#-------------------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc + +# ----- Topology ----- + +edof = np.array([[1, 2, 5, 6], + [3, 4, 5, 6]]) + +# ----- Element properties and global coordinates ------------------------- + +E=10e9 +A1=4e-2 +A2=1e-2 +ep1=np.array([E, A1]) +ep2=np.array([E, A2]) + +ex1=np.array([0., 1.6]) +ey1=np.array([0., 0.]) +ex2=np.array([0., 1.6]) +ey2=np.array([1.2, 0]) + +# ----- Initial values for the iteration ---------------------------------- + +eps=1e-6 # Error norm +QX1=0.01 +QX2=0; # Initial axial forces +QX01=1 # Axial force of the initial former iteration +n=0 # Iteration counter + +# ----- Iteration procedure ----------------------------------------------- +while abs((QX1-QX01)/QX01) > eps: + n += 1 + + K = np.zeros((6,6)) + f = np.zeros((6,1)) + f[4] = -10e6 + f[5] = -0.2e6 + + Ke1 = cfc.bar2g(ex1,ey1,ep1,QX1) + Ke2 = cfc.bar2g(ex2,ey2,ep2,QX2) + K = cfc.assem(edof[0,:],K,Ke1) + K=cfc.assem(edof[1,:],K,Ke2) + bc = np.array([1,2,3,4]) + a, r = cfc.solveq(K,f,bc) + + Ed = cfc.extract_ed(edof,a) + + QX01 = QX1 + es1, QX1, ed1, _ = cfc.bar2gs(ex1,ey1,ep1,Ed[0,:]) + es2, QX2, ed2, _ = cfc.bar2gs(ex2,ey2,ep2,Ed[1,:]) + + if n>20: + print("The solution does not converge") + break + +# ----- Results ----------------------------------------------- +print("Displacements:") +print(a) +print("Normal forces:") +print(QX1) +print(QX2) \ No newline at end of file diff --git a/examples/exn_bar2m.py b/examples/exn_bar2m.py new file mode 100644 index 0000000..9e72afc --- /dev/null +++ b/examples/exn_bar2m.py @@ -0,0 +1,98 @@ +# example exn_bar2m +#-------------------------------------------------------------------------- +# PURPOSE +# Analysis of a plane truss considering material nonlinearity. +#-------------------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc +import calfem.vis_mpl as cfv + +edof = np.array([ + [1, 2, 5, 6], + [5, 6, 7, 8], + [3, 4, 5, 6] +]) + +bc = np.array([1, 2, 3, 4, 7, 8]) + +ex = np.array([ + [0., 1.6], + [1.6, 1.6], + [0., 1.6] +]) + +ey = np.array([ + [0., 0.], + [0., 1.2], + [1.2, 0.] +]) + +E = np.array([200e9, 200e9, 200e9]) +A = np.array([6.0e-4, 3.0e-4, 10.0e-4]) +SY = 400e6 +Ns = (SY*A).reshape(-1,1) + +dp = 4e3 + +incr = 100 + +a = np.zeros((8,1)) +r = np.zeros((8,1)) +es = np.zeros((3,1)) + +plbar = 0 +pl = np.array([0., 0.]) + +# Forward Euler increamental solution + +for i in range(incr): + K = np.zeros((8,8)) + df = np.zeros((8,1)) + df[5] = -dp + + # Create and assemble element tangent stiffness matrix + for j in range(3): + ep = np.array([E[j], A[j]]) + Ke = cfc.bar2e(ex[j,:],ey[j,:],ep) + K = cfc.assem(edof[j,:], K, Ke) + + # Stop iteration if determinant det(Kr) <= 0 + fdof = np.setdiff1d(np.arange(1,9),bc) - 1 + Kr = K[np.ix_(fdof,fdof)] + if np.linalg.det(Kr) <= 0: + print("Determinant zero after increment ", i) + break + + # Solve for the displacement increment and determine total displacements + da, dr = cfc.solveq(K,df,bc) + a += da + r += dr + + # Determine normal forces in elements + ded = cfc.extract_ed(edof,da) + des = np.zeros((3,1)) + for j in range(3): + ep = np.array([E[j], A[j]]) + desj = cfc.bar2s(ex[j,:],ey[j,:],ep,ded[j,:]) + des[j,0] = desj + es += des + for j in range(3): + if abs(es[j,0]) >= Ns[j]: + E[j] = 0 + + # Determine if the stress in a bar has reached the yield stress + newplbar = np.sum(abs(es)>Ns) + if newplbar > plbar: + plbar = newplbar + print(plbar, "plastic elements for increment ", i+1, " at load = ", (i+1)*dp) + + # Save variables for curve plotting + pl = np.vstack((pl, np.array([-a[5,0], (i+1)*dp]))) + +# Plot force-displacement relation +cfv.figure(1, fig_size=(7,4)) +cfv.plt.plot(pl[:,0],pl[:,1]) +cfv.plt.xlabel("Displacement") +cfv.plt.ylabel("Force") +cfv.showAndWait() \ No newline at end of file diff --git a/examples/exn_beam2.py b/examples/exn_beam2.py new file mode 100644 index 0000000..4a8ad3e --- /dev/null +++ b/examples/exn_beam2.py @@ -0,0 +1,148 @@ +# example exn_beam2g +# ---------------------------------------------------------------- +# PURPOSE +# Geometrically nonlinear analysis of a plane frame. +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc +import calfem.vis_mpl as cfv + + +#----- Topology ------------------------------------------------- + +edof = np.array([ + [4, 5, 6, 1, 2, 3], + [7, 8, 9, 10, 11, 12], + [4, 5, 6, 7, 8, 9] +]) + +#----- Element stiffness and element load matrices ------------- + +E=200e9 +A1=2e-3 +A2=6e-3 +I1=1.6e-5 +I2=5.4e-5 + +ep1 = np.array([E, A1, I1]) +ep3 = np.array([E, A2, I2]) + +ex1 = np.array([0.,0.]) +ey1 = np.array([4.,0.]) +ex2 = np.array([6.,6.]) +ey2 = np.array([4.,0.]) +ex3 = np.array([0.,6.]) +ey3 = np.array([4.,4.]) + +eq1 = np.array([0.]) +eq2 = np.array([0.]) +eq3 = np.array([-50e3]) + +# ----- Initial axial forces ---------------------------------------------- + +QX1 = 1e-4 +QX2 = 0 +QX3 = 0 +QX01 = 1 + +# ----- Iteration for convergence ----------------------------------------- + +eps = 1e-6 +n=0 + +while abs((QX1-QX01)/QX01) > eps: + n += 1 + K = np.zeros([12,12]) + f = np.zeros([12,1]) + f[3,0] = 10e3 + + Ke1 = cfc.beam2g(ex1,ey1,ep1,QX1) + Ke2 = cfc.beam2g(ex2,ey2,ep1,QX2) + Ke3, fe3 = cfc.beam2g(ex3,ey3,ep3,QX3,eq3) + + K = cfc.assem(edof[0,:],K,Ke1) + K = cfc.assem(edof[1,:],K,Ke2) + K, f = cfc.assem(edof[2,:],K,Ke3,f,fe3) + + bc = np.array([1, 2, 3, 10, 11]) + a, r = cfc.solveq(K, f, bc) + + ed = cfc.extract_ed(edof,a) + + QX01=QX1 + es1 = cfc.beam2gs(ex1,ey1,ep1,ed[0,:],QX1,eq1) + es2 = cfc.beam2gs(ex2,ey2,ep1,ed[1,:],QX2,eq2) + es3 = cfc.beam2gs(ex3,ey3,ep3,ed[2,:],QX3,eq3) + QX1 = es1[0,0] + QX2 = es2[0,0] + QX3 = es3[0,0] + + if n==1: + ed0 = ed + + if n>20: + print("The solution does not converge") + break + + +# #----- Section forces --------------------------------------- + +eq1 = np.array([0.,eq1.item()]) +eq2 = np.array([0.,eq2.item()]) +eq3 = np.array([0.,eq3.item()]) +es1, edi1, eci1 = cfc.beam2s(ex1,ey1,ep1,ed[0,:],eq1,21) +es2, edi2, eci2 = cfc.beam2s(ex2,ey2,ep1,ed[1,:],eq2,21) +es3, edi3, eci3 = cfc.beam2s(ex3,ey3,ep3,ed[2,:],eq3,21) + + +#----- Draw deformed frame --------------------------------------- +cfv.figure(1,fig_size=(6,4)) +plotpar=[3,1,0] +cfv.eldraw2(ex1,ey1,plotpar) +cfv.eldraw2(ex2,ey2,plotpar) +cfv.eldraw2(ex3,ey3,plotpar) +sfac=cfv.scalfact2(ex3,ey3,edi3,0.1) +plotpar=[1,2,1] +cfv.eldisp2(ex1,ey1,ed[0,:],plotpar,sfac) +cfv.eldisp2(ex2,ey2,ed[1,:],plotpar,sfac) +cfv.eldisp2(ex3,ey3,ed[2,:],plotpar,sfac) +plotpar=[2,4,2] +cfv.eldisp2(ex1,ey1,ed0[0,:],plotpar,sfac) +cfv.eldisp2(ex2,ey2,ed0[1,:],plotpar,sfac) +cfv.eldisp2(ex3,ey3,ed0[2,:],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Displacements") + + +#----- Draw normal force diagram -------------------------------- +cfv.figure(2,fig_size=(6,4)) +plotpar=[2,1] +sfac=cfv.scalfact2(ex1,ey1,es1[:,0],0.2) +cfv.secforce2(ex1,ey1,es1[:,0],plotpar,sfac) +cfv.secforce2(ex2,ey2,es2[:,0],plotpar,sfac) +cfv.secforce2(ex3,ey3,es3[:,0],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Normal force") + +#----- Draw shear force diagram --------------------------------- +cfv.figure(3,fig_size=(6,4)) +plotpar=[2,1] +sfac=cfv.scalfact2(ex3,ey3,es3[:,1],0.2) +cfv.secforce2(ex1,ey1,es1[:,1],plotpar,sfac) +cfv.secforce2(ex2,ey2,es2[:,1],plotpar,sfac) +cfv.secforce2(ex3,ey3,es3[:,1],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Shear force") + +#----- Draw moment diagram -------------------------------------- +cfv.figure(4,fig_size=(6,4)) +plotpar=[2,1] +sfac=cfv.scalfact2(ex3,ey3,es3[:,2],0.2) +cfv.secforce2(ex1,ey1,es1[:,2],plotpar,sfac) +cfv.secforce2(ex2,ey2,es2[:,2],plotpar,sfac) +cfv.secforce2(ex3,ey3,es3[:,2],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Bending moment") +cfv.showAndWait() +#------------------------ end ----------------------------------- \ No newline at end of file diff --git a/examples/exn_beam2_b.py b/examples/exn_beam2_b.py new file mode 100644 index 0000000..471b301 --- /dev/null +++ b/examples/exn_beam2_b.py @@ -0,0 +1,112 @@ +# example exn_beam2g_b +# ---------------------------------------------------------------- +# PURPOSE +# Buckling analysis of a plane frame. +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc +import calfem.vis_mpl as cfv + + +#----- Topology ------------------------------------------------- + +edof = np.array([ + [4, 5, 6, 1, 2, 3], + [7, 8, 9, 10, 11, 12], + [4, 5, 6, 7, 8, 9] +]) + +#----- Element stiffness and element load matrices ------------- + +E=200e9 +A1=2e-3 +A2=6e-3 +I1=1.6e-5 +I2=5.4e-5 + +ep1 = np.array([E, A1, I1]) +ep3 = np.array([E, A2, I2]) + +ex1 = np.array([0.,0.]) +ey1 = np.array([4.,0.]) +ex2 = np.array([6.,6.]) +ey2 = np.array([4.,0.]) +ex3 = np.array([0.,6.]) +ey3 = np.array([4.,4.]) + +eq1 = np.array([0.]) +eq2 = np.array([0.]) +eq3 = np.array([-50e3]) + +# ----- Initial axial forces ---------------------------------------------- + +QX1 = 1e-4 +QX2 = 0 +QX3 = 0 +QX01 = 1 + +# ----- Iteration for convergence ----------------------------------------- + +eps = 1e-6 +n=0 + +while abs((QX1-QX01)/QX01) > eps: + n += 1 + K = np.zeros([12,12]) + f = np.zeros([12,1]) + f[3,0] = 10e3 + + Ke1 = cfc.beam2g(ex1,ey1,ep1,QX1) + Ke2 = cfc.beam2g(ex2,ey2,ep1,QX2) + Ke3, fe3 = cfc.beam2g(ex3,ey3,ep3,QX3,eq3) + + K = cfc.assem(edof[0,:],K,Ke1) + K = cfc.assem(edof[1,:],K,Ke2) + K, f = cfc.assem(edof[2,:],K,Ke3,f,fe3) + if n==1: + K0 = K + + bc = np.array([1, 2, 3, 10, 11]) + a, r = cfc.solveq(K, f, bc) + + ed = cfc.extract_ed(edof,a) + + QX01=QX1 + es1 = cfc.beam2gs(ex1,ey1,ep1,ed[0,:],QX1,eq1) + es2 = cfc.beam2gs(ex2,ey2,ep1,ed[1,:],QX2,eq2) + es3 = cfc.beam2gs(ex3,ey3,ep3,ed[2,:],QX3,eq3) + QX1 = es1[0,0] + QX2 = es2[0,0] + QX3 = es3[0,0] + + if n>20: + print("The solution does not converge") + break + + +# ----- Buckling analysis ------------------------------------------------- + +lam, phi = cfc.eigen(K,K0,bc) +one = np.ones(lam.shape) +alpha = np.divide(one,one-lam) +print(alpha[0]) + +# ----- Draw shape at instability ----------------------------------------- + +Ed = cfc.extract_ed(edof,-phi[:,0]) +cfv.figure(1,fig_size=(6,4)) +plotpar=[3,1,0] +cfv.eldraw2(ex1,ey1,plotpar) +cfv.eldraw2(ex2,ey2,plotpar) +cfv.eldraw2(ex3,ey3,plotpar) +sfac=cfv.scalfact2(ex3,ey3,Ed[2,:],0.1) +plotpar=[1,2,1] +cfv.eldisp2(ex1,ey1,Ed[0,:],plotpar,sfac) +cfv.eldisp2(ex2,ey2,Ed[1,:],plotpar,sfac) +cfv.eldisp2(ex3,ey3,Ed[2,:],plotpar,sfac) +cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.title("Shape at instability") +cfv.showAndWait() + +#------------------------ end ----------------------------------- \ No newline at end of file From 01a2350431a2418cd9b810cf6e61c7979b1af3f3 Mon Sep 17 00:00:00 2001 From: Adam Sciegaj Date: Mon, 19 Dec 2022 11:10:26 +0100 Subject: [PATCH 08/17] Fixed a small bug in step2 --- calfem/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/calfem/core.py b/calfem/core.py index ac16b25..d821851 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -4073,7 +4073,7 @@ def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): dim(dofhist['d2ahist']) = ndof x (nstep + 1) """ ndof, _ = K.shape - if not C: + if not np.array(C).any(): C = np.zeros((ndof,ndof)) dt, tottime, alpha, delta = ip b1 = dt*dt*0.5*(1-2*alpha) @@ -4108,7 +4108,7 @@ def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): modelhist = {} sa=0 - if not times.any(): + if not np.array(times).any(): ntimes=0 sa=1 modelhist['a'] = np.zeros((ndof,nstep+1)) @@ -4123,7 +4123,7 @@ def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): modelhist['d2a'] = np.zeros((ndof,ntimes)) dofhist = {} - if dofs.all(): + if np.array(dofs).all(): ndofs = len(dofs) if ndofs: dofhist['a'] = np.zeros((ndofs,nstep+1)) From 1615ee3010ae21fed20944448ef4f99fd8897189 Mon Sep 17 00:00:00 2001 From: Adam Sciegaj Date: Mon, 19 Dec 2022 12:46:22 +0100 Subject: [PATCH 09/17] Added step1 function to core --- calfem/core.py | 186 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 183 insertions(+), 3 deletions(-) diff --git a/calfem/core.py b/calfem/core.py index d821851..6d937a8 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -4018,6 +4018,185 @@ def gfunc(G,dt): return ti, g1 +def step1(K,C,f,a0,bc,ip,times,dofs): + """ + Algorithm for dynamic solution of first-order + FE equations considering boundary conditions. + + Parameters: + + K conductivity matrix, dim(K) = ndof x ndof + C capacity matrix, dim(C) = ndof x ndof + f load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial vector a(0), dim(a0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha], where + dt is the size of the time increment, + tottime is the total time, + alpha is time integration constant. + Frequently used values of alpha are: + alpha=0: forward difference; forward Euler, + alpha=1/2: trapezoidal rule; Crank-Nicholson + alpha=1: backward difference; backward Euler + times array [t(i) ...] of times at which output should be written to a and da + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist and dahist + + Returns: + + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains values of a at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains values of da at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains time history of a at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains time history of daat the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + dt, tottime, alpha = ip + a1 = (1-alpha)*dt + a2 = alpha*dt + + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 + + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 + + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns + + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 + + itime = 0 + + # Calculate initial second time derivative d2a0 + da0 = np.linalg.solve(C,tf[:,0].reshape(-1,1) - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + itime += 1 + + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = C[np.ix_(fdof,fdof)] + a2*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = C + a2*K + + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + apred = aold + a1*daold + if not bound: + reff = tf[:,j].reshape(-1,1) - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + danew = np.linalg.solve(U,y) + anew = apred + a2*danew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + + return modelhist, dofhist + + def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): """ Algorithm for dynamic solution of second-order @@ -4040,11 +4219,11 @@ def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): and the subsequent columns contain the time history. If dim(bc) = nbc x 2, the values from the second column are kept constant during time integration - ip list [dt, tottime, alpha, delta], where + ip array [dt, tottime, alpha, delta], where dt is the size of the time increment, tottime is the total time, alpha and delta are time integration constants for the Newmark family of methods. - Frequently used values of alpha and delta: + Frequently used values of alpha and delta are: alpha=1/4, delta=1/2: average acceleration (trapezoidal) rule, alpha=1/6, delta=1/2: linear acceleration alpha=0, delta=1/2: central difference @@ -4064,7 +4243,7 @@ def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): modelhist['d2a'] constains acceleration values at all timesteps, alternatively at times specified in 'times' dim(modelhist['d2a']) = ndof x (nstep + 1) or ndof x ntimes - dofhist dictionary containing solution history for the selected 'dofs': + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': dofhist['a'] constains displacement time history at the dofs specified in 'dofs' dim(dofhist['ahist']) = ndof x (nstep + 1) dofhist['da'] constains velocity time history at the dofs specified in 'dofs' @@ -4223,6 +4402,7 @@ def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): return modelhist, dofhist + def extract_eldisp(edof, a): """ Extract element displacements from the global displacement From 7c0a4a4f10231d8183e062e50159284bc880f672 Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Sun, 5 Feb 2023 17:40:27 +0100 Subject: [PATCH 10/17] Update core.py --- calfem/core.py | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/calfem/core.py b/calfem/core.py index b4e58c0..75f89e4 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -1265,37 +1265,25 @@ def beam3e(ex, ey, ez, eo, ep, eq=None): qx, qy, qz, qw, qz*L/6, -qy*L/6]).T n2 = np.array([0., 0., 0.]) - n2[0] = n3[1]*n1[2]-n3[2]*n1[1] + n2[0] = n3[1]*n1[2]-n3[2]*n1[1] n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] - n2[2] = n3[0]*n1[1]-n1[0]*n3[1] + n2[2] = n3[0]*n1[1]-n1[0]*n3[1] #An = np.append([n1,n2],[n3],0) G = np.mat([ - [n1[0], n1[1], n1[2], 0, 0, 0, - 0, 0, 0, 0, 0, 0], - [n2[0], n2[1], n2[2], 0, 0, 0, - 0, 0, 0, 0, 0, 0], - [n3[0], n3[1], n3[2], 0, 0, 0, - 0, 0, 0, 0, 0, 0], - [0, 0, 0, n1[0], n1[1], n1[2], - 0, 0, 0, 0, 0, 0], - [0, 0, 0, n2[0], n2[1], n2[2], - 0, 0, 0, 0, 0, 0], - [0, 0, 0, n3[0], n3[1], n3[2], - 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, - n1[0], n1[1], n1[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, - n2[0], n2[1], n2[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, - n3[0], n3[1], n3[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, - 0, 0, n1[0], n1[1], n1[2]], - [0, 0, 0, 0, 0, 0, 0, - 0, 0, n2[0], n2[1], n2[2]], - [0, 0, 0, 0, 0, 0, - 0, 0, 0, n3[0], n3[1], n3[2]] + [n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2]], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2]], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2]] ]) Ke = G.T*Kle*G From 8f9cb282b9e37b16774767c7dc30536539ebe228 Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Fri, 17 Feb 2023 09:32:21 +0100 Subject: [PATCH 11/17] Updated spring/bar/beam elements and vis module. --- calfem/core.py | 7828 +++++++++++++++++++++-------------------- calfem/core_compat.py | 4877 +++++++++++++++++++++++++ calfem/vis_mpl.py | 367 +- 3 files changed, 9058 insertions(+), 4014 deletions(-) create mode 100644 calfem/core_compat.py diff --git a/calfem/core.py b/calfem/core.py index 901803b..e85072e 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -78,1660 +78,1644 @@ def info(msg): cflog.info(" calfem.core: "+msg) -def spring1e(ep): - """ - Compute element stiffness matrix for spring element. - - :param float ep: spring stiffness or analog quantity (ep = k). - :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 - """ - k = ep - return np.mat([[k, -k], [-k, k]], 'd') -def spring1s(ep, ed): +def flw2te(ex, ey, ep, D, eq=None): """ - Compute element force in spring element (spring1e). + Compute element stiffness (conductivity) matrix for a triangular field element. - :param float ep: spring stiffness or analog quantity - :param list ed: element displacements [d0, d1] - :return float es: element force [N] - """ - k = ep - return k*(ed[1]-ed[0]) - - -def bar1e(ep): - """ - Compute element stiffness matrix for spring element. + Parameters: - :param ep float: spring stiffness or analog quantity - :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 - """ - k = ep - return np.mat([[k, -k], [-k, k]], 'd') - - -def bar1s(ep, ed): - """ - Compute element force in spring element (spring1e). + ex = [x1 x2 x3] + ey = [y1 y2 y3] element coordinates - :param float ep: spring stiffness or analog quantity - :param list ed: element displacements [d0, d1] - :return float es: element force - """ - k = ep - return k*(ed[1]-ed[0]) + ep = [t] element thickness + D = [kxx kxy; + kyx kyy] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (3 x 3) -def bar2e(ex, ey, ep): - """ - Compute the element stiffness matrix for two dimensional bar element. + fe element load vector (3 x 1) - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: [E, A]: E - Young's modulus, A - Cross section area - :return mat Ke: stiffness matrix, [4 x 4] """ - E = ep[0] - A = ep[1] - - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - - Kle = np.mat([[1., -1.], [-1., 1.]])*E*A/L + t = ep[0] + if eq == None: + eq = 0. - n = np.asarray(b.T/L).reshape(2,) + exm = np.asmatrix(ex) + eym = np.asmatrix(ey) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I + A = 0.5*np.linalg.det(C) - G = np.mat([ - [n[0], n[1], 0., 0.], - [0., 0., n[0], n[1]] - ]) + Ke = B.T*D*B*t*A + fe = np.matrix([[1., 1., 1.]]).T*eq*A*t/3 - return G.T*Kle*G + if eq == 0.: + return Ke + else: + return Ke, fe -def bar2g(ex, ey, ep, N): +def flw2ts(ex, ey, D, ed): """ - Compute element stiffness matrix for two dimensional geometric - nonlinear bar element. + Compute flows or corresponding quantities in the triangular field element. + + Parameters: + + ex = [x1 x2 x3] + ey = [y1 y2 y3] element coordinates + + D = [kxx kxy + kyx kyy] constitutive matrix + + ed =[u1 u2 u3] u1,u2,u3: nodal values + .. .. ..; + + Returns: + + es=[ qx qy ] + ... ..] element flows + + et=[ gx gy ] + ... ..] element gradients - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :param float N: normal force - :return mat Ke: stiffness matrix [4 x 4] """ - E = ep[0] - A = ep[1] - - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() + if len(ex.shape) > 1: + qs = np.zeros([ex.shape[0], 2]) + qt = np.zeros([ex.shape[0], 2]) + row = 0 + for exr, eyr, edr in zip(ex, ey, ed): + exm = np.asmatrix(exr) + eym = np.asmatrix(eyr) + edm = np.asmatrix(edr) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I - n = np.asarray(b.T/L).reshape(2,) + qs[row, :] = (-D*B*edm.T).T + qt[row, :] = (B*edm.T).T + row += 1 - G = np.mat([ - [n[0], n[1], 0., 0.], - [-n[1], n[0], 0., 0.], - [0., 0., n[0], n[1]], - [0., 0., -n[1], n[0]] - ]) + return qs, qt + else: + exm = np.asmatrix(ex) + eym = np.asmatrix(ey) + edm = np.asmatrix(ed) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I - Kle = E*A/L*np.mat([ - [1, 0, -1, 0], - [0, 0, 0, 0], - [-1, 0, 1, 0], - [0, 0, 0, 0] - ])+N/L*np.mat([ - [0, 0, 0, 0], - [0, 1, 0, -1], - [0, 0, 0, 0], - [0, -1, 0, 1] - ]) + qs = -D*B*edm.T + qt = B*edm.T - return G.T*Kle*G + return qs.T, qt.T -def bar2s(ex, ey, ep, ed): +def flw2qe(ex, ey, ep, D, eq=None): """ - Compute normal force in two dimensional bar element. + Compute element stiffness (conductivity) matrix for a triangular field element. - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :param list ed: element displacements [u1, u2, u3, u4] - :return float N: element foce [N] - """ - E = ep[0] - A = ep[1] + Parameters: + + ex = [x1, x2, x3, x4] + ey = [y1, y2, y3, y4] element coordinates + + ep = [t] element thickness - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (4 x 4) - #Kle = np.mat([[1.,-1.],[-1.,1.]])*E*A/L + fe element load vector (4 x 1) + + """ + xc = sum(ex)/4. + yc = sum(ey)/4. - n = np.asarray(b.T/L).reshape(2,) + K = np.zeros((5, 5)) + f = np.zeros((5, 1)) - G = np.mat([ - [n[0], n[1], 0., 0.], - [0., 0., n[0], n[1]] - ]) + if eq == None: + k1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D) + K = assem(np.array([1, 2, 5]), K, k1) + k1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D) + K = assem(np.array([2, 3, 5]), K, k1) + k1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D) + K = assem(np.array([3, 4, 5]), K, k1) + k1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D) + K = assem(np.array([4, 1, 5]), K, k1) + else: + k1, f1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D, eq) + K, f = assem(np.array([1, 2, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D, eq) + K, f = assem(np.array([2, 3, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D, eq) + K, f = assem(np.array([3, 4, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D, eq) + K, f = assem(np.array([4, 1, 5]), K, k1, f, f1) + Ke1, fe1 = statcon(K, f, np.array([5])) - u = np.asmatrix(ed).T - N = E*A/L*np.mat([[-1., 1.]])*G*u - return N.item() + Ke = Ke1 + fe = fe1 + + if eq == None: + return Ke + else: + return Ke, fe -def bar2gs(ex, ey, ep, ed): +def flw2qs(ex, ey, ep, D, ed, eq=None): """ - Calculate section forces in a two dimensional geometric - nonlinear bar element (bar2g). + Compute flows or corresponding quantities in the + quadrilateral field element. + Parameters: - ex = [x1 x2] element node coordinates - ey = [y1 y2] + + ex = [x1, x2, x3, x4] + ey = [y1, y2, y3, y4] element coordinates + + ep = [t] element thickness - ep = [E A] element properties; - E: Young's modulus - A: cross section area - - ed = [u1 ... u4] element displacement vector + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + ed = [[u1, u2, u3, u4], + [.., .., .., ..]] u1,u2,u3,u4: nodal values + + eq heat supply per unit volume + Returns: - es = [N1; - N2 ] section forces, local directions - - QX: axial force - - edi = [ u1 ; element displacements, local directions, - u2 ; in n points along the bar, dim(es)= n x 1 - ...] - - eci = [ x1 ; local x-coordinates of the evaluation - x2 ; points, (x1=0 and xn=L) - ...] - """ - EA = ep[0]*ep[1] - ne = 2 - - dx = ex[1] - ex[0] - dy = ey[1] - ey[0] - L = np.sqrt(dx**2 + dy**2) - - n = [dx/L, dy/L, -dy/L, dx/L] - G = np.array([ - [n[0], n[1], 0., 0.], - [n[2], n[3], 0., 0.], - [0., 0., n[0], n[1]], - [0., 0., n[2], n[3]] - ]) - - edl = G@ed.reshape(-1,1) - a1 = np.array([edl[0], edl[2]]).reshape(-1,1) - - C1 = np.array([[1., 0.,], - [-1/L, 1/L]]) - C1a = C1@a1 - - x = np.linspace(0,L,ne).reshape(-1,1) - zero = np.zeros(x.shape) - one = np.ones(x.shape) - - u = np.concatenate((one, x),axis=1)@C1a - du = np.concatenate((zero, one),axis=1)@C1a - - N = EA*du - return N, N[0].item(), u, x - - -def bar3e(ex, ey, ez, ep): - """ - Compute element stiffness matrix for three dimensional bar element. - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ez: element z coordinates [z1, z2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :return mat Ke: stiffness matrix, [6 x 6] - """ - E = ep[0] - A = ep[1] - - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() - - n = np.asarray(b.T/L).reshape(3) - - G = np.mat([ - [n[0], n[1], n[2], 0., 0., 0.], - [0., 0., 0., n[0], n[1], n[2]] - ]) - - Kle = E*A/L*np.mat([ - [1, -1], - [-1, 1] - ]) - - return G.T*Kle*G - + es = [[qx, qy], + [.., ..]] element flows -def bar3s(ex, ey, ez, ep, ed): - """ - Compute normal force in three dimensional bar element. + et = [[gx, gy], + [.., ..]] element gradients - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ez: element z coordinates [z1, z2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :param list ed: element displacements [u1, ..., u6] - :return float N: normal force """ - E = ep[0] - A = ep[1] + K = np.zeros((5, 5)) + f = np.zeros((5, 1)) - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() + xm = sum(ex)/4 + ym = sum(ey)/4 - n = np.asarray(b.T/L).reshape(3) + if eq == None: + q = 0 + else: + q = eq - G = np.mat([ - [n[0], n[1], n[2], 0., 0., 0.], - [0., 0., 0., n[0], n[1], n[2]] + En = np.array([ + [1, 2, 5], + [2, 3, 5], + [3, 4, 5], + [4, 1, 5] ]) + ex1 = np.array([ex[0], ex[1], xm]) + ey1 = np.array([ey[0], ey[1], ym]) + ex2 = np.array([ex[1], ex[2], xm]) + ey2 = np.array([ey[1], ey[2], ym]) + ex3 = np.array([ex[2], ex[3], xm]) + ey3 = np.array([ey[2], ey[3], ym]) + ex4 = np.array([ex[3], ex[0], xm]) + ey4 = np.array([ey[3], ey[0], ym]) - #Kle = E*A/L*np.mat([ - # [ 1,-1], - # [-1, 1] - #]) - - u = np.asmatrix(ed).T - N = E*A/L*np.mat([[-1., 1.]])*G*u - - return N.item() + if eq == None: + k1 = flw2te(ex1, ey1, ep, D) + K = assem(En[0], K, k1) + k1 = flw2te(ex2, ey2, ep, D) + K = assem(En[1], K, k1) + k1 = flw2te(ex3, ey3, ep, D) + K = assem(En[2], K, k1) + k1 = flw2te(ex4, ey4, ep, D) + K = assem(En[3], K, k1) + else: + k1, f1 = flw2te(ex1, ey1, ep, D, q) + K, f = assem(En[0], K, k1, f, f1) + k1, f1 = flw2te(ex2, ey2, ep, D, q) + K, f = assem(En[1], K, k1, f, f1) + k1, f1 = flw2te(ex3, ey3, ep, D, q) + K, f = assem(En[2], K, k1, f, f1) + k1, f1 = flw2te(ex4, ey4, ep, D, q) + K, f = assem(En[3], K, k1, f, f1) -def beam1e(ex, ep, eq=None): - """ - Compute the stiffness matrix for a one dimensional beam element. + if ed.ndim == 1: + ed = np.array([ed]) - :param list ex: element x coordinates [x1, x2] - :param list ep: element properties [E, I], E - Young's modulus, I - Moment of inertia - :param float eq: distributed load [qy] - :return mat Ke: element stiffness matrix [4 x 4] - :return mat fe: element load vector [4 x 1] (if eq!=None) - """ - L = ex[1]-ex[0] + ni, nj = np.shape(ed) - E = ep[0] - I = ep[1] + a = np.zeros((5, ni)) + for i in range(ni): + a[np.ix_(range(5), [i])], r = np.asarray( + solveq(K, f, np.arange(1, 5), ed[i])) - qy = 0. - if eq: - qy = eq + s1, t1 = flw2ts(ex1, ey1, D, a[np.ix_(En[0, :]-1, np.arange(ni))].T) + s2, t2 = flw2ts(ex2, ey2, D, a[np.ix_(En[1, :]-1, np.arange(ni))].T) + s3, t3 = flw2ts(ex3, ey3, D, a[np.ix_(En[2, :]-1, np.arange(ni))].T) + s4, t4 = flw2ts(ex4, ey4, D, a[np.ix_(En[3, :]-1, np.arange(ni))].T) - Ke = E*I/(L**3) * np.mat([ - [12, 6*L, -12, 6*L], - [6*L, 4*L**2, -6*L, 2*L**2], - [-12, -6*L, 12, -6*L], - [6*L, 2*L**2, -6*L, 4*L**2] - ]) + es = (s1+s2+s3+s4)/4. + et = (t1+t2+t3+t4)/4. - fe = qy*np.mat([L/2, L**2/12, L/2, -L**2/12]).T + return es, et - if eq is None: - return Ke - else: - return Ke, fe -def beam1s(ex, ep, ed, eq=None, nep=None): +def flw2i4e(ex, ey, ep, D, eq=None): """ - Compute section forces in one dimensional beam element (beam1e). + Compute element stiffness (conductivity) + matrix for 4 node isoparametric field element Parameters: + + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] - ex = [x1 x2] element node coordinates - - ep = [E I] element properties, - E: Young's modulus - I: moment of inertia - - ed = [u1 ... u4] element displacements + ep = [t ir] thickness and integration rule - eq = qy distributed load, local directions + D = [[kxx kxy], + [kyx kyy]] constitutive matrix - nep number of evaluation points ( default=2 ) + eq heat supply per unit volume Returns: - - es = [ V1 M1 section forces, local directions, in - V2 M2 n points along the beam, dim(es)= n x 2 - .........] - - edi = [ v1 element displacements, local directions, - v2 in n points along the beam, dim(es)= n x 1 - .......] - - eci = [ x1 local x-coordinates of the evaluation - x2 points, (x1=0 and xn=L) - ...] + Ke element 'stiffness' matrix (4 x 4) + fe element load vector (4 x 1) """ - EI = ep[0]*ep[1] - L = ex[1]-ex[0] - - qy = 0. - - if eq: - qy = eq - - ne = 2 - - if nep != None: - ne = nep + t = ep[0] + ir = ep[1] + ngp = ir*ir - Cinv = np.mat([ - [1, 0, 0, 0], - [0, 1, 0, 0], - [-3/(L**2), -2/L, 3/(L**2), -1/L], - [2/(L**3), 1/(L**2), -2/(L**3), 1/(L**2)] - ]) + if eq == None: + q = 0 + else: + q = eq - Ca = (Cinv@ed).T + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) - x = np.asmatrix(np.linspace(0., L, nep)).T - zero = np.asmatrix(np.zeros([len(x)])).T - one = np.asmatrix(np.ones([len(x)])).T + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 - v = np.concatenate((one, x, np.power(x, 2), np.power(x, 3)), 1)@Ca \ - + qy/(24*EI)*(np.power(x,4) - 2*L*np.power(x,3) + (L**2)*np.power(x,2)) - d2v = np.concatenate((zero, zero, 2*one, 6*x), 1)@Ca \ - + qy/(12*EI)*(6*np.power(x,2) - 6*L*x + L**2) - d3v = np.concatenate((zero, zero, zero, 6*one), 1)@Ca + qy/(2*EI)*(2*x - L) + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) - M = EI*d2v - V = -EI*d3v - edi = v - eci = x - es = np.concatenate((V, M), 1) + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. - return (es, edi, eci) + Ke1 = np.mat(np.zeros((4, 4))) + fe1 = np.mat(np.zeros((4, 1))) + JT = dNr*np.mat([ex, ey]).T + + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] + if eq == None: + return Ke1*t + else: + return Ke1*t, fe1*t*eq -def beam2e(ex, ey, ep, eq=None): +def flw2i4s(ex, ey, ep, D, ed): """ - Compute the stiffness matrix for a two dimensional beam element. + Compute flows or corresponding quantities in the + 4 node isoparametric element. - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: element properties [E, A, I], E - Young's modulus, A - Cross section area, I - Moment of inertia - :param list eq: distributed loads, local directions [qx, qy] - :return mat Ke: element stiffness matrix [6 x 6] - :return mat fe: element stiffness matrix [6 x 1] (if eq!=None) - """ + Parameters: + + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2,) + ep = [t ir] thickness and integration rule - E = ep[0] - A = ep[1] - I = ep[2] + D = [[kxx kxy], + [kyx kyy]] constitutive matrix - qx = 0. - qy = 0. - if not eq is None: - qx = eq[0] - qy = eq[1] + ed = [u1, u2, u3, u4] u1,u2,u3,u4: nodal values - Kle = np.mat([ - [E*A/L, 0., 0., -E*A/L, 0., 0.], - [0., 12*E*I/L**3., 6*E*I/L**2., 0., -12*E*I/L**3., 6*E*I/L**2.], - [0., 6*E*I/L**2., 4*E*I/L, 0., -6*E*I/L**2., 2*E*I/L], - [-E*A/L, 0., 0., E*A/L, 0., 0.], - [0., -12*E*I/L**3., -6*E*I/L**2., 0., 12*E*I/L**3., -6*E*I/L**2.], - [0., 6*E*I/L**2., 2*E*I/L, 0., -6*E*I/L**2., 4*E*I/L] - ]) + Returns: + es = [[qx, qy], + [.., ..]] element flows - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + et = [[qx, qy], + [... ..]] element gradients - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] - ]) + eci=[[ix1, iy1], Gauss point location vector + [... ...], nint: number of integration points + [ix(nint), iy(nint)] - Ke = G.T*Kle*G - fe = G.T*fle + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir - if eq is None: - return Ke + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) else: - return Ke, fe - + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) -def beam2s(ex, ey, ep, ed, eq=None, nep=None): - """ - Compute section forces in two dimensional beam element (beam2e). - - Parameters: - - ex = [x1 x2] - ey = [y1 y2] element node coordinates + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 - ep = [E A I] element properties, - E: Young's modulus - A: cross section area - I: moment of inertia + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) - ed = [u1 ... u6] element displacements + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. - eq = [qx qy] distributed loads, local directions + eci = N*np.mat([ex, ey]).T + if ed.ndim == 1: + ed = np.array([ed]) - nep number of evaluation points ( default=2 ) - - Returns: - - es = [ N1 V1 M1 section forces, local directions, in - N2 V2 M2 n points along the beam, dim(es)= n x 3 - .........] - - edi = [ u1 v1 element displacements, local directions, - u2 v2 in n points along the beam, dim(es)= n x 2 - .......] + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey]).T - eci = [ x1 local x-coordinates of the evaluation - x2 points, (x1=0 and xn=L) - ...] - + es = np.mat(np.zeros((ngp*red, 2))) + et = np.mat(np.zeros((ngp*red, 2))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinatn == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + + return es, et, eci + + +def flw2i8e(ex, ey, ep, D, eq=None): """ - EA = ep[0]*ep[1] - EI = ep[0]*ep[2] - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) + Compute element stiffness (conductivity) + matrix for 8 node isoparametric field element. + + Parameters: + + ex = [x1, ..., x8] element coordinates + ey = [y1, ..., y8] + + ep = [t, ir] thickness and integration rule - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2,) + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix - qx = 0. - qy = 0. + eq heat supply per unit volume - if not eq is None: - qx = eq[0] - qy = eq[1] + Returns: + + Ke element 'stiffness' matrix (8 x 8) + fe element load vector (8 x 1) - ne = 2 + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir - if nep != None: - ne = nep + if eq == None: + q = 0 + else: + q = eq - C = np.mat([ - [0., 0., 0., 1., 0., 0.], - [0., 0., 0., 0., 0., 1.], - [0., 0., 0., 0., 1., 0.], - [L, 0., 0., 1., 0., 0.], - [0., L**3, L**2, 0., L, 1.], - [0., 3*L**2, 2*L, 0., 1., 0.] - ]) + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] - ]) + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 - M = np.ravel(C.I*(G*np.asmatrix(ed).T - - np.matrix([0., 0., 0., -qx*L**2/(2*EA), qy*L**4/(24*EI), qy*L**3/(6*EI)]).T)) - A = np.matrix([M[0], M[3]]).T - B = np.matrix([M[1], M[2], M[4], M[5]]).T + N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) + N = np.append(N, np.multiply( + (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) + N = np.append(N, np.multiply( + (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) - x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T - zero = np.asmatrix(np.zeros([len(x)])).T - one = np.asmatrix(np.ones([len(x)])).T + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - + np.multiply((1+xsi), (1-eta)))/4. + dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + + np.multiply((1-xsi), (1+eta)))/4. + dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) + dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. + dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) + dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. + dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + + np.multiply((1+xsi), (1-eta)))/4. + dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - + np.multiply((1-xsi), (1+eta)))/4. + dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) + dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) - u = np.concatenate((x, one), 1)*A-np.power(x, 2)*qx/(2*EA) - du = np.concatenate((one, zero), 1)*A-x*qx/EA - v = np.concatenate((np.power(x, 3), np.power(x, 2), x, - one), 1)*B+np.power(x, 4)*qy/(24*EI) - d2v = np.concatenate((6*x, 2*one, zero, zero), 1) * \ - B+np.power(x, 2)*qy/(2*EI) - d3v = np.concatenate((6*one, zero, zero, zero), 1)*B+x*qy/EI + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey]).T - N = EA*du - M = EI*d2v - V = -EI*d3v - edi = np.concatenate((u, v), 1) - eci = x - es = np.concatenate((N, V, M), 1) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminanten lika med noll!") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] - return (es, edi, eci) + if eq != None: + return Ke1*t, fe1*t*q + else: + return Ke1*t -def beam2t(ex, ey, ep, eq=None): +def flw2i8s(ex, ey, ep, D, ed): """ - Compute the stiffness matrix for a two dimensional elastic - Timoshenko beam element. + Compute flows or corresponding quantities in the + 8 node isoparametric element. Parameters: - - ex = [x1 x2] - ey = [y1 y2] element node coordinates - - ep = [E G A I ks] element properties - E: Young's modulus - G: Shear modulus - A: Cross section area - I: Moment of inertia - ks: Shear correction factor - - eq = [qx qy] distributed loads, local directions - Returns: - - Ke element stiffness matrix (6 x 6) - - fe element load vector (6 x 1) - - """ + ex = [x1,x2,x3....,x8] element coordinates + ey = [y1,y2,y3....,y8] - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2) + ep = [t,ir] thickness and integration rule - E = ep[0] - Gm = ep[1] - A = ep[2] - I = ep[3] - ks = ep[4] + D = [[kxx,kxy], + [kyx,kyy]] constitutive matrix - qx = 0. - qy = 0. - if eq != None: - qx = eq[0] - qy = eq[1] + ed = [u1,....,u8] u1,....,u8: nodal values - m = (12/L**2)*(E*I/(Gm*A*ks)) + Returns: + es = [[qx,qy], + [..,..]] element flows - Kle = E/(1+m)*np.mat([ - [A*(1+m)/L, 0., 0., -A*(1+m)/L, 0., 0.], - [0., 12*I/L**3., 6*I/L**2., 0., -12*I/L**3., 6*I/L**2.], - [0., 6*I/L**2., 4*I * - (1+m/4.)/L, 0., -6*I/L**2., 2*I*(1-m/2)/L], - [-A*(1+m)/L, 0., 0., - A*(1+m)/L, 0., 0.], - [0., -12*I/L**3., -6*I/L**2., - 0., 12*I/L**3., -6*I/L**2.], - [0., 6*I/L**2., 2*I * - (1-m/2)/L, 0., -6*I/L**2., 4*I*(1+m/4)/L] - ]) - - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + et = [[qx,qy], + [..,..]] element gradients - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] - ]) + eci=[[ix1,iy1], Gauss point location vector + [...,...], nint: number of integration points + [ix(nint),iy(nint)]] - Ke = G.T*Kle*G - fe = G.T*fle + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir - if eq == None: - return Ke + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) else: - return Ke, fe - + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) -def beam2ts(ex, ey, ep, ed, eq=None, nep=None): - """ - Compute section forces in two dimensional beam element (beam2e). - - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 - ep = [E,G,A,I,ks] element properties, - E: Young's modulus - G: shear modulus - A: cross section area - I: moment of inertia + N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) + N = np.append(N, np.multiply( + (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) + N = np.append(N, np.multiply( + (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) - ed = [u1, ... ,u6] element displacements + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - + np.multiply((1+xsi), (1-eta)))/4. + dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + + np.multiply((1-xsi), (1+eta)))/4. + dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) + dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. + dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) + dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. + dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + + np.multiply((1+xsi), (1-eta)))/4. + dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - + np.multiply((1-xsi), (1+eta)))/4. + dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) + dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) - eq = [qx, qy] distributed loads, local directions + eci = N*np.mat([ex, ey]).T + if ed.ndim == 1: + ed = np.array([ed]) + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey]).T - nep number of evaluation points ( default=2 ) - - Returns: - - es = [[N1,V1,M1], section forces, local directions, in - [N2,V2,M2], n points along the beam, dim(es)= n x 3 - ..........] - - edi = [[u1,v1,teta1], element displacements, local directions, - [u2,v2,teta2], and rotation of cross section at - .............] in n points along the beam, dim(es)= n x 2 - - (Note! Rotation of the cross section is not equal to dv/dx for Timoshenko beam element) - - eci = [[x1], local x-coordinates of the evaluation - [x2], points, (x1=0 and xn=L) - ....] - - """ - EA = ep[0]*ep[2] - EI = ep[0]*ep[3] - GAK = ep[1]*ep[2]*ep[4] - alfa = EI/GAK + es = np.mat(np.zeros((ngp*red, 2))) + et = np.mat(np.zeros((ngp*red, 2))) - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T - qx = 0. - qy = 0. - if eq != None: - qx = eq[0] - qy = eq[1] + return es, et, eci - ne = 2 - if nep != None: - ne = nep +def flw3i8e(ex, ey, ez, ep, D, eq=None): + """ + Compute element stiffness (conductivity) + matrix for 8 node isoparametric field element. + + Parameters: + + ex = [x1,x2,x3,...,x8] + ey = [y1,y2,y3,...,y8] element coordinates + ez = [z1,z2,z3,...,z8] - C = np.mat([ - [0., 0., 0., 1., 0., 0.], - [0., 0., 0., 0., 0., 1.], - [0., 6*alfa, 0., 0., 1., 0.], - [L, 0., 0., 1., 0., 0.], - [0., L**3, L**2, 0., L, 1.], - [0., 3*(L**2+2*alfa), 2*L, 0., 1., 0.] - ]) + ep = [ir] Ir: Integration rule - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] - ]) + D = [[kxx,kxy,kxz], + [kyx,kyy,kyz], + [kzx,kzy,kzz]] constitutive matrix - M = np.ravel(C.I*(G*np.asmatrix(ed).T-np.mat([0., 0., 0., -qx*L**2/( - 2*EA), qy*L**4/(24*EI)-qy*L**2/(2*GAK), qy*L**3/(6*EI)]).T)) - C2 = np.mat([M[0], M[3]]).T - C4 = np.mat([M[1], M[2], M[4], M[5]]).T + eq heat supply per unit volume - x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T - zero = np.asmatrix(np.zeros([len(x)])).T - one = np.asmatrix(np.ones([len(x)])).T + Output: - u = np.concatenate((x, one), 1)*C2-qx/(2*EA)*np.power(x, 2) - du = np.concatenate((one, zero), 1)*C2-qx*x/EA + Ke element 'stiffness' matrix (8 x 8) + fe element load vector (8 x 1) - v = np.concatenate((np.power(x, 3), np.power(x, 2), x, one), 1) * \ - C4+qy/(24*EI)*np.np.power(x, 4)-qy/(2*GAK)*np.power(x, 2) - dv = np.concatenate((3*np.power(x, 2), 2*x, one, zero), - 1)*C4+qy*np.power(x, 3)/(6*EI)-qy*x/GAK + """ + ir = ep[0] + ngp = ir*ir*ir - teta = np.concatenate((3*(np.power(x, 2)+2*alfa*one), - 2*x, one, zero), 1)*C4+qy*np.power(x, 3)/(6*EI) - dteta = np.concatenate((6*x, 2*one, zero, zero), 1) * \ - C4+qy*np.power(x, 2)/(2*EI) + if eq == None: + q = 0 + else: + q = eq - N = EA*du - M = EI*dteta - V = GAK*(dv-teta) - - es = np.concatenate((N, V, M), 1) - edi = np.concatenate((u, v, teta), 1) - eci = x - - if nep != None: - return es, edi, eci + if ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-1, -1, -1], + [1, -1, -1], + [1, 1, -1], + [-1, 1, -1], + [-1, -1, 1], + [1, -1, 1], + [1, 1, 1], + [-1, 1, 1] + ])*g1 + w = np.mat(np.ones((8, 3)))*w1 + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat(np.zeros((27, 3))) + w = np.mat(np.zeros((27, 3))) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) + gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] + I1 = abs(I1) + I2 = abs(I2) + w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) + gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] + I1 = abs(I1) + I2 = abs(I2) + w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) + I3 = abs(I1) + gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 + gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] + w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 + w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] else: - return es - - -def beam2w(ex, ey, ep, eq=None): - """ - Compute the stiffness matrix for a two dimensional beam element - on elastic foundation. - - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - - ep = [E,A,I,ka,kt] element properties, - E: Young's modulus - A: cross section area - I: moment of inertia - ka: axial foundation stiffness - kt: transversal foundation stiffness - - eq = [qx, qy] distributed loads, local directions - - Returns: - - Ke beam stiffness matrix (6 x 6) - - fe element load vector (6 x 1) - """ - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2) - - E, A, I, ka, kt = ep + info("Used number of integration points not implemented") + return - qx = 0 - qy = 0 - if eq != None: - qx, qy = eq + wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) - K1 = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], - [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], - [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] - ]) + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 - K2 = L/420*np.mat([ - [140*ka, 0, 0, 70*ka, 0, 0], - [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], - [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], - [70*ka, 0, 0, 140*ka, 0, 0], - [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], - [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] - ]) + N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1+zet))/8., axis=1) - Kle = K1+K2 - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) + dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) + dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) + dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) + dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) + dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) + dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) + dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) + dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) + dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) + dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) + dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) + dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) + dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) + dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) + dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) + dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) + dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) + dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) + dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) + dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) + dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) + dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) + dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) + dNr = dNr/8. - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey, ez]).T - Ke = G.T*Kle*G - fe = G.T*fle + for i in range(ngp): + indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] if eq != None: - return Ke, fe + return Ke1, fe1*q else: - return Ke + return Ke1 -def beam2ws(ex, ey, ep, ed, eq=None): +def flw3i8s(ex, ey, ez, ep, D, ed): """ - Compute section forces in a two dimensional beam element - on elastic foundation. + Compute flows or corresponding quantities in the + 8 node (3-dim) isoparametric field element. Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - - ep = [E,A,I,ka,kt] element properties, - E: Young's modulus - A: cross section area - I: moment of inertia - ka: axial foundation stiffness - kt: transversal foundation stiffness - - ed = [u1, ... ,u6] element displacement vector + + ex = [x1,x2,x3,...,x8] + ey = [y1,y2,y3,...,y8] element coordinates + ez = [z1,z2,z3,...,z8] - eq = [qx, qy] distributed loads, local directions + ep = [ir] Ir: Integration rule - Returns: + D = [[kxx,kxy,kxz], + [kyx,kyy,kyz], + [kzx,kzy,kzz]] constitutive matrix - es = [[N1, V1, M1], - [N2, V2, M2]] element forces, local direction - """ - if np.asmatrix(ed).shape[0] > 1: - error("Only one row is allowed in the ed matrix !!!") - return + ed = [[u1,....,u8], element nodal values + [..,....,..]] - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) + Output: - E, A, I, ka, kt = ep + es = [[qx,qy,qz], + [..,..,..]] element flows(s) - qx = 0 - qy = 0 - if eq != None: - qx, qy = eq + et = [[qx,qy,qz], element gradients(s) + [..,..,..]] - K1 = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], - [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], - [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] - ]) + eci = [[ix1,ix1,iz1], location vector + [...,...,...], nint: number of integration points + [ix(nint),iy(nint),iz(nint)]] - K2 = L/420*np.mat([ - [140*ka, 0, 0, 70*ka, 0, 0], - [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], - [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], - [70*ka, 0, 0, 140*ka, 0, 0], - [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], - [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] - ]) + """ + ir = ep[0] + ngp = ir*ir*ir - Kle = K1+K2 - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + if ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-1, -1, -1], + [1, -1, -1], + [1, 1, -1], + [-1, 1, -1], + [-1, -1, 1], + [1, -1, 1], + [1, 1, 1], + [-1, 1, 1] + ])*g1 + w = np.mat(np.ones((8, 3)))*w1 + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat(np.zeros((27, 3))) + w = np.mat(np.zeros((27, 3))) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) + gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] + I1 = abs(I1) + I2 = abs(I2) + w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) + gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] + I1 = abs(I1) + I2 = abs(I2) + w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) + I3 = abs(I1) + gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 + gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] + w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 + w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] + else: + info("Used number of integration points not implemented") + return - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) - P = Kle*G*np.asmatrix(ed).T-fle + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 - es = np.mat([ - [-P[0, 0], -P[1, 0], -P[2, 0]], - [P[3, 0], P[4, 0], P[5, 0]] - ]) + N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1+zet))/8., axis=1) - return es + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) + dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) + dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) + dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) + dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) + dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) + dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) + dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) + dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) + dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) + dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) + dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) + dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) + dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) + dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) + dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) + dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) + dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) + dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) + dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) + dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) + dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) + dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) + dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) + dNr = dNr/8. + + eci = N*np.mat([ex, ey, ez]).T + if ed.ndim == 1: + ed = np.array([ed]) + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey, ez]).T + + es = np.mat(np.zeros((ngp*red, 3))) + et = np.mat(np.zeros((ngp*red, 3))) + for i in range(ngp): + indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminanten lika med noll!") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + + return es, et, eci -def beam2g(ex, ey, ep, N, eq=None): +def plante(ex, ey, ep, D, eq=None): """ - Compute the element stiffness matrix for a two dimensional - beam element with respect to geometric nonlinearity. + Calculate the stiffness matrix for a triangular plane stress or plane strain element. Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - - ep = [E,A,I] element properties; - E: Young's modulus - A: cross section area - I: moment of inertia + + ex = [x1,x2,x3] element coordinates + ey = [y1,y2,y3] + + ep = [ptype,t] ptype: analysis type + t: thickness + + D constitutive matrix + + eq = [[bx], bx: body force x-dir + [by]] by: body force y-dir + + Returns: + + Ke element stiffness matrix (6 x 6) + fe equivalent nodal forces (6 x 1) (if eq is given) - N axial force in the beam + """ - eq distributed transverse load + ptype, t = ep - Returns: + bx = 0.0 + by = 0.0 - Ke element stiffness matrix (6 x 6) - - fe element load vector (6 x 1) - """ - if eq != None: - if np.size(eq) > 1: - error("eq should be a scalar !!!") - return - else: - q = eq[0] - else: - q = 0 + if not eq is None: + bx = eq[0] + by = eq[1] - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) - E, A, I = ep + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) - rho = -N*L**2/(np.pi**2*E*I) + # --------- plane stress -------------------------------------- - kL = np.pi*np.sqrt(abs(rho))+np.finfo(float).eps + if ptype == 1: + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) - if rho > 0: - f1 = (kL/2)/np.tan(kL/2) - f2 = (1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) - elif rho < 0: - f1 = (kL/2)/np.tanh(kL/2) - f2 = -(1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) - else: - f1 = f2 = f3 = f4 = f5 = h = 1 + colD = D.shape[1] - Kle = np.mat([ - [E*A/L, 0., 0., -E*A/L, 0., 0.], - [0., 12*E*I*f5/L**3., 6*E*I*f2/L**2., - 0., -12*E*I*f5/L**3., 6*E*I*f2/L**2.], - [0., 6*E*I*f2/L**2., 4*E*I*f3/L, - 0., -6*E*I*f2/L**2., 2*E*I*f4/L], - [-E*A/L, 0., 0., E*A/L, 0., 0.], - [0., -12*E*I*f5/L**3., -6*E*I*f2/L**2., - 0., 12*E*I*f5/L**3., -6*E*I*f2/L**2.], - [0., 6*E*I*f2/L**2., 2*E*I*f4/L, - 0., -6*E*I*f2/L**2., 4*E*I*f3/L] - ]) + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) + else: + Dm = D - fle = q*L*np.mat([0., 1/2., L*h/12, 0., 1/2., -L*h/12]).T + Ke = B.T*Dm*B*A*t + fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + if eq is None: + return Ke + else: + return Ke, fe.T - Ke = G.T*Kle*G - fe = G.T*fle - - if eq != None: - return Ke, fe - else: - return Ke - - -def beam2gs(ex, ey, ep, ed, N, eq=None): - """ - Calculate section forces in a two dimensional nonlinear - beam element. - - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates + #--------- plane strain -------------------------------------- - ep = [E,A,I] element properties; - E: Young's modulus - A: cross section area - I: moment of inertia + elif ptype == 2: + B = np.mat([ + [0, 1, 0, 0, 0, 0, ], + [0, 0, 0, 0, 0, 1, ], + [0, 0, 1, 0, 1, 0, ] + ])*np.linalg.inv(C) - ed = [u1, ... ,u6] element displacement vector + colD = D.shape[1] - N axial force + if colD > 3: + Dm = D[np.ix_((0, 1, 3), (0, 1, 3))] + else: + Dm = D - eq = [qy] distributed transverse load + Ke = B.T*Dm*B*A*t + fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t - Returns: + if eq == None: + return Ke + else: + return Ke, fe.T - es = [[N1,V1,M1], element forces, local directions - [N2,V2,M2]] - """ - if eq != None: - eq = eq[0] else: - eq = 0 + info("Error ! Check first argument, ptype=1 or 2 allowed") + if eq == None: + return None + else: + return None, None - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) - E, A, I = ep +def plants(ex, ey, ep, D, ed): + """ + Calculate element normal and shear stress for a + triangular plane stress or plane strain element. + + INPUT: ex = [x1 x2 x3] element coordinates + ey = [y1 y2 y3] + + ep = [ptype t ] ptype: analysis type + t: thickness + + D constitutive matrix + + ed =[u1 u2 ...u6 element displacement vector + ...... ] one row for each element + + OUTPUT: es = [ sigx sigy [sigz] tauxy element stress matrix + ...... ] one row for each element + + et = [ epsx epsy [epsz] gamxy element strain matrix + ...... ] one row for each element + """ - rho = -N*L**2/(np.pi**2*E*I) + ptype = ep[0] - eps = 2.2204e-16 - kL = np.pi*np.sqrt(abs(rho))+eps + if np.ndim(ex) == 1: + ex = np.array([ex]) + if np.ndim(ey) == 1: + ey = np.array([ey]) + if np.ndim(ed) == 1: + ed = np.array([ed]) - if rho > 0: - f1 = (kL/2)/np.tan(kL/2) - f2 = (1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) - elif rho < 0: - f1 = (kL/2)/np.tanh(kL/2) - f2 = -(1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) - else: - f1 = f2 = f3 = f4 = f5 = h = 1 + rowed = ed.shape[0] + rowex = ex.shape[0] - Kle = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I*f5/L**3, 6*E*I*f2/L**2, - 0, -12*E*I*f5/L**3, 6*E*I*f2/L**2], - [0, 6*E*I*f2/L**2, 4*E*I*f3/L, 0, -6*E*I*f2/L**2, 2*E*I*f4/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I*f5/L**3, -6*E*I*f2/L**2, - 0, 12*E*I*f5/L**3, -6*E*I*f2/L**2], - [0, 6*E*I*f2/L**2, 2*E*I*f4/L, 0, -6*E*I*f2/L**2, 4*E*I*f3/L] - ]) + # --------- plane stress -------------------------------------- - fle = eq*L*np.mat([0, 1/2., L*h/12, 0, 1/2., -L*h/12]).T + if ptype == 1: - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + colD = D.shape[1] - u = np.asmatrix(ed).T - P = Kle*G*u-fle + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) + else: + Dm = D - es = np.mat([ - [-P[0, 0], -P[1, 0], -P[2, 0]], - [P[3, 0], P[4, 0], P[5, 0]] - ]) + incie = 0 - return es + if rowex == 1: + incie = 0 + else: + incie = 1 + et = np.zeros([rowed, colD]) + es = np.zeros([rowed, colD]) -def beam2d(ex, ey, ep): - """ - Calculate the stiffness matrix Ke, the mass matrix Me - and the damping matrix Ce for a 2D elastic Bernoulli - beam element. + ie = 0 - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates + for i in range(rowed): + C = np.matrix( + [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], + [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], + [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] + ) - ep = [E,A,I,m,(a,b)] element properties; - E: Young's modulus - A: cross section area - I: moment of inertia - m: mass per unit length - a,b: damping coefficients, - Ce=aMe+bKe + B = np.matrix([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) - Returns: + ee = B*np.asmatrix(ed[ie, :]).T - Ke element stiffness matrix (6 x 6) - Me element mass martix - Ce element damping matrix, optional - """ - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) + if colD > 3: + ss = np.zeros([colD, 1]) + ss[[0, 1, 3]] = Dm*ee + ee = Cm*ss + else: + ss = Dm*ee - a = 0 - b = 0 - if np.size(ep) == 4: - E, A, I, m = ep - elif np.size(ep) == 6: - E, A, I, m, a, b = ep + et[ie, :] = ee.T + es[ie, :] = ss.T - Kle = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], - [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], - [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] - ]) + ie = ie + incie - Mle = m*L/420*np.mat([ - [140, 0, 0, 70, 0, 0], - [0, 156, 22*L, 0, 54, -13*L], - [0, 22*L, 4*L**2, 0, 13*L, -3*L**2], - [70, 0, 0, 140, 0, 0], - [0, 54, 13*L, 0, 156, -22*L], - [0, -13*L, -3*L**2, 0, -22*L, 4*L**2] - ]) + return es, et - Cle = a*Mle+b*Kle + # --------- plane strain -------------------------------------- + elif ptype == 2: # Implementation by LAPM + colD = D.shape[1] + incie = 0 - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + if rowex == 1: + incie = 0 + else: + incie = 1 - Ke = G.T*Kle*G - Me = G.T*Mle*G - Ce = G.T*Cle*G + et = np.zeros([rowed, colD]) + es = np.zeros([rowed, colD]) - if np.size(ep) == 4: - return Ke, Me - elif np.size(ep) == 6: - return Ke, Me, Ce + ie = 0 + ee = np.zeros([colD, 1]) -def beam3e(ex, ey, ez, eo, ep, eq=None): - """ - Calculate the stiffness matrix for a 3D elastic Bernoulli - beam element. - - Parameters: - - ex = [x1 x2] - ey = [y1 y2] - ez = [z1 z2] element node coordinates - - eo = [xz yz zz] orientation of local z axis - - ep = [E G A Iy Iz Kv] element properties - E: Young's modulus - G: Shear modulus - A: Cross section area - Iy: Moment of inertia, local y-axis - Iz: Moment of inertia, local z-axis - Kv: Saint-Venant's torsion constant - - eq = [qx qy qz qw] distributed loads + for i in range(rowed): + C = np.matrix( + [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], + [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], + [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] + ) - Returns: + B = np.matrix([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) - Ke beam stiffness matrix (12 x 12) + e = B*np.asmatrix(ed[ie, :]).T - fe equivalent nodal forces (12 x 1) + if colD > 3: + ee[[0, 1, 3]] = e + else: + ee = e + + et[ie, :] = ee.T + es[ie, :] = (D*ee).T + + ie = ie + incie + + return es, et + + else: + print("Error ! Check first argument, ptype=1 or 2 allowed") + return None + +def plantf(ex, ey, ep, es): """ - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() - n1 = np.asarray(b.T/L).reshape(3,) + Compute internal element force vector in a triangular element + in plane stress or plane strain. - eo = np.asmatrix(eo) - lc = np.sqrt(eo*eo.T).item() - n3 = np.asarray(eo/lc).reshape(3,) + Parameters: - E, Gs, A, Iy, Iz, Kv = ep + ex = [x1,x2,x3] node coordinates + ey = [y1,y2,y3] - qx = 0. - qy = 0. - qz = 0. - qw = 0. - if eq != None: - qx, qy, qz, qw = eq + ep = [ptype,t] ptype: analysis type + t: thickness - a = E*A/L - b = 12*E*Iz/L**3 - c = 6*E*Iz/L**2 - d = 12*E*Iy/L**3 - e = 6*E*Iy/L**2 - f = Gs*Kv/L - g = 2*E*Iy/L - h = 2*E*Iz/L + es = [[sigx,sigy,[sigz],tauxy] element stress matrix + [ ...... ]] one row for each element - Kle = np.mat([ - [a, 0, 0, 0, 0, 0, -a, 0, 0, 0, 0, 0], - [0, b, 0, 0, 0, c, 0, -b, 0, 0, 0, c], - [0, 0, d, 0, -e, 0, 0, 0, -d, 0, -e, 0], - [0, 0, 0, f, 0, 0, 0, 0, 0, -f, 0, 0], - [0, 0, -e, 0, 2*g, 0, 0, 0, e, 0, g, 0], - [0, c, 0, 0, 0, 2*h, 0, -c, 0, 0, 0, h], - [-a, 0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0], - [0, -b, 0, 0, 0, -c, 0, b, 0, 0, 0, -c], - [0, 0, -d, 0, e, 0, 0, 0, d, 0, e, 0], - [0, 0, 0, -f, 0, 0, 0, 0, 0, f, 0, 0], - [0, 0, -e, 0, g, 0, 0, 0, e, 0, 2*g, 0], - [0, c, 0, 0, 0, h, 0, -c, 0, 0, 0, 2*h] - ]) + OUTPUT: - fle = L/2*np.mat([qx, qy, qz, qw, -qz*L/6, qy*L/6, - qx, qy, qz, qw, qz*L/6, -qy*L/6]).T + fe = [[f1],[f2],...,[f8]] internal force vector - n2 = np.array([0., 0., 0.]) - n2[0] = n3[1]*n1[2]-n3[2]*n1[1] - n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] - n2[2] = n3[0]*n1[1]-n1[0]*n3[1] + """ - #An = np.append([n1,n2],[n3],0) + ptype, t = ep - G = np.mat([ - [n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], - [n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], - [n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0], - [0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0], - [0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2]], - [0, 0, 0, 0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2]], - [0, 0, 0, 0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2]] - ]) + colD = es.shape[1] - Ke = G.T*Kle*G - fe = G.T*fle + #--------- plane stress -------------------------------------- - if eq == None: - return Ke - else: - return Ke, fe + if ptype == 1: + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) -def beam3s(ex, ey, ez, eo, ep, ed, eq=None, n=None): - """ - Calculate the variation of the section forces and displacements - along a three-dimensional beam element. - - Parameters: - - ex = [x1 x2] element node coordinates - ey = [y1 y2] - ez = [z1 z2] + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) - eo = [xz yz zz] orientation of local z axis - - ep = [E G A Iy Iz Kv] element properties - E: Young's modulus - G: Shear modulus - A: Cross section area - Iy: Moment of inertia, local y-axis - Iz: Moment of inertia, local z-axis - Kv: Saint-Venant's torsion constant + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) - ed the element displacement vector from the - global coordinate system - - eq = [qx qy qz qw] the disibuted axial, transversal and - torsional loads + if colD > 3: + stress = np.asmatrix(es[np.ix_((0, 1, 3))]) + else: + stress = np.asmatrix(es) - n the number of point in which displacements - and section forces are to be computed + ef = (A*t*B.T*stress.T).T - Returns: + return np.reshape(np.asarray(ef), 6) - es = [[N1,Vy1,Vz1,T1,My1,Mz1], section forces in n points along - [N2,Vy2,Vz2,T2,My2,Mz2], the local x-axis - [..,...,...,..,...,...], - [Nn,Vyn,Vzn,Tn,Myn,Mzn]] + #--------- plane strain -------------------------------------- - edi = [[u1,v1,w1,fi1], displacements in n points along - [u2,v2,w2,fi2], the local x-axis - [..,..,..,...], - [un,vn,wn,fin]] + elif ptype == 2: - eci = [[x1], local x-coordinates of the evaluation - [x2], points - [..], - [xn]] + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) - """ - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() - n1 = np.asarray(b.T/L).reshape(3,) + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) - eo = np.asmatrix(eo) - lc = np.sqrt(eo*eo.T).item() - n3 = np.asarray(eo/lc).reshape(3,) + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) - EA = ep[0]*ep[2] - EIy = ep[0]*ep[3] - EIz = ep[0]*ep[4] - GKv = ep[1]*ep[5] + if colD > 3: + stress = np.asmatrix(es[np.ix_((1, 2, 4))]) + else: + stress = np.asmatrix(es) - qx = 0. - qy = 0. - qz = 0. - qw = 0. - if eq != None: - qx, qy, qz, qw = eq + ef = (A*t*B.T*stress.T).T - ne = 2 - if n != None: - ne = n + return np.reshape(np.asarray(ef), 6) - n2 = np.array([0., 0., 0.]) - n2[0] = n3[1]*n1[2]-n3[2]*n1[1] - n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] - n2[2] = n3[0]*n1[1]-n1[0]*n3[1] + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + return None - G = np.mat([ - [n1[0], n1[1], n1[2], 0, 0, 0, - 0, 0, 0, 0, 0, 0], - [n2[0], n2[1], n2[2], 0, 0, 0, - 0, 0, 0, 0, 0, 0], - [n3[0], n3[1], n3[2], 0, 0, 0, - 0, 0, 0, 0, 0, 0], - [0, 0, 0, n1[0], n1[1], n1[2], - 0, 0, 0, 0, 0, 0], - [0, 0, 0, n2[0], n2[1], n2[2], - 0, 0, 0, 0, 0, 0], - [0, 0, 0, n3[0], n3[1], n3[2], - 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, - n1[0], n1[1], n1[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, - n2[0], n2[1], n2[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, - n3[0], n3[1], n3[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, - 0, 0, n1[0], n1[1], n1[2]], - [0, 0, 0, 0, 0, 0, 0, - 0, 0, n2[0], n2[1], n2[2]], - [0, 0, 0, 0, 0, 0, - 0, 0, 0, n3[0], n3[1], n3[2]] - ]) - u = G*np.asmatrix(ed).T-np.array([ # u is the local element displacement - [0], # vector minus the particular solution - [0], # to the beam's diff.eq:s - [0], - [0], - [0], - [0], - [-qx*L**2/(2*EA)], - [qy*L**4/(24*EIz)], - [qz*L**4/(24*EIy)], - [-qw*L**2/(2*GKv)], - [-qz*L**3/(6*EIy)], - [qy*L**3/(6*EIz)] - ]) +def platre(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a rectangular plate element. + NOTE! Element sides must be parallel to the coordinate axis. + + Parameters: - C = np.mat([ - [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], - [L, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], - [0, 0, L**3, L**2, L, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, L**3, L**2, L, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L, 1], - [0, 0, 0, 0, 0, 0, -3*L**2, -2*L, -1, 0, 0, 0], - [0, 0, 3*L**2, 2*L, 1, 0, 0, 0, 0, 0, 0, 0], - ]) + ex = [x1,x2,x3,x4] element coordinates + ey = [y1,y2,y3,y4] - m = np.linalg.inv(C)*u - eci = np.zeros((ne, 1)) - es = np.zeros((ne, 6)) - edi = np.zeros((ne, 4)) - for i in np.arange(ne): - x = i*L/(ne-1) - eci[i, 0] = x - es[i, :] = (np.mat([ - [EA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, -6*EIz, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, -6*EIy, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GKv, 0], - [0, 0, 0, 0, 0, 0, -6*EIy*x, -2*EIy, 0, 0, 0, 0], - [0, 0, 6*EIz*x, 2*EIz, 0, 0, 0, 0, 0, 0, 0, 0] - ])*m+np.array([-qx*x, -qy*x, -qz*x, -qw*x, -qz*x**2/2, qy*x**2/2]).reshape(6, 1)).T + ep = [t] thicknes - edi[i, :] = (np.mat([ - [x, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, x**3, x**2, x, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, x**3, x**2, x, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x, 1] - ])*m+np.array([-qx*x**2/(2*EA), qy*x**4/(24*EIz), qz*x**4/(24*EIy), -qw*x**2/(2*GKv)]).reshape(4, 1)).T + D constitutive matrix for + plane stress - if n == None: - return es + eq = [qz] load/unit area + Returns: + + Ke element stiffness matrix (12 x 12) + fe equivalent nodal forces (12 x 1) + + """ + Lx = (ex[2]-ex[0]).astype(float) + Ly = (ey[2]-ey[0]).astype(float) + t = ep[0] + + D = t**3/12.*D + + A1 = Ly/(Lx**3) + A2 = Lx/(Ly**3) + A3 = 1/Lx/Ly + A4 = Ly/(Lx**2) + A5 = Lx/(Ly**2) + A6 = 1/Lx + A7 = 1/Ly + A8 = Ly/Lx + A9 = Lx/Ly + + C1 = 4*A1*D[0, 0]+4*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] + C2 = -4*A1*D[0, 0]+2*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] + C3 = 2*A1*D[0, 0]-4*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] + C4 = -2*A1*D[0, 0]-2*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] + C5 = 2*A5*D[1, 1]+A6*D[0, 1]+0.4*A6*D[2, 2] + C6 = 2*A4*D[0, 0]+A7*D[0, 1]+0.4*A7*D[2, 2] + + C7 = 2*A5*D[1, 1]+0.4*A6*D[2, 2] + C8 = 2*A4*D[0, 0]+0.4*A7*D[2, 2] + C9 = A5*D[1, 1]-A6*D[0, 1]-0.4*A6*D[2, 2] + C10 = A4*D[0, 0]-A7*D[0, 1]-0.4*A7*D[2, 2] + C11 = A5*D[1, 1]-0.4*A6*D[2, 2] + C12 = A4*D[0, 0]-0.4*A7*D[2, 2] + + C13 = 4/3.*A9*D[1, 1]+8/15.*A8*D[2, 2] + C14 = 4/3.*A8*D[0, 0]+8/15.*A9*D[2, 2] + C15 = 2/3.*A9*D[1, 1]-8/15.*A8*D[2, 2] + C16 = 2/3.*A8*D[0, 0]-8/15.*A9*D[2, 2] + C17 = 2/3.*A9*D[1, 1]-2/15.*A8*D[2, 2] + C18 = 2/3.*A8*D[0, 0]-2/15.*A9*D[2, 2] + C19 = 1/3.*A9*D[1, 1]+2/15.*A8*D[2, 2] + C20 = 1/3.*A8*D[0, 0]+2/15.*A9*D[2, 2] + C21 = D[0, 1] + + Keq = np.mat(np.zeros((12, 12))) + Keq[0, 0:13] = C1, C5, -C6, C2, C9, -C8, C4, C11, -C12, C3, C7, -C10 + Keq[1, 1:13] = C13, -C21, C9, C15, 0, -C11, C19, 0, -C7, C17, 0 + Keq[2, 2:13] = C14, C8, 0, C18, C12, 0, C20, -C10, 0, C16 + Keq[3, 3:13] = C1, C5, C6, C3, C7, C10, C4, C11, C12 + Keq[4, 4:13] = C13, C21, -C7, C17, 0, -C11, C19, 0 + Keq[5, 5:13] = C14, C10, 0, C16, -C12, 0, C20 + Keq[6, 6:13] = C1, -C5, C6, C2, -C9, C8 + Keq[7, 7:13] = C13, -C21, -C9, C15, 0 + Keq[8, 8:13] = C14, -C8, 0, C18 + Keq[9, 9:13] = C1, -C5, -C6 + Keq[10, 10:13] = C13, C21 + Keq[11, 11] = C14 + Keq = Keq.T+Keq-np.diag(np.diag(Keq)) + + if eq != None: + q = eq + R1 = q*Lx*Ly/4 + R2 = q*Lx*Ly**2/24 + R3 = q*Ly*Lx**2/24 + + feq = np.mat([R1, R2, -R3, R1, R2, R3, R1, -R2, R3, R1, -R2, -R3]) + + if eq != None: + return Keq, feq else: - return es, edi, eci + return Keq -def flw2te(ex, ey, ep, D, eq=None): +def planqe(ex, ey, ep, D, eq=None): """ - Compute element stiffness (conductivity) matrix for a triangular field element. - + Calculate the stiffness matrix for a quadrilateral + plane stress or plane strain element. + Parameters: - - ex = [x1 x2 x3] - ey = [y1 y2 y3] element coordinates - - ep = [t] element thickness + ex=[x1 x2 x3 x4] element coordinates + ey=[y1 y2 y3 y4] + + ep = [ptype, t] ptype: analysis type + t: element thickness - D = [kxx kxy; - kyx kyy] constitutive matrix - - eq heat supply per unit volume - - Returns: - - Ke element 'stiffness' matrix (3 x 3) + D constitutive matrix - fe element load vector (3 x 1) - + eq = [bx; bx: body force in x direction + by] by: body force in y direction + + OUTPUT: Ke : element stiffness matrix (8 x 8) + fe : equivalent nodal forces (row array) """ - t = ep[0] - if eq == None: - eq = 0. + K = np.zeros((10, 10)) + f = np.zeros((10, 1)) - exm = np.asmatrix(ex) - eym = np.asmatrix(ey) - C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) - B = np.matrix([ - [0., 1., 0.], - [0., 0., 1.] - ])*C.I - A = 0.5*np.linalg.det(C) + xm = sum(ex)/4. + ym = sum(ey)/4. - Ke = B.T*D*B*t*A - fe = np.matrix([[1., 1., 1.]]).T*eq*A*t/3 + b1 = eq if eq is not None else np.array([[0], [0]]) - if eq == 0.: + ke1, fe1 = plante(np.array([ex[0], ex[1], xm]), + np.array([ey[0], ey[1], ym]), ep, D, b1) + K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[1], ex[2], xm]), + np.array([ey[1], ey[2], ym]), ep, D, b1) + K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[2], ex[3], xm]), + np.array([ey[2], ey[3], ym]), ep, D, b1) + K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[3], ex[0], xm]), + np.array([ey[3], ey[0], ym]), ep, D, b1) + K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) + Ke, fe = statcon(K, f, np.array([[9], [10]])) + + if eq == None: return Ke else: return Ke, fe -def flw2ts(ex, ey, D, ed): +def planqs(ex, ey, ep, D, ed, eq=None): """ - Compute flows or corresponding quantities in the triangular field element. + Calculate element normal and shear stress for a quadrilateral + plane stress or plane strain element. Parameters: + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] - ex = [x1 x2 x3] - ey = [y1 y2 y3] element coordinates - - D = [kxx kxy - kyx kyy] constitutive matrix - - ed =[u1 u2 u3] u1,u2,u3: nodal values - .. .. ..; - - Returns: + ep = [ptype, t] ptype: analysis type + t: thickness + + D constitutive matrix - es=[ qx qy ] - ... ..] element flows + ed = [u1 u2 ..u8] element displacement vector - et=[ gx gy ] - ... ..] element gradients + eq = [[bx] bx: body force in x direction + [by]] by: body force in y direction + OUTPUT: es = [ sigx sigy (sigz) tauxy] element stress array + et = [ epsx epsy (epsz) gamxy] element strain array """ - if len(ex.shape) > 1: - qs = np.zeros([ex.shape[0], 2]) - qt = np.zeros([ex.shape[0], 2]) - row = 0 - for exr, eyr, edr in zip(ex, ey, ed): - exm = np.asmatrix(exr) - eym = np.asmatrix(eyr) - edm = np.asmatrix(edr) - C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) - B = np.matrix([ - [0., 1., 0.], - [0., 0., 1.] - ])*C.I - - qs[row, :] = (-D*B*edm.T).T - qt[row, :] = (B*edm.T).T - row += 1 - - return qs, qt - else: - exm = np.asmatrix(ex) - eym = np.asmatrix(ey) - edm = np.asmatrix(ed) - C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) - B = np.matrix([ - [0., 1., 0.], - [0., 0., 1.] - ])*C.I - - qs = -D*B*edm.T - qt = B*edm.T - - return qs.T, qt.T - - -def flw2qe(ex, ey, ep, D, eq=None): - """ - Compute element stiffness (conductivity) matrix for a triangular field element. - - Parameters: - - ex = [x1, x2, x3, x4] - ey = [y1, y2, y3, y4] element coordinates - - ep = [t] element thickness - - D = [[kxx, kxy], - [kyx, kyy]] constitutive matrix - - eq heat supply per unit volume - - Returns: - - Ke element 'stiffness' matrix (4 x 4) - - fe element load vector (4 x 1) - - """ - xc = sum(ex)/4. - yc = sum(ey)/4. - - K = np.zeros((5, 5)) - f = np.zeros((5, 1)) - - if eq == None: - k1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D) - K = assem(np.array([1, 2, 5]), K, k1) - k1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D) - K = assem(np.array([2, 3, 5]), K, k1) - k1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D) - K = assem(np.array([3, 4, 5]), K, k1) - k1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D) - K = assem(np.array([4, 1, 5]), K, k1) - else: - k1, f1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D, eq) - K, f = assem(np.array([1, 2, 5]), K, k1, f, f1) - k1, f1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D, eq) - K, f = assem(np.array([2, 3, 5]), K, k1, f, f1) - k1, f1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D, eq) - K, f = assem(np.array([3, 4, 5]), K, k1, f, f1) - k1, f1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D, eq) - K, f = assem(np.array([4, 1, 5]), K, k1, f, f1) - Ke1, fe1 = statcon(K, f, np.array([5])) - - Ke = Ke1 - fe = fe1 - - if eq == None: - return Ke - else: - return Ke, fe - - -def flw2qs(ex, ey, ep, D, ed, eq=None): - """ - Compute flows or corresponding quantities in the - quadrilateral field element. - - Parameters: - - ex = [x1, x2, x3, x4] - ey = [y1, y2, y3, y4] element coordinates - - ep = [t] element thickness - - D = [[kxx, kxy], - [kyx, kyy]] constitutive matrix - - ed = [[u1, u2, u3, u4], - [.., .., .., ..]] u1,u2,u3,u4: nodal values - - eq heat supply per unit volume - - Returns: - - es = [[qx, qy], - [.., ..]] element flows + if ex.shape != (4,) or ey.shape != (4,) or ed.shape != (8,): + raise ValueError( + 'Error ! PLANQS: only one element at the time (ex, ey, ed must be a row arrays)') - et = [[gx, gy], - [.., ..]] element gradients - - """ - K = np.zeros((5, 5)) - f = np.zeros((5, 1)) + K = np.zeros((10, 10)) + f = np.zeros((10, 1)) - xm = sum(ex)/4 - ym = sum(ey)/4 + xm = sum(ex)/4. + ym = sum(ey)/4. - if eq == None: - q = 0 - else: - q = eq + b1 = eq if eq is not None else np.array([[0], [0]]) - En = np.array([ - [1, 2, 5], - [2, 3, 5], - [3, 4, 5], - [4, 1, 5] - ]) ex1 = np.array([ex[0], ex[1], xm]) ey1 = np.array([ey[0], ey[1], ym]) ex2 = np.array([ex[1], ex[2], xm]) @@ -1741,77 +1725,81 @@ def flw2qs(ex, ey, ep, D, ed, eq=None): ex4 = np.array([ex[3], ex[0], xm]) ey4 = np.array([ey[3], ey[0], ym]) - if eq == None: - k1 = flw2te(ex1, ey1, ep, D) - K = assem(En[0], K, k1) - k1 = flw2te(ex2, ey2, ep, D) - K = assem(En[1], K, k1) - k1 = flw2te(ex3, ey3, ep, D) - K = assem(En[2], K, k1) - k1 = flw2te(ex4, ey4, ep, D) - K = assem(En[3], K, k1) - else: - k1, f1 = flw2te(ex1, ey1, ep, D, q) - K, f = assem(En[0], K, k1, f, f1) - k1, f1 = flw2te(ex2, ey2, ep, D, q) - K, f = assem(En[1], K, k1, f, f1) - k1, f1 = flw2te(ex3, ey3, ep, D, q) - K, f = assem(En[2], K, k1, f, f1) - k1, f1 = flw2te(ex4, ey4, ep, D, q) - K, f = assem(En[3], K, k1, f, f1) + ke1, fe1 = plante(ex1, ey1, ep, D, b1) + K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex2, ey2, ep, D, b1) + K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex3, ey3, ep, D, b1) + K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex4, ey4, ep, D, b1) + K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) - if ed.ndim == 1: - ed = np.array([ed]) + A1 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex1).T, np.mat(ey1).T])) + A2 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex2).T, np.mat(ey2).T])) + A3 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex3).T, np.mat(ey3).T])) + A4 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex4).T, np.mat(ey4).T])) + Atot = A1+A2+A3+A4 - ni, nj = np.shape(ed) + a, _ = solveq(K, f, np.array(range(1, 9)), ed) - a = np.zeros((5, ni)) - for i in range(ni): - a[np.ix_(range(5), [i])], r = np.asarray( - solveq(K, f, np.arange(1, 5), ed[i])) +# ni = ed.shape[0] +# a = np.mat(empty((10,ni))) +# for i in range(ni): +# a[:,i] = solveq(K, f, np.array(range(1,9)), ed[i,:])[0] +# #a = np.hstack([a, solveq(K, f, np.hstack([matrix(range(1,9)).T, ed[i,:].T]) ) ]) - s1, t1 = flw2ts(ex1, ey1, D, a[np.ix_(En[0, :]-1, np.arange(ni))].T) - s2, t2 = flw2ts(ex2, ey2, D, a[np.ix_(En[1, :]-1, np.arange(ni))].T) - s3, t3 = flw2ts(ex3, ey3, D, a[np.ix_(En[2, :]-1, np.arange(ni))].T) - s4, t4 = flw2ts(ex4, ey4, D, a[np.ix_(En[3, :]-1, np.arange(ni))].T) + s1, t1 = plants(ex1, ey1, ep, D, np.hstack([a[[0, 1, 2, 3, 8, 9], :].T])) + s2, t2 = plants(ex2, ey2, ep, D, np.hstack([a[[2, 3, 4, 5, 8, 9], :].T])) + s3, t3 = plants(ex3, ey3, ep, D, np.hstack([a[[4, 5, 6, 7, 8, 9], :].T])) + s4, t4 = plants(ex4, ey4, ep, D, np.hstack([a[[6, 7, 0, 1, 8, 9], :].T])) - es = (s1+s2+s3+s4)/4. - et = (t1+t2+t3+t4)/4. + es = (s1*A1+s2*A2+s3*A3+s4*A4)/Atot + et = (t1*A1+t2*A2+t3*A3+t4*A4)/Atot - return es, et + # [0] because these are 1-by-3 arrays and we want row arrays out. + return es[0], et[0] -def flw2i4e(ex, ey, ep, D, eq=None): +def plani4e(ex, ey, ep, D, eq=None): """ - Compute element stiffness (conductivity) - matrix for 4 node isoparametric field element - + Calculate the stiffness matrix for a 4 node isoparametric + element in plane strain or plane stress. + Parameters: - - ex = [x1 x2 x3 x4] element coordinates - ey = [y1 y2 y3 y4] - - ep = [t ir] thickness and integration rule - - D = [[kxx kxy], - [kyx kyy]] constitutive matrix - - eq heat supply per unit volume - + ex = [x1 ... x4] element coordinates. Row array + ey = [y1 ... y4] + + ep =[ptype, t, ir] ptype: analysis type + t : thickness + ir: integration rule + + D constitutive matrix + + eq = [bx; by] bx: body force in x direction + by: body force in y direction + Any array with 2 elements acceptable + Returns: - Ke element 'stiffness' matrix (4 x 4) - fe element load vector (4 x 1) - + Ke : element stiffness matrix (8 x 8) + fe : equivalent nodal forces (8 x 1) """ - t = ep[0] - ir = ep[1] + ptype = ep[0] + t = ep[1] + ir = ep[2] ngp = ir*ir - if eq == None: - q = 0 + q = np.zeros((2, 1)) else: - q = eq - + q = np.reshape(eq, (2, 1)) +#--------- gauss points -------------------------------------- if ir == 1: g1 = 0.0 w1 = 2.0 @@ -1824,14 +1812,12 @@ def flw2i4e(ex, ey, ep, D, eq=None): [-g1, -g1], [g1, -g1], [-g1, g1], - [g1, g1] - ]) + [g1, g1]]) w = np.mat([ [w1, w1], [w1, w1], [w1, w1], - [w1, w1] - ]) + [w1, w1]]) elif ir == 3: g1 = 0.774596669241483 g2 = 0. @@ -1846,8 +1832,7 @@ def flw2i4e(ex, ey, ep, D, eq=None): [g1, g2], [-g1, g1], [g2, g1], - [g1, g1] - ]) + [g1, g1]]) w = np.mat([ [w1, w1], [w2, w1], @@ -1857,16 +1842,14 @@ def flw2i4e(ex, ey, ep, D, eq=None): [w1, w2], [w1, w1], [w2, w1], - [w1, w1] - ]) + [w1, w1]]) else: - info("Used number of integration points not implemented") + info("Used number of integrat ion points not implemented") wp = np.multiply(w[:, 0], w[:, 1]) - xsi = gp[:, 0] eta = gp[:, 1] r2 = ngp*2 - + # Shape Functions N = np.multiply((1-xsi), (1-eta))/4. N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) @@ -1882,2996 +1865,3019 @@ def flw2i4e(ex, ey, ep, D, eq=None): dNr[1:r2+1:2, 2] = (1+xsi)/4. dNr[1:r2+1:2, 3] = (1-xsi)/4. - Ke1 = np.mat(np.zeros((4, 4))) - fe1 = np.mat(np.zeros((4, 1))) +# + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) JT = dNr*np.mat([ex, ey]).T + # --------- plane stress -------------------------------------- + if ptype == 1: + colD = np.shape(D)[0] + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_([0, 1, 3], [0, 1, 3])]) + else: + Dm = D +# + B = np.matrix(np.zeros((3, 8))) + N2 = np.matrix(np.zeros((2, 8))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant equal or less than zero!") + JTinv = np.linalg.inv(JT[indx-1, :]) + dNx = JTinv*dNr[indx-1, :] +# + index_array_even = np.array([0, 2, 4, 6]) + index_array_odd = np.array([1, 3, 5, 7]) +# + counter = 0 + for index in index_array_even: + B[0, index] = dNx[0, counter] + B[2, index] = dNx[1, counter] + N2[0, index] = N[i, counter] + counter = counter+1 +# + counter = 0 + for index in index_array_odd: + B[1, index] = dNx[1, counter] + B[2, index] = dNx[0, counter] + N2[1, index] = N[i, counter] + counter = counter+1 +# + Ke1 = Ke1+B.T*Dm*B*detJ*wp[i].item()*t + fe1 = fe1 + N2.T * q * detJ * wp[i].item() * t - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinant == 0") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() - fe1 = fe1+N[i, :].T*detJ*wp[i] - - if eq == None: - return Ke1*t + return Ke1, fe1 +#--------- plane strain -------------------------------------- + elif ptype == 2: + # + colD = np.shape(D)[0] + if colD > 3: + Dm = D[np.ix_([0, 1, 3], [0, 1, 3])] + else: + Dm = D +# + B = np.matrix(np.zeros((3, 8))) + N2 = np.matrix(np.zeros((2, 8))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminant equal or less than zero!") + JTinv = np.linalg.inv(JT[indx-1, :]) + dNx = JTinv*dNr[indx-1, :] +# + index_array_even = np.array([0, 2, 4, 6]) + index_array_odd = np.array([1, 3, 5, 7]) +# + counter = 0 + for index in index_array_even: + # + B[0, index] = dNx[0, counter] + B[2, index] = dNx[1, counter] + N2[0, index] = N[i, counter] +# + counter = counter+1 +# + counter = 0 + for index in index_array_odd: + B[1, index] = dNx[1, counter] + B[2, index] = dNx[0, counter] + N2[1, index] = N[i, counter] + counter = counter+1 +# + Ke1 = Ke1 + B.T * Dm * B * detJ * np.asscalar(wp[i]) * t + fe1 = fe1+N2.T*q*detJ*np.asscalar(wp[i])*t + return Ke1, fe1 else: - return Ke1*t, fe1*t*eq + info("Error ! Check first argument, ptype=1 or 2 allowed") -def flw2i4s(ex, ey, ep, D, ed): +def soli8e(ex, ey, ez, ep, D, eqp=None): """ - Compute flows or corresponding quantities in the - 4 node isoparametric element. - - Parameters: - - ex = [x1 x2 x3 x4] element coordinates - ey = [y1 y2 y3 y4] - - ep = [t ir] thickness and integration rule + Ke=soli8e(ex,ey,ez,ep,D) + [Ke,fe]=soli8e(ex,ey,ez,ep,D,eq) + ------------------------------------------------------------- + PURPOSE + Calculate the stiffness matrix for a 8 node (brick) + isoparametric element. - D = [[kxx kxy], - [kyx kyy]] constitutive matrix + INPUT: ex = [x1 x2 x3 ... x8] + ey = [y1 y2 y3 ... y8] element coordinates + ez = [z1 z2 z3 ... z8] - ed = [u1, u2, u3, u4] u1,u2,u3,u4: nodal values + ep = [ir] ir integration rule - Returns: - es = [[qx, qy], - [.., ..]] element flows + D constitutive matrix - et = [[qx, qy], - [... ..]] element gradients + eq = [bx; by; bz] bx: body force in x direction + by: body force in y direction + bz: body force in z direction - eci=[[ix1, iy1], Gauss point location vector - [... ...], nint: number of integration points - [ix(nint), iy(nint)] + OUTPUT: Ke : element stiffness matrix + fe : equivalent nodal forces + ------------------------------------------------------------- + LAST MODIFIED: M Ristinmaa 1995-10-25 + J Lindemann 2022-01-24 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - t = ep[0] - ir = ep[1] - ngp = ir*ir + ir = ep[0] + ngp = ir*ir*ir + + if eqp == None: + eq = np.zeros((3, 1)) + else: + eq = eqp if ir == 1: g1 = 0.0 w1 = 2.0 - gp = np.mat([g1, g1]) - w = np.mat([w1, w1]) + gp = np.array([g1, g1, g1]).reshape(1, 3) + w = np.array([w1, w1, w1]).reshape(1, 3) elif ir == 2: g1 = 0.577350269189626 w1 = 1 - gp = np.mat([ - [-g1, -g1], - [g1, -g1], - [-g1, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w1, w1], - [w1, w1], - [w1, w1] - ]) - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. + gp = np.zeros((8, 3)) + w = np.zeros((8, 3)) + gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 + w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 + w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 + w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + else: + g1 = 0.774596669241483, + g2 = 0.0 w1 = 0.555555555555555 w2 = 0.888888888888888 - gp = np.mat([ - [-g1, -g1], - [-g2, -g1], - [g1, -g1], - [-g1, g2], - [g2, g2], - [g1, g2], - [-g1, g1], - [g2, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w2, w1], - [w1, w1], - [w1, w2], - [w2, w2], - [w1, w2], - [w1, w1], - [w2, w1], - [w1, w1] - ]) - else: - info("Used number of integration points not implemented") - wp = np.multiply(w[:, 0], w[:, 1]) - xsi = gp[:, 0] - eta = gp[:, 1] - r2 = ngp*2 + gp = np.zeros((27, 3)) + w = np.zeros((27, 3)) - N = np.multiply((1-xsi), (1-eta))/4. - N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) - N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) - N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) - dNr = np.mat(np.zeros((r2, 4))) - dNr[0:r2:2, 0] = -(1-eta)/4. - dNr[0:r2:2, 1] = (1-eta)/4. - dNr[0:r2:2, 2] = (1+eta)/4. - dNr[0:r2:2, 3] = -(1+eta)/4. - dNr[1:r2+1:2, 0] = -(1-xsi)/4. - dNr[1:r2+1:2, 1] = -(1+xsi)/4. - dNr[1:r2+1:2, 2] = (1+xsi)/4. - dNr[1:r2+1:2, 3] = (1-xsi)/4. + gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] - eci = N*np.mat([ex, ey]).T - if ed.ndim == 1: - ed = np.array([ed]) + I1 = np.abs(I1) + I2 = np.abs(I2) - red, ced = np.shape(ed) - JT = dNr*np.mat([ex, ey]).T - - es = np.mat(np.zeros((ngp*red, 2))) - et = np.mat(np.zeros((ngp*red, 2))) - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinatn == 0") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - p1 = -D*B*ed.T - p2 = B*ed.T - es[i:ngp*red:ngp, :] = p1.T - et[i:ngp*red:ngp, :] = p2.T - - return es, et, eci + w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) -def flw2i8e(ex, ey, ep, D, eq=None): - """ - Compute element stiffness (conductivity) - matrix for 8 node isoparametric field element. - - Parameters: - - ex = [x1, ..., x8] element coordinates - ey = [y1, ..., y8] - - ep = [t, ir] thickness and integration rule + gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] - D = [[kxx, kxy], - [kyx, kyy]] constitutive matrix + I1 = np.abs(I1) + I2 = np.abs(I2) - eq heat supply per unit volume + w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] - Returns: - - Ke element 'stiffness' matrix (8 x 8) - fe element load vector (8 x 1) + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) + I3 = np.abs(I1) - """ - t = ep[0] - ir = ep[1] - ngp = ir*ir + gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 + gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] - if eq == None: - q = 0 - else: - q = eq + w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 + w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.mat([g1, g1]) - w = np.mat([w1, w1]) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-g1, -g1], - [g1, -g1], - [-g1, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w1, w1], - [w1, w1], - [w1, w1] - ]) - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat([ - [-g1, -g1], - [-g2, -g1], - [g1, -g1], - [-g1, g2], - [g2, g2], - [g1, g2], - [-g1, g1], - [g2, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w2, w1], - [w1, w1], - [w1, w2], - [w2, w2], - [w1, w2], - [w1, w1], - [w2, w1], - [w1, w1] - ]) - else: - info("Used number of integration points not implemented") - wp = np.multiply(w[:, 0], w[:, 1]) + wp = w[:, 0]*w[:, 1]*w[:, 2] xsi = gp[:, 0] eta = gp[:, 1] - r2 = ngp*2 - - N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. - N = np.append(N, np.multiply( - np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) - N = np.append(N, np.multiply( - np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) - N = np.append(N, np.multiply( - np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) - N = np.append(N, np.multiply( - (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) - N = np.append(N, np.multiply( - (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) - N = np.append(N, np.multiply( - (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) - N = np.append(N, np.multiply( - (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) + zet = gp[:, 2] + r2 = ngp*3 - dNr = np.mat(np.zeros((r2, 8))) - dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + - np.multiply((1-xsi), (1-eta)))/4. - dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - - np.multiply((1+xsi), (1-eta)))/4. - dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - - np.multiply((1+xsi), (1+eta)))/4. - dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + - np.multiply((1-xsi), (1+eta)))/4. - dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) - dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. - dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) - dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. - dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + - np.multiply((1-xsi), (1-eta)))/4. - dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + - np.multiply((1+xsi), (1-eta)))/4. - dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - - np.multiply((1+xsi), (1+eta)))/4. - dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - - np.multiply((1-xsi), (1+eta)))/4. - dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. - dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) - dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. - dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) + N = np.zeros((ngp, 8)) + dNr = np.zeros((r2, 8)) - Ke1 = np.mat(np.zeros((8, 8))) - fe1 = np.mat(np.zeros((8, 1))) - JT = dNr*np.mat([ex, ey]).T + N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 + N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 + N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 + N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 + N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 + N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 + N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 + N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobideterminanten lika med noll!") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() - fe1 = fe1+N[i, :].T*detJ*wp[i] + dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) + dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) + dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) + dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) + dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) + dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) + dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) + dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) + dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) + dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) + dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) + dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) + dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) + dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) + dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) + dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) + dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) + dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) + dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) + dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) + dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) + dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) + dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) + dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) - if eq != None: - return Ke1*t, fe1*t*q - else: - return Ke1*t + dNr = dNr/8.0 + Ke = np.zeros((24, 24)) + fe = np.zeros((24, 1)) -def flw2i8s(ex, ey, ep, D, ed): - """ - Compute flows or corresponding quantities in the - 8 node isoparametric element. - - Parameters: - - ex = [x1,x2,x3....,x8] element coordinates - ey = [y1,y2,y3....,y8] + ex = np.asarray(ex).reshape((8, 1)) + ey = np.asarray(ey).reshape((8, 1)) + ez = np.asarray(ez).reshape((8, 1)) - ep = [t,ir] thickness and integration rule + JT = dNr@np.concatenate((ex, ey, ez), axis=1) - D = [[kxx,kxy], - [kyx,kyy]] constitutive matrix + eps = np.finfo(float).eps - ed = [u1,....,u8] u1,....,u8: nodal values + for i in range(ngp): + indx = [i*3, i*3+1, i*3+2] + detJ = np.linalg.det(JT[indx, :]) + if detJ < 10*eps: + print('Jacobideterminant equal or less than zero!') + JTinv = np.linalg.inv(JT[indx, :]) + dNx = JTinv@dNr[indx, :] - Returns: - es = [[qx,qy], - [..,..]] element flows + B = np.zeros((6, 24)) + N2 = np.zeros((3, 24)) - et = [[qx,qy], - [..,..]] element gradients + B[0, 0:24:3] = dNx[0, :] + B[1, 1:25:3] = dNx[1, :] + B[2, 2:26:3] = dNx[2, :] + B[3, 0:24:3] = dNx[1, :] + B[3, 1:25:3] = dNx[0, :] + B[4, 0:24:3] = dNx[2, :] + B[4, 2:26:3] = dNx[0, :] + B[5, 1:25:3] = dNx[2, :] + B[5, 2:26:3] = dNx[1, :] - eci=[[ix1,iy1], Gauss point location vector - [...,...], nint: number of integration points - [ix(nint),iy(nint)]] + N2[0, 0:24:3] = N[i, :] + N2[1, 1:25:3] = N[i, :] + N2[2, 2:26:3] = N[i, :] + Ke = Ke + (np.transpose(B)@D@B)*detJ*wp[i] + fe = fe + (np.transpose(N2)@eq)*detJ*wp[i] + + if eqp != None: + return Ke, fe + else: + return Ke + + +def soli8s(ex, ey, ez, ep, D, ed): + """ + [es,et]=soli8s(ex,ey,ez,ep,D,ed) + ------------------------------------------------------------- + PURPOSE + Calculate element normal and shear stress for a + 8 node (brick) isoparametric element. + + INPUT: ex = [x1 x2 x3 ... x8] + ey = [y1 y2 y3 ... y8] element coordinates + ez = [z1 z2 z3 ... z8] + + ep = [Ir] Ir: integration rule + + D constitutive matrix + + ed = [u1 u2 ..u24] element displacement vector + + OUTPUT: es = [ sigx sigy sigz sigxy sigyz sigxz ; + ...... ... ] + element stress matrix, one row for each + integration point + + es = [ eps epsy epsz epsxy epsyz epsxz ; + ...... ... ] + element strain matrix, one row for each + integration point + ------------------------------------------------------------- + + LAST MODIFIED: M Ristinmaa 1995-10-25 + J Lindemann 2022-02-23 (Python version) + + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - t = ep[0] - ir = ep[1] - ngp = ir*ir + + ir = ep[0] + ngp = ir*ir*ir + + ir = ep[0] + ngp = ir*ir*ir if ir == 1: g1 = 0.0 w1 = 2.0 - gp = np.mat([g1, g1]) - w = np.mat([w1, w1]) + gp = np.array([g1, g1, g1]).reshape(1, 3) + w = np.array([w1, w1, w1]).reshape(1, 3) elif ir == 2: g1 = 0.577350269189626 w1 = 1 - gp = np.mat([ - [-g1, -g1], - [g1, -g1], - [-g1, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w1, w1], - [w1, w1], - [w1, w1] - ]) - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. + gp = np.zeros((8, 3)) + w = np.zeros((8, 3)) + gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 + w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 + w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 + w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + else: + g1 = 0.774596669241483, + g2 = 0.0 w1 = 0.555555555555555 w2 = 0.888888888888888 - gp = np.mat([ - [-g1, -g1], - [-g2, -g1], - [g1, -g1], - [-g1, g2], - [g2, g2], - [g1, g2], - [-g1, g1], - [g2, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w2, w1], - [w1, w1], - [w1, w2], - [w2, w2], - [w1, w2], - [w1, w1], - [w2, w1], - [w1, w1] - ]) - else: - info("Used number of integration points not implemented") - wp = np.multiply(w[:, 0], w[:, 1]) - xsi = gp[:, 0] - eta = gp[:, 1] - r2 = ngp*2 + gp = np.zeros((27, 3)) + w = np.zeros((27, 3)) - N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. - N = np.append(N, np.multiply( - np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) - N = np.append(N, np.multiply( - np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) - N = np.append(N, np.multiply( - np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) - N = np.append(N, np.multiply( - (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) - N = np.append(N, np.multiply( - (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) - N = np.append(N, np.multiply( - (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) - N = np.append(N, np.multiply( - (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) - dNr = np.mat(np.zeros((r2, 8))) - dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + - np.multiply((1-xsi), (1-eta)))/4. - dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - - np.multiply((1+xsi), (1-eta)))/4. - dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - - np.multiply((1+xsi), (1+eta)))/4. - dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + - np.multiply((1-xsi), (1+eta)))/4. - dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) - dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. - dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) - dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. - dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + - np.multiply((1-xsi), (1-eta)))/4. - dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + - np.multiply((1+xsi), (1-eta)))/4. - dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - - np.multiply((1+xsi), (1+eta)))/4. - dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - - np.multiply((1-xsi), (1+eta)))/4. - dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. - dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) - dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. - dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) + gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] - eci = N*np.mat([ex, ey]).T - if ed.ndim == 1: - ed = np.array([ed]) - red, ced = np.shape(ed) - JT = dNr*np.mat([ex, ey]).T + I1 = np.abs(I1) + I2 = np.abs(I2) - es = np.mat(np.zeros((ngp*red, 2))) - et = np.mat(np.zeros((ngp*red, 2))) + w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinant == 0") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - p1 = -D*B*ed.T - p2 = B*ed.T - es[i:ngp*red:ngp, :] = p1.T - et[i:ngp*red:ngp, :] = p2.T + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) - return es, et, eci + gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] + I1 = np.abs(I1) + I2 = np.abs(I2) -def flw3i8e(ex, ey, ez, ep, D, eq=None): - """ - Compute element stiffness (conductivity) - matrix for 8 node isoparametric field element. - - Parameters: - - ex = [x1,x2,x3,...,x8] - ey = [y1,y2,y3,...,y8] element coordinates - ez = [z1,z2,z3,...,z8] + w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] - ep = [ir] Ir: Integration rule + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) + I3 = np.abs(I1) - D = [[kxx,kxy,kxz], - [kyx,kyy,kyz], - [kzx,kzy,kzz]] constitutive matrix + gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 + gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] - eq heat supply per unit volume + w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 + w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] - Output: + wp = w[:, 0]*w[:, 1]*w[:, 2] - Ke element 'stiffness' matrix (8 x 8) - fe element load vector (8 x 1) + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 - """ - ir = ep[0] - ngp = ir*ir*ir + N = np.zeros((ngp, 8)) + dNr = np.zeros((r2, 8)) - if eq == None: - q = 0 - else: - q = eq + N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 + N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 + N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 + N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 + N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 + N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 + N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 + N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 - if ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-1, -1, -1], - [1, -1, -1], - [1, 1, -1], - [-1, 1, -1], - [-1, -1, 1], - [1, -1, 1], - [1, 1, 1], - [-1, 1, 1] - ])*g1 - w = np.mat(np.ones((8, 3)))*w1 - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat(np.zeros((27, 3))) - w = np.mat(np.zeros((27, 3))) - I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) - I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) - gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 - gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] - I1 = abs(I1) - I2 = abs(I2) - w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 - w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] - I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) - I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) - gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 - gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] - I1 = abs(I1) - I2 = abs(I2) - w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 - w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] - I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) - I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) - I3 = abs(I1) - gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 - gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] - w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 - w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] - else: - info("Used number of integration points not implemented") - return + dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) + dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) + dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) + dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) + dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) + dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) + dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) + dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) + dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) + dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) + dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) + dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) + dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) + dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) + dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) + dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) + dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) + dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) + dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) + dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) + dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) + dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) + dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) + dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) - wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) + dNr = dNr/8.0 - xsi = gp[:, 0] - eta = gp[:, 1] - zet = gp[:, 2] - r2 = ngp*3 + ex = np.asarray(ex).reshape((8, 1)) + ey = np.asarray(ey).reshape((8, 1)) + ez = np.asarray(ez).reshape((8, 1)) - N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1-eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1+eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1+eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1-eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1-eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1+eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1+eta)), (1+zet))/8., axis=1) + JT = dNr@np.concatenate((ex, ey, ez), axis=1) - dNr = np.mat(np.zeros((r2, 8))) - dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) - dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) - dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) - dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) - dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) - dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) - dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) - dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) - dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) - dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) - dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) - dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) - dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) - dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) - dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) - dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) - dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) - dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) - dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) - dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) - dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) - dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) - dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) - dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) - dNr = dNr/8. + eps = np.finfo(float).eps + + eci = N@np.concatenate((ex, ey, ez), axis=1) + et = np.zeros((ngp, 6)) + es = np.zeros((ngp, 6)) - Ke1 = np.mat(np.zeros((8, 8))) - fe1 = np.mat(np.zeros((8, 1))) - JT = dNr*np.mat([ex, ey, ez]).T + ed = ed.reshape(1, 24) for i in range(ngp): - indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinant == 0") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() - fe1 = fe1+N[i, :].T*detJ*wp[i] + indx = [i*3, i*3+1, i*3+2] + detJ = np.linalg.det(JT[indx, :]) + if detJ < 10*eps: + print('Jacobideterminant equal or less than zero!') + JTinv = np.linalg.inv(JT[indx, :]) + dNx = JTinv@dNr[indx, :] - if eq != None: - return Ke1, fe1*q + B = np.zeros((6, 24)) + N2 = np.zeros((3, 24)) + + B[0, 0:24:3] = dNx[0, :] + B[1, 1:25:3] = dNx[1, :] + B[2, 2:26:3] = dNx[2, :] + B[3, 0:24:3] = dNx[1, :] + B[3, 1:25:3] = dNx[0, :] + B[4, 0:24:3] = dNx[2, :] + B[4, 2:26:3] = dNx[0, :] + B[5, 1:25:3] = dNx[2, :] + B[5, 2:26:3] = dNx[1, :] + + N2[0, 0:24:3] = N[i, :] + N2[1, 1:25:3] = N[i, :] + N2[2, 2:26:3] = N[i, :] + + # [6x24] x [24,1] + ee = B@np.transpose(ed) + + et[i, :] = ee.reshape(6,) + es[i, :] = (D@ee).reshape(6,) + + return et, es, eci + + +def assem(edof, K, Ke, f=None, fe=None): + """ + Assemble element matrices Ke ( and fe ) into the global + stiffness matrix K ( and the global force vector f ) + according to the topology matrix edof. + + Parameters: + + edof dof topology array + K the global stiffness matrix + Ke element stiffness matrix + f the global force vector + fe element force vector + + Output parameters: + + K the new global stiffness matrix + f the new global force vector + fe element force vector + + """ + + if edof.ndim == 1: + idx = edof-1 + K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke + if (not f is None) and (not fe is None): + f[np.ix_(idx)] = f[np.ix_(idx)] + fe else: - return Ke1 + for row in edof: + idx = row-1 + K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke + if (not f is None) and (not fe is None): + f[np.ix_(idx)] = f[np.ix_(idx)] + fe + + if f is None: + return K + else: + return K, f -def flw3i8s(ex, ey, ez, ep, D, ed): +def solveq(K, f, bcPrescr, bcVal=None): """ - Compute flows or corresponding quantities in the - 8 node (3-dim) isoparametric field element. + Solve static FE-equations considering boundary conditions. Parameters: - ex = [x1,x2,x3,...,x8] - ey = [y1,y2,y3,...,y8] element coordinates - ez = [z1,z2,z3,...,z8] + K global stiffness matrix, dim(K)= nd x nd + f global load vector, dim(f)= nd x 1 + + bcPrescr 1-dim integer array containing prescribed dofs. + bcVal 1-dim float array containing prescribed values. + If not given all prescribed dofs are assumed 0. + + Returns: + + a solution including boundary values + Q reaction force vector + dim(a)=dim(Q)= nd x 1, nd : number of dof's + + """ - ep = [ir] Ir: Integration rule + nDofs = K.shape[0] + nPdofs = bcPrescr.shape[0] - D = [[kxx,kxy,kxz], - [kyx,kyy,kyz], - [kzx,kzy,kzz]] constitutive matrix + if bcVal is None: + bcVal = np.zeros([nPdofs], 'd') - ed = [[u1,....,u8], element nodal values - [..,....,..]] + bc = np.ones(nDofs, 'bool') + bcDofs = np.arange(nDofs) - Output: + bc[np.ix_(bcPrescr-1)] = False + bcDofs = bcDofs[bc] - es = [[qx,qy,qz], - [..,..,..]] element flows(s) + fsys = f[bcDofs]-K[np.ix_((bcDofs), (bcPrescr-1))] * \ + np.asmatrix(bcVal).reshape(nPdofs, 1) + asys = np.linalg.solve(K[np.ix_((bcDofs), (bcDofs))], fsys) - et = [[qx,qy,qz], element gradients(s) - [..,..,..]] + a = np.zeros([nDofs, 1]) + a[np.ix_(bcPrescr-1)] = np.asmatrix(bcVal).reshape(nPdofs, 1) + a[np.ix_(bcDofs)] = asys - eci = [[ix1,ix1,iz1], location vector - [...,...,...], nint: number of integration points - [ix(nint),iy(nint),iz(nint)]] + Q = K*np.asmatrix(a)-f - """ - ir = ep[0] - ngp = ir*ir*ir - - if ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-1, -1, -1], - [1, -1, -1], - [1, 1, -1], - [-1, 1, -1], - [-1, -1, 1], - [1, -1, 1], - [1, 1, 1], - [-1, 1, 1] - ])*g1 - w = np.mat(np.ones((8, 3)))*w1 - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat(np.zeros((27, 3))) - w = np.mat(np.zeros((27, 3))) - I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) - I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) - gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 - gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] - I1 = abs(I1) - I2 = abs(I2) - w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 - w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] - I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) - I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) - gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 - gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] - I1 = abs(I1) - I2 = abs(I2) - w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 - w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] - I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) - I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) - I3 = abs(I1) - gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 - gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] - w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 - w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] - else: - info("Used number of integration points not implemented") - return - - wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) - - xsi = gp[:, 0] - eta = gp[:, 1] - zet = gp[:, 2] - r2 = ngp*3 - - N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1-eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1+eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1+eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1-eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1-eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1+eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1+eta)), (1+zet))/8., axis=1) - - dNr = np.mat(np.zeros((r2, 8))) - dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) - dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) - dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) - dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) - dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) - dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) - dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) - dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) - dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) - dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) - dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) - dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) - dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) - dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) - dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) - dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) - dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) - dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) - dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) - dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) - dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) - dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) - dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) - dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) - dNr = dNr/8. - - eci = N*np.mat([ex, ey, ez]).T - if ed.ndim == 1: - ed = np.array([ed]) - red, ced = np.shape(ed) - JT = dNr*np.mat([ex, ey, ez]).T - - es = np.mat(np.zeros((ngp*red, 3))) - et = np.mat(np.zeros((ngp*red, 3))) - for i in range(ngp): - indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobideterminanten lika med noll!") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - p1 = -D*B*ed.T - p2 = B*ed.T - es[i:ngp*red:ngp, :] = p1.T - et[i:ngp*red:ngp, :] = p2.T - - return es, et, eci + return (np.asmatrix(a), Q) -def plante(ex, ey, ep, D, eq=None): +def spsolveq(K, f, bcPrescr, bcVal=None): """ - Calculate the stiffness matrix for a triangular plane stress or plane strain element. + Solve static FE-equations considering boundary conditions. Parameters: - ex = [x1,x2,x3] element coordinates - ey = [y1,y2,y3] - - ep = [ptype,t] ptype: analysis type - t: thickness - - D constitutive matrix + K global stiffness matrix, dim(K)= nd x nd + f global load vector, dim(f)= nd x 1 - eq = [[bx], bx: body force x-dir - [by]] by: body force y-dir - + bcPrescr 1-dim integer array containing prescribed dofs. + bcVal 1-dim float array containing prescribed values. + If not given all prescribed dofs are assumed 0. + Returns: - Ke element stiffness matrix (6 x 6) - fe equivalent nodal forces (6 x 1) (if eq is given) - + a solution including boundary values + Q reaction force vector + dim(a)=dim(Q)= nd x 1, nd : number of dof's + """ - ptype, t = ep - - bx = 0.0 - by = 0.0 - - if not eq is None: - bx = eq[0] - by = eq[1] - - C = np.mat([ - [1, ex[0], ey[0], 0, 0, 0], - [0, 0, 0, 1, ex[0], ey[0]], - [1, ex[1], ey[1], 0, 0, 0], - [0, 0, 0, 1, ex[1], ey[1]], - [1, ex[2], ey[2], 0, 0, 0], - [0, 0, 0, 1, ex[2], ey[2]] - ]) + nDofs = K.shape[0] + nPdofs = bcPrescr.shape[0] - A = 0.5*np.linalg.det(np.mat([ - [1, ex[0], ey[0]], - [1, ex[1], ey[1]], - [1, ex[2], ey[2]] - ])) + if bcVal is None: + bcVal = np.zeros([nPdofs], 'd') - # --------- plane stress -------------------------------------- + bc = np.ones(nDofs, 'bool') + bcDofs = np.arange(nDofs) - if ptype == 1: - B = np.mat([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0] - ])*np.linalg.inv(C) + bc[np.ix_(bcPrescr-1)] = False + bcDofs = bcDofs[bc] - colD = D.shape[1] + bcVal_m = np.asmatrix(bcVal).reshape(nPdofs, 1) - if colD > 3: - Cm = np.linalg.inv(D) - Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) - else: - Dm = D + info("Preparing system matrix...") - Ke = B.T*Dm*B*A*t - fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t + mask = np.ones(K.shape[0], dtype=bool) + mask[bcDofs] = False - if eq is None: - return Ke - else: - return Ke, fe.T + info("step 1... converting K->CSR") + Kcsr = K.asformat("csr") + info("step 2... Kt") + #Kt1 = K[bcDofs] + #Kt = Kt1[:,bcPrescr] + Kt = K[np.ix_((bcDofs), (bcPrescr-1))] + info("step 3... fsys") + fsys = f[bcDofs]-Kt*bcVal_m + info("step 4... Ksys") + Ksys1 = Kcsr[bcDofs] + Ksys = Ksys1[:, bcDofs] + #Ksys = Kcsr[np.ix_((bcDofs),(bcDofs))] + info("done...") - #--------- plane strain -------------------------------------- + info("Solving system...") + asys = dsolve.spsolve(Ksys, fsys) - elif ptype == 2: - B = np.mat([ - [0, 1, 0, 0, 0, 0, ], - [0, 0, 0, 0, 0, 1, ], - [0, 0, 1, 0, 1, 0, ] - ])*np.linalg.inv(C) + info("Reconstructing full a...") + a = np.zeros([nDofs, 1]) + a[np.ix_(bcPrescr-1)] = bcVal_m + a[np.ix_(bcDofs)] = np.asmatrix(asys).transpose() - colD = D.shape[1] + a_m = np.asmatrix(a) + Q = K*a_m-f + info("done...") + return (a_m, Q) - if colD > 3: - Dm = D[np.ix_((0, 1, 3), (0, 1, 3))] - else: - Dm = D - Ke = B.T*Dm*B*A*t - fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t +def eigen(K,M,b=None): + """ + Solve the generalized eigenvalue problem + |K-LM|X = 0, considering boundary conditions - if eq == None: - return Ke - else: - return Ke, fe.T + Parameters: - else: - info("Error ! Check first argument, ptype=1 or 2 allowed") - if eq == None: - return None - else: - return None, None + K global stiffness matrix, dim(K) = ndof x ndof + M global mass matrix, dim(M) = ndof x ndof + b boundary condition vector, dim(b) = nbc x 1 + Returns: -def plants(ex, ey, ep, D, ed): + L eigenvalue vector, dim(L) = (ndof-nbc) x 1 + X eigenvectors, dim(X) = ndof x (ndof-nbc) """ - Calculate element normal and shear stress for a - triangular plane stress or plane strain element. - - INPUT: ex = [x1 x2 x3] element coordinates - ey = [y1 y2 y3] - - ep = [ptype t ] ptype: analysis type - t: thickness - - D constitutive matrix - - ed =[u1 u2 ...u6 element displacement vector - ...... ] one row for each element - - OUTPUT: es = [ sigx sigy [sigz] tauxy element stress matrix - ...... ] one row for each element - - et = [ epsx epsy [epsz] gamxy element strain matrix - ...... ] one row for each element - """ - - ptype = ep[0] + nd, _ = K.shape + if b is not None: + fdof = np.setdiff1d(np.arange(nd), b-1) + D, X1 = eig(K[np.ix_(fdof,fdof)], M[np.ix_(fdof,fdof)]) + D = np.real(D) + nfdof, _ = X1.shape + for j in range(nfdof): + mnorm = np.sqrt(X1[:,j].T@M[np.ix_(fdof,fdof)]@X1[:,j]) + X1[:,j] /= mnorm + s_order = np.argsort(D) + L = np.sort(D) + X2 = np.zeros(X1.shape) + for ind,j in enumerate(s_order): + X2[:,ind] = X1[:,j] + X = np.zeros((nd,nfdof)) + X[fdof,:] = X2 + return L, X + else: + D, X1 = eig(K, M) + D = np.real(D) + for j in range(nd): + mnorm = np.sqrt(X1[:,j].T@M@X1[:,j]) + X1[:,j] /= mnorm + s_order = np.argsort(D) + L = np.sort(D) + X = np.copy(X1) + for ind,j in enumerate(s_order): + X[:,ind] = X1[:,j] + return L, X - if np.ndim(ex) == 1: - ex = np.array([ex]) - if np.ndim(ey) == 1: - ey = np.array([ey]) - if np.ndim(ed) == 1: - ed = np.array([ed]) - rowed = ed.shape[0] - rowex = ex.shape[0] +def gfunc(G,dt): + """ + Form vector with function values at equally spaced + points by linear interpolation - # --------- plane stress -------------------------------------- + Parameters: - if ptype == 1: + G = [t_i, g_i] t_i: time i, g_i: g(t_i) + dim(G) = np x 2, np = number of points + dt time step - colD = D.shape[1] + Returns: - if colD > 3: - Cm = np.linalg.inv(D) - Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) - else: - Dm = D + t 1-D vector with equally spaced time points + g 1-D vector with corresponding function values + """ + ti = np.arange(G[0,0],G[-1,0]+dt,dt) + g1 = np.interp(ti,G[:,0],G[:,1]) + return ti, g1 - incie = 0 - if rowex == 1: - incie = 0 - else: - incie = 1 +def step1(K,C,f,a0,bc,ip,times,dofs): + """ + Algorithm for dynamic solution of first-order + FE equations considering boundary conditions. - et = np.zeros([rowed, colD]) - es = np.zeros([rowed, colD]) + Parameters: - ie = 0 + K conductivity matrix, dim(K) = ndof x ndof + C capacity matrix, dim(C) = ndof x ndof + f load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial vector a(0), dim(a0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha], where + dt is the size of the time increment, + tottime is the total time, + alpha is time integration constant. + Frequently used values of alpha are: + alpha=0: forward difference; forward Euler, + alpha=1/2: trapezoidal rule; Crank-Nicholson + alpha=1: backward difference; backward Euler + times array [t(i) ...] of times at which output should be written to a and da + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist and dahist - for i in range(rowed): - C = np.matrix( - [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], - [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], - [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] - ) + Returns: - B = np.matrix([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains values of a at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains values of da at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains time history of a at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains time history of daat the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + dt, tottime, alpha = ip + a1 = (1-alpha)*dt + a2 = alpha*dt - ee = B*np.asmatrix(ed[ie, :]).T + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 - if colD > 3: - ss = np.zeros([colD, 1]) - ss[[0, 1, 3]] = Dm*ee - ee = Cm*ss - else: - ss = Dm*ee + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 - et[ie, :] = ee.T - es[ie, :] = ss.T + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns - ie = ie + incie + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) - return es, et + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) - # --------- plane strain -------------------------------------- - elif ptype == 2: # Implementation by LAPM - colD = D.shape[1] - incie = 0 + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 - if rowex == 1: - incie = 0 - else: - incie = 1 + itime = 0 - et = np.zeros([rowed, colD]) - es = np.zeros([rowed, colD]) + # Calculate initial second time derivative d2a0 + da0 = np.linalg.solve(C,tf[:,0].reshape(-1,1) - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + itime += 1 - ie = 0 + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() - ee = np.zeros([colD, 1]) + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = C[np.ix_(fdof,fdof)] + a2*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = C + a2*K - for i in range(rowed): - C = np.matrix( - [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], - [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], - [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] - ) + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] - B = np.matrix([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) - - e = B*np.asmatrix(ed[ie, :]).T - - if colD > 3: - ee[[0, 1, 3]] = e - else: - ee = e - - et[ie, :] = ee.T - es[ie, :] = (D*ee).T - - ie = ie + incie - - return es, et + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + apred = aold + a1*daold + if not bound: + reff = tf[:,j].reshape(-1,1) - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + danew = np.linalg.solve(U,y) + anew = apred + a2*danew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() - else: - print("Error ! Check first argument, ptype=1 or 2 allowed") - return None + return modelhist, dofhist -def plantf(ex, ey, ep, es): +def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): """ - Compute internal element force vector in a triangular element - in plane stress or plane strain. + Algorithm for dynamic solution of second-order + FE equations considering boundary conditions. Parameters: - ex = [x1,x2,x3] node coordinates - ey = [y1,y2,y3] - - ep = [ptype,t] ptype: analysis type - t: thickness - - es = [[sigx,sigy,[sigz],tauxy] element stress matrix - [ ...... ]] one row for each element - - OUTPUT: + K global stiffness matrix, dim(K) = ndof x ndof + C global damping matrix, dim(C) = ndof x ndof + If there is no damping in the system, simply set C=[] + M global mass matrix, dim(M) = ndof x ndof + f global load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial displacement vector a(0), dim(a0) = ndof x 1 + da0 initial velocity vector v(0), dim(da0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha, delta], where + dt is the size of the time increment, + tottime is the total time, + alpha and delta are time integration constants for the Newmark family of methods. + Frequently used values of alpha and delta are: + alpha=1/4, delta=1/2: average acceleration (trapezoidal) rule, + alpha=1/6, delta=1/2: linear acceleration + alpha=0, delta=1/2: central difference + times array [t(i) ...] of times at which output should be written to a, da and d2a + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist, dahist and d2ahist - fe = [[f1],[f2],...,[f8]] internal force vector + Returns: + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains displacement values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains velocity values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['d2a'] constains acceleration values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['d2a']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains displacement time history at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains velocity time history at the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + dofhist['d2a'] constains acceleration time history at the dofs specified in 'dofs' + dim(dofhist['d2ahist']) = ndof x (nstep + 1) """ + ndof, _ = K.shape + if not np.array(C).any(): + C = np.zeros((ndof,ndof)) + dt, tottime, alpha, delta = ip + b1 = dt*dt*0.5*(1-2*alpha) + b2 = (1-delta)*dt + b3 = delta*dt + b4 = alpha*dt*dt - ptype, t = ep - - colD = es.shape[1] - - #--------- plane stress -------------------------------------- + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 - if ptype == 1: + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 - C = np.mat([ - [1, ex[0], ey[0], 0, 0, 0], - [0, 0, 0, 1, ex[0], ey[0]], - [1, ex[1], ey[1], 0, 0, 0], - [0, 0, 0, 1, ex[1], ey[1]], - [1, ex[2], ey[2], 0, 0, 0], - [0, 0, 0, 1, ex[2], ey[2]] - ]) + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns - A = 0.5*np.linalg.det(np.mat([ - [1, ex[0], ey[0]], - [1, ex[1], ey[1]], - [1, ex[2], ey[2]] - ])) + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) - B = np.mat([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0] - ])*np.linalg.inv(C) + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + modelhist['d2a'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + modelhist['d2a'] = np.zeros((ndof,ntimes)) - if colD > 3: - stress = np.asmatrix(es[np.ix_((0, 1, 3))]) - else: - stress = np.asmatrix(es) + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + dofhist['d2a'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 - ef = (A*t*B.T*stress.T).T + itime = 0 - return np.reshape(np.asarray(ef), 6) + # Calculate initial second time derivative d2a0 + d2a0 = np.linalg.solve(M,tf[:,0].reshape(-1,1) - C@da0 - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + modelhist['d2a'][:,0] = d2a0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + modelhist['d2a'][:,itime] = d2a0.ravel() + itime += 1 - #--------- plane strain -------------------------------------- + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,0] = d2a0[np.ix_(dofs-1)].ravel() - elif ptype == 2: + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + tempd2a = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = M[np.ix_(fdof,fdof)] + b3*C[np.ix_(fdof,fdof)] +b4*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = M + b3*C + b4*K - C = np.mat([ - [1, ex[0], ey[0], 0, 0, 0], - [0, 0, 0, 1, ex[0], ey[0]], - [1, ex[1], ey[1], 0, 0, 0], - [0, 0, 0, 1, ex[1], ey[1]], - [1, ex[2], ey[2], 0, 0, 0], - [0, 0, 0, 1, ex[2], ey[2]] - ]) + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + d2anew = d2a0[np.ix_(fdof)] - A = 0.5*np.linalg.det(np.mat([ - [1, ex[0], ey[0]], - [1, ex[1], ey[1]], - [1, ex[2], ey[2]] - ])) - - B = np.mat([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0] - ])*np.linalg.inv(C) - - if colD > 3: - stress = np.asmatrix(es[np.ix_((1, 2, 4))]) + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + d2aold = np.copy(d2anew) + apred = aold + dt*daold + b1*d2aold + dapred = daold + b2*d2aold + if not bound: + reff = tf[:,j].reshape(-1,1) - C@dapred - K@apred else: - stress = np.asmatrix(es) - - ef = (A*t*B.T*stress.T).T - - return np.reshape(np.asarray(ef), 6) + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - C[np.ix_(fdof,fdof)]@dapred - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + d2anew = np.linalg.solve(U,y) + anew = apred + b4*d2anew + danew = dapred + b3*d2anew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + tempd2a[np.ix_(fdof)] = d2anew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + modelhist['d2a'][:,j] = tempd2a.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + modelhist['d2a'][:,itime] = tempd2a.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,j] = tempd2a[np.ix_(dofs-1)].ravel() - else: - info("Error ! Check first argument, ptype=1 or 2 allowed") - return None + return modelhist, dofhist -def platre(ex, ey, ep, D, eq=None): +def extract_eldisp(edof, a): """ - Calculate the stiffness matrix for a rectangular plate element. - NOTE! Element sides must be parallel to the coordinate axis. + Extract element displacements from the global displacement + vector according to the topology matrix edof. Parameters: + + a the global displacement vector + edof dof topology array + + Returns: + + ed: element displacement array + + """ - ex = [x1,x2,x3,x4] element coordinates - ey = [y1,y2,y3,y4] - - ep = [t] thicknes + ed = None - D constitutive matrix for - plane stress + if edof.ndim == 1: + nDofs = len(edof) + ed = np.zeros([nDofs]) + idx = edof-1 + ed[:] = a[np.ix_(idx)].T + else: + nElements = edof.shape[0] + nDofs = edof.shape[1] + ed = np.zeros([nElements, nDofs]) + i = 0 + for row in edof: + idx = row-1 + ed[i, :] = a[np.ix_(idx)].T + i += 1 - eq = [qz] load/unit area - Returns: + return ed - Ke element stiffness matrix (12 x 12) - fe equivalent nodal forces (12 x 1) - """ - Lx = (ex[2]-ex[0]).astype(float) - Ly = (ey[2]-ey[0]).astype(float) - t = ep[0] +extractEldisp = extract_eldisp +extract_ed = extract_eldisp - D = t**3/12.*D - A1 = Ly/(Lx**3) - A2 = Lx/(Ly**3) - A3 = 1/Lx/Ly - A4 = Ly/(Lx**2) - A5 = Lx/(Ly**2) - A6 = 1/Lx - A7 = 1/Ly - A8 = Ly/Lx - A9 = Lx/Ly +def statcon(K, f, cd): + """ + Condensation of static FE-equations according to the vector cd. - C1 = 4*A1*D[0, 0]+4*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] - C2 = -4*A1*D[0, 0]+2*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] - C3 = 2*A1*D[0, 0]-4*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] - C4 = -2*A1*D[0, 0]-2*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] - C5 = 2*A5*D[1, 1]+A6*D[0, 1]+0.4*A6*D[2, 2] - C6 = 2*A4*D[0, 0]+A7*D[0, 1]+0.4*A7*D[2, 2] + Parameters: + + K global stiffness matrix, dim(K) = nd x nd + f global load vector, dim(f)= nd x 1 - C7 = 2*A5*D[1, 1]+0.4*A6*D[2, 2] - C8 = 2*A4*D[0, 0]+0.4*A7*D[2, 2] - C9 = A5*D[1, 1]-A6*D[0, 1]-0.4*A6*D[2, 2] - C10 = A4*D[0, 0]-A7*D[0, 1]-0.4*A7*D[2, 2] - C11 = A5*D[1, 1]-0.4*A6*D[2, 2] - C12 = A4*D[0, 0]-0.4*A7*D[2, 2] + cd vector containing dof's to be eliminated + dim(cd)= nc x 1, nc: number of condensed dof's + Returns: + + K1 condensed stiffness matrix, + dim(K1)= (nd-nc) x (nd-nc) + f1 condensed load vector, dim(f1)= (nd-nc) x 1 + """ + nd, nd = np.shape(K) + cd = (cd-1).flatten() - C13 = 4/3.*A9*D[1, 1]+8/15.*A8*D[2, 2] - C14 = 4/3.*A8*D[0, 0]+8/15.*A9*D[2, 2] - C15 = 2/3.*A9*D[1, 1]-8/15.*A8*D[2, 2] - C16 = 2/3.*A8*D[0, 0]-8/15.*A9*D[2, 2] - C17 = 2/3.*A9*D[1, 1]-2/15.*A8*D[2, 2] - C18 = 2/3.*A8*D[0, 0]-2/15.*A9*D[2, 2] - C19 = 1/3.*A9*D[1, 1]+2/15.*A8*D[2, 2] - C20 = 1/3.*A8*D[0, 0]+2/15.*A9*D[2, 2] - C21 = D[0, 1] + aindx = np.arange(nd) + aindx = np.delete(aindx, cd, 0) + bindx = cd - Keq = np.mat(np.zeros((12, 12))) - Keq[0, 0:13] = C1, C5, -C6, C2, C9, -C8, C4, C11, -C12, C3, C7, -C10 - Keq[1, 1:13] = C13, -C21, C9, C15, 0, -C11, C19, 0, -C7, C17, 0 - Keq[2, 2:13] = C14, C8, 0, C18, C12, 0, C20, -C10, 0, C16 - Keq[3, 3:13] = C1, C5, C6, C3, C7, C10, C4, C11, C12 - Keq[4, 4:13] = C13, C21, -C7, C17, 0, -C11, C19, 0 - Keq[5, 5:13] = C14, C10, 0, C16, -C12, 0, C20 - Keq[6, 6:13] = C1, -C5, C6, C2, -C9, C8 - Keq[7, 7:13] = C13, -C21, -C9, C15, 0 - Keq[8, 8:13] = C14, -C8, 0, C18 - Keq[9, 9:13] = C1, -C5, -C6 - Keq[10, 10:13] = C13, C21 - Keq[11, 11] = C14 - Keq = Keq.T+Keq-np.diag(np.diag(Keq)) + Kaa = np.mat(K[np.ix_(aindx, aindx)]) + Kab = np.mat(K[np.ix_(aindx, bindx)]) + Kbb = np.mat(K[np.ix_(bindx, bindx)]) - if eq != None: - q = eq - R1 = q*Lx*Ly/4 - R2 = q*Lx*Ly**2/24 - R3 = q*Ly*Lx**2/24 + fa = np.mat(f[aindx]) + fb = np.mat(f[bindx]) - feq = np.mat([R1, R2, -R3, R1, R2, R3, R1, -R2, R3, R1, -R2, -R3]) + K1 = Kaa-Kab*Kbb.I*Kab.T + f1 = fa-Kab*Kbb.I*fb - if eq != None: - return Keq, feq - else: - return Keq + return K1, f1 -def planqe(ex, ey, ep, D, eq=None): - """ - Calculate the stiffness matrix for a quadrilateral - plane stress or plane strain element. +def c_mul(a, b): + return eval(hex((np.long(a) * b) & 0xFFFFFFFF)[:-1]) - Parameters: - ex=[x1 x2 x3 x4] element coordinates - ey=[y1 y2 y3 y4] - - ep = [ptype, t] ptype: analysis type - t: element thickness - D constitutive matrix +def dofHash(dof): + if len(dof) == 1: + return dof[0] + value = 0x345678 + for item in dof: + value = c_mul(1000003, value) ^ hash(item) + value = value ^ len(dof) + if value == -1: + value = -2 + return value - eq = [bx; bx: body force in x direction - by] by: body force in y direction - OUTPUT: Ke : element stiffness matrix (8 x 8) - fe : equivalent nodal forces (row array) +def create_dofs(nCoords, nDof): """ - K = np.zeros((10, 10)) - f = np.zeros((10, 1)) - - xm = sum(ex)/4. - ym = sum(ey)/4. - - b1 = eq if eq is not None else np.array([[0], [0]]) + Create dof array [nCoords x nDof] + """ + return np.arange(nCoords*nDof).reshape(nCoords, nDof)+1 - ke1, fe1 = plante(np.array([ex[0], ex[1], xm]), - np.array([ey[0], ey[1], ym]), ep, D, b1) - K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(np.array([ex[1], ex[2], xm]), - np.array([ey[1], ey[2], ym]), ep, D, b1) - K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(np.array([ex[2], ex[3], xm]), - np.array([ey[2], ey[3], ym]), ep, D, b1) - K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(np.array([ex[3], ex[0], xm]), - np.array([ey[3], ey[0], ym]), ep, D, b1) - K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) - Ke, fe = statcon(K, f, np.array([[9], [10]])) - if eq == None: - return Ke - else: - return Ke, fe +createdofs = create_dofs -def planqs(ex, ey, ep, D, ed, eq=None): +def coordxtr(edof, coords, dofs, nen=-1): """ - Calculate element normal and shear stress for a quadrilateral - plane stress or plane strain element. + Create element coordinate matrices ex, ey, ez from edof + coord and dofs matrices. Parameters: - ex = [x1 x2 x3 x4] element coordinates - ey = [y1 y2 y3 y4] - - ep = [ptype, t] ptype: analysis type - t: thickness - - D constitutive matrix - ed = [u1 u2 ..u8] element displacement vector - - eq = [[bx] bx: body force in x direction - [by]] by: body force in y direction + edof [nel x (nen * nnd)], nnd = number of node dofs + coords [ncoords x ndims], ndims = node dimensions + dofs [ncoords x nnd] + + Returns: - OUTPUT: es = [ sigx sigy (sigz) tauxy] element stress array - et = [ epsx epsy (epsz) gamxy] element strain array + ex if ndims = 1 + ex, ey if ndims = 2 + ex, ey, ez if ndims = 3 """ - if ex.shape != (4,) or ey.shape != (4,) or ed.shape != (8,): - raise ValueError( - 'Error ! PLANQS: only one element at the time (ex, ey, ed must be a row arrays)') + # Create dictionary with dof indices - K = np.zeros((10, 10)) - f = np.zeros((10, 1)) + dofDict = {} + nDofs = np.size(dofs, 1) + nElements = np.size(edof, 0) + n_element_dofs = np.size(edof, 1) + nDimensions = np.size(coords, 1) + nElementDofs = np.size(edof, 1) - xm = sum(ex)/4. - ym = sum(ey)/4. + if nen == -1: + nElementNodes = int(nElementDofs/nDofs) + else: + nElementNodes = nen - b1 = eq if eq is not None else np.array([[0], [0]]) + if nElementNodes*nDofs != n_element_dofs: + nDofs = nElementNodes*nDofs - n_element_dofs + user_warning( + "dofs/edof mismatch. Using %d dofs per node when indexing." % nDofs) - ex1 = np.array([ex[0], ex[1], xm]) - ey1 = np.array([ey[0], ey[1], ym]) - ex2 = np.array([ex[1], ex[2], xm]) - ey2 = np.array([ey[1], ey[2], ym]) - ex3 = np.array([ex[2], ex[3], xm]) - ey3 = np.array([ey[2], ey[3], ym]) - ex4 = np.array([ex[3], ex[0], xm]) - ey4 = np.array([ey[3], ey[0], ym]) + idx = 0 + for dof in dofs: + #dofDict[dofHash(dof)] = idx + dofDict[hash(tuple(dof[0:nDofs]))] = idx + idx += 1 - ke1, fe1 = plante(ex1, ey1, ep, D, b1) - K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(ex2, ey2, ep, D, b1) - K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(ex3, ey3, ep, D, b1) - K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(ex4, ey4, ep, D, b1) - K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) + # Loop over edof and extract element coords - A1 = 0.5 * \ - np.linalg.det( - np.hstack([np.ones((3, 1)), np.mat(ex1).T, np.mat(ey1).T])) - A2 = 0.5 * \ - np.linalg.det( - np.hstack([np.ones((3, 1)), np.mat(ex2).T, np.mat(ey2).T])) - A3 = 0.5 * \ - np.linalg.det( - np.hstack([np.ones((3, 1)), np.mat(ex3).T, np.mat(ey3).T])) - A4 = 0.5 * \ - np.linalg.det( - np.hstack([np.ones((3, 1)), np.mat(ex4).T, np.mat(ey4).T])) - Atot = A1+A2+A3+A4 + ex = np.zeros((nElements, nElementNodes)) + ey = np.zeros((nElements, nElementNodes)) + ez = np.zeros((nElements, nElementNodes)) - a, _ = solveq(K, f, np.array(range(1, 9)), ed) + elementIdx = 0 + for etopo in edof: + for i in range(nElementNodes): + i0 = i*nDofs + i1 = i*nDofs+nDofs-1 + dof = [] + if i0 == i1: + dof = [etopo[i*nDofs]] + else: + dof = etopo[i*nDofs:(i*nDofs+nDofs)] -# ni = ed.shape[0] -# a = np.mat(empty((10,ni))) -# for i in range(ni): -# a[:,i] = solveq(K, f, np.array(range(1,9)), ed[i,:])[0] -# #a = np.hstack([a, solveq(K, f, np.hstack([matrix(range(1,9)).T, ed[i,:].T]) ) ]) + nodeCoord = coords[dofDict[hash(tuple(dof[0:nDofs]))]] - s1, t1 = plants(ex1, ey1, ep, D, np.hstack([a[[0, 1, 2, 3, 8, 9], :].T])) - s2, t2 = plants(ex2, ey2, ep, D, np.hstack([a[[2, 3, 4, 5, 8, 9], :].T])) - s3, t3 = plants(ex3, ey3, ep, D, np.hstack([a[[4, 5, 6, 7, 8, 9], :].T])) - s4, t4 = plants(ex4, ey4, ep, D, np.hstack([a[[6, 7, 0, 1, 8, 9], :].T])) + if nDimensions >= 1: + ex[elementIdx, i] = nodeCoord[0] + if nDimensions >= 2: + ey[elementIdx, i] = nodeCoord[1] + if nDimensions >= 3: + ez[elementIdx, i] = nodeCoord[2] - es = (s1*A1+s2*A2+s3*A3+s4*A4)/Atot - et = (t1*A1+t2*A2+t3*A3+t4*A4)/Atot + elementIdx += 1 - # [0] because these are 1-by-3 arrays and we want row arrays out. - return es[0], et[0] + if nDimensions == 1: + return ex + if nDimensions == 2: + return ex, ey -def plani4e(ex, ey, ep, D, eq=None): + if nDimensions == 3: + return ex, ey, ez + + +coord_extract = coordxtr + + +def hooke(ptype, E, v): """ - Calculate the stiffness matrix for a 4 node isoparametric - element in plane strain or plane stress. + Calculate the material matrix for a linear + elastic and isotropic material. Parameters: - ex = [x1 ... x4] element coordinates. Row array - ey = [y1 ... y4] - - ep =[ptype, t, ir] ptype: analysis type - t : thickness - ir: integration rule - - D constitutive matrix - eq = [bx; by] bx: body force in x direction - by: body force in y direction - Any array with 2 elements acceptable + ptype= 1: plane stress + 2: plane strain + 3: axisymmetry + 4: three dimensional + E Young's modulus + v Poissons const. + Returns: - Ke : element stiffness matrix (8 x 8) - fe : equivalent nodal forces (8 x 1) + + D material matrix + """ - ptype = ep[0] - t = ep[1] - ir = ep[2] - ngp = ir*ir - if eq == None: - q = np.zeros((2, 1)) - else: - q = np.reshape(eq, (2, 1)) -#--------- gauss points -------------------------------------- - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.mat([g1, g1]) - w = np.mat([w1, w1]) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-g1, -g1], - [g1, -g1], - [-g1, g1], - [g1, g1]]) - w = np.mat([ - [w1, w1], - [w1, w1], - [w1, w1], - [w1, w1]]) - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat([ - [-g1, -g1], - [-g2, -g1], - [g1, -g1], - [-g1, g2], - [g2, g2], - [g1, g2], - [-g1, g1], - [g2, g1], - [g1, g1]]) - w = np.mat([ - [w1, w1], - [w2, w1], - [w1, w1], - [w1, w2], - [w2, w2], - [w1, w2], - [w1, w1], - [w2, w1], - [w1, w1]]) + + if ptype == 1: + D = E*np.matrix( + [[1, v, 0], + [v, 1, 0], + [0, 0, (1-v)/2]] + )/(1-v**2) + elif ptype == 2: + D = E/(1+v)*np.matrix( + [[1-v, v, v, 0], + [v, 1-v, v, 0], + [v, v, 1-v, 0], + [0, 0, 0, (1-2*v)/2]] + )/(1-2*v) + elif ptype == 3: + D = E/(1+v)*np.matrix( + [[1-v, v, v, 0], + [v, 1-v, v, 0], + [v, v, 1-v, 0], + [0, 0, 0, (1-2*v)/2]] + )/(1-2*v) + elif ptype == 4: + D = E*np.matrix( + [[1-v, v, v, 0, 0, 0], + [v, 1-v, v, 0, 0, 0], + [v, v, 1-v, 0, 0, 0], + [0, 0, 0, (1-2*v)/2, 0, 0], + [0, 0, 0, 0, (1-2*v)/2, 0], + [0, 0, 0, 0, 0, (1-2*v)/2]] + )/(1+v)/(1-2*v) else: - info("Used number of integrat ion points not implemented") - wp = np.multiply(w[:, 0], w[:, 1]) - xsi = gp[:, 0] - eta = gp[:, 1] - r2 = ngp*2 - # Shape Functions - N = np.multiply((1-xsi), (1-eta))/4. - N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) - N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) - N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + info("ptype not supported.") - dNr = np.mat(np.zeros((r2, 4))) - dNr[0:r2:2, 0] = -(1-eta)/4. - dNr[0:r2:2, 1] = (1-eta)/4. - dNr[0:r2:2, 2] = (1+eta)/4. - dNr[0:r2:2, 3] = -(1+eta)/4. - dNr[1:r2+1:2, 0] = -(1-xsi)/4. - dNr[1:r2+1:2, 1] = -(1+xsi)/4. - dNr[1:r2+1:2, 2] = (1+xsi)/4. - dNr[1:r2+1:2, 3] = (1-xsi)/4. + return D -# - Ke1 = np.mat(np.zeros((8, 8))) - fe1 = np.mat(np.zeros((8, 1))) - JT = dNr*np.mat([ex, ey]).T - # --------- plane stress -------------------------------------- - if ptype == 1: - colD = np.shape(D)[0] - if colD > 3: - Cm = np.linalg.inv(D) - Dm = np.linalg.inv(Cm[np.ix_([0, 1, 3], [0, 1, 3])]) - else: - Dm = D -# - B = np.matrix(np.zeros((3, 8))) - N2 = np.matrix(np.zeros((2, 8))) - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinant equal or less than zero!") - JTinv = np.linalg.inv(JT[indx-1, :]) - dNx = JTinv*dNr[indx-1, :] -# - index_array_even = np.array([0, 2, 4, 6]) - index_array_odd = np.array([1, 3, 5, 7]) -# - counter = 0 - for index in index_array_even: - B[0, index] = dNx[0, counter] - B[2, index] = dNx[1, counter] - N2[0, index] = N[i, counter] - counter = counter+1 -# - counter = 0 - for index in index_array_odd: - B[1, index] = dNx[1, counter] - B[2, index] = dNx[0, counter] - N2[1, index] = N[i, counter] - counter = counter+1 -# - Ke1 = Ke1+B.T*Dm*B*detJ*wp[i].item()*t - fe1 = fe1 + N2.T * q * detJ * wp[i].item() * t - - return Ke1, fe1 -#--------- plane strain -------------------------------------- - elif ptype == 2: - # - colD = np.shape(D)[0] - if colD > 3: - Dm = D[np.ix_([0, 1, 3], [0, 1, 3])] - else: - Dm = D -# - B = np.matrix(np.zeros((3, 8))) - N2 = np.matrix(np.zeros((2, 8))) - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobideterminant equal or less than zero!") - JTinv = np.linalg.inv(JT[indx-1, :]) - dNx = JTinv*dNr[indx-1, :] -# - index_array_even = np.array([0, 2, 4, 6]) - index_array_odd = np.array([1, 3, 5, 7]) -# - counter = 0 - for index in index_array_even: - # - B[0, index] = dNx[0, counter] - B[2, index] = dNx[1, counter] - N2[0, index] = N[i, counter] -# - counter = counter+1 -# - counter = 0 - for index in index_array_odd: - B[1, index] = dNx[1, counter] - B[2, index] = dNx[0, counter] - N2[1, index] = N[i, counter] - counter = counter+1 -# - Ke1 = Ke1 + B.T * Dm * B * detJ * np.asscalar(wp[i]) * t - fe1 = fe1+N2.T*q*detJ*np.asscalar(wp[i])*t - return Ke1, fe1 - else: - info("Error ! Check first argument, ptype=1 or 2 allowed") - -def soli8e(ex, ey, ez, ep, D, eqp=None): +def effmises(es, ptype): + """ + Calculate effective von mises stresses. + + Parameters: + + es + + ptype= 1: plane stress + 2: plane strain + 3: axisymmetry + 4: three dimensional + + es = [[sigx,sigy,[sigz],tauxy] element stress matrix + [ ...... ]] one row for each element + + Returns: + + eseff = [eseff_0 .. eseff_nel-1] + """ - Ke=soli8e(ex,ey,ez,ep,D) - [Ke,fe]=soli8e(ex,ey,ez,ep,D,eq) - ------------------------------------------------------------- - PURPOSE - Calculate the stiffness matrix for a 8 node (brick) - isoparametric element. - - INPUT: ex = [x1 x2 x3 ... x8] - ey = [y1 y2 y3 ... y8] element coordinates - ez = [z1 z2 z3 ... z8] - ep = [ir] ir integration rule + nel = np.size(es, 0) + escomps = np.size(es, 1) - D constitutive matrix + eseff = np.zeros([nel]) - eq = [bx; by; bz] bx: body force in x direction - by: body force in y direction - bz: body force in z direction + if ptype == 1: + sigxx = es[:, 0] + sigyy = es[:, 1] + sigxy = es[:, 2] + eseff = np.sqrt(sigxx*sigxx+sigyy*sigyy-sigxx*sigyy+3*sigxy*sigxy) + return eseff - OUTPUT: Ke : element stiffness matrix - fe : equivalent nodal forces - ------------------------------------------------------------- - LAST MODIFIED: M Ristinmaa 1995-10-25 - J Lindemann 2022-01-24 (Python version) - Copyright (c) Division of Structural Mechanics and - Division of Solid Mechanics. - Lund University - ------------------------------------------------------------- +def stress2nodal(eseff, edof): + """ + Convert element effective stresses to nodal effective + stresses. + + Parameters: + + eseff = [eseff_0 .. eseff_nel-1] + edof = [dof topology array] + + Returns: + + ev: element value array [[ev_0_0 ev_0_1 ev_0_nen-1 ] + .. + ev_nel-1_0 ev_nel-1_1 ev_nel-1_nen-1] + """ - ir = ep[0] - ngp = ir*ir*ir - if eqp == None: - eq = np.zeros((3, 1)) - else: - eq = eqp + values = np.zeros(edof.max()) + elnodes = int(np.size(edof, 1) / 2) - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.array([g1, g1, g1]).reshape(1, 3) - w = np.array([w1, w1, w1]).reshape(1, 3) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.zeros((8, 3)) - w = np.zeros((8, 3)) - gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 - w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 - w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 - w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - else: - g1 = 0.774596669241483, - g2 = 0.0 - w1 = 0.555555555555555 - w2 = 0.888888888888888 + for etopo, eleseff in zip(edof, eseff): + values[etopo-1] = values[etopo-1] + eleseff / elnodes - gp = np.zeros((27, 3)) - w = np.zeros((27, 3)) + evtemp = extractEldisp(edof, values) + ev = evtemp[:, range(0, elnodes*2, 2)] - I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) - I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) + return ev - gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 - gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] - I1 = np.abs(I1) - I2 = np.abs(I2) +def beam2crd_old(ex, ey, ed, mag): + """ + ------------------------------------------------------------- + PURPOSE + Calculate the element continous displacements for a + number of identical 2D Bernoulli beam elements. + + INPUT: ex,ey, + ed, + mag + + OUTPUT: excd,eycd + ------------------------------------------------------------- - w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 - w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] + LAST MODIFIED: P-E AUSTRELL 1993-10-15 + J Lindemann 2021-12-30 (Python) - I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) - I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + nie, ned = ed.shape - gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 - gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] + excd = np.zeros([nie, 20]) + eycd = np.zeros([nie, 20]) - I1 = np.abs(I1) - I2 = np.abs(I2) + for i in range(nie): - w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 - w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] + b = np.array([ex[i, 1]-ex[i, 0], ey[i, 1]-ey[i, 0]]) + L = np.asscalar(np.sqrt(b@np.transpose(b))) + n = b/L - I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) - I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) - I3 = np.abs(I1) + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) - gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 - gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] + d = ed[i, :] + dl = G @ d - w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 - w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] + xl = np.linspace(0.0, L, 20) + one = np.ones(xl.shape) - wp = w[:, 0]*w[:, 1]*w[:, 2] + Cis = np.array([ + [-1.0, 1.0], + [L, 0.0] + ]) / L - xsi = gp[:, 0] - eta = gp[:, 1] - zet = gp[:, 2] - r2 = ngp*3 - - N = np.zeros((ngp, 8)) - dNr = np.zeros((r2, 8)) - - N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 - N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 - N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 - N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 - N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 - N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 - N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 - N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 - - dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) - dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) - dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) - dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) - dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) - dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) - dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) - dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) - dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) - dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) - dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) - dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) - dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) - dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) - dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) - dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) - dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) - dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) - dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) - dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) - dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) - dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) - dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) - dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) - - dNr = dNr/8.0 - - Ke = np.zeros((24, 24)) - fe = np.zeros((24, 1)) + ds = np.array([dl[0], dl[3]]).reshape(2, 1) - ex = np.asarray(ex).reshape((8, 1)) - ey = np.asarray(ey).reshape((8, 1)) - ez = np.asarray(ez).reshape((8, 1)) + xl_one = np.transpose(np.vstack((xl, one))) - JT = dNr@np.concatenate((ex, ey, ez), axis=1) + ul = np.transpose(xl_one@Cis@ds) # [20x1][2] - eps = np.finfo(float).eps + Cib = np.array([ + [12, 6*L, -12, 6*L], + [-6*L, -4*L**2, 6*L, -2*L**2], + [0, L**3, 0, 0], + [L**3, 0, 0, 0] + ])/L**3 - for i in range(ngp): - indx = [i*3, i*3+1, i*3+2] - detJ = np.linalg.det(JT[indx, :]) - if detJ < 10*eps: - print('Jacobideterminant equal or less than zero!') - JTinv = np.linalg.inv(JT[indx, :]) - dNx = JTinv@dNr[indx, :] + db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) + vl = np.transpose(np.transpose( + np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) - B = np.zeros((6, 24)) - N2 = np.zeros((3, 24)) + cld = np.vstack((ul, vl)) + A = np.array([ + [n[0], -n[1]], + [n[1], n[0]] + ]) + cd = A@cld - B[0, 0:24:3] = dNx[0, :] - B[1, 1:25:3] = dNx[1, :] - B[2, 2:26:3] = dNx[2, :] - B[3, 0:24:3] = dNx[1, :] - B[3, 1:25:3] = dNx[0, :] - B[4, 0:24:3] = dNx[2, :] - B[4, 2:26:3] = dNx[0, :] - B[5, 1:25:3] = dNx[2, :] - B[5, 2:26:3] = dNx[1, :] + # [2,1] x [1,20] + [2 x 1] x [1 x 20] + # [2 x 20] + [2 x 20] - N2[0, 0:24:3] = N[i, :] - N2[1, 1:25:3] = N[i, :] - N2[2, 2:26:3] = N[i, :] + AA = A[:, 0].reshape(2, 1) + XL = xl.reshape(1, 20) + xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]])@one.reshape(1, 20) - Ke = Ke + (np.transpose(B)@D@B)*detJ*wp[i] - fe = fe + (np.transpose(N2)@eq)*detJ*wp[i] + excd[i, :] = xyc[0, :]+mag*cd[0, :] + eycd[i, :] = xyc[1, :]+mag*cd[1, :] - if eqp != None: - return Ke, fe - else: - return Ke + return excd, eycd -def soli8s(ex, ey, ez, ep, D, ed): +def beam2crd(ex=None, ey=None, ed=None, mag=None): """ - [es,et]=soli8s(ex,ey,ez,ep,D,ed) ------------------------------------------------------------- - PURPOSE - Calculate element normal and shear stress for a - 8 node (brick) isoparametric element. - - INPUT: ex = [x1 x2 x3 ... x8] - ey = [y1 y2 y3 ... y8] element coordinates - ez = [z1 z2 z3 ... z8] - - ep = [Ir] Ir: integration rule + PURPOSE + Calculate the element continous displacements for a + number of identical 2D Bernoulli beam elements. - D constitutive matrix + INPUT: ex,ey, + ed, + mag - ed = [u1 u2 ..u24] element displacement vector - - OUTPUT: es = [ sigx sigy sigz sigxy sigyz sigxz ; - ...... ... ] - element stress matrix, one row for each - integration point - - es = [ eps epsy epsz epsxy epsyz epsxz ; - ...... ... ] - element strain matrix, one row for each - integration point + OUTPUT: excd,eycd ------------------------------------------------------------- - - LAST MODIFIED: M Ristinmaa 1995-10-25 - J Lindemann 2022-02-23 (Python version) - - Copyright (c) Division of Structural Mechanics and + + LAST MODIFIED: P-E AUSTRELL 1993-10-15 + Copyright (c) Division of Structural Mechanics and Division of Solid Mechanics. Lund University ------------------------------------------------------------- """ - ir = ep[0] - ngp = ir*ir*ir + nie, ned = ed.shape - ir = ep[0] - ngp = ir*ir*ir + n_coords = 21 - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.array([g1, g1, g1]).reshape(1, 3) - w = np.array([w1, w1, w1]).reshape(1, 3) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.zeros((8, 3)) - w = np.zeros((8, 3)) - gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 - w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 - w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 - w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - else: - g1 = 0.774596669241483, - g2 = 0.0 - w1 = 0.555555555555555 - w2 = 0.888888888888888 + excd = np.zeros([nie, n_coords]) + eycd = np.zeros([nie, n_coords]) - gp = np.zeros((27, 3)) - w = np.zeros((27, 3)) + for i in range(nie): + b = np.array([ex[i, 1] - ex[i, 0], ey[i, 1] - ey[i, 0]]) + L = np.sqrt(b @ np.transpose(b)) + n = b / L - I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) - I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, - n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) - gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 - gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] + d = np.transpose(ed[i, :]) + dl = G @ d + xl = np.transpose(np.linspace(0, L, n_coords)) + one = np.ones(xl.shape) - I1 = np.abs(I1) - I2 = np.abs(I2) + Cis = np.array([ + [-1, 1], + [L, 0] + ]) / L - w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 - w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] + ds = np.array([dl[0], dl[3]]).reshape(2, 1) + xl_one = np.transpose(np.vstack((xl, one))) + ul = np.transpose(xl_one@Cis@ds) # [20x1][2] - I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) - I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) + Cib = np.array([ + [12, 6 * L, - 12, 6 * L], + [- 6 * L, - 4 * L ** 2, 6 * L, - 2 * L ** 2], + [0, L ** 3, 0, 0], + [L ** 3, 0, 0, 0] + ]) / L ** 3 - gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 - gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] + db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) + vl = np.transpose(np.transpose( + np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) - I1 = np.abs(I1) - I2 = np.abs(I2) + cld = np.vstack((ul, vl)) + A = np.array([ + [n[0], -n[1]], + [n[1], n[0]] + ]) + cd = A@cld - w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 - w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] + # [2,1] x [1,20] + [2 x 1] x [1 x 20] + # [2 x 20] + [2 x 20] - I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) - I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) - I3 = np.abs(I1) + AA = A[:, 0].reshape(2, 1) + XL = xl.reshape(1, n_coords) + xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]] + )@one.reshape(1, n_coords) - gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 - gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] + excd[i, :] = xyc[0, :]+mag*cd[0, :] + eycd[i, :] = xyc[1, :]+mag*cd[1, :] - w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 - w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] + return excd, eycd - wp = w[:, 0]*w[:, 1]*w[:, 2] +# ----------------------------------------------------------------- +# ----------------------------------------------------------------- +# ----------------------------------------------------------------- +# ----------------------------------------------------------------- - xsi = gp[:, 0] - eta = gp[:, 1] - zet = gp[:, 2] - r2 = ngp*3 +def _spring1e(ep): + """ + Compute element stiffness matrix for spring element. + + :param float ep: spring stiffness or analog quantity (ep = k). + :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 + """ + k = ep + return np.mat([[k, -k], [-k, k]], 'd') - N = np.zeros((ngp, 8)) - dNr = np.zeros((r2, 8)) - - N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 - N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 - N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 - N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 - N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 - N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 - N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 - N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 - dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) - dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) - dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) - dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) - dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) - dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) - dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) - dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) - dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) - dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) - dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) - dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) - dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) - dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) - dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) - dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) - dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) - dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) - dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) - dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) - dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) - dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) - dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) - dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) +def _spring1s(ep, ed): + """ + Compute element force in spring element (spring1e). + + :param float ep: spring stiffness or analog quantity + :param list ed: element displacements [d0, d1] + :return float es: element force [N] + """ + k = ep + return k*(ed[1]-ed[0]) - dNr = dNr/8.0 - ex = np.asarray(ex).reshape((8, 1)) - ey = np.asarray(ey).reshape((8, 1)) - ez = np.asarray(ez).reshape((8, 1)) +def _bar1e(ep): + """ + Compute element stiffness matrix for spring element. + + :param ep float: spring stiffness or analog quantity + :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 + """ + k = ep + return np.mat([[k, -k], [-k, k]], 'd') - JT = dNr@np.concatenate((ex, ey, ez), axis=1) - eps = np.finfo(float).eps +def _bar1s(ep, ed): + """ + Compute element force in spring element (spring1e). - eci = N@np.concatenate((ex, ey, ez), axis=1) - et = np.zeros((ngp, 6)) - es = np.zeros((ngp, 6)) - - ed = ed.reshape(1, 24) + :param float ep: spring stiffness or analog quantity + :param list ed: element displacements [d0, d1] + :return float es: element force + """ + k = ep + return k*(ed[1]-ed[0]) - for i in range(ngp): - indx = [i*3, i*3+1, i*3+2] - detJ = np.linalg.det(JT[indx, :]) - if detJ < 10*eps: - print('Jacobideterminant equal or less than zero!') - JTinv = np.linalg.inv(JT[indx, :]) - dNx = JTinv@dNr[indx, :] - B = np.zeros((6, 24)) - N2 = np.zeros((3, 24)) +def _bar2e(ex, ey, ep): + """ + Compute the element stiffness matrix for two dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: [E, A]: E - Young's modulus, A - Cross section area + :return mat Ke: stiffness matrix, [4 x 4] + """ + E = ep[0] + A = ep[1] - B[0, 0:24:3] = dNx[0, :] - B[1, 1:25:3] = dNx[1, :] - B[2, 2:26:3] = dNx[2, :] - B[3, 0:24:3] = dNx[1, :] - B[3, 1:25:3] = dNx[0, :] - B[4, 0:24:3] = dNx[2, :] - B[4, 2:26:3] = dNx[0, :] - B[5, 1:25:3] = dNx[2, :] - B[5, 2:26:3] = dNx[1, :] + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() - N2[0, 0:24:3] = N[i, :] - N2[1, 1:25:3] = N[i, :] - N2[2, 2:26:3] = N[i, :] + Kle = np.mat([[1., -1.], [-1., 1.]])*E*A/L - # [6x24] x [24,1] - ee = B@np.transpose(ed) + n = np.asarray(b.T/L).reshape(2,) - et[i, :] = ee.reshape(6,) - es[i, :] = (D@ee).reshape(6,) + G = np.mat([ + [n[0], n[1], 0., 0.], + [0., 0., n[0], n[1]] + ]) - return et, es, eci + return G.T*Kle*G -def assem(edof, K, Ke, f=None, fe=None): +def _bar2g(ex, ey, ep, N): """ - Assemble element matrices Ke ( and fe ) into the global - stiffness matrix K ( and the global force vector f ) - according to the topology matrix edof. - - Parameters: - - edof dof topology array - K the global stiffness matrix - Ke element stiffness matrix - f the global force vector - fe element force vector - - Output parameters: - - K the new global stiffness matrix - f the new global force vector - fe element force vector + Compute element stiffness matrix for two dimensional geometric + nonlinear bar element. + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :param float N: normal force + :return mat Ke: stiffness matrix [4 x 4] """ + E = ep[0] + A = ep[1] - if edof.ndim == 1: - idx = edof-1 - K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke - if (not f is None) and (not fe is None): - f[np.ix_(idx)] = f[np.ix_(idx)] + fe - else: - for row in edof: - idx = row-1 - K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke - if (not f is None) and (not fe is None): - f[np.ix_(idx)] = f[np.ix_(idx)] + fe + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) - if f is None: - return K - else: - return K, f + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2,) -def solveq(K, f, bcPrescr, bcVal=None): + G = np.mat([ + [n[0], n[1], 0., 0.], + [-n[1], n[0], 0., 0.], + [0., 0., n[0], n[1]], + [0., 0., -n[1], n[0]] + ]) + + Kle = E*A/L*np.mat([ + [1, 0, -1, 0], + [0, 0, 0, 0], + [-1, 0, 1, 0], + [0, 0, 0, 0] + ])+N/L*np.mat([ + [0, 0, 0, 0], + [0, 1, 0, -1], + [0, 0, 0, 0], + [0, -1, 0, 1] + ]) + + return G.T*Kle*G + + +def _bar2s(ex, ey, ep, ed): """ - Solve static FE-equations considering boundary conditions. - - Parameters: - - K global stiffness matrix, dim(K)= nd x nd - f global load vector, dim(f)= nd x 1 - - bcPrescr 1-dim integer array containing prescribed dofs. - bcVal 1-dim float array containing prescribed values. - If not given all prescribed dofs are assumed 0. - - Returns: - - a solution including boundary values - Q reaction force vector - dim(a)=dim(Q)= nd x 1, nd : number of dof's + Compute normal force in two dimensional bar element. + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :param list ed: element displacements [u1, u2, u3, u4] + :return float N: element foce [N] """ + E = ep[0] + A = ep[1] - nDofs = K.shape[0] - nPdofs = bcPrescr.shape[0] + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() - if bcVal is None: - bcVal = np.zeros([nPdofs], 'd') + #Kle = np.mat([[1.,-1.],[-1.,1.]])*E*A/L - bc = np.ones(nDofs, 'bool') - bcDofs = np.arange(nDofs) + n = np.asarray(b.T/L).reshape(2,) - bc[np.ix_(bcPrescr-1)] = False - bcDofs = bcDofs[bc] + G = np.mat([ + [n[0], n[1], 0., 0.], + [0., 0., n[0], n[1]] + ]) - fsys = f[bcDofs]-K[np.ix_((bcDofs), (bcPrescr-1))] * \ - np.asmatrix(bcVal).reshape(nPdofs, 1) - asys = np.linalg.solve(K[np.ix_((bcDofs), (bcDofs))], fsys) + u = np.asmatrix(ed).T + N = E*A/L*np.mat([[-1., 1.]])*G*u + return N.item() - a = np.zeros([nDofs, 1]) - a[np.ix_(bcPrescr-1)] = np.asmatrix(bcVal).reshape(nPdofs, 1) - a[np.ix_(bcDofs)] = asys - Q = K*np.asmatrix(a)-f +def _bar2gs(ex, ey, ep, ed): + """ + Calculate section forces in a two dimensional geometric + nonlinear bar element (bar2g). + Parameters: + ex = [x1 x2] element node coordinates + ey = [y1 y2] - return (np.asmatrix(a), Q) + ep = [E A] element properties; + E: Young's modulus + A: cross section area + ed = [u1 ... u4] element displacement vector -def spsolveq(K, f, bcPrescr, bcVal=None): - """ - Solve static FE-equations considering boundary conditions. - - Parameters: - - K global stiffness matrix, dim(K)= nd x nd - f global load vector, dim(f)= nd x 1 - - bcPrescr 1-dim integer array containing prescribed dofs. - bcVal 1-dim float array containing prescribed values. - If not given all prescribed dofs are assumed 0. - Returns: - - a solution including boundary values - Q reaction force vector - dim(a)=dim(Q)= nd x 1, nd : number of dof's - + es = [N1; + N2 ] section forces, local directions + + QX: axial force + + edi = [ u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(es)= n x 1 + ...] + + eci = [ x1 ; local x-coordinates of the evaluation + x2 ; points, (x1=0 and xn=L) + ...] """ + EA = ep[0]*ep[1] + ne = 2 - nDofs = K.shape[0] - nPdofs = bcPrescr.shape[0] + dx = ex[1] - ex[0] + dy = ey[1] - ey[0] + L = np.sqrt(dx**2 + dy**2) - if bcVal is None: - bcVal = np.zeros([nPdofs], 'd') + n = [dx/L, dy/L, -dy/L, dx/L] + G = np.array([ + [n[0], n[1], 0., 0.], + [n[2], n[3], 0., 0.], + [0., 0., n[0], n[1]], + [0., 0., n[2], n[3]] + ]) - bc = np.ones(nDofs, 'bool') - bcDofs = np.arange(nDofs) + edl = G@ed.reshape(-1,1) + a1 = np.array([edl[0], edl[2]]).reshape(-1,1) - bc[np.ix_(bcPrescr-1)] = False - bcDofs = bcDofs[bc] + C1 = np.array([[1., 0.,], + [-1/L, 1/L]]) + C1a = C1@a1 - bcVal_m = np.asmatrix(bcVal).reshape(nPdofs, 1) + x = np.linspace(0,L,ne).reshape(-1,1) + zero = np.zeros(x.shape) + one = np.ones(x.shape) - info("Preparing system matrix...") + u = np.concatenate((one, x),axis=1)@C1a + du = np.concatenate((zero, one),axis=1)@C1a - mask = np.ones(K.shape[0], dtype=bool) - mask[bcDofs] = False + N = EA*du + return N, N[0].item(), u, x - info("step 1... converting K->CSR") - Kcsr = K.asformat("csr") - info("step 2... Kt") - #Kt1 = K[bcDofs] - #Kt = Kt1[:,bcPrescr] - Kt = K[np.ix_((bcDofs), (bcPrescr-1))] - info("step 3... fsys") - fsys = f[bcDofs]-Kt*bcVal_m - info("step 4... Ksys") - Ksys1 = Kcsr[bcDofs] - Ksys = Ksys1[:, bcDofs] - #Ksys = Kcsr[np.ix_((bcDofs),(bcDofs))] - info("done...") - info("Solving system...") - asys = dsolve.spsolve(Ksys, fsys) +def _bar3e(ex, ey, ez, ep): + """ + Compute element stiffness matrix for three dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ez: element z coordinates [z1, z2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :return mat Ke: stiffness matrix, [6 x 6] + """ + E = ep[0] + A = ep[1] - info("Reconstructing full a...") - a = np.zeros([nDofs, 1]) - a[np.ix_(bcPrescr-1)] = bcVal_m - a[np.ix_(bcDofs)] = np.asmatrix(asys).transpose() + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() - a_m = np.asmatrix(a) - Q = K*a_m-f - info("done...") - return (a_m, Q) + n = np.asarray(b.T/L).reshape(3) + G = np.mat([ + [n[0], n[1], n[2], 0., 0., 0.], + [0., 0., 0., n[0], n[1], n[2]] + ]) -def eigen(K,M,b=None): + Kle = E*A/L*np.mat([ + [1, -1], + [-1, 1] + ]) + + return G.T*Kle*G + + +def _bar3s(ex, ey, ez, ep, ed): """ - Solve the generalized eigenvalue problem - |K-LM|X = 0, considering boundary conditions + Compute normal force in three dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ez: element z coordinates [z1, z2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :param list ed: element displacements [u1, ..., u6] + :return float N: normal force + """ + E = ep[0] + A = ep[1] - Parameters: + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() - K global stiffness matrix, dim(K) = ndof x ndof - M global mass matrix, dim(M) = ndof x ndof - b boundary condition vector, dim(b) = nbc x 1 + n = np.asarray(b.T/L).reshape(3) - Returns: + G = np.mat([ + [n[0], n[1], n[2], 0., 0., 0.], + [0., 0., 0., n[0], n[1], n[2]] + ]) - L eigenvalue vector, dim(L) = (ndof-nbc) x 1 - X eigenvectors, dim(X) = ndof x (ndof-nbc) - """ - nd, _ = K.shape - if b is not None: - fdof = np.setdiff1d(np.arange(nd), b-1) - D, X1 = eig(K[np.ix_(fdof,fdof)], M[np.ix_(fdof,fdof)]) - D = np.real(D) - nfdof, _ = X1.shape - for j in range(nfdof): - mnorm = np.sqrt(X1[:,j].T@M[np.ix_(fdof,fdof)]@X1[:,j]) - X1[:,j] /= mnorm - s_order = np.argsort(D) - L = np.sort(D) - X2 = np.zeros(X1.shape) - for ind,j in enumerate(s_order): - X2[:,ind] = X1[:,j] - X = np.zeros((nd,nfdof)) - X[fdof,:] = X2 - return L, X - else: - D, X1 = eig(K, M) - D = np.real(D) - for j in range(nd): - mnorm = np.sqrt(X1[:,j].T@M@X1[:,j]) - X1[:,j] /= mnorm - s_order = np.argsort(D) - L = np.sort(D) - X = np.copy(X1) - for ind,j in enumerate(s_order): - X[:,ind] = X1[:,j] - return L, X + #Kle = E*A/L*np.mat([ + # [ 1,-1], + # [-1, 1] + #]) + u = np.asmatrix(ed).T + N = E*A/L*np.mat([[-1., 1.]])*G*u -def gfunc(G,dt): + return N.item() + +def _beam1e(ex, ep, eq=None): """ - Form vector with function values at equally spaced - points by linear interpolation + Compute the stiffness matrix for a one dimensional beam element. - Parameters: + :param list ex: element x coordinates [x1, x2] + :param list ep: element properties [E, I], E - Young's modulus, I - Moment of inertia + :param float eq: distributed load [qy] + :return mat Ke: element stiffness matrix [4 x 4] + :return mat fe: element load vector [4 x 1] (if eq!=None) + """ + L = ex[1]-ex[0] - G = [t_i, g_i] t_i: time i, g_i: g(t_i) - dim(G) = np x 2, np = number of points - dt time step + E = ep[0] + I = ep[1] - Returns: + qy = 0. + if eq: + qy = eq - t 1-D vector with equally spaced time points - g 1-D vector with corresponding function values - """ - ti = np.arange(G[0,0],G[-1,0]+dt,dt) - g1 = np.interp(ti,G[:,0],G[:,1]) - return ti, g1 + Ke = E*I/(L**3) * np.mat([ + [12, 6*L, -12, 6*L], + [6*L, 4*L**2, -6*L, 2*L**2], + [-12, -6*L, 12, -6*L], + [6*L, 2*L**2, -6*L, 4*L**2] + ]) + fe = qy*np.mat([L/2, L**2/12, L/2, -L**2/12]).T -def step1(K,C,f,a0,bc,ip,times,dofs): + if eq is None: + return Ke + else: + return Ke, fe + +def _beam1s(ex, ep, ed, eq=None, nep=None): """ - Algorithm for dynamic solution of first-order - FE equations considering boundary conditions. + Compute section forces in one dimensional beam element (beam1e). Parameters: - K conductivity matrix, dim(K) = ndof x ndof - C capacity matrix, dim(C) = ndof x ndof - f load vector, dim(f) = ndof x (nstep + 1), - If dim(f) = ndof x 1, the values are kept constant - during time integration - a0 initial vector a(0), dim(a0) = ndof x 1 - bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) - where nbc = number of prescribed degrees of freedom (either constant or time-dependent) - The first column contains the numbers of the prescribed degrees of freedom - and the subsequent columns contain the time history. - If dim(bc) = nbc x 2, the values from the second column are kept constant - during time integration - ip array [dt, tottime, alpha], where - dt is the size of the time increment, - tottime is the total time, - alpha is time integration constant. - Frequently used values of alpha are: - alpha=0: forward difference; forward Euler, - alpha=1/2: trapezoidal rule; Crank-Nicholson - alpha=1: backward difference; backward Euler - times array [t(i) ...] of times at which output should be written to a and da - dofs array [dof(i) ...] of degree of freedom numbers for which history output - should be written to ahist and dahist + ex = [x1 x2] element node coordinates - Returns: + ep = [E I] element properties, + E: Young's modulus + I: moment of inertia - modelhist dictionary containing solution history for the whole model at following keys: - modelhist['a'] constains values of a at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes - modelhist['da'] constains values of da at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes - dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': - dofhist['a'] constains time history of a at the dofs specified in 'dofs' - dim(dofhist['ahist']) = ndof x (nstep + 1) - dofhist['da'] constains time history of daat the dofs specified in 'dofs' - dim(dofhist['dahist']) = ndof x (nstep + 1) - """ - ndof, _ = K.shape - dt, tottime, alpha = ip - a1 = (1-alpha)*dt - a2 = alpha*dt + ed = [u1 ... u4] element displacements - nstep = 1 - if np.array(f).any(): - _, ncf = f.shape - if ncf>1: - nstep = ncf-1 + eq = qy distributed load, local directions - if np.array(bc).any(): - _, ncb = bc.shape - if ncb>2: - nstep = ncb-2 - bound = 1 - if not np.array(bc).any(): - bound = 0 + nep number of evaluation points ( default=2 ) - ns = int(tottime/dt) - if (ns < nstep or nstep==1): - nstep=ns + Returns: - tf = np.zeros((ndof,nstep+1)) - if np.array(f).any(): - if ncf==1: - tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) - if ncf>1: - tf = np.copy(f) + es = [ V1 M1 section forces, local directions, in + V2 M2 n points along the beam, dim(es)= n x 2 + .........] - modelhist = {} - sa=0 - if not np.array(times).any(): - ntimes=0 - sa=1 - modelhist['a'] = np.zeros((ndof,nstep+1)) - modelhist['da'] = np.zeros((ndof,nstep+1)) - else: - ntimes = len(times) - if ntimes: - sa=2 - modelhist['a'] = np.zeros((ndof,ntimes)) - modelhist['da'] = np.zeros((ndof,ntimes)) + edi = [ v1 element displacements, local directions, + v2 in n points along the beam, dim(es)= n x 1 + .......] - dofhist = {} - if np.array(dofs).all(): - ndofs = len(dofs) - if ndofs: - dofhist['a'] = np.zeros((ndofs,nstep+1)) - dofhist['da'] = np.zeros((ndofs,nstep+1)) - else: - ndofs=0 + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] - itime = 0 + """ + EI = ep[0]*ep[1] + L = ex[1]-ex[0] - # Calculate initial second time derivative d2a0 - da0 = np.linalg.solve(C,tf[:,0].reshape(-1,1) - K@a0) - # Save initial values - if sa==1: - modelhist['a'][:,0] = a0.ravel() - modelhist['da'][:,0] = da0.ravel() - elif sa==2: - if times[itime]==0: - modelhist['a'][:,itime] = a0.ravel() - modelhist['da'][:,itime] = da0.ravel() - itime += 1 + qy = 0. - if ndofs: - dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() - dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + if eq: + qy = eq - # Reduce matrices due to bcs - tempa = np.zeros((ndof,1)) - tempda = np.zeros((ndof,1)) - fdof=np.arange(1,ndof+1).astype(int) - if bound: - nrb, ncb = bc.shape - if ncb==2: - pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) - pda = np.zeros((nrb,nstep+1)) - elif ncb>2: - pa = np.copy(bc[:,1:]) - pda1 = (pa[:,1]-pa[:,0])/dt - pdarest = (pa[:,1:] - pa[:,0:-1])/dt - pda = np.hstack((pda1.reshape(-1,1),pdarest)) - pdof = np.copy(bc[:,0]).astype(int) - fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 - pdof -= 1 #adjusting for indexing starting from 0 - Keff = C[np.ix_(fdof,fdof)] + a2*K[np.ix_(fdof,fdof)] - else: - fdof -= 1 #adjusting for indexing starting from 0 - Keff = C + a2*K + ne = 2 - L, U = lu(Keff,permute_l=True) - anew = a0[np.ix_(fdof)] - danew = da0[np.ix_(fdof)] + if nep != None: + ne = nep - # Iterate over time steps - for j in range(1,nstep+1): - time = dt*j - aold = np.copy(anew) - daold = np.copy(danew) - apred = aold + a1*daold - if not bound: - reff = tf[:,j].reshape(-1,1) - K@apred - else: - pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) - reff = tf[np.ix_(fdof),j].reshape(-1,1) - K[np.ix_(fdof,fdof)]@apred - pdeff - y = np.linalg.solve(L,reff) - danew = np.linalg.solve(U,y) - anew = apred + a2*danew - # Save to modelhist and dofhist - if bound: - tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) - tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) - tempa[np.ix_(fdof)] = anew - tempda[np.ix_(fdof)] = danew - if sa==1: - modelhist['a'][:,j] = tempa.ravel() - modelhist['da'][:,j] = tempda.ravel() - elif sa==2: - if ntimes and itime < ntimes: - if time >= times[itime]: - modelhist['a'][:,itime] = tempa.ravel() - modelhist['da'][:,itime] = tempda.ravel() - itime += 1 - if ndofs: - dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() - dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + Cinv = np.mat([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [-3/(L**2), -2/L, 3/(L**2), -1/L], + [2/(L**3), 1/(L**2), -2/(L**3), 1/(L**2)] + ]) - return modelhist, dofhist + Ca = (Cinv@ed).T + x = np.asmatrix(np.linspace(0., L, nep)).T + zero = np.asmatrix(np.zeros([len(x)])).T + one = np.asmatrix(np.ones([len(x)])).T -def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): - """ - Algorithm for dynamic solution of second-order - FE equations considering boundary conditions. + v = np.concatenate((one, x, np.power(x, 2), np.power(x, 3)), 1)@Ca \ + + qy/(24*EI)*(np.power(x,4) - 2*L*np.power(x,3) + (L**2)*np.power(x,2)) + d2v = np.concatenate((zero, zero, 2*one, 6*x), 1)@Ca \ + + qy/(12*EI)*(6*np.power(x,2) - 6*L*x + L**2) + d3v = np.concatenate((zero, zero, zero, 6*one), 1)@Ca + qy/(2*EI)*(2*x - L) - Parameters: + M = EI*d2v + V = -EI*d3v + edi = v + eci = x + es = np.concatenate((V, M), 1) - K global stiffness matrix, dim(K) = ndof x ndof - C global damping matrix, dim(C) = ndof x ndof - If there is no damping in the system, simply set C=[] - M global mass matrix, dim(M) = ndof x ndof - f global load vector, dim(f) = ndof x (nstep + 1), - If dim(f) = ndof x 1, the values are kept constant - during time integration - a0 initial displacement vector a(0), dim(a0) = ndof x 1 - da0 initial velocity vector v(0), dim(da0) = ndof x 1 - bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) - where nbc = number of prescribed degrees of freedom (either constant or time-dependent) - The first column contains the numbers of the prescribed degrees of freedom - and the subsequent columns contain the time history. - If dim(bc) = nbc x 2, the values from the second column are kept constant - during time integration - ip array [dt, tottime, alpha, delta], where - dt is the size of the time increment, - tottime is the total time, - alpha and delta are time integration constants for the Newmark family of methods. - Frequently used values of alpha and delta are: - alpha=1/4, delta=1/2: average acceleration (trapezoidal) rule, - alpha=1/6, delta=1/2: linear acceleration - alpha=0, delta=1/2: central difference - times array [t(i) ...] of times at which output should be written to a, da and d2a - dofs array [dof(i) ...] of degree of freedom numbers for which history output - should be written to ahist, dahist and d2ahist + return (es, edi, eci) - Returns: - modelhist dictionary containing solution history for the whole model at following keys: - modelhist['a'] constains displacement values at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes - modelhist['da'] constains velocity values at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes - modelhist['d2a'] constains acceleration values at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['d2a']) = ndof x (nstep + 1) or ndof x ntimes - dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': - dofhist['a'] constains displacement time history at the dofs specified in 'dofs' - dim(dofhist['ahist']) = ndof x (nstep + 1) - dofhist['da'] constains velocity time history at the dofs specified in 'dofs' - dim(dofhist['dahist']) = ndof x (nstep + 1) - dofhist['d2a'] constains acceleration time history at the dofs specified in 'dofs' - dim(dofhist['d2ahist']) = ndof x (nstep + 1) + +def _beam2e(ex, ey, ep, eq=None): + """ + Compute the stiffness matrix for a two dimensional beam element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: element properties [E, A, I], E - Young's modulus, A - Cross section area, I - Moment of inertia + :param list eq: distributed loads, local directions [qx, qy] + :return mat Ke: element stiffness matrix [6 x 6] + :return mat fe: element stiffness matrix [6 x 1] (if eq!=None) """ - ndof, _ = K.shape - if not np.array(C).any(): - C = np.zeros((ndof,ndof)) - dt, tottime, alpha, delta = ip - b1 = dt*dt*0.5*(1-2*alpha) - b2 = (1-delta)*dt - b3 = delta*dt - b4 = alpha*dt*dt - nstep = 1 - if np.array(f).any(): - _, ncf = f.shape - if ncf>1: - nstep = ncf-1 + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2,) - if np.array(bc).any(): - _, ncb = bc.shape - if ncb>2: - nstep = ncb-2 - bound = 1 - if not np.array(bc).any(): - bound = 0 + E = ep[0] + A = ep[1] + I = ep[2] - ns = int(tottime/dt) - if (ns < nstep or nstep==1): - nstep=ns + qx = 0. + qy = 0. + if not eq is None: + qx = eq[0] + qy = eq[1] - tf = np.zeros((ndof,nstep+1)) - if np.array(f).any(): - if ncf==1: - tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) - if ncf>1: - tf = np.copy(f) + Kle = np.mat([ + [E*A/L, 0., 0., -E*A/L, 0., 0.], + [0., 12*E*I/L**3., 6*E*I/L**2., 0., -12*E*I/L**3., 6*E*I/L**2.], + [0., 6*E*I/L**2., 4*E*I/L, 0., -6*E*I/L**2., 2*E*I/L], + [-E*A/L, 0., 0., E*A/L, 0., 0.], + [0., -12*E*I/L**3., -6*E*I/L**2., 0., 12*E*I/L**3., -6*E*I/L**2.], + [0., 6*E*I/L**2., 2*E*I/L, 0., -6*E*I/L**2., 4*E*I/L] + ]) - modelhist = {} - sa=0 - if not np.array(times).any(): - ntimes=0 - sa=1 - modelhist['a'] = np.zeros((ndof,nstep+1)) - modelhist['da'] = np.zeros((ndof,nstep+1)) - modelhist['d2a'] = np.zeros((ndof,nstep+1)) - else: - ntimes = len(times) - if ntimes: - sa=2 - modelhist['a'] = np.zeros((ndof,ntimes)) - modelhist['da'] = np.zeros((ndof,ntimes)) - modelhist['d2a'] = np.zeros((ndof,ntimes)) + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T - dofhist = {} - if np.array(dofs).all(): - ndofs = len(dofs) - if ndofs: - dofhist['a'] = np.zeros((ndofs,nstep+1)) - dofhist['da'] = np.zeros((ndofs,nstep+1)) - dofhist['d2a'] = np.zeros((ndofs,nstep+1)) + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq is None: + return Ke else: - ndofs=0 + return Ke, fe - itime = 0 - # Calculate initial second time derivative d2a0 - d2a0 = np.linalg.solve(M,tf[:,0].reshape(-1,1) - C@da0 - K@a0) - # Save initial values - if sa==1: - modelhist['a'][:,0] = a0.ravel() - modelhist['da'][:,0] = da0.ravel() - modelhist['d2a'][:,0] = d2a0.ravel() - elif sa==2: - if times[itime]==0: - modelhist['a'][:,itime] = a0.ravel() - modelhist['da'][:,itime] = da0.ravel() - modelhist['d2a'][:,itime] = d2a0.ravel() - itime += 1 +def _beam2s(ex, ey, ep, ed, eq=None, nep=None): + """ + Compute section forces in two dimensional beam element (beam2e). + + Parameters: + + ex = [x1 x2] + ey = [y1 y2] element node coordinates - if ndofs: - dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() - dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() - dofhist['d2a'][:,0] = d2a0[np.ix_(dofs-1)].ravel() + ep = [E A I] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia - # Reduce matrices due to bcs - tempa = np.zeros((ndof,1)) - tempda = np.zeros((ndof,1)) - tempd2a = np.zeros((ndof,1)) - fdof=np.arange(1,ndof+1).astype(int) - if bound: - nrb, ncb = bc.shape - if ncb==2: - pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) - pda = np.zeros((nrb,nstep+1)) - elif ncb>2: - pa = np.copy(bc[:,1:]) - pda1 = (pa[:,1]-pa[:,0])/dt - pdarest = (pa[:,1:] - pa[:,0:-1])/dt - pda = np.hstack((pda1.reshape(-1,1),pdarest)) - pdof = np.copy(bc[:,0]).astype(int) - fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 - pdof -= 1 #adjusting for indexing starting from 0 - Keff = M[np.ix_(fdof,fdof)] + b3*C[np.ix_(fdof,fdof)] +b4*K[np.ix_(fdof,fdof)] + ed = [u1 ... u6] element displacements + + eq = [qx qy] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + Returns: + + es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + .........] + + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .......] + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + + """ + EA = ep[0]*ep[1] + EI = ep[0]*ep[2] + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2,) + + qx = 0. + qy = 0. + + if not eq is None: + qx = eq[0] + qy = eq[1] + + ne = 2 + + if nep != None: + ne = nep + + C = np.mat([ + [0., 0., 0., 1., 0., 0.], + [0., 0., 0., 0., 0., 1.], + [0., 0., 0., 0., 1., 0.], + [L, 0., 0., 1., 0., 0.], + [0., L**3, L**2, 0., L, 1.], + [0., 3*L**2, 2*L, 0., 1., 0.] + ]) + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + M = np.ravel(C.I*(G*np.asmatrix(ed).T - + np.matrix([0., 0., 0., -qx*L**2/(2*EA), qy*L**4/(24*EI), qy*L**3/(6*EI)]).T)) + A = np.matrix([M[0], M[3]]).T + B = np.matrix([M[1], M[2], M[4], M[5]]).T + + x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T + zero = np.asmatrix(np.zeros([len(x)])).T + one = np.asmatrix(np.ones([len(x)])).T + + u = np.concatenate((x, one), 1)*A-np.power(x, 2)*qx/(2*EA) + du = np.concatenate((one, zero), 1)*A-x*qx/EA + v = np.concatenate((np.power(x, 3), np.power(x, 2), x, + one), 1)*B+np.power(x, 4)*qy/(24*EI) + d2v = np.concatenate((6*x, 2*one, zero, zero), 1) * \ + B+np.power(x, 2)*qy/(2*EI) + d3v = np.concatenate((6*one, zero, zero, zero), 1)*B+x*qy/EI + + N = EA*du + M = EI*d2v + V = -EI*d3v + edi = np.concatenate((u, v), 1) + eci = x + es = np.concatenate((N, V, M), 1) + + return (es, edi, eci) + + +def _beam2t(ex, ey, ep, eq=None): + """ + Compute the stiffness matrix for a two dimensional elastic + Timoshenko beam element. + + Parameters: + + ex = [x1 x2] + ey = [y1 y2] element node coordinates + + ep = [E G A I ks] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + I: Moment of inertia + ks: Shear correction factor + + eq = [qx qy] distributed loads, local directions + + Returns: + + Ke element stiffness matrix (6 x 6) + + fe element load vector (6 x 1) + + """ + + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2) + + E = ep[0] + Gm = ep[1] + A = ep[2] + I = ep[3] + ks = ep[4] + + qx = 0. + qy = 0. + if eq != None: + qx = eq[0] + qy = eq[1] + + m = (12/L**2)*(E*I/(Gm*A*ks)) + + Kle = E/(1+m)*np.mat([ + [A*(1+m)/L, 0., 0., -A*(1+m)/L, 0., 0.], + [0., 12*I/L**3., 6*I/L**2., 0., -12*I/L**3., 6*I/L**2.], + [0., 6*I/L**2., 4*I * + (1+m/4.)/L, 0., -6*I/L**2., 2*I*(1-m/2)/L], + [-A*(1+m)/L, 0., 0., + A*(1+m)/L, 0., 0.], + [0., -12*I/L**3., -6*I/L**2., + 0., 12*I/L**3., -6*I/L**2.], + [0., 6*I/L**2., 2*I * + (1-m/2)/L, 0., -6*I/L**2., 4*I*(1+m/4)/L] + ]) + + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq == None: + return Ke else: - fdof -= 1 #adjusting for indexing starting from 0 - Keff = M + b3*C + b4*K + return Ke, fe + + +def _beam2ts(ex, ey, ep, ed, eq=None, nep=None): + """ + Compute section forces in two dimensional beam element (beam2e). + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,G,A,I,ks] element properties, + E: Young's modulus + G: shear modulus + A: cross section area + I: moment of inertia + + ed = [u1, ... ,u6] element displacements + + eq = [qx, qy] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + Returns: + + es = [[N1,V1,M1], section forces, local directions, in + [N2,V2,M2], n points along the beam, dim(es)= n x 3 + ..........] + + edi = [[u1,v1,teta1], element displacements, local directions, + [u2,v2,teta2], and rotation of cross section at + .............] in n points along the beam, dim(es)= n x 2 + + (Note! Rotation of the cross section is not equal to dv/dx for Timoshenko beam element) + + eci = [[x1], local x-coordinates of the evaluation + [x2], points, (x1=0 and xn=L) + ....] + + """ + EA = ep[0]*ep[2] + EI = ep[0]*ep[3] + GAK = ep[1]*ep[2]*ep[4] + alfa = EI/GAK + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2) + + qx = 0. + qy = 0. + if eq != None: + qx = eq[0] + qy = eq[1] + + ne = 2 + + if nep != None: + ne = nep + + C = np.mat([ + [0., 0., 0., 1., 0., 0.], + [0., 0., 0., 0., 0., 1.], + [0., 6*alfa, 0., 0., 1., 0.], + [L, 0., 0., 1., 0., 0.], + [0., L**3, L**2, 0., L, 1.], + [0., 3*(L**2+2*alfa), 2*L, 0., 1., 0.] + ]) + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + M = np.ravel(C.I*(G*np.asmatrix(ed).T-np.mat([0., 0., 0., -qx*L**2/( + 2*EA), qy*L**4/(24*EI)-qy*L**2/(2*GAK), qy*L**3/(6*EI)]).T)) + C2 = np.mat([M[0], M[3]]).T + C4 = np.mat([M[1], M[2], M[4], M[5]]).T - L, U = lu(Keff,permute_l=True) - anew = a0[np.ix_(fdof)] - danew = da0[np.ix_(fdof)] - d2anew = d2a0[np.ix_(fdof)] + x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T + zero = np.asmatrix(np.zeros([len(x)])).T + one = np.asmatrix(np.ones([len(x)])).T - # Iterate over time steps - for j in range(1,nstep+1): - time = dt*j - aold = np.copy(anew) - daold = np.copy(danew) - d2aold = np.copy(d2anew) - apred = aold + dt*daold + b1*d2aold - dapred = daold + b2*d2aold - if not bound: - reff = tf[:,j].reshape(-1,1) - C@dapred - K@apred - else: - pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) - reff = tf[np.ix_(fdof),j].reshape(-1,1) - C[np.ix_(fdof,fdof)]@dapred - K[np.ix_(fdof,fdof)]@apred - pdeff - y = np.linalg.solve(L,reff) - d2anew = np.linalg.solve(U,y) - anew = apred + b4*d2anew - danew = dapred + b3*d2anew - # Save to modelhist and dofhist - if bound: - tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) - tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) - tempa[np.ix_(fdof)] = anew - tempda[np.ix_(fdof)] = danew - tempd2a[np.ix_(fdof)] = d2anew - if sa==1: - modelhist['a'][:,j] = tempa.ravel() - modelhist['da'][:,j] = tempda.ravel() - modelhist['d2a'][:,j] = tempd2a.ravel() - elif sa==2: - if ntimes and itime < ntimes: - if time >= times[itime]: - modelhist['a'][:,itime] = tempa.ravel() - modelhist['da'][:,itime] = tempda.ravel() - modelhist['d2a'][:,itime] = tempd2a.ravel() - itime += 1 - if ndofs: - dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() - dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() - dofhist['d2a'][:,j] = tempd2a[np.ix_(dofs-1)].ravel() + u = np.concatenate((x, one), 1)*C2-qx/(2*EA)*np.power(x, 2) + du = np.concatenate((one, zero), 1)*C2-qx*x/EA - return modelhist, dofhist + v = np.concatenate((np.power(x, 3), np.power(x, 2), x, one), 1) * \ + C4+qy/(24*EI)*np.np.power(x, 4)-qy/(2*GAK)*np.power(x, 2) + dv = np.concatenate((3*np.power(x, 2), 2*x, one, zero), + 1)*C4+qy*np.power(x, 3)/(6*EI)-qy*x/GAK + + teta = np.concatenate((3*(np.power(x, 2)+2*alfa*one), + 2*x, one, zero), 1)*C4+qy*np.power(x, 3)/(6*EI) + dteta = np.concatenate((6*x, 2*one, zero, zero), 1) * \ + C4+qy*np.power(x, 2)/(2*EI) + N = EA*du + M = EI*dteta + V = GAK*(dv-teta) -def extract_eldisp(edof, a): + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v, teta), 1) + eci = x + + if nep != None: + return es, edi, eci + else: + return es + + +def _beam2w(ex, ey, ep, eq=None): """ - Extract element displacements from the global displacement - vector according to the topology matrix edof. + Compute the stiffness matrix for a two dimensional beam element + on elastic foundation. Parameters: - - a the global displacement vector - edof dof topology array - + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,ka,kt] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + ka: axial foundation stiffness + kt: transversal foundation stiffness + + eq = [qx, qy] distributed loads, local directions + Returns: - - ed: element displacement array - + + Ke beam stiffness matrix (6 x 6) + + fe element load vector (6 x 1) """ + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2) - ed = None + E, A, I, ka, kt = ep - if edof.ndim == 1: - nDofs = len(edof) - ed = np.zeros([nDofs]) - idx = edof-1 - ed[:] = a[np.ix_(idx)].T - else: - nElements = edof.shape[0] - nDofs = edof.shape[1] - ed = np.zeros([nElements, nDofs]) - i = 0 - for row in edof: - idx = row-1 - ed[i, :] = a[np.ix_(idx)].T - i += 1 + qx = 0 + qy = 0 + if eq != None: + qx, qy = eq - return ed + K1 = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) + K2 = L/420*np.mat([ + [140*ka, 0, 0, 70*ka, 0, 0], + [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], + [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], + [70*ka, 0, 0, 140*ka, 0, 0], + [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], + [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] + ]) -extractEldisp = extract_eldisp -extract_ed = extract_eldisp + Kle = K1+K2 + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) -def statcon(K, f, cd): - """ - Condensation of static FE-equations according to the vector cd. + Ke = G.T*Kle*G + fe = G.T*fle - Parameters: - - K global stiffness matrix, dim(K) = nd x nd - f global load vector, dim(f)= nd x 1 + if eq != None: + return Ke, fe + else: + return Ke - cd vector containing dof's to be eliminated - dim(cd)= nc x 1, nc: number of condensed dof's - Returns: - - K1 condensed stiffness matrix, - dim(K1)= (nd-nc) x (nd-nc) - f1 condensed load vector, dim(f1)= (nd-nc) x 1 + +def _beam2ws(ex, ey, ep, ed, eq=None): """ - nd, nd = np.shape(K) - cd = (cd-1).flatten() + Compute section forces in a two dimensional beam element + on elastic foundation. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates - aindx = np.arange(nd) - aindx = np.delete(aindx, cd, 0) - bindx = cd + ep = [E,A,I,ka,kt] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + ka: axial foundation stiffness + kt: transversal foundation stiffness - Kaa = np.mat(K[np.ix_(aindx, aindx)]) - Kab = np.mat(K[np.ix_(aindx, bindx)]) - Kbb = np.mat(K[np.ix_(bindx, bindx)]) + ed = [u1, ... ,u6] element displacement vector - fa = np.mat(f[aindx]) - fb = np.mat(f[bindx]) + eq = [qx, qy] distributed loads, local directions - K1 = Kaa-Kab*Kbb.I*Kab.T - f1 = fa-Kab*Kbb.I*fb + Returns: - return K1, f1 + es = [[N1, V1, M1], + [N2, V2, M2]] element forces, local direction + """ + if np.asmatrix(ed).shape[0] > 1: + error("Only one row is allowed in the ed matrix !!!") + return + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) -def c_mul(a, b): - return eval(hex((np.long(a) * b) & 0xFFFFFFFF)[:-1]) + E, A, I, ka, kt = ep + qx = 0 + qy = 0 + if eq != None: + qx, qy = eq -def dofHash(dof): - if len(dof) == 1: - return dof[0] - value = 0x345678 - for item in dof: - value = c_mul(1000003, value) ^ hash(item) - value = value ^ len(dof) - if value == -1: - value = -2 - return value + K1 = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) + + K2 = L/420*np.mat([ + [140*ka, 0, 0, 70*ka, 0, 0], + [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], + [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], + [70*ka, 0, 0, 140*ka, 0, 0], + [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], + [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] + ]) + + Kle = K1+K2 + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) -def create_dofs(nCoords, nDof): - """ - Create dof array [nCoords x nDof] - """ - return np.arange(nCoords*nDof).reshape(nCoords, nDof)+1 + P = Kle*G*np.asmatrix(ed).T-fle + es = np.mat([ + [-P[0, 0], -P[1, 0], -P[2, 0]], + [P[3, 0], P[4, 0], P[5, 0]] + ]) -createdofs = create_dofs + return es -def coordxtr(edof, coords, dofs, nen=-1): +def _beam2g(ex, ey, ep, N, eq=None): """ - Create element coordinate matrices ex, ey, ez from edof - coord and dofs matrices. + Compute the element stiffness matrix for a two dimensional + beam element with respect to geometric nonlinearity. Parameters: - - edof [nel x (nen * nnd)], nnd = number of node dofs - coords [ncoords x ndims], ndims = node dimensions - dofs [ncoords x nnd] - + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + + N axial force in the beam + + eq distributed transverse load + Returns: - - ex if ndims = 1 - ex, ey if ndims = 2 - ex, ey, ez if ndims = 3 + + Ke element stiffness matrix (6 x 6) + + fe element load vector (6 x 1) """ + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return + else: + q = eq[0] + else: + q = 0 - # Create dictionary with dof indices + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) - dofDict = {} - nDofs = np.size(dofs, 1) - nElements = np.size(edof, 0) - n_element_dofs = np.size(edof, 1) - nDimensions = np.size(coords, 1) - nElementDofs = np.size(edof, 1) + E, A, I = ep - if nen == -1: - nElementNodes = int(nElementDofs/nDofs) - else: - nElementNodes = nen + rho = -N*L**2/(np.pi**2*E*I) - if nElementNodes*nDofs != n_element_dofs: - nDofs = nElementNodes*nDofs - n_element_dofs - user_warning( - "dofs/edof mismatch. Using %d dofs per node when indexing." % nDofs) + kL = np.pi*np.sqrt(abs(rho))+np.finfo(float).eps - idx = 0 - for dof in dofs: - #dofDict[dofHash(dof)] = idx - dofDict[hash(tuple(dof[0:nDofs]))] = idx - idx += 1 + if rho > 0: + f1 = (kL/2)/np.tan(kL/2) + f2 = (1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) + elif rho < 0: + f1 = (kL/2)/np.tanh(kL/2) + f2 = -(1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) + else: + f1 = f2 = f3 = f4 = f5 = h = 1 - # Loop over edof and extract element coords + Kle = np.mat([ + [E*A/L, 0., 0., -E*A/L, 0., 0.], + [0., 12*E*I*f5/L**3., 6*E*I*f2/L**2., + 0., -12*E*I*f5/L**3., 6*E*I*f2/L**2.], + [0., 6*E*I*f2/L**2., 4*E*I*f3/L, + 0., -6*E*I*f2/L**2., 2*E*I*f4/L], + [-E*A/L, 0., 0., E*A/L, 0., 0.], + [0., -12*E*I*f5/L**3., -6*E*I*f2/L**2., + 0., 12*E*I*f5/L**3., -6*E*I*f2/L**2.], + [0., 6*E*I*f2/L**2., 2*E*I*f4/L, + 0., -6*E*I*f2/L**2., 4*E*I*f3/L] + ]) - ex = np.zeros((nElements, nElementNodes)) - ey = np.zeros((nElements, nElementNodes)) - ez = np.zeros((nElements, nElementNodes)) + fle = q*L*np.mat([0., 1/2., L*h/12, 0., 1/2., -L*h/12]).T - elementIdx = 0 - for etopo in edof: - for i in range(nElementNodes): - i0 = i*nDofs - i1 = i*nDofs+nDofs-1 - dof = [] - if i0 == i1: - dof = [etopo[i*nDofs]] - else: - dof = etopo[i*nDofs:(i*nDofs+nDofs)] + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) - nodeCoord = coords[dofDict[hash(tuple(dof[0:nDofs]))]] + Ke = G.T*Kle*G + fe = G.T*fle - if nDimensions >= 1: - ex[elementIdx, i] = nodeCoord[0] - if nDimensions >= 2: - ey[elementIdx, i] = nodeCoord[1] - if nDimensions >= 3: - ez[elementIdx, i] = nodeCoord[2] + if eq != None: + return Ke, fe + else: + return Ke - elementIdx += 1 - if nDimensions == 1: - return ex +def _beam2gs(ex, ey, ep, ed, N, eq=None): + """ + Calculate section forces in a two dimensional nonlinear + beam element. - if nDimensions == 2: - return ex, ey + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates - if nDimensions == 3: - return ex, ey, ez + ep = [E,A,I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + ed = [u1, ... ,u6] element displacement vector -coord_extract = coordxtr + N axial force + eq = [qy] distributed transverse load -def hooke(ptype, E, v): - """ - Calculate the material matrix for a linear - elastic and isotropic material. - - Parameters: - - ptype= 1: plane stress - 2: plane strain - 3: axisymmetry - 4: three dimensional - - E Young's modulus - v Poissons const. - Returns: - - D material matrix - + + es = [[N1,V1,M1], element forces, local directions + [N2,V2,M2]] """ + if eq != None: + eq = eq[0] + else: + eq = 0 - if ptype == 1: - D = E*np.matrix( - [[1, v, 0], - [v, 1, 0], - [0, 0, (1-v)/2]] - )/(1-v**2) - elif ptype == 2: - D = E/(1+v)*np.matrix( - [[1-v, v, v, 0], - [v, 1-v, v, 0], - [v, v, 1-v, 0], - [0, 0, 0, (1-2*v)/2]] - )/(1-2*v) - elif ptype == 3: - D = E/(1+v)*np.matrix( - [[1-v, v, v, 0], - [v, 1-v, v, 0], - [v, v, 1-v, 0], - [0, 0, 0, (1-2*v)/2]] - )/(1-2*v) - elif ptype == 4: - D = E*np.matrix( - [[1-v, v, v, 0, 0, 0], - [v, 1-v, v, 0, 0, 0], - [v, v, 1-v, 0, 0, 0], - [0, 0, 0, (1-2*v)/2, 0, 0], - [0, 0, 0, 0, (1-2*v)/2, 0], - [0, 0, 0, 0, 0, (1-2*v)/2]] - )/(1+v)/(1-2*v) + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) + + E, A, I = ep + + rho = -N*L**2/(np.pi**2*E*I) + + eps = 2.2204e-16 + kL = np.pi*np.sqrt(abs(rho))+eps + + if rho > 0: + f1 = (kL/2)/np.tan(kL/2) + f2 = (1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) + elif rho < 0: + f1 = (kL/2)/np.tanh(kL/2) + f2 = -(1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) else: - info("ptype not supported.") + f1 = f2 = f3 = f4 = f5 = h = 1 - return D + Kle = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I*f5/L**3, 6*E*I*f2/L**2, + 0, -12*E*I*f5/L**3, 6*E*I*f2/L**2], + [0, 6*E*I*f2/L**2, 4*E*I*f3/L, 0, -6*E*I*f2/L**2, 2*E*I*f4/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I*f5/L**3, -6*E*I*f2/L**2, + 0, 12*E*I*f5/L**3, -6*E*I*f2/L**2], + [0, 6*E*I*f2/L**2, 2*E*I*f4/L, 0, -6*E*I*f2/L**2, 4*E*I*f3/L] + ]) + fle = eq*L*np.mat([0, 1/2., L*h/12, 0, 1/2., -L*h/12]).T -def effmises(es, ptype): - """ - Calculate effective von mises stresses. - - Parameters: - - es - - ptype= 1: plane stress - 2: plane strain - 3: axisymmetry - 4: three dimensional - - es = [[sigx,sigy,[sigz],tauxy] element stress matrix - [ ...... ]] one row for each element - - Returns: - - eseff = [eseff_0 .. eseff_nel-1] - - """ + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) - nel = np.size(es, 0) - escomps = np.size(es, 1) + u = np.asmatrix(ed).T + P = Kle*G*u-fle - eseff = np.zeros([nel]) + es = np.mat([ + [-P[0, 0], -P[1, 0], -P[2, 0]], + [P[3, 0], P[4, 0], P[5, 0]] + ]) - if ptype == 1: - sigxx = es[:, 0] - sigyy = es[:, 1] - sigxy = es[:, 2] - eseff = np.sqrt(sigxx*sigxx+sigyy*sigyy-sigxx*sigyy+3*sigxy*sigxy) - return eseff + return es -def stress2nodal(eseff, edof): +def _beam2d(ex, ey, ep): """ - Convert element effective stresses to nodal effective - stresses. - + Calculate the stiffness matrix Ke, the mass matrix Me + and the damping matrix Ce for a 2D elastic Bernoulli + beam element. + Parameters: - - eseff = [eseff_0 .. eseff_nel-1] - edof = [dof topology array] - + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,m,(a,b)] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + m: mass per unit length + a,b: damping coefficients, + Ce=aMe+bKe + Returns: - - ev: element value array [[ev_0_0 ev_0_1 ev_0_nen-1 ] - .. - ev_nel-1_0 ev_nel-1_1 ev_nel-1_nen-1] - - """ - values = np.zeros(edof.max()) - elnodes = int(np.size(edof, 1) / 2) + Ke element stiffness matrix (6 x 6) + Me element mass martix + Ce element damping matrix, optional + """ + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) - for etopo, eleseff in zip(edof, eseff): - values[etopo-1] = values[etopo-1] + eleseff / elnodes + a = 0 + b = 0 + if np.size(ep) == 4: + E, A, I, m = ep + elif np.size(ep) == 6: + E, A, I, m, a, b = ep - evtemp = extractEldisp(edof, values) - ev = evtemp[:, range(0, elnodes*2, 2)] + Kle = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) - return ev + Mle = m*L/420*np.mat([ + [140, 0, 0, 70, 0, 0], + [0, 156, 22*L, 0, 54, -13*L], + [0, 22*L, 4*L**2, 0, 13*L, -3*L**2], + [70, 0, 0, 140, 0, 0], + [0, 54, 13*L, 0, 156, -22*L], + [0, -13*L, -3*L**2, 0, -22*L, 4*L**2] + ]) + Cle = a*Mle+b*Kle -def beam2crd_old(ex, ey, ed, mag): - """ - ------------------------------------------------------------- - PURPOSE - Calculate the element continous displacements for a - number of identical 2D Bernoulli beam elements. - - INPUT: ex,ey, - ed, - mag - - OUTPUT: excd,eycd - ------------------------------------------------------------- + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) - LAST MODIFIED: P-E AUSTRELL 1993-10-15 - J Lindemann 2021-12-30 (Python) + Ke = G.T*Kle*G + Me = G.T*Mle*G + Ce = G.T*Cle*G - Copyright (c) Division of Structural Mechanics and - Division of Solid Mechanics. - Lund University - ------------------------------------------------------------- - """ - nie, ned = ed.shape + if np.size(ep) == 4: + return Ke, Me + elif np.size(ep) == 6: + return Ke, Me, Ce - excd = np.zeros([nie, 20]) - eycd = np.zeros([nie, 20]) - for i in range(nie): +def _beam3e(ex, ey, ez, eo, ep, eq=None): + """ + Calculate the stiffness matrix for a 3D elastic Bernoulli + beam element. + + Parameters: + + ex = [x1 x2] + ey = [y1 y2] + ez = [z1 z2] element node coordinates + + eo = [xz yz zz] orientation of local z axis + + ep = [E G A Iy Iz Kv] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + Iy: Moment of inertia, local y-axis + Iz: Moment of inertia, local z-axis + Kv: Saint-Venant's torsion constant + + eq = [qx qy qz qw] distributed loads - b = np.array([ex[i, 1]-ex[i, 0], ey[i, 1]-ey[i, 0]]) - L = np.asscalar(np.sqrt(b@np.transpose(b))) - n = b/L + Returns: - G = np.array([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + Ke beam stiffness matrix (12 x 12) - d = ed[i, :] - dl = G @ d + fe equivalent nodal forces (12 x 1) - xl = np.linspace(0.0, L, 20) - one = np.ones(xl.shape) + """ + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + n1 = np.asarray(b.T/L).reshape(3,) - Cis = np.array([ - [-1.0, 1.0], - [L, 0.0] - ]) / L + eo = np.asmatrix(eo) + lc = np.sqrt(eo*eo.T).item() + n3 = np.asarray(eo/lc).reshape(3,) - ds = np.array([dl[0], dl[3]]).reshape(2, 1) + E, Gs, A, Iy, Iz, Kv = ep - xl_one = np.transpose(np.vstack((xl, one))) + qx = 0. + qy = 0. + qz = 0. + qw = 0. + if eq != None: + qx, qy, qz, qw = eq - ul = np.transpose(xl_one@Cis@ds) # [20x1][2] + a = E*A/L + b = 12*E*Iz/L**3 + c = 6*E*Iz/L**2 + d = 12*E*Iy/L**3 + e = 6*E*Iy/L**2 + f = Gs*Kv/L + g = 2*E*Iy/L + h = 2*E*Iz/L - Cib = np.array([ - [12, 6*L, -12, 6*L], - [-6*L, -4*L**2, 6*L, -2*L**2], - [0, L**3, 0, 0], - [L**3, 0, 0, 0] - ])/L**3 + Kle = np.mat([ + [a, 0, 0, 0, 0, 0, -a, 0, 0, 0, 0, 0], + [0, b, 0, 0, 0, c, 0, -b, 0, 0, 0, c], + [0, 0, d, 0, -e, 0, 0, 0, -d, 0, -e, 0], + [0, 0, 0, f, 0, 0, 0, 0, 0, -f, 0, 0], + [0, 0, -e, 0, 2*g, 0, 0, 0, e, 0, g, 0], + [0, c, 0, 0, 0, 2*h, 0, -c, 0, 0, 0, h], + [-a, 0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0], + [0, -b, 0, 0, 0, -c, 0, b, 0, 0, 0, -c], + [0, 0, -d, 0, e, 0, 0, 0, d, 0, e, 0], + [0, 0, 0, -f, 0, 0, 0, 0, 0, f, 0, 0], + [0, 0, -e, 0, g, 0, 0, 0, e, 0, 2*g, 0], + [0, c, 0, 0, 0, h, 0, -c, 0, 0, 0, 2*h] + ]) - db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) - vl = np.transpose(np.transpose( - np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) + fle = L/2*np.mat([qx, qy, qz, qw, -qz*L/6, qy*L/6, + qx, qy, qz, qw, qz*L/6, -qy*L/6]).T - cld = np.vstack((ul, vl)) - A = np.array([ - [n[0], -n[1]], - [n[1], n[0]] - ]) - cd = A@cld + n2 = np.array([0., 0., 0.]) + n2[0] = n3[1]*n1[2]-n3[2]*n1[1] + n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] + n2[2] = n3[0]*n1[1]-n1[0]*n3[1] - # [2,1] x [1,20] + [2 x 1] x [1 x 20] - # [2 x 20] + [2 x 20] + #An = np.append([n1,n2],[n3],0) - AA = A[:, 0].reshape(2, 1) - XL = xl.reshape(1, 20) - xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]])@one.reshape(1, 20) + G = np.mat([ + [n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2]], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2]], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2]] + ]) - excd[i, :] = xyc[0, :]+mag*cd[0, :] - eycd[i, :] = xyc[1, :]+mag*cd[1, :] + Ke = G.T*Kle*G + fe = G.T*fle - return excd, eycd + if eq == None: + return Ke + else: + return Ke, fe -def beam2crd(ex=None, ey=None, ed=None, mag=None): +def _beam3s(ex, ey, ez, eo, ep, ed, eq=None, n=None): """ - ------------------------------------------------------------- - PURPOSE - Calculate the element continous displacements for a - number of identical 2D Bernoulli beam elements. + Calculate the variation of the section forces and displacements + along a three-dimensional beam element. - INPUT: ex,ey, - ed, - mag + Parameters: + + ex = [x1 x2] element node coordinates + ey = [y1 y2] + ez = [z1 z2] + + eo = [xz yz zz] orientation of local z axis + + ep = [E G A Iy Iz Kv] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + Iy: Moment of inertia, local y-axis + Iz: Moment of inertia, local z-axis + Kv: Saint-Venant's torsion constant + + ed the element displacement vector from the + global coordinate system - OUTPUT: excd,eycd - ------------------------------------------------------------- + eq = [qx qy qz qw] the disibuted axial, transversal and + torsional loads - LAST MODIFIED: P-E AUSTRELL 1993-10-15 - Copyright (c) Division of Structural Mechanics and - Division of Solid Mechanics. - Lund University - ------------------------------------------------------------- - """ + n the number of point in which displacements + and section forces are to be computed - nie, ned = ed.shape + Returns: - n_coords = 21 + es = [[N1,Vy1,Vz1,T1,My1,Mz1], section forces in n points along + [N2,Vy2,Vz2,T2,My2,Mz2], the local x-axis + [..,...,...,..,...,...], + [Nn,Vyn,Vzn,Tn,Myn,Mzn]] - excd = np.zeros([nie, n_coords]) - eycd = np.zeros([nie, n_coords]) + edi = [[u1,v1,w1,fi1], displacements in n points along + [u2,v2,w2,fi2], the local x-axis + [..,..,..,...], + [un,vn,wn,fin]] - for i in range(nie): - b = np.array([ex[i, 1] - ex[i, 0], ey[i, 1] - ey[i, 0]]) - L = np.sqrt(b @ np.transpose(b)) - n = b / L + eci = [[x1], local x-coordinates of the evaluation + [x2], points + [..], + [xn]] - G = np.array([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, - n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + """ + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + n1 = np.asarray(b.T/L).reshape(3,) - d = np.transpose(ed[i, :]) - dl = G @ d - xl = np.transpose(np.linspace(0, L, n_coords)) - one = np.ones(xl.shape) + eo = np.asmatrix(eo) + lc = np.sqrt(eo*eo.T).item() + n3 = np.asarray(eo/lc).reshape(3,) - Cis = np.array([ - [-1, 1], - [L, 0] - ]) / L + EA = ep[0]*ep[2] + EIy = ep[0]*ep[3] + EIz = ep[0]*ep[4] + GKv = ep[1]*ep[5] - ds = np.array([dl[0], dl[3]]).reshape(2, 1) - xl_one = np.transpose(np.vstack((xl, one))) - ul = np.transpose(xl_one@Cis@ds) # [20x1][2] + qx = 0. + qy = 0. + qz = 0. + qw = 0. + if eq != None: + qx, qy, qz, qw = eq - Cib = np.array([ - [12, 6 * L, - 12, 6 * L], - [- 6 * L, - 4 * L ** 2, 6 * L, - 2 * L ** 2], - [0, L ** 3, 0, 0], - [L ** 3, 0, 0, 0] - ]) / L ** 3 + ne = 2 + if n != None: + ne = n - db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) - vl = np.transpose(np.transpose( - np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) + n2 = np.array([0., 0., 0.]) + n2[0] = n3[1]*n1[2]-n3[2]*n1[1] + n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] + n2[2] = n3[0]*n1[1]-n1[0]*n3[1] - cld = np.vstack((ul, vl)) - A = np.array([ - [n[0], -n[1]], - [n[1], n[0]] - ]) - cd = A@cld + G = np.mat([ + [n1[0], n1[1], n1[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n2[0], n2[1], n2[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n3[0], n3[1], n3[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n1[0], n1[1], n1[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n2[0], n2[1], n2[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n3[0], n3[1], n3[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n1[0], n1[1], n1[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n2[0], n2[1], n2[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n3[0], n3[1], n3[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n1[0], n1[1], n1[2]], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n2[0], n2[1], n2[2]], + [0, 0, 0, 0, 0, 0, + 0, 0, 0, n3[0], n3[1], n3[2]] + ]) - # [2,1] x [1,20] + [2 x 1] x [1 x 20] - # [2 x 20] + [2 x 20] + u = G*np.asmatrix(ed).T-np.array([ # u is the local element displacement + [0], # vector minus the particular solution + [0], # to the beam's diff.eq:s + [0], + [0], + [0], + [0], + [-qx*L**2/(2*EA)], + [qy*L**4/(24*EIz)], + [qz*L**4/(24*EIy)], + [-qw*L**2/(2*GKv)], + [-qz*L**3/(6*EIy)], + [qy*L**3/(6*EIz)] + ]) - AA = A[:, 0].reshape(2, 1) - XL = xl.reshape(1, n_coords) - xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]] - )@one.reshape(1, n_coords) + C = np.mat([ + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [L, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], + [0, 0, L**3, L**2, L, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, L**3, L**2, L, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L, 1], + [0, 0, 0, 0, 0, 0, -3*L**2, -2*L, -1, 0, 0, 0], + [0, 0, 3*L**2, 2*L, 1, 0, 0, 0, 0, 0, 0, 0], + ]) - excd[i, :] = xyc[0, :]+mag*cd[0, :] - eycd[i, :] = xyc[1, :]+mag*cd[1, :] + m = np.linalg.inv(C)*u + eci = np.zeros((ne, 1)) + es = np.zeros((ne, 6)) + edi = np.zeros((ne, 4)) + for i in np.arange(ne): + x = i*L/(ne-1) + eci[i, 0] = x + es[i, :] = (np.mat([ + [EA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, -6*EIz, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, -6*EIy, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GKv, 0], + [0, 0, 0, 0, 0, 0, -6*EIy*x, -2*EIy, 0, 0, 0, 0], + [0, 0, 6*EIz*x, 2*EIz, 0, 0, 0, 0, 0, 0, 0, 0] + ])*m+np.array([-qx*x, -qy*x, -qz*x, -qw*x, -qz*x**2/2, qy*x**2/2]).reshape(6, 1)).T + + edi[i, :] = (np.mat([ + [x, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, x**3, x**2, x, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, x**3, x**2, x, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x, 1] + ])*m+np.array([-qx*x**2/(2*EA), qy*x**4/(24*EIz), qz*x**4/(24*EIy), -qw*x**2/(2*GKv)]).reshape(4, 1)).T - return excd, eycd \ No newline at end of file + if n == None: + return es + else: + return es, edi, eci diff --git a/calfem/core_compat.py b/calfem/core_compat.py new file mode 100644 index 0000000..901803b --- /dev/null +++ b/calfem/core_compat.py @@ -0,0 +1,4877 @@ +# -*- coding: iso-8859-15 -*- +""" +CALFEM Core module + +Contains all the functions implementing CALFEM standard functionality +""" + +from scipy.sparse.linalg import dsolve +from scipy.linalg import eig, lu +import numpy as np + +import logging as cflog +import sys +import traceback + +__prev_exception_hook = sys.excepthook + + +def exception_logging(exctype, value, tb): + """ + Log exception by using the root logger. + + Parameters + ---------- + exctype : type + value : NameError + tb : traceback + """ + write_val = {'exception_type': str(exctype), + 'message': str(traceback.format_tb(tb, 10))} + print('Error: %s \n in "%s", line %d' % + (value, tb.tb_frame.f_code.co_filename, tb.tb_lineno)) + + +def enable_friendly_errors(): + __prev_exception_hook = sys.excepthook + sys.excepthook = exception_logging + + +def disable_friendly_errors(): + sys.excepthook = __prev_exception_hook + + +easy_on = enable_friendly_errors +easy_off = disable_friendly_errors + + +def check_list_array(v, error_string): + + fname = sys._getframe(1).f_code.co_name + + if (type(v) != list) and (type(v) != np.ndarray): + raise TypeError("%s (%s)" % (error_string, fname)) + + +def check_length(v, length, error_string): + + fname = sys._getframe(1).f_code.co_name + + if len(v) != length: + raise ValueError("%s (%s)" % (error_string, fname)) + + +def user_warning(msg): + + fname = sys._getframe(1).f_code.co_name + + print("Warning: %s (%s)" % (msg, fname)) + + +def error(msg): + """Write ``msg`` to error log.""" + cflog.error(" calfem.core: "+msg) + + +def info(msg): + """Write ``msg`` to info log.""" + cflog.info(" calfem.core: "+msg) + + +def spring1e(ep): + """ + Compute element stiffness matrix for spring element. + + :param float ep: spring stiffness or analog quantity (ep = k). + :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 + """ + k = ep + return np.mat([[k, -k], [-k, k]], 'd') + + +def spring1s(ep, ed): + """ + Compute element force in spring element (spring1e). + + :param float ep: spring stiffness or analog quantity + :param list ed: element displacements [d0, d1] + :return float es: element force [N] + """ + k = ep + return k*(ed[1]-ed[0]) + + +def bar1e(ep): + """ + Compute element stiffness matrix for spring element. + + :param ep float: spring stiffness or analog quantity + :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 + """ + k = ep + return np.mat([[k, -k], [-k, k]], 'd') + + +def bar1s(ep, ed): + """ + Compute element force in spring element (spring1e). + + :param float ep: spring stiffness or analog quantity + :param list ed: element displacements [d0, d1] + :return float es: element force + """ + k = ep + return k*(ed[1]-ed[0]) + + +def bar2e(ex, ey, ep): + """ + Compute the element stiffness matrix for two dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: [E, A]: E - Young's modulus, A - Cross section area + :return mat Ke: stiffness matrix, [4 x 4] + """ + E = ep[0] + A = ep[1] + + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + + Kle = np.mat([[1., -1.], [-1., 1.]])*E*A/L + + n = np.asarray(b.T/L).reshape(2,) + + G = np.mat([ + [n[0], n[1], 0., 0.], + [0., 0., n[0], n[1]] + ]) + + return G.T*Kle*G + + +def bar2g(ex, ey, ep, N): + """ + Compute element stiffness matrix for two dimensional geometric + nonlinear bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :param float N: normal force + :return mat Ke: stiffness matrix [4 x 4] + """ + E = ep[0] + A = ep[1] + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + + L = np.sqrt(b.T*b).item() + + n = np.asarray(b.T/L).reshape(2,) + + G = np.mat([ + [n[0], n[1], 0., 0.], + [-n[1], n[0], 0., 0.], + [0., 0., n[0], n[1]], + [0., 0., -n[1], n[0]] + ]) + + Kle = E*A/L*np.mat([ + [1, 0, -1, 0], + [0, 0, 0, 0], + [-1, 0, 1, 0], + [0, 0, 0, 0] + ])+N/L*np.mat([ + [0, 0, 0, 0], + [0, 1, 0, -1], + [0, 0, 0, 0], + [0, -1, 0, 1] + ]) + + return G.T*Kle*G + + +def bar2s(ex, ey, ep, ed): + """ + Compute normal force in two dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :param list ed: element displacements [u1, u2, u3, u4] + :return float N: element foce [N] + """ + E = ep[0] + A = ep[1] + + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + + #Kle = np.mat([[1.,-1.],[-1.,1.]])*E*A/L + + n = np.asarray(b.T/L).reshape(2,) + + G = np.mat([ + [n[0], n[1], 0., 0.], + [0., 0., n[0], n[1]] + ]) + + u = np.asmatrix(ed).T + N = E*A/L*np.mat([[-1., 1.]])*G*u + return N.item() + + +def bar2gs(ex, ey, ep, ed): + """ + Calculate section forces in a two dimensional geometric + nonlinear bar element (bar2g). + Parameters: + ex = [x1 x2] element node coordinates + ey = [y1 y2] + + ep = [E A] element properties; + E: Young's modulus + A: cross section area + + ed = [u1 ... u4] element displacement vector + + Returns: + es = [N1; + N2 ] section forces, local directions + + QX: axial force + + edi = [ u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(es)= n x 1 + ...] + + eci = [ x1 ; local x-coordinates of the evaluation + x2 ; points, (x1=0 and xn=L) + ...] + """ + EA = ep[0]*ep[1] + ne = 2 + + dx = ex[1] - ex[0] + dy = ey[1] - ey[0] + L = np.sqrt(dx**2 + dy**2) + + n = [dx/L, dy/L, -dy/L, dx/L] + G = np.array([ + [n[0], n[1], 0., 0.], + [n[2], n[3], 0., 0.], + [0., 0., n[0], n[1]], + [0., 0., n[2], n[3]] + ]) + + edl = G@ed.reshape(-1,1) + a1 = np.array([edl[0], edl[2]]).reshape(-1,1) + + C1 = np.array([[1., 0.,], + [-1/L, 1/L]]) + C1a = C1@a1 + + x = np.linspace(0,L,ne).reshape(-1,1) + zero = np.zeros(x.shape) + one = np.ones(x.shape) + + u = np.concatenate((one, x),axis=1)@C1a + du = np.concatenate((zero, one),axis=1)@C1a + + N = EA*du + return N, N[0].item(), u, x + + +def bar3e(ex, ey, ez, ep): + """ + Compute element stiffness matrix for three dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ez: element z coordinates [z1, z2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :return mat Ke: stiffness matrix, [6 x 6] + """ + E = ep[0] + A = ep[1] + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + + n = np.asarray(b.T/L).reshape(3) + + G = np.mat([ + [n[0], n[1], n[2], 0., 0., 0.], + [0., 0., 0., n[0], n[1], n[2]] + ]) + + Kle = E*A/L*np.mat([ + [1, -1], + [-1, 1] + ]) + + return G.T*Kle*G + + +def bar3s(ex, ey, ez, ep, ed): + """ + Compute normal force in three dimensional bar element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ez: element z coordinates [z1, z2] + :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area + :param list ed: element displacements [u1, ..., u6] + :return float N: normal force + """ + E = ep[0] + A = ep[1] + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + + n = np.asarray(b.T/L).reshape(3) + + G = np.mat([ + [n[0], n[1], n[2], 0., 0., 0.], + [0., 0., 0., n[0], n[1], n[2]] + ]) + + #Kle = E*A/L*np.mat([ + # [ 1,-1], + # [-1, 1] + #]) + + u = np.asmatrix(ed).T + N = E*A/L*np.mat([[-1., 1.]])*G*u + + return N.item() + +def beam1e(ex, ep, eq=None): + """ + Compute the stiffness matrix for a one dimensional beam element. + + :param list ex: element x coordinates [x1, x2] + :param list ep: element properties [E, I], E - Young's modulus, I - Moment of inertia + :param float eq: distributed load [qy] + :return mat Ke: element stiffness matrix [4 x 4] + :return mat fe: element load vector [4 x 1] (if eq!=None) + """ + L = ex[1]-ex[0] + + E = ep[0] + I = ep[1] + + qy = 0. + if eq: + qy = eq + + Ke = E*I/(L**3) * np.mat([ + [12, 6*L, -12, 6*L], + [6*L, 4*L**2, -6*L, 2*L**2], + [-12, -6*L, 12, -6*L], + [6*L, 2*L**2, -6*L, 4*L**2] + ]) + + fe = qy*np.mat([L/2, L**2/12, L/2, -L**2/12]).T + + if eq is None: + return Ke + else: + return Ke, fe + +def beam1s(ex, ep, ed, eq=None, nep=None): + """ + Compute section forces in one dimensional beam element (beam1e). + + Parameters: + + ex = [x1 x2] element node coordinates + + ep = [E I] element properties, + E: Young's modulus + I: moment of inertia + + ed = [u1 ... u4] element displacements + + eq = qy distributed load, local directions + + nep number of evaluation points ( default=2 ) + + Returns: + + es = [ V1 M1 section forces, local directions, in + V2 M2 n points along the beam, dim(es)= n x 2 + .........] + + edi = [ v1 element displacements, local directions, + v2 in n points along the beam, dim(es)= n x 1 + .......] + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + + """ + EI = ep[0]*ep[1] + L = ex[1]-ex[0] + + qy = 0. + + if eq: + qy = eq + + ne = 2 + + if nep != None: + ne = nep + + Cinv = np.mat([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [-3/(L**2), -2/L, 3/(L**2), -1/L], + [2/(L**3), 1/(L**2), -2/(L**3), 1/(L**2)] + ]) + + Ca = (Cinv@ed).T + + x = np.asmatrix(np.linspace(0., L, nep)).T + zero = np.asmatrix(np.zeros([len(x)])).T + one = np.asmatrix(np.ones([len(x)])).T + + v = np.concatenate((one, x, np.power(x, 2), np.power(x, 3)), 1)@Ca \ + + qy/(24*EI)*(np.power(x,4) - 2*L*np.power(x,3) + (L**2)*np.power(x,2)) + d2v = np.concatenate((zero, zero, 2*one, 6*x), 1)@Ca \ + + qy/(12*EI)*(6*np.power(x,2) - 6*L*x + L**2) + d3v = np.concatenate((zero, zero, zero, 6*one), 1)@Ca + qy/(2*EI)*(2*x - L) + + M = EI*d2v + V = -EI*d3v + edi = v + eci = x + es = np.concatenate((V, M), 1) + + return (es, edi, eci) + + + +def beam2e(ex, ey, ep, eq=None): + """ + Compute the stiffness matrix for a two dimensional beam element. + + :param list ex: element x coordinates [x1, x2] + :param list ey: element y coordinates [y1, y2] + :param list ep: element properties [E, A, I], E - Young's modulus, A - Cross section area, I - Moment of inertia + :param list eq: distributed loads, local directions [qx, qy] + :return mat Ke: element stiffness matrix [6 x 6] + :return mat fe: element stiffness matrix [6 x 1] (if eq!=None) + """ + + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2,) + + E = ep[0] + A = ep[1] + I = ep[2] + + qx = 0. + qy = 0. + if not eq is None: + qx = eq[0] + qy = eq[1] + + Kle = np.mat([ + [E*A/L, 0., 0., -E*A/L, 0., 0.], + [0., 12*E*I/L**3., 6*E*I/L**2., 0., -12*E*I/L**3., 6*E*I/L**2.], + [0., 6*E*I/L**2., 4*E*I/L, 0., -6*E*I/L**2., 2*E*I/L], + [-E*A/L, 0., 0., E*A/L, 0., 0.], + [0., -12*E*I/L**3., -6*E*I/L**2., 0., 12*E*I/L**3., -6*E*I/L**2.], + [0., 6*E*I/L**2., 2*E*I/L, 0., -6*E*I/L**2., 4*E*I/L] + ]) + + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq is None: + return Ke + else: + return Ke, fe + + +def beam2s(ex, ey, ep, ed, eq=None, nep=None): + """ + Compute section forces in two dimensional beam element (beam2e). + + Parameters: + + ex = [x1 x2] + ey = [y1 y2] element node coordinates + + ep = [E A I] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + + ed = [u1 ... u6] element displacements + + eq = [qx qy] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + Returns: + + es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + .........] + + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .......] + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + + """ + EA = ep[0]*ep[1] + EI = ep[0]*ep[2] + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2,) + + qx = 0. + qy = 0. + + if not eq is None: + qx = eq[0] + qy = eq[1] + + ne = 2 + + if nep != None: + ne = nep + + C = np.mat([ + [0., 0., 0., 1., 0., 0.], + [0., 0., 0., 0., 0., 1.], + [0., 0., 0., 0., 1., 0.], + [L, 0., 0., 1., 0., 0.], + [0., L**3, L**2, 0., L, 1.], + [0., 3*L**2, 2*L, 0., 1., 0.] + ]) + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + M = np.ravel(C.I*(G*np.asmatrix(ed).T - + np.matrix([0., 0., 0., -qx*L**2/(2*EA), qy*L**4/(24*EI), qy*L**3/(6*EI)]).T)) + A = np.matrix([M[0], M[3]]).T + B = np.matrix([M[1], M[2], M[4], M[5]]).T + + x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T + zero = np.asmatrix(np.zeros([len(x)])).T + one = np.asmatrix(np.ones([len(x)])).T + + u = np.concatenate((x, one), 1)*A-np.power(x, 2)*qx/(2*EA) + du = np.concatenate((one, zero), 1)*A-x*qx/EA + v = np.concatenate((np.power(x, 3), np.power(x, 2), x, + one), 1)*B+np.power(x, 4)*qy/(24*EI) + d2v = np.concatenate((6*x, 2*one, zero, zero), 1) * \ + B+np.power(x, 2)*qy/(2*EI) + d3v = np.concatenate((6*one, zero, zero, zero), 1)*B+x*qy/EI + + N = EA*du + M = EI*d2v + V = -EI*d3v + edi = np.concatenate((u, v), 1) + eci = x + es = np.concatenate((N, V, M), 1) + + return (es, edi, eci) + + +def beam2t(ex, ey, ep, eq=None): + """ + Compute the stiffness matrix for a two dimensional elastic + Timoshenko beam element. + + Parameters: + + ex = [x1 x2] + ey = [y1 y2] element node coordinates + + ep = [E G A I ks] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + I: Moment of inertia + ks: Shear correction factor + + eq = [qx qy] distributed loads, local directions + + Returns: + + Ke element stiffness matrix (6 x 6) + + fe element load vector (6 x 1) + + """ + + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2) + + E = ep[0] + Gm = ep[1] + A = ep[2] + I = ep[3] + ks = ep[4] + + qx = 0. + qy = 0. + if eq != None: + qx = eq[0] + qy = eq[1] + + m = (12/L**2)*(E*I/(Gm*A*ks)) + + Kle = E/(1+m)*np.mat([ + [A*(1+m)/L, 0., 0., -A*(1+m)/L, 0., 0.], + [0., 12*I/L**3., 6*I/L**2., 0., -12*I/L**3., 6*I/L**2.], + [0., 6*I/L**2., 4*I * + (1+m/4.)/L, 0., -6*I/L**2., 2*I*(1-m/2)/L], + [-A*(1+m)/L, 0., 0., + A*(1+m)/L, 0., 0.], + [0., -12*I/L**3., -6*I/L**2., + 0., 12*I/L**3., -6*I/L**2.], + [0., 6*I/L**2., 2*I * + (1-m/2)/L, 0., -6*I/L**2., 4*I*(1+m/4)/L] + ]) + + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq == None: + return Ke + else: + return Ke, fe + + +def beam2ts(ex, ey, ep, ed, eq=None, nep=None): + """ + Compute section forces in two dimensional beam element (beam2e). + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,G,A,I,ks] element properties, + E: Young's modulus + G: shear modulus + A: cross section area + I: moment of inertia + + ed = [u1, ... ,u6] element displacements + + eq = [qx, qy] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + Returns: + + es = [[N1,V1,M1], section forces, local directions, in + [N2,V2,M2], n points along the beam, dim(es)= n x 3 + ..........] + + edi = [[u1,v1,teta1], element displacements, local directions, + [u2,v2,teta2], and rotation of cross section at + .............] in n points along the beam, dim(es)= n x 2 + + (Note! Rotation of the cross section is not equal to dv/dx for Timoshenko beam element) + + eci = [[x1], local x-coordinates of the evaluation + [x2], points, (x1=0 and xn=L) + ....] + + """ + EA = ep[0]*ep[2] + EI = ep[0]*ep[3] + GAK = ep[1]*ep[2]*ep[4] + alfa = EI/GAK + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b.T/L).reshape(2) + + qx = 0. + qy = 0. + if eq != None: + qx = eq[0] + qy = eq[1] + + ne = 2 + + if nep != None: + ne = nep + + C = np.mat([ + [0., 0., 0., 1., 0., 0.], + [0., 0., 0., 0., 0., 1.], + [0., 6*alfa, 0., 0., 1., 0.], + [L, 0., 0., 1., 0., 0.], + [0., L**3, L**2, 0., L, 1.], + [0., 3*(L**2+2*alfa), 2*L, 0., 1., 0.] + ]) + + G = np.mat([ + [n[0], n[1], 0., 0., 0., 0.], + [-n[1], n[0], 0., 0., 0., 0.], + [0., 0., 1., 0., 0., 0.], + [0., 0., 0., n[0], n[1], 0.], + [0., 0., 0., -n[1], n[0], 0.], + [0., 0., 0., 0., 0., 1.] + ]) + + M = np.ravel(C.I*(G*np.asmatrix(ed).T-np.mat([0., 0., 0., -qx*L**2/( + 2*EA), qy*L**4/(24*EI)-qy*L**2/(2*GAK), qy*L**3/(6*EI)]).T)) + C2 = np.mat([M[0], M[3]]).T + C4 = np.mat([M[1], M[2], M[4], M[5]]).T + + x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T + zero = np.asmatrix(np.zeros([len(x)])).T + one = np.asmatrix(np.ones([len(x)])).T + + u = np.concatenate((x, one), 1)*C2-qx/(2*EA)*np.power(x, 2) + du = np.concatenate((one, zero), 1)*C2-qx*x/EA + + v = np.concatenate((np.power(x, 3), np.power(x, 2), x, one), 1) * \ + C4+qy/(24*EI)*np.np.power(x, 4)-qy/(2*GAK)*np.power(x, 2) + dv = np.concatenate((3*np.power(x, 2), 2*x, one, zero), + 1)*C4+qy*np.power(x, 3)/(6*EI)-qy*x/GAK + + teta = np.concatenate((3*(np.power(x, 2)+2*alfa*one), + 2*x, one, zero), 1)*C4+qy*np.power(x, 3)/(6*EI) + dteta = np.concatenate((6*x, 2*one, zero, zero), 1) * \ + C4+qy*np.power(x, 2)/(2*EI) + + N = EA*du + M = EI*dteta + V = GAK*(dv-teta) + + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v, teta), 1) + eci = x + + if nep != None: + return es, edi, eci + else: + return es + + +def beam2w(ex, ey, ep, eq=None): + """ + Compute the stiffness matrix for a two dimensional beam element + on elastic foundation. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,ka,kt] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + ka: axial foundation stiffness + kt: transversal foundation stiffness + + eq = [qx, qy] distributed loads, local directions + + Returns: + + Ke beam stiffness matrix (6 x 6) + + fe element load vector (6 x 1) + """ + b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2) + + E, A, I, ka, kt = ep + + qx = 0 + qy = 0 + if eq != None: + qx, qy = eq + + K1 = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) + + K2 = L/420*np.mat([ + [140*ka, 0, 0, 70*ka, 0, 0], + [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], + [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], + [70*ka, 0, 0, 140*ka, 0, 0], + [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], + [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] + ]) + + Kle = K1+K2 + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq != None: + return Ke, fe + else: + return Ke + + +def beam2ws(ex, ey, ep, ed, eq=None): + """ + Compute section forces in a two dimensional beam element + on elastic foundation. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,ka,kt] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + ka: axial foundation stiffness + kt: transversal foundation stiffness + + ed = [u1, ... ,u6] element displacement vector + + eq = [qx, qy] distributed loads, local directions + + Returns: + + es = [[N1, V1, M1], + [N2, V2, M2]] element forces, local direction + """ + if np.asmatrix(ed).shape[0] > 1: + error("Only one row is allowed in the ed matrix !!!") + return + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) + + E, A, I, ka, kt = ep + + qx = 0 + qy = 0 + if eq != None: + qx, qy = eq + + K1 = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) + + K2 = L/420*np.mat([ + [140*ka, 0, 0, 70*ka, 0, 0], + [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], + [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], + [70*ka, 0, 0, 140*ka, 0, 0], + [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], + [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] + ]) + + Kle = K1+K2 + fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + P = Kle*G*np.asmatrix(ed).T-fle + + es = np.mat([ + [-P[0, 0], -P[1, 0], -P[2, 0]], + [P[3, 0], P[4, 0], P[5, 0]] + ]) + + return es + + +def beam2g(ex, ey, ep, N, eq=None): + """ + Compute the element stiffness matrix for a two dimensional + beam element with respect to geometric nonlinearity. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + + N axial force in the beam + + eq distributed transverse load + + Returns: + + Ke element stiffness matrix (6 x 6) + + fe element load vector (6 x 1) + """ + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return + else: + q = eq[0] + else: + q = 0 + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) + + E, A, I = ep + + rho = -N*L**2/(np.pi**2*E*I) + + kL = np.pi*np.sqrt(abs(rho))+np.finfo(float).eps + + if rho > 0: + f1 = (kL/2)/np.tan(kL/2) + f2 = (1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) + elif rho < 0: + f1 = (kL/2)/np.tanh(kL/2) + f2 = -(1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) + else: + f1 = f2 = f3 = f4 = f5 = h = 1 + + Kle = np.mat([ + [E*A/L, 0., 0., -E*A/L, 0., 0.], + [0., 12*E*I*f5/L**3., 6*E*I*f2/L**2., + 0., -12*E*I*f5/L**3., 6*E*I*f2/L**2.], + [0., 6*E*I*f2/L**2., 4*E*I*f3/L, + 0., -6*E*I*f2/L**2., 2*E*I*f4/L], + [-E*A/L, 0., 0., E*A/L, 0., 0.], + [0., -12*E*I*f5/L**3., -6*E*I*f2/L**2., + 0., 12*E*I*f5/L**3., -6*E*I*f2/L**2.], + [0., 6*E*I*f2/L**2., 2*E*I*f4/L, + 0., -6*E*I*f2/L**2., 4*E*I*f3/L] + ]) + + fle = q*L*np.mat([0., 1/2., L*h/12, 0., 1/2., -L*h/12]).T + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq != None: + return Ke, fe + else: + return Ke + + +def beam2gs(ex, ey, ep, ed, N, eq=None): + """ + Calculate section forces in a two dimensional nonlinear + beam element. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + + ed = [u1, ... ,u6] element displacement vector + + N axial force + + eq = [qy] distributed transverse load + + Returns: + + es = [[N1,V1,M1], element forces, local directions + [N2,V2,M2]] + """ + if eq != None: + eq = eq[0] + else: + eq = 0 + + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) + + E, A, I = ep + + rho = -N*L**2/(np.pi**2*E*I) + + eps = 2.2204e-16 + kL = np.pi*np.sqrt(abs(rho))+eps + + if rho > 0: + f1 = (kL/2)/np.tan(kL/2) + f2 = (1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) + elif rho < 0: + f1 = (kL/2)/np.tanh(kL/2) + f2 = -(1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) + else: + f1 = f2 = f3 = f4 = f5 = h = 1 + + Kle = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I*f5/L**3, 6*E*I*f2/L**2, + 0, -12*E*I*f5/L**3, 6*E*I*f2/L**2], + [0, 6*E*I*f2/L**2, 4*E*I*f3/L, 0, -6*E*I*f2/L**2, 2*E*I*f4/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I*f5/L**3, -6*E*I*f2/L**2, + 0, 12*E*I*f5/L**3, -6*E*I*f2/L**2], + [0, 6*E*I*f2/L**2, 2*E*I*f4/L, 0, -6*E*I*f2/L**2, 4*E*I*f3/L] + ]) + + fle = eq*L*np.mat([0, 1/2., L*h/12, 0, 1/2., -L*h/12]).T + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + u = np.asmatrix(ed).T + P = Kle*G*u-fle + + es = np.mat([ + [-P[0, 0], -P[1, 0], -P[2, 0]], + [P[3, 0], P[4, 0], P[5, 0]] + ]) + + return es + + +def beam2d(ex, ey, ep): + """ + Calculate the stiffness matrix Ke, the mass matrix Me + and the damping matrix Ce for a 2D elastic Bernoulli + beam element. + + Parameters: + + ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,m,(a,b)] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + m: mass per unit length + a,b: damping coefficients, + Ce=aMe+bKe + + Returns: + + Ke element stiffness matrix (6 x 6) + Me element mass martix + Ce element damping matrix, optional + """ + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T*b).item() + n = np.asarray(b/L).reshape(2,) + + a = 0 + b = 0 + if np.size(ep) == 4: + E, A, I, m = ep + elif np.size(ep) == 6: + E, A, I, m, a, b = ep + + Kle = np.mat([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) + + Mle = m*L/420*np.mat([ + [140, 0, 0, 70, 0, 0], + [0, 156, 22*L, 0, 54, -13*L], + [0, 22*L, 4*L**2, 0, 13*L, -3*L**2], + [70, 0, 0, 140, 0, 0], + [0, 54, 13*L, 0, 156, -22*L], + [0, -13*L, -3*L**2, 0, -22*L, 4*L**2] + ]) + + Cle = a*Mle+b*Kle + + G = np.mat([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T*Kle*G + Me = G.T*Mle*G + Ce = G.T*Cle*G + + if np.size(ep) == 4: + return Ke, Me + elif np.size(ep) == 6: + return Ke, Me, Ce + + +def beam3e(ex, ey, ez, eo, ep, eq=None): + """ + Calculate the stiffness matrix for a 3D elastic Bernoulli + beam element. + + Parameters: + + ex = [x1 x2] + ey = [y1 y2] + ez = [z1 z2] element node coordinates + + eo = [xz yz zz] orientation of local z axis + + ep = [E G A Iy Iz Kv] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + Iy: Moment of inertia, local y-axis + Iz: Moment of inertia, local z-axis + Kv: Saint-Venant's torsion constant + + eq = [qx qy qz qw] distributed loads + + Returns: + + Ke beam stiffness matrix (12 x 12) + + fe equivalent nodal forces (12 x 1) + + """ + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + n1 = np.asarray(b.T/L).reshape(3,) + + eo = np.asmatrix(eo) + lc = np.sqrt(eo*eo.T).item() + n3 = np.asarray(eo/lc).reshape(3,) + + E, Gs, A, Iy, Iz, Kv = ep + + qx = 0. + qy = 0. + qz = 0. + qw = 0. + if eq != None: + qx, qy, qz, qw = eq + + a = E*A/L + b = 12*E*Iz/L**3 + c = 6*E*Iz/L**2 + d = 12*E*Iy/L**3 + e = 6*E*Iy/L**2 + f = Gs*Kv/L + g = 2*E*Iy/L + h = 2*E*Iz/L + + Kle = np.mat([ + [a, 0, 0, 0, 0, 0, -a, 0, 0, 0, 0, 0], + [0, b, 0, 0, 0, c, 0, -b, 0, 0, 0, c], + [0, 0, d, 0, -e, 0, 0, 0, -d, 0, -e, 0], + [0, 0, 0, f, 0, 0, 0, 0, 0, -f, 0, 0], + [0, 0, -e, 0, 2*g, 0, 0, 0, e, 0, g, 0], + [0, c, 0, 0, 0, 2*h, 0, -c, 0, 0, 0, h], + [-a, 0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0], + [0, -b, 0, 0, 0, -c, 0, b, 0, 0, 0, -c], + [0, 0, -d, 0, e, 0, 0, 0, d, 0, e, 0], + [0, 0, 0, -f, 0, 0, 0, 0, 0, f, 0, 0], + [0, 0, -e, 0, g, 0, 0, 0, e, 0, 2*g, 0], + [0, c, 0, 0, 0, h, 0, -c, 0, 0, 0, 2*h] + ]) + + fle = L/2*np.mat([qx, qy, qz, qw, -qz*L/6, qy*L/6, + qx, qy, qz, qw, qz*L/6, -qy*L/6]).T + + n2 = np.array([0., 0., 0.]) + n2[0] = n3[1]*n1[2]-n3[2]*n1[1] + n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] + n2[2] = n3[0]*n1[1]-n1[0]*n3[1] + + #An = np.append([n1,n2],[n3],0) + + G = np.mat([ + [n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2]], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2]], + [0, 0, 0, 0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2]] + ]) + + Ke = G.T*Kle*G + fe = G.T*fle + + if eq == None: + return Ke + else: + return Ke, fe + + +def beam3s(ex, ey, ez, eo, ep, ed, eq=None, n=None): + """ + Calculate the variation of the section forces and displacements + along a three-dimensional beam element. + + Parameters: + + ex = [x1 x2] element node coordinates + ey = [y1 y2] + ez = [z1 z2] + + eo = [xz yz zz] orientation of local z axis + + ep = [E G A Iy Iz Kv] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + Iy: Moment of inertia, local y-axis + Iz: Moment of inertia, local z-axis + Kv: Saint-Venant's torsion constant + + ed the element displacement vector from the + global coordinate system + + eq = [qx qy qz qw] the disibuted axial, transversal and + torsional loads + + n the number of point in which displacements + and section forces are to be computed + + Returns: + + es = [[N1,Vy1,Vz1,T1,My1,Mz1], section forces in n points along + [N2,Vy2,Vz2,T2,My2,Mz2], the local x-axis + [..,...,...,..,...,...], + [Nn,Vyn,Vzn,Tn,Myn,Mzn]] + + edi = [[u1,v1,w1,fi1], displacements in n points along + [u2,v2,w2,fi2], the local x-axis + [..,..,..,...], + [un,vn,wn,fin]] + + eci = [[x1], local x-coordinates of the evaluation + [x2], points + [..], + [xn]] + + """ + b = np.mat([ + [ex[1]-ex[0]], + [ey[1]-ey[0]], + [ez[1]-ez[0]] + ]) + L = np.sqrt(b.T*b).item() + n1 = np.asarray(b.T/L).reshape(3,) + + eo = np.asmatrix(eo) + lc = np.sqrt(eo*eo.T).item() + n3 = np.asarray(eo/lc).reshape(3,) + + EA = ep[0]*ep[2] + EIy = ep[0]*ep[3] + EIz = ep[0]*ep[4] + GKv = ep[1]*ep[5] + + qx = 0. + qy = 0. + qz = 0. + qw = 0. + if eq != None: + qx, qy, qz, qw = eq + + ne = 2 + if n != None: + ne = n + + n2 = np.array([0., 0., 0.]) + n2[0] = n3[1]*n1[2]-n3[2]*n1[1] + n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] + n2[2] = n3[0]*n1[1]-n1[0]*n3[1] + + G = np.mat([ + [n1[0], n1[1], n1[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n2[0], n2[1], n2[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n3[0], n3[1], n3[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n1[0], n1[1], n1[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n2[0], n2[1], n2[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n3[0], n3[1], n3[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n1[0], n1[1], n1[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n2[0], n2[1], n2[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n3[0], n3[1], n3[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n1[0], n1[1], n1[2]], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n2[0], n2[1], n2[2]], + [0, 0, 0, 0, 0, 0, + 0, 0, 0, n3[0], n3[1], n3[2]] + ]) + + u = G*np.asmatrix(ed).T-np.array([ # u is the local element displacement + [0], # vector minus the particular solution + [0], # to the beam's diff.eq:s + [0], + [0], + [0], + [0], + [-qx*L**2/(2*EA)], + [qy*L**4/(24*EIz)], + [qz*L**4/(24*EIy)], + [-qw*L**2/(2*GKv)], + [-qz*L**3/(6*EIy)], + [qy*L**3/(6*EIz)] + ]) + + C = np.mat([ + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [L, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], + [0, 0, L**3, L**2, L, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, L**3, L**2, L, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L, 1], + [0, 0, 0, 0, 0, 0, -3*L**2, -2*L, -1, 0, 0, 0], + [0, 0, 3*L**2, 2*L, 1, 0, 0, 0, 0, 0, 0, 0], + ]) + + m = np.linalg.inv(C)*u + eci = np.zeros((ne, 1)) + es = np.zeros((ne, 6)) + edi = np.zeros((ne, 4)) + for i in np.arange(ne): + x = i*L/(ne-1) + eci[i, 0] = x + es[i, :] = (np.mat([ + [EA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, -6*EIz, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, -6*EIy, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GKv, 0], + [0, 0, 0, 0, 0, 0, -6*EIy*x, -2*EIy, 0, 0, 0, 0], + [0, 0, 6*EIz*x, 2*EIz, 0, 0, 0, 0, 0, 0, 0, 0] + ])*m+np.array([-qx*x, -qy*x, -qz*x, -qw*x, -qz*x**2/2, qy*x**2/2]).reshape(6, 1)).T + + edi[i, :] = (np.mat([ + [x, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, x**3, x**2, x, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, x**3, x**2, x, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x, 1] + ])*m+np.array([-qx*x**2/(2*EA), qy*x**4/(24*EIz), qz*x**4/(24*EIy), -qw*x**2/(2*GKv)]).reshape(4, 1)).T + + if n == None: + return es + else: + return es, edi, eci + + +def flw2te(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) matrix for a triangular field element. + + Parameters: + + ex = [x1 x2 x3] + ey = [y1 y2 y3] element coordinates + + ep = [t] element thickness + + D = [kxx kxy; + kyx kyy] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (3 x 3) + + fe element load vector (3 x 1) + + """ + t = ep[0] + if eq == None: + eq = 0. + + exm = np.asmatrix(ex) + eym = np.asmatrix(ey) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I + A = 0.5*np.linalg.det(C) + + Ke = B.T*D*B*t*A + fe = np.matrix([[1., 1., 1.]]).T*eq*A*t/3 + + if eq == 0.: + return Ke + else: + return Ke, fe + + +def flw2ts(ex, ey, D, ed): + """ + Compute flows or corresponding quantities in the triangular field element. + + Parameters: + + ex = [x1 x2 x3] + ey = [y1 y2 y3] element coordinates + + D = [kxx kxy + kyx kyy] constitutive matrix + + ed =[u1 u2 u3] u1,u2,u3: nodal values + .. .. ..; + + Returns: + + es=[ qx qy ] + ... ..] element flows + + et=[ gx gy ] + ... ..] element gradients + + """ + + if len(ex.shape) > 1: + qs = np.zeros([ex.shape[0], 2]) + qt = np.zeros([ex.shape[0], 2]) + row = 0 + for exr, eyr, edr in zip(ex, ey, ed): + exm = np.asmatrix(exr) + eym = np.asmatrix(eyr) + edm = np.asmatrix(edr) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I + + qs[row, :] = (-D*B*edm.T).T + qt[row, :] = (B*edm.T).T + row += 1 + + return qs, qt + else: + exm = np.asmatrix(ex) + eym = np.asmatrix(ey) + edm = np.asmatrix(ed) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I + + qs = -D*B*edm.T + qt = B*edm.T + + return qs.T, qt.T + + +def flw2qe(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) matrix for a triangular field element. + + Parameters: + + ex = [x1, x2, x3, x4] + ey = [y1, y2, y3, y4] element coordinates + + ep = [t] element thickness + + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (4 x 4) + + fe element load vector (4 x 1) + + """ + xc = sum(ex)/4. + yc = sum(ey)/4. + + K = np.zeros((5, 5)) + f = np.zeros((5, 1)) + + if eq == None: + k1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D) + K = assem(np.array([1, 2, 5]), K, k1) + k1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D) + K = assem(np.array([2, 3, 5]), K, k1) + k1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D) + K = assem(np.array([3, 4, 5]), K, k1) + k1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D) + K = assem(np.array([4, 1, 5]), K, k1) + else: + k1, f1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D, eq) + K, f = assem(np.array([1, 2, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D, eq) + K, f = assem(np.array([2, 3, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D, eq) + K, f = assem(np.array([3, 4, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D, eq) + K, f = assem(np.array([4, 1, 5]), K, k1, f, f1) + Ke1, fe1 = statcon(K, f, np.array([5])) + + Ke = Ke1 + fe = fe1 + + if eq == None: + return Ke + else: + return Ke, fe + + +def flw2qs(ex, ey, ep, D, ed, eq=None): + """ + Compute flows or corresponding quantities in the + quadrilateral field element. + + Parameters: + + ex = [x1, x2, x3, x4] + ey = [y1, y2, y3, y4] element coordinates + + ep = [t] element thickness + + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + ed = [[u1, u2, u3, u4], + [.., .., .., ..]] u1,u2,u3,u4: nodal values + + eq heat supply per unit volume + + Returns: + + es = [[qx, qy], + [.., ..]] element flows + + et = [[gx, gy], + [.., ..]] element gradients + + """ + K = np.zeros((5, 5)) + f = np.zeros((5, 1)) + + xm = sum(ex)/4 + ym = sum(ey)/4 + + if eq == None: + q = 0 + else: + q = eq + + En = np.array([ + [1, 2, 5], + [2, 3, 5], + [3, 4, 5], + [4, 1, 5] + ]) + ex1 = np.array([ex[0], ex[1], xm]) + ey1 = np.array([ey[0], ey[1], ym]) + ex2 = np.array([ex[1], ex[2], xm]) + ey2 = np.array([ey[1], ey[2], ym]) + ex3 = np.array([ex[2], ex[3], xm]) + ey3 = np.array([ey[2], ey[3], ym]) + ex4 = np.array([ex[3], ex[0], xm]) + ey4 = np.array([ey[3], ey[0], ym]) + + if eq == None: + k1 = flw2te(ex1, ey1, ep, D) + K = assem(En[0], K, k1) + k1 = flw2te(ex2, ey2, ep, D) + K = assem(En[1], K, k1) + k1 = flw2te(ex3, ey3, ep, D) + K = assem(En[2], K, k1) + k1 = flw2te(ex4, ey4, ep, D) + K = assem(En[3], K, k1) + else: + k1, f1 = flw2te(ex1, ey1, ep, D, q) + K, f = assem(En[0], K, k1, f, f1) + k1, f1 = flw2te(ex2, ey2, ep, D, q) + K, f = assem(En[1], K, k1, f, f1) + k1, f1 = flw2te(ex3, ey3, ep, D, q) + K, f = assem(En[2], K, k1, f, f1) + k1, f1 = flw2te(ex4, ey4, ep, D, q) + K, f = assem(En[3], K, k1, f, f1) + + if ed.ndim == 1: + ed = np.array([ed]) + + ni, nj = np.shape(ed) + + a = np.zeros((5, ni)) + for i in range(ni): + a[np.ix_(range(5), [i])], r = np.asarray( + solveq(K, f, np.arange(1, 5), ed[i])) + + s1, t1 = flw2ts(ex1, ey1, D, a[np.ix_(En[0, :]-1, np.arange(ni))].T) + s2, t2 = flw2ts(ex2, ey2, D, a[np.ix_(En[1, :]-1, np.arange(ni))].T) + s3, t3 = flw2ts(ex3, ey3, D, a[np.ix_(En[2, :]-1, np.arange(ni))].T) + s4, t4 = flw2ts(ex4, ey4, D, a[np.ix_(En[3, :]-1, np.arange(ni))].T) + + es = (s1+s2+s3+s4)/4. + et = (t1+t2+t3+t4)/4. + + return es, et + + +def flw2i4e(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) + matrix for 4 node isoparametric field element + + Parameters: + + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] + + ep = [t ir] thickness and integration rule + + D = [[kxx kxy], + [kyx kyy]] constitutive matrix + + eq heat supply per unit volume + + Returns: + Ke element 'stiffness' matrix (4 x 4) + fe element load vector (4 x 1) + + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir + + if eq == None: + q = 0 + else: + q = eq + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. + + Ke1 = np.mat(np.zeros((4, 4))) + fe1 = np.mat(np.zeros((4, 1))) + JT = dNr*np.mat([ex, ey]).T + + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] + + if eq == None: + return Ke1*t + else: + return Ke1*t, fe1*t*eq + + +def flw2i4s(ex, ey, ep, D, ed): + """ + Compute flows or corresponding quantities in the + 4 node isoparametric element. + + Parameters: + + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] + + ep = [t ir] thickness and integration rule + + D = [[kxx kxy], + [kyx kyy]] constitutive matrix + + ed = [u1, u2, u3, u4] u1,u2,u3,u4: nodal values + + Returns: + es = [[qx, qy], + [.., ..]] element flows + + et = [[qx, qy], + [... ..]] element gradients + + eci=[[ix1, iy1], Gauss point location vector + [... ...], nint: number of integration points + [ix(nint), iy(nint)] + + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. + + eci = N*np.mat([ex, ey]).T + if ed.ndim == 1: + ed = np.array([ed]) + + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey]).T + + es = np.mat(np.zeros((ngp*red, 2))) + et = np.mat(np.zeros((ngp*red, 2))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinatn == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + + return es, et, eci + + +def flw2i8e(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) + matrix for 8 node isoparametric field element. + + Parameters: + + ex = [x1, ..., x8] element coordinates + ey = [y1, ..., y8] + + ep = [t, ir] thickness and integration rule + + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (8 x 8) + fe element load vector (8 x 1) + + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir + + if eq == None: + q = 0 + else: + q = eq + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + + N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) + N = np.append(N, np.multiply( + (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) + N = np.append(N, np.multiply( + (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) + + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - + np.multiply((1+xsi), (1-eta)))/4. + dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + + np.multiply((1-xsi), (1+eta)))/4. + dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) + dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. + dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) + dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. + dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + + np.multiply((1+xsi), (1-eta)))/4. + dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - + np.multiply((1-xsi), (1+eta)))/4. + dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) + dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) + + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey]).T + + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminanten lika med noll!") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] + + if eq != None: + return Ke1*t, fe1*t*q + else: + return Ke1*t + + +def flw2i8s(ex, ey, ep, D, ed): + """ + Compute flows or corresponding quantities in the + 8 node isoparametric element. + + Parameters: + + ex = [x1,x2,x3....,x8] element coordinates + ey = [y1,y2,y3....,y8] + + ep = [t,ir] thickness and integration rule + + D = [[kxx,kxy], + [kyx,kyy]] constitutive matrix + + ed = [u1,....,u8] u1,....,u8: nodal values + + Returns: + es = [[qx,qy], + [..,..]] element flows + + et = [[qx,qy], + [..,..]] element gradients + + eci=[[ix1,iy1], Gauss point location vector + [...,...], nint: number of integration points + [ix(nint),iy(nint)]] + + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + + N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) + N = np.append(N, np.multiply( + (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) + N = np.append(N, np.multiply( + (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) + + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - + np.multiply((1+xsi), (1-eta)))/4. + dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + + np.multiply((1-xsi), (1+eta)))/4. + dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) + dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. + dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) + dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. + dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + + np.multiply((1+xsi), (1-eta)))/4. + dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - + np.multiply((1-xsi), (1+eta)))/4. + dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) + dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) + + eci = N*np.mat([ex, ey]).T + if ed.ndim == 1: + ed = np.array([ed]) + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey]).T + + es = np.mat(np.zeros((ngp*red, 2))) + et = np.mat(np.zeros((ngp*red, 2))) + + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + + return es, et, eci + + +def flw3i8e(ex, ey, ez, ep, D, eq=None): + """ + Compute element stiffness (conductivity) + matrix for 8 node isoparametric field element. + + Parameters: + + ex = [x1,x2,x3,...,x8] + ey = [y1,y2,y3,...,y8] element coordinates + ez = [z1,z2,z3,...,z8] + + ep = [ir] Ir: Integration rule + + D = [[kxx,kxy,kxz], + [kyx,kyy,kyz], + [kzx,kzy,kzz]] constitutive matrix + + eq heat supply per unit volume + + Output: + + Ke element 'stiffness' matrix (8 x 8) + fe element load vector (8 x 1) + + """ + ir = ep[0] + ngp = ir*ir*ir + + if eq == None: + q = 0 + else: + q = eq + + if ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-1, -1, -1], + [1, -1, -1], + [1, 1, -1], + [-1, 1, -1], + [-1, -1, 1], + [1, -1, 1], + [1, 1, 1], + [-1, 1, 1] + ])*g1 + w = np.mat(np.ones((8, 3)))*w1 + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat(np.zeros((27, 3))) + w = np.mat(np.zeros((27, 3))) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) + gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] + I1 = abs(I1) + I2 = abs(I2) + w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) + gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] + I1 = abs(I1) + I2 = abs(I2) + w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) + I3 = abs(I1) + gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 + gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] + w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 + w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] + else: + info("Used number of integration points not implemented") + return + + wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) + + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 + + N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1+zet))/8., axis=1) + + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) + dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) + dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) + dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) + dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) + dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) + dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) + dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) + dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) + dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) + dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) + dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) + dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) + dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) + dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) + dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) + dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) + dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) + dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) + dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) + dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) + dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) + dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) + dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) + dNr = dNr/8. + + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey, ez]).T + + for i in range(ngp): + indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] + + if eq != None: + return Ke1, fe1*q + else: + return Ke1 + + +def flw3i8s(ex, ey, ez, ep, D, ed): + """ + Compute flows or corresponding quantities in the + 8 node (3-dim) isoparametric field element. + + Parameters: + + ex = [x1,x2,x3,...,x8] + ey = [y1,y2,y3,...,y8] element coordinates + ez = [z1,z2,z3,...,z8] + + ep = [ir] Ir: Integration rule + + D = [[kxx,kxy,kxz], + [kyx,kyy,kyz], + [kzx,kzy,kzz]] constitutive matrix + + ed = [[u1,....,u8], element nodal values + [..,....,..]] + + Output: + + es = [[qx,qy,qz], + [..,..,..]] element flows(s) + + et = [[qx,qy,qz], element gradients(s) + [..,..,..]] + + eci = [[ix1,ix1,iz1], location vector + [...,...,...], nint: number of integration points + [ix(nint),iy(nint),iz(nint)]] + + """ + ir = ep[0] + ngp = ir*ir*ir + + if ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-1, -1, -1], + [1, -1, -1], + [1, 1, -1], + [-1, 1, -1], + [-1, -1, 1], + [1, -1, 1], + [1, 1, 1], + [-1, 1, 1] + ])*g1 + w = np.mat(np.ones((8, 3)))*w1 + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat(np.zeros((27, 3))) + w = np.mat(np.zeros((27, 3))) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) + gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] + I1 = abs(I1) + I2 = abs(I2) + w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) + gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] + I1 = abs(I1) + I2 = abs(I2) + w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) + I3 = abs(I1) + gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 + gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] + w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 + w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] + else: + info("Used number of integration points not implemented") + return + + wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) + + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 + + N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1+zet))/8., axis=1) + + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) + dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) + dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) + dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) + dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) + dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) + dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) + dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) + dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) + dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) + dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) + dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) + dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) + dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) + dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) + dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) + dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) + dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) + dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) + dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) + dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) + dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) + dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) + dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) + dNr = dNr/8. + + eci = N*np.mat([ex, ey, ez]).T + if ed.ndim == 1: + ed = np.array([ed]) + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey, ez]).T + + es = np.mat(np.zeros((ngp*red, 3))) + et = np.mat(np.zeros((ngp*red, 3))) + for i in range(ngp): + indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminanten lika med noll!") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + + return es, et, eci + + +def plante(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a triangular plane stress or plane strain element. + + Parameters: + + ex = [x1,x2,x3] element coordinates + ey = [y1,y2,y3] + + ep = [ptype,t] ptype: analysis type + t: thickness + + D constitutive matrix + + eq = [[bx], bx: body force x-dir + [by]] by: body force y-dir + + Returns: + + Ke element stiffness matrix (6 x 6) + fe equivalent nodal forces (6 x 1) (if eq is given) + + """ + + ptype, t = ep + + bx = 0.0 + by = 0.0 + + if not eq is None: + bx = eq[0] + by = eq[1] + + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) + + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) + + # --------- plane stress -------------------------------------- + + if ptype == 1: + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) + + colD = D.shape[1] + + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) + else: + Dm = D + + Ke = B.T*Dm*B*A*t + fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t + + if eq is None: + return Ke + else: + return Ke, fe.T + + #--------- plane strain -------------------------------------- + + elif ptype == 2: + B = np.mat([ + [0, 1, 0, 0, 0, 0, ], + [0, 0, 0, 0, 0, 1, ], + [0, 0, 1, 0, 1, 0, ] + ])*np.linalg.inv(C) + + colD = D.shape[1] + + if colD > 3: + Dm = D[np.ix_((0, 1, 3), (0, 1, 3))] + else: + Dm = D + + Ke = B.T*Dm*B*A*t + fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t + + if eq == None: + return Ke + else: + return Ke, fe.T + + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + if eq == None: + return None + else: + return None, None + + +def plants(ex, ey, ep, D, ed): + """ + Calculate element normal and shear stress for a + triangular plane stress or plane strain element. + + INPUT: ex = [x1 x2 x3] element coordinates + ey = [y1 y2 y3] + + ep = [ptype t ] ptype: analysis type + t: thickness + + D constitutive matrix + + ed =[u1 u2 ...u6 element displacement vector + ...... ] one row for each element + + OUTPUT: es = [ sigx sigy [sigz] tauxy element stress matrix + ...... ] one row for each element + + et = [ epsx epsy [epsz] gamxy element strain matrix + ...... ] one row for each element + """ + + ptype = ep[0] + + if np.ndim(ex) == 1: + ex = np.array([ex]) + if np.ndim(ey) == 1: + ey = np.array([ey]) + if np.ndim(ed) == 1: + ed = np.array([ed]) + + rowed = ed.shape[0] + rowex = ex.shape[0] + + # --------- plane stress -------------------------------------- + + if ptype == 1: + + colD = D.shape[1] + + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) + else: + Dm = D + + incie = 0 + + if rowex == 1: + incie = 0 + else: + incie = 1 + + et = np.zeros([rowed, colD]) + es = np.zeros([rowed, colD]) + + ie = 0 + + for i in range(rowed): + C = np.matrix( + [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], + [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], + [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] + ) + + B = np.matrix([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) + + ee = B*np.asmatrix(ed[ie, :]).T + + if colD > 3: + ss = np.zeros([colD, 1]) + ss[[0, 1, 3]] = Dm*ee + ee = Cm*ss + else: + ss = Dm*ee + + et[ie, :] = ee.T + es[ie, :] = ss.T + + ie = ie + incie + + return es, et + + # --------- plane strain -------------------------------------- + elif ptype == 2: # Implementation by LAPM + colD = D.shape[1] + incie = 0 + + if rowex == 1: + incie = 0 + else: + incie = 1 + + et = np.zeros([rowed, colD]) + es = np.zeros([rowed, colD]) + + ie = 0 + + ee = np.zeros([colD, 1]) + + for i in range(rowed): + C = np.matrix( + [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], + [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], + [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] + ) + + B = np.matrix([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) + + e = B*np.asmatrix(ed[ie, :]).T + + if colD > 3: + ee[[0, 1, 3]] = e + else: + ee = e + + et[ie, :] = ee.T + es[ie, :] = (D*ee).T + + ie = ie + incie + + return es, et + + else: + print("Error ! Check first argument, ptype=1 or 2 allowed") + return None + + +def plantf(ex, ey, ep, es): + """ + Compute internal element force vector in a triangular element + in plane stress or plane strain. + + Parameters: + + ex = [x1,x2,x3] node coordinates + ey = [y1,y2,y3] + + ep = [ptype,t] ptype: analysis type + t: thickness + + es = [[sigx,sigy,[sigz],tauxy] element stress matrix + [ ...... ]] one row for each element + + OUTPUT: + + fe = [[f1],[f2],...,[f8]] internal force vector + + """ + + ptype, t = ep + + colD = es.shape[1] + + #--------- plane stress -------------------------------------- + + if ptype == 1: + + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) + + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) + + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) + + if colD > 3: + stress = np.asmatrix(es[np.ix_((0, 1, 3))]) + else: + stress = np.asmatrix(es) + + ef = (A*t*B.T*stress.T).T + + return np.reshape(np.asarray(ef), 6) + + #--------- plane strain -------------------------------------- + + elif ptype == 2: + + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) + + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) + + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) + + if colD > 3: + stress = np.asmatrix(es[np.ix_((1, 2, 4))]) + else: + stress = np.asmatrix(es) + + ef = (A*t*B.T*stress.T).T + + return np.reshape(np.asarray(ef), 6) + + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + return None + + +def platre(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a rectangular plate element. + NOTE! Element sides must be parallel to the coordinate axis. + + Parameters: + + ex = [x1,x2,x3,x4] element coordinates + ey = [y1,y2,y3,y4] + + ep = [t] thicknes + + D constitutive matrix for + plane stress + + eq = [qz] load/unit area + Returns: + + Ke element stiffness matrix (12 x 12) + fe equivalent nodal forces (12 x 1) + + """ + Lx = (ex[2]-ex[0]).astype(float) + Ly = (ey[2]-ey[0]).astype(float) + t = ep[0] + + D = t**3/12.*D + + A1 = Ly/(Lx**3) + A2 = Lx/(Ly**3) + A3 = 1/Lx/Ly + A4 = Ly/(Lx**2) + A5 = Lx/(Ly**2) + A6 = 1/Lx + A7 = 1/Ly + A8 = Ly/Lx + A9 = Lx/Ly + + C1 = 4*A1*D[0, 0]+4*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] + C2 = -4*A1*D[0, 0]+2*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] + C3 = 2*A1*D[0, 0]-4*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] + C4 = -2*A1*D[0, 0]-2*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] + C5 = 2*A5*D[1, 1]+A6*D[0, 1]+0.4*A6*D[2, 2] + C6 = 2*A4*D[0, 0]+A7*D[0, 1]+0.4*A7*D[2, 2] + + C7 = 2*A5*D[1, 1]+0.4*A6*D[2, 2] + C8 = 2*A4*D[0, 0]+0.4*A7*D[2, 2] + C9 = A5*D[1, 1]-A6*D[0, 1]-0.4*A6*D[2, 2] + C10 = A4*D[0, 0]-A7*D[0, 1]-0.4*A7*D[2, 2] + C11 = A5*D[1, 1]-0.4*A6*D[2, 2] + C12 = A4*D[0, 0]-0.4*A7*D[2, 2] + + C13 = 4/3.*A9*D[1, 1]+8/15.*A8*D[2, 2] + C14 = 4/3.*A8*D[0, 0]+8/15.*A9*D[2, 2] + C15 = 2/3.*A9*D[1, 1]-8/15.*A8*D[2, 2] + C16 = 2/3.*A8*D[0, 0]-8/15.*A9*D[2, 2] + C17 = 2/3.*A9*D[1, 1]-2/15.*A8*D[2, 2] + C18 = 2/3.*A8*D[0, 0]-2/15.*A9*D[2, 2] + C19 = 1/3.*A9*D[1, 1]+2/15.*A8*D[2, 2] + C20 = 1/3.*A8*D[0, 0]+2/15.*A9*D[2, 2] + C21 = D[0, 1] + + Keq = np.mat(np.zeros((12, 12))) + Keq[0, 0:13] = C1, C5, -C6, C2, C9, -C8, C4, C11, -C12, C3, C7, -C10 + Keq[1, 1:13] = C13, -C21, C9, C15, 0, -C11, C19, 0, -C7, C17, 0 + Keq[2, 2:13] = C14, C8, 0, C18, C12, 0, C20, -C10, 0, C16 + Keq[3, 3:13] = C1, C5, C6, C3, C7, C10, C4, C11, C12 + Keq[4, 4:13] = C13, C21, -C7, C17, 0, -C11, C19, 0 + Keq[5, 5:13] = C14, C10, 0, C16, -C12, 0, C20 + Keq[6, 6:13] = C1, -C5, C6, C2, -C9, C8 + Keq[7, 7:13] = C13, -C21, -C9, C15, 0 + Keq[8, 8:13] = C14, -C8, 0, C18 + Keq[9, 9:13] = C1, -C5, -C6 + Keq[10, 10:13] = C13, C21 + Keq[11, 11] = C14 + Keq = Keq.T+Keq-np.diag(np.diag(Keq)) + + if eq != None: + q = eq + R1 = q*Lx*Ly/4 + R2 = q*Lx*Ly**2/24 + R3 = q*Ly*Lx**2/24 + + feq = np.mat([R1, R2, -R3, R1, R2, R3, R1, -R2, R3, R1, -R2, -R3]) + + if eq != None: + return Keq, feq + else: + return Keq + + +def planqe(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a quadrilateral + plane stress or plane strain element. + + Parameters: + ex=[x1 x2 x3 x4] element coordinates + ey=[y1 y2 y3 y4] + + ep = [ptype, t] ptype: analysis type + t: element thickness + + D constitutive matrix + + eq = [bx; bx: body force in x direction + by] by: body force in y direction + + OUTPUT: Ke : element stiffness matrix (8 x 8) + fe : equivalent nodal forces (row array) + """ + K = np.zeros((10, 10)) + f = np.zeros((10, 1)) + + xm = sum(ex)/4. + ym = sum(ey)/4. + + b1 = eq if eq is not None else np.array([[0], [0]]) + + ke1, fe1 = plante(np.array([ex[0], ex[1], xm]), + np.array([ey[0], ey[1], ym]), ep, D, b1) + K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[1], ex[2], xm]), + np.array([ey[1], ey[2], ym]), ep, D, b1) + K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[2], ex[3], xm]), + np.array([ey[2], ey[3], ym]), ep, D, b1) + K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[3], ex[0], xm]), + np.array([ey[3], ey[0], ym]), ep, D, b1) + K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) + Ke, fe = statcon(K, f, np.array([[9], [10]])) + + if eq == None: + return Ke + else: + return Ke, fe + + +def planqs(ex, ey, ep, D, ed, eq=None): + """ + Calculate element normal and shear stress for a quadrilateral + plane stress or plane strain element. + + Parameters: + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] + + ep = [ptype, t] ptype: analysis type + t: thickness + + D constitutive matrix + + ed = [u1 u2 ..u8] element displacement vector + + eq = [[bx] bx: body force in x direction + [by]] by: body force in y direction + + OUTPUT: es = [ sigx sigy (sigz) tauxy] element stress array + et = [ epsx epsy (epsz) gamxy] element strain array + """ + + if ex.shape != (4,) or ey.shape != (4,) or ed.shape != (8,): + raise ValueError( + 'Error ! PLANQS: only one element at the time (ex, ey, ed must be a row arrays)') + + K = np.zeros((10, 10)) + f = np.zeros((10, 1)) + + xm = sum(ex)/4. + ym = sum(ey)/4. + + b1 = eq if eq is not None else np.array([[0], [0]]) + + ex1 = np.array([ex[0], ex[1], xm]) + ey1 = np.array([ey[0], ey[1], ym]) + ex2 = np.array([ex[1], ex[2], xm]) + ey2 = np.array([ey[1], ey[2], ym]) + ex3 = np.array([ex[2], ex[3], xm]) + ey3 = np.array([ey[2], ey[3], ym]) + ex4 = np.array([ex[3], ex[0], xm]) + ey4 = np.array([ey[3], ey[0], ym]) + + ke1, fe1 = plante(ex1, ey1, ep, D, b1) + K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex2, ey2, ep, D, b1) + K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex3, ey3, ep, D, b1) + K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex4, ey4, ep, D, b1) + K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) + + A1 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex1).T, np.mat(ey1).T])) + A2 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex2).T, np.mat(ey2).T])) + A3 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex3).T, np.mat(ey3).T])) + A4 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex4).T, np.mat(ey4).T])) + Atot = A1+A2+A3+A4 + + a, _ = solveq(K, f, np.array(range(1, 9)), ed) + +# ni = ed.shape[0] +# a = np.mat(empty((10,ni))) +# for i in range(ni): +# a[:,i] = solveq(K, f, np.array(range(1,9)), ed[i,:])[0] +# #a = np.hstack([a, solveq(K, f, np.hstack([matrix(range(1,9)).T, ed[i,:].T]) ) ]) + + s1, t1 = plants(ex1, ey1, ep, D, np.hstack([a[[0, 1, 2, 3, 8, 9], :].T])) + s2, t2 = plants(ex2, ey2, ep, D, np.hstack([a[[2, 3, 4, 5, 8, 9], :].T])) + s3, t3 = plants(ex3, ey3, ep, D, np.hstack([a[[4, 5, 6, 7, 8, 9], :].T])) + s4, t4 = plants(ex4, ey4, ep, D, np.hstack([a[[6, 7, 0, 1, 8, 9], :].T])) + + es = (s1*A1+s2*A2+s3*A3+s4*A4)/Atot + et = (t1*A1+t2*A2+t3*A3+t4*A4)/Atot + + # [0] because these are 1-by-3 arrays and we want row arrays out. + return es[0], et[0] + + +def plani4e(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a 4 node isoparametric + element in plane strain or plane stress. + + Parameters: + ex = [x1 ... x4] element coordinates. Row array + ey = [y1 ... y4] + + ep =[ptype, t, ir] ptype: analysis type + t : thickness + ir: integration rule + + D constitutive matrix + + eq = [bx; by] bx: body force in x direction + by: body force in y direction + Any array with 2 elements acceptable + + Returns: + Ke : element stiffness matrix (8 x 8) + fe : equivalent nodal forces (8 x 1) + """ + ptype = ep[0] + t = ep[1] + ir = ep[2] + ngp = ir*ir + if eq == None: + q = np.zeros((2, 1)) + else: + q = np.reshape(eq, (2, 1)) +#--------- gauss points -------------------------------------- + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1]]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1]]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1]]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1]]) + else: + info("Used number of integrat ion points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + # Shape Functions + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. + +# + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey]).T + # --------- plane stress -------------------------------------- + if ptype == 1: + colD = np.shape(D)[0] + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_([0, 1, 3], [0, 1, 3])]) + else: + Dm = D +# + B = np.matrix(np.zeros((3, 8))) + N2 = np.matrix(np.zeros((2, 8))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant equal or less than zero!") + JTinv = np.linalg.inv(JT[indx-1, :]) + dNx = JTinv*dNr[indx-1, :] +# + index_array_even = np.array([0, 2, 4, 6]) + index_array_odd = np.array([1, 3, 5, 7]) +# + counter = 0 + for index in index_array_even: + B[0, index] = dNx[0, counter] + B[2, index] = dNx[1, counter] + N2[0, index] = N[i, counter] + counter = counter+1 +# + counter = 0 + for index in index_array_odd: + B[1, index] = dNx[1, counter] + B[2, index] = dNx[0, counter] + N2[1, index] = N[i, counter] + counter = counter+1 +# + Ke1 = Ke1+B.T*Dm*B*detJ*wp[i].item()*t + fe1 = fe1 + N2.T * q * detJ * wp[i].item() * t + + return Ke1, fe1 +#--------- plane strain -------------------------------------- + elif ptype == 2: + # + colD = np.shape(D)[0] + if colD > 3: + Dm = D[np.ix_([0, 1, 3], [0, 1, 3])] + else: + Dm = D +# + B = np.matrix(np.zeros((3, 8))) + N2 = np.matrix(np.zeros((2, 8))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminant equal or less than zero!") + JTinv = np.linalg.inv(JT[indx-1, :]) + dNx = JTinv*dNr[indx-1, :] +# + index_array_even = np.array([0, 2, 4, 6]) + index_array_odd = np.array([1, 3, 5, 7]) +# + counter = 0 + for index in index_array_even: + # + B[0, index] = dNx[0, counter] + B[2, index] = dNx[1, counter] + N2[0, index] = N[i, counter] +# + counter = counter+1 +# + counter = 0 + for index in index_array_odd: + B[1, index] = dNx[1, counter] + B[2, index] = dNx[0, counter] + N2[1, index] = N[i, counter] + counter = counter+1 +# + Ke1 = Ke1 + B.T * Dm * B * detJ * np.asscalar(wp[i]) * t + fe1 = fe1+N2.T*q*detJ*np.asscalar(wp[i])*t + return Ke1, fe1 + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + + +def soli8e(ex, ey, ez, ep, D, eqp=None): + """ + Ke=soli8e(ex,ey,ez,ep,D) + [Ke,fe]=soli8e(ex,ey,ez,ep,D,eq) + ------------------------------------------------------------- + PURPOSE + Calculate the stiffness matrix for a 8 node (brick) + isoparametric element. + + INPUT: ex = [x1 x2 x3 ... x8] + ey = [y1 y2 y3 ... y8] element coordinates + ez = [z1 z2 z3 ... z8] + + ep = [ir] ir integration rule + + D constitutive matrix + + eq = [bx; by; bz] bx: body force in x direction + by: body force in y direction + bz: body force in z direction + + OUTPUT: Ke : element stiffness matrix + fe : equivalent nodal forces + ------------------------------------------------------------- + + LAST MODIFIED: M Ristinmaa 1995-10-25 + J Lindemann 2022-01-24 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + ir = ep[0] + ngp = ir*ir*ir + + if eqp == None: + eq = np.zeros((3, 1)) + else: + eq = eqp + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.array([g1, g1, g1]).reshape(1, 3) + w = np.array([w1, w1, w1]).reshape(1, 3) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.zeros((8, 3)) + w = np.zeros((8, 3)) + gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 + w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 + w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 + w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + else: + g1 = 0.774596669241483, + g2 = 0.0 + w1 = 0.555555555555555 + w2 = 0.888888888888888 + + gp = np.zeros((27, 3)) + w = np.zeros((27, 3)) + + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) + + gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] + + I1 = np.abs(I1) + I2 = np.abs(I2) + + w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] + + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) + + gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] + + I1 = np.abs(I1) + I2 = np.abs(I2) + + w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] + + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) + I3 = np.abs(I1) + + gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 + gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] + + w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 + w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] + + wp = w[:, 0]*w[:, 1]*w[:, 2] + + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 + + N = np.zeros((ngp, 8)) + dNr = np.zeros((r2, 8)) + + N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 + N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 + N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 + N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 + N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 + N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 + N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 + N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 + + dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) + dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) + dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) + dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) + dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) + dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) + dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) + dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) + dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) + dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) + dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) + dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) + dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) + dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) + dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) + dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) + dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) + dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) + dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) + dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) + dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) + dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) + dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) + dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) + + dNr = dNr/8.0 + + Ke = np.zeros((24, 24)) + fe = np.zeros((24, 1)) + + ex = np.asarray(ex).reshape((8, 1)) + ey = np.asarray(ey).reshape((8, 1)) + ez = np.asarray(ez).reshape((8, 1)) + + JT = dNr@np.concatenate((ex, ey, ez), axis=1) + + eps = np.finfo(float).eps + + for i in range(ngp): + indx = [i*3, i*3+1, i*3+2] + detJ = np.linalg.det(JT[indx, :]) + if detJ < 10*eps: + print('Jacobideterminant equal or less than zero!') + JTinv = np.linalg.inv(JT[indx, :]) + dNx = JTinv@dNr[indx, :] + + B = np.zeros((6, 24)) + N2 = np.zeros((3, 24)) + + B[0, 0:24:3] = dNx[0, :] + B[1, 1:25:3] = dNx[1, :] + B[2, 2:26:3] = dNx[2, :] + B[3, 0:24:3] = dNx[1, :] + B[3, 1:25:3] = dNx[0, :] + B[4, 0:24:3] = dNx[2, :] + B[4, 2:26:3] = dNx[0, :] + B[5, 1:25:3] = dNx[2, :] + B[5, 2:26:3] = dNx[1, :] + + N2[0, 0:24:3] = N[i, :] + N2[1, 1:25:3] = N[i, :] + N2[2, 2:26:3] = N[i, :] + + Ke = Ke + (np.transpose(B)@D@B)*detJ*wp[i] + fe = fe + (np.transpose(N2)@eq)*detJ*wp[i] + + if eqp != None: + return Ke, fe + else: + return Ke + + +def soli8s(ex, ey, ez, ep, D, ed): + """ + [es,et]=soli8s(ex,ey,ez,ep,D,ed) + ------------------------------------------------------------- + PURPOSE + Calculate element normal and shear stress for a + 8 node (brick) isoparametric element. + + INPUT: ex = [x1 x2 x3 ... x8] + ey = [y1 y2 y3 ... y8] element coordinates + ez = [z1 z2 z3 ... z8] + + ep = [Ir] Ir: integration rule + + D constitutive matrix + + ed = [u1 u2 ..u24] element displacement vector + + OUTPUT: es = [ sigx sigy sigz sigxy sigyz sigxz ; + ...... ... ] + element stress matrix, one row for each + integration point + + es = [ eps epsy epsz epsxy epsyz epsxz ; + ...... ... ] + element strain matrix, one row for each + integration point + ------------------------------------------------------------- + + LAST MODIFIED: M Ristinmaa 1995-10-25 + J Lindemann 2022-02-23 (Python version) + + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + + ir = ep[0] + ngp = ir*ir*ir + + ir = ep[0] + ngp = ir*ir*ir + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.array([g1, g1, g1]).reshape(1, 3) + w = np.array([w1, w1, w1]).reshape(1, 3) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.zeros((8, 3)) + w = np.zeros((8, 3)) + gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 + w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 + w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 + w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + else: + g1 = 0.774596669241483, + g2 = 0.0 + w1 = 0.555555555555555 + w2 = 0.888888888888888 + + gp = np.zeros((27, 3)) + w = np.zeros((27, 3)) + + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) + + gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] + + I1 = np.abs(I1) + I2 = np.abs(I2) + + w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] + + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) + + gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] + + I1 = np.abs(I1) + I2 = np.abs(I2) + + w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] + + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) + I3 = np.abs(I1) + + gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 + gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] + + w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 + w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] + + wp = w[:, 0]*w[:, 1]*w[:, 2] + + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 + + N = np.zeros((ngp, 8)) + dNr = np.zeros((r2, 8)) + + N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 + N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 + N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 + N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 + N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 + N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 + N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 + N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 + + dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) + dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) + dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) + dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) + dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) + dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) + dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) + dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) + dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) + dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) + dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) + dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) + dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) + dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) + dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) + dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) + dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) + dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) + dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) + dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) + dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) + dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) + dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) + dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) + + dNr = dNr/8.0 + + ex = np.asarray(ex).reshape((8, 1)) + ey = np.asarray(ey).reshape((8, 1)) + ez = np.asarray(ez).reshape((8, 1)) + + JT = dNr@np.concatenate((ex, ey, ez), axis=1) + + eps = np.finfo(float).eps + + eci = N@np.concatenate((ex, ey, ez), axis=1) + et = np.zeros((ngp, 6)) + es = np.zeros((ngp, 6)) + + ed = ed.reshape(1, 24) + + for i in range(ngp): + indx = [i*3, i*3+1, i*3+2] + detJ = np.linalg.det(JT[indx, :]) + if detJ < 10*eps: + print('Jacobideterminant equal or less than zero!') + JTinv = np.linalg.inv(JT[indx, :]) + dNx = JTinv@dNr[indx, :] + + B = np.zeros((6, 24)) + N2 = np.zeros((3, 24)) + + B[0, 0:24:3] = dNx[0, :] + B[1, 1:25:3] = dNx[1, :] + B[2, 2:26:3] = dNx[2, :] + B[3, 0:24:3] = dNx[1, :] + B[3, 1:25:3] = dNx[0, :] + B[4, 0:24:3] = dNx[2, :] + B[4, 2:26:3] = dNx[0, :] + B[5, 1:25:3] = dNx[2, :] + B[5, 2:26:3] = dNx[1, :] + + N2[0, 0:24:3] = N[i, :] + N2[1, 1:25:3] = N[i, :] + N2[2, 2:26:3] = N[i, :] + + # [6x24] x [24,1] + ee = B@np.transpose(ed) + + et[i, :] = ee.reshape(6,) + es[i, :] = (D@ee).reshape(6,) + + return et, es, eci + + +def assem(edof, K, Ke, f=None, fe=None): + """ + Assemble element matrices Ke ( and fe ) into the global + stiffness matrix K ( and the global force vector f ) + according to the topology matrix edof. + + Parameters: + + edof dof topology array + K the global stiffness matrix + Ke element stiffness matrix + f the global force vector + fe element force vector + + Output parameters: + + K the new global stiffness matrix + f the new global force vector + fe element force vector + + """ + + if edof.ndim == 1: + idx = edof-1 + K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke + if (not f is None) and (not fe is None): + f[np.ix_(idx)] = f[np.ix_(idx)] + fe + else: + for row in edof: + idx = row-1 + K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke + if (not f is None) and (not fe is None): + f[np.ix_(idx)] = f[np.ix_(idx)] + fe + + if f is None: + return K + else: + return K, f + + +def solveq(K, f, bcPrescr, bcVal=None): + """ + Solve static FE-equations considering boundary conditions. + + Parameters: + + K global stiffness matrix, dim(K)= nd x nd + f global load vector, dim(f)= nd x 1 + + bcPrescr 1-dim integer array containing prescribed dofs. + bcVal 1-dim float array containing prescribed values. + If not given all prescribed dofs are assumed 0. + + Returns: + + a solution including boundary values + Q reaction force vector + dim(a)=dim(Q)= nd x 1, nd : number of dof's + + """ + + nDofs = K.shape[0] + nPdofs = bcPrescr.shape[0] + + if bcVal is None: + bcVal = np.zeros([nPdofs], 'd') + + bc = np.ones(nDofs, 'bool') + bcDofs = np.arange(nDofs) + + bc[np.ix_(bcPrescr-1)] = False + bcDofs = bcDofs[bc] + + fsys = f[bcDofs]-K[np.ix_((bcDofs), (bcPrescr-1))] * \ + np.asmatrix(bcVal).reshape(nPdofs, 1) + asys = np.linalg.solve(K[np.ix_((bcDofs), (bcDofs))], fsys) + + a = np.zeros([nDofs, 1]) + a[np.ix_(bcPrescr-1)] = np.asmatrix(bcVal).reshape(nPdofs, 1) + a[np.ix_(bcDofs)] = asys + + Q = K*np.asmatrix(a)-f + + return (np.asmatrix(a), Q) + + +def spsolveq(K, f, bcPrescr, bcVal=None): + """ + Solve static FE-equations considering boundary conditions. + + Parameters: + + K global stiffness matrix, dim(K)= nd x nd + f global load vector, dim(f)= nd x 1 + + bcPrescr 1-dim integer array containing prescribed dofs. + bcVal 1-dim float array containing prescribed values. + If not given all prescribed dofs are assumed 0. + + Returns: + + a solution including boundary values + Q reaction force vector + dim(a)=dim(Q)= nd x 1, nd : number of dof's + + """ + + nDofs = K.shape[0] + nPdofs = bcPrescr.shape[0] + + if bcVal is None: + bcVal = np.zeros([nPdofs], 'd') + + bc = np.ones(nDofs, 'bool') + bcDofs = np.arange(nDofs) + + bc[np.ix_(bcPrescr-1)] = False + bcDofs = bcDofs[bc] + + bcVal_m = np.asmatrix(bcVal).reshape(nPdofs, 1) + + info("Preparing system matrix...") + + mask = np.ones(K.shape[0], dtype=bool) + mask[bcDofs] = False + + info("step 1... converting K->CSR") + Kcsr = K.asformat("csr") + info("step 2... Kt") + #Kt1 = K[bcDofs] + #Kt = Kt1[:,bcPrescr] + Kt = K[np.ix_((bcDofs), (bcPrescr-1))] + info("step 3... fsys") + fsys = f[bcDofs]-Kt*bcVal_m + info("step 4... Ksys") + Ksys1 = Kcsr[bcDofs] + Ksys = Ksys1[:, bcDofs] + #Ksys = Kcsr[np.ix_((bcDofs),(bcDofs))] + info("done...") + + info("Solving system...") + asys = dsolve.spsolve(Ksys, fsys) + + info("Reconstructing full a...") + a = np.zeros([nDofs, 1]) + a[np.ix_(bcPrescr-1)] = bcVal_m + a[np.ix_(bcDofs)] = np.asmatrix(asys).transpose() + + a_m = np.asmatrix(a) + Q = K*a_m-f + info("done...") + return (a_m, Q) + + +def eigen(K,M,b=None): + """ + Solve the generalized eigenvalue problem + |K-LM|X = 0, considering boundary conditions + + Parameters: + + K global stiffness matrix, dim(K) = ndof x ndof + M global mass matrix, dim(M) = ndof x ndof + b boundary condition vector, dim(b) = nbc x 1 + + Returns: + + L eigenvalue vector, dim(L) = (ndof-nbc) x 1 + X eigenvectors, dim(X) = ndof x (ndof-nbc) + """ + nd, _ = K.shape + if b is not None: + fdof = np.setdiff1d(np.arange(nd), b-1) + D, X1 = eig(K[np.ix_(fdof,fdof)], M[np.ix_(fdof,fdof)]) + D = np.real(D) + nfdof, _ = X1.shape + for j in range(nfdof): + mnorm = np.sqrt(X1[:,j].T@M[np.ix_(fdof,fdof)]@X1[:,j]) + X1[:,j] /= mnorm + s_order = np.argsort(D) + L = np.sort(D) + X2 = np.zeros(X1.shape) + for ind,j in enumerate(s_order): + X2[:,ind] = X1[:,j] + X = np.zeros((nd,nfdof)) + X[fdof,:] = X2 + return L, X + else: + D, X1 = eig(K, M) + D = np.real(D) + for j in range(nd): + mnorm = np.sqrt(X1[:,j].T@M@X1[:,j]) + X1[:,j] /= mnorm + s_order = np.argsort(D) + L = np.sort(D) + X = np.copy(X1) + for ind,j in enumerate(s_order): + X[:,ind] = X1[:,j] + return L, X + + +def gfunc(G,dt): + """ + Form vector with function values at equally spaced + points by linear interpolation + + Parameters: + + G = [t_i, g_i] t_i: time i, g_i: g(t_i) + dim(G) = np x 2, np = number of points + dt time step + + Returns: + + t 1-D vector with equally spaced time points + g 1-D vector with corresponding function values + """ + ti = np.arange(G[0,0],G[-1,0]+dt,dt) + g1 = np.interp(ti,G[:,0],G[:,1]) + return ti, g1 + + +def step1(K,C,f,a0,bc,ip,times,dofs): + """ + Algorithm for dynamic solution of first-order + FE equations considering boundary conditions. + + Parameters: + + K conductivity matrix, dim(K) = ndof x ndof + C capacity matrix, dim(C) = ndof x ndof + f load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial vector a(0), dim(a0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha], where + dt is the size of the time increment, + tottime is the total time, + alpha is time integration constant. + Frequently used values of alpha are: + alpha=0: forward difference; forward Euler, + alpha=1/2: trapezoidal rule; Crank-Nicholson + alpha=1: backward difference; backward Euler + times array [t(i) ...] of times at which output should be written to a and da + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist and dahist + + Returns: + + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains values of a at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains values of da at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains time history of a at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains time history of daat the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + dt, tottime, alpha = ip + a1 = (1-alpha)*dt + a2 = alpha*dt + + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 + + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 + + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns + + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 + + itime = 0 + + # Calculate initial second time derivative d2a0 + da0 = np.linalg.solve(C,tf[:,0].reshape(-1,1) - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + itime += 1 + + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = C[np.ix_(fdof,fdof)] + a2*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = C + a2*K + + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + apred = aold + a1*daold + if not bound: + reff = tf[:,j].reshape(-1,1) - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + danew = np.linalg.solve(U,y) + anew = apred + a2*danew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + + return modelhist, dofhist + + +def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): + """ + Algorithm for dynamic solution of second-order + FE equations considering boundary conditions. + + Parameters: + + K global stiffness matrix, dim(K) = ndof x ndof + C global damping matrix, dim(C) = ndof x ndof + If there is no damping in the system, simply set C=[] + M global mass matrix, dim(M) = ndof x ndof + f global load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial displacement vector a(0), dim(a0) = ndof x 1 + da0 initial velocity vector v(0), dim(da0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha, delta], where + dt is the size of the time increment, + tottime is the total time, + alpha and delta are time integration constants for the Newmark family of methods. + Frequently used values of alpha and delta are: + alpha=1/4, delta=1/2: average acceleration (trapezoidal) rule, + alpha=1/6, delta=1/2: linear acceleration + alpha=0, delta=1/2: central difference + times array [t(i) ...] of times at which output should be written to a, da and d2a + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist, dahist and d2ahist + + Returns: + + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains displacement values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains velocity values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['d2a'] constains acceleration values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['d2a']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains displacement time history at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains velocity time history at the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + dofhist['d2a'] constains acceleration time history at the dofs specified in 'dofs' + dim(dofhist['d2ahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + if not np.array(C).any(): + C = np.zeros((ndof,ndof)) + dt, tottime, alpha, delta = ip + b1 = dt*dt*0.5*(1-2*alpha) + b2 = (1-delta)*dt + b3 = delta*dt + b4 = alpha*dt*dt + + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 + + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 + + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns + + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + modelhist['d2a'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + modelhist['d2a'] = np.zeros((ndof,ntimes)) + + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + dofhist['d2a'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 + + itime = 0 + + # Calculate initial second time derivative d2a0 + d2a0 = np.linalg.solve(M,tf[:,0].reshape(-1,1) - C@da0 - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + modelhist['d2a'][:,0] = d2a0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + modelhist['d2a'][:,itime] = d2a0.ravel() + itime += 1 + + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,0] = d2a0[np.ix_(dofs-1)].ravel() + + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + tempd2a = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = M[np.ix_(fdof,fdof)] + b3*C[np.ix_(fdof,fdof)] +b4*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = M + b3*C + b4*K + + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + d2anew = d2a0[np.ix_(fdof)] + + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + d2aold = np.copy(d2anew) + apred = aold + dt*daold + b1*d2aold + dapred = daold + b2*d2aold + if not bound: + reff = tf[:,j].reshape(-1,1) - C@dapred - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - C[np.ix_(fdof,fdof)]@dapred - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + d2anew = np.linalg.solve(U,y) + anew = apred + b4*d2anew + danew = dapred + b3*d2anew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + tempd2a[np.ix_(fdof)] = d2anew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + modelhist['d2a'][:,j] = tempd2a.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + modelhist['d2a'][:,itime] = tempd2a.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,j] = tempd2a[np.ix_(dofs-1)].ravel() + + return modelhist, dofhist + + +def extract_eldisp(edof, a): + """ + Extract element displacements from the global displacement + vector according to the topology matrix edof. + + Parameters: + + a the global displacement vector + edof dof topology array + + Returns: + + ed: element displacement array + + """ + + ed = None + + if edof.ndim == 1: + nDofs = len(edof) + ed = np.zeros([nDofs]) + idx = edof-1 + ed[:] = a[np.ix_(idx)].T + else: + nElements = edof.shape[0] + nDofs = edof.shape[1] + ed = np.zeros([nElements, nDofs]) + i = 0 + for row in edof: + idx = row-1 + ed[i, :] = a[np.ix_(idx)].T + i += 1 + + return ed + + +extractEldisp = extract_eldisp +extract_ed = extract_eldisp + + +def statcon(K, f, cd): + """ + Condensation of static FE-equations according to the vector cd. + + Parameters: + + K global stiffness matrix, dim(K) = nd x nd + f global load vector, dim(f)= nd x 1 + + cd vector containing dof's to be eliminated + dim(cd)= nc x 1, nc: number of condensed dof's + Returns: + + K1 condensed stiffness matrix, + dim(K1)= (nd-nc) x (nd-nc) + f1 condensed load vector, dim(f1)= (nd-nc) x 1 + """ + nd, nd = np.shape(K) + cd = (cd-1).flatten() + + aindx = np.arange(nd) + aindx = np.delete(aindx, cd, 0) + bindx = cd + + Kaa = np.mat(K[np.ix_(aindx, aindx)]) + Kab = np.mat(K[np.ix_(aindx, bindx)]) + Kbb = np.mat(K[np.ix_(bindx, bindx)]) + + fa = np.mat(f[aindx]) + fb = np.mat(f[bindx]) + + K1 = Kaa-Kab*Kbb.I*Kab.T + f1 = fa-Kab*Kbb.I*fb + + return K1, f1 + + +def c_mul(a, b): + return eval(hex((np.long(a) * b) & 0xFFFFFFFF)[:-1]) + + +def dofHash(dof): + if len(dof) == 1: + return dof[0] + value = 0x345678 + for item in dof: + value = c_mul(1000003, value) ^ hash(item) + value = value ^ len(dof) + if value == -1: + value = -2 + return value + + +def create_dofs(nCoords, nDof): + """ + Create dof array [nCoords x nDof] + """ + return np.arange(nCoords*nDof).reshape(nCoords, nDof)+1 + + +createdofs = create_dofs + + +def coordxtr(edof, coords, dofs, nen=-1): + """ + Create element coordinate matrices ex, ey, ez from edof + coord and dofs matrices. + + Parameters: + + edof [nel x (nen * nnd)], nnd = number of node dofs + coords [ncoords x ndims], ndims = node dimensions + dofs [ncoords x nnd] + + Returns: + + ex if ndims = 1 + ex, ey if ndims = 2 + ex, ey, ez if ndims = 3 + """ + + # Create dictionary with dof indices + + dofDict = {} + nDofs = np.size(dofs, 1) + nElements = np.size(edof, 0) + n_element_dofs = np.size(edof, 1) + nDimensions = np.size(coords, 1) + nElementDofs = np.size(edof, 1) + + if nen == -1: + nElementNodes = int(nElementDofs/nDofs) + else: + nElementNodes = nen + + if nElementNodes*nDofs != n_element_dofs: + nDofs = nElementNodes*nDofs - n_element_dofs + user_warning( + "dofs/edof mismatch. Using %d dofs per node when indexing." % nDofs) + + idx = 0 + for dof in dofs: + #dofDict[dofHash(dof)] = idx + dofDict[hash(tuple(dof[0:nDofs]))] = idx + idx += 1 + + # Loop over edof and extract element coords + + ex = np.zeros((nElements, nElementNodes)) + ey = np.zeros((nElements, nElementNodes)) + ez = np.zeros((nElements, nElementNodes)) + + elementIdx = 0 + for etopo in edof: + for i in range(nElementNodes): + i0 = i*nDofs + i1 = i*nDofs+nDofs-1 + dof = [] + if i0 == i1: + dof = [etopo[i*nDofs]] + else: + dof = etopo[i*nDofs:(i*nDofs+nDofs)] + + nodeCoord = coords[dofDict[hash(tuple(dof[0:nDofs]))]] + + if nDimensions >= 1: + ex[elementIdx, i] = nodeCoord[0] + if nDimensions >= 2: + ey[elementIdx, i] = nodeCoord[1] + if nDimensions >= 3: + ez[elementIdx, i] = nodeCoord[2] + + elementIdx += 1 + + if nDimensions == 1: + return ex + + if nDimensions == 2: + return ex, ey + + if nDimensions == 3: + return ex, ey, ez + + +coord_extract = coordxtr + + +def hooke(ptype, E, v): + """ + Calculate the material matrix for a linear + elastic and isotropic material. + + Parameters: + + ptype= 1: plane stress + 2: plane strain + 3: axisymmetry + 4: three dimensional + + E Young's modulus + v Poissons const. + + Returns: + + D material matrix + + """ + + if ptype == 1: + D = E*np.matrix( + [[1, v, 0], + [v, 1, 0], + [0, 0, (1-v)/2]] + )/(1-v**2) + elif ptype == 2: + D = E/(1+v)*np.matrix( + [[1-v, v, v, 0], + [v, 1-v, v, 0], + [v, v, 1-v, 0], + [0, 0, 0, (1-2*v)/2]] + )/(1-2*v) + elif ptype == 3: + D = E/(1+v)*np.matrix( + [[1-v, v, v, 0], + [v, 1-v, v, 0], + [v, v, 1-v, 0], + [0, 0, 0, (1-2*v)/2]] + )/(1-2*v) + elif ptype == 4: + D = E*np.matrix( + [[1-v, v, v, 0, 0, 0], + [v, 1-v, v, 0, 0, 0], + [v, v, 1-v, 0, 0, 0], + [0, 0, 0, (1-2*v)/2, 0, 0], + [0, 0, 0, 0, (1-2*v)/2, 0], + [0, 0, 0, 0, 0, (1-2*v)/2]] + )/(1+v)/(1-2*v) + else: + info("ptype not supported.") + + return D + + +def effmises(es, ptype): + """ + Calculate effective von mises stresses. + + Parameters: + + es + + ptype= 1: plane stress + 2: plane strain + 3: axisymmetry + 4: three dimensional + + es = [[sigx,sigy,[sigz],tauxy] element stress matrix + [ ...... ]] one row for each element + + Returns: + + eseff = [eseff_0 .. eseff_nel-1] + + """ + + nel = np.size(es, 0) + escomps = np.size(es, 1) + + eseff = np.zeros([nel]) + + if ptype == 1: + sigxx = es[:, 0] + sigyy = es[:, 1] + sigxy = es[:, 2] + eseff = np.sqrt(sigxx*sigxx+sigyy*sigyy-sigxx*sigyy+3*sigxy*sigxy) + return eseff + + +def stress2nodal(eseff, edof): + """ + Convert element effective stresses to nodal effective + stresses. + + Parameters: + + eseff = [eseff_0 .. eseff_nel-1] + edof = [dof topology array] + + Returns: + + ev: element value array [[ev_0_0 ev_0_1 ev_0_nen-1 ] + .. + ev_nel-1_0 ev_nel-1_1 ev_nel-1_nen-1] + + """ + + values = np.zeros(edof.max()) + elnodes = int(np.size(edof, 1) / 2) + + for etopo, eleseff in zip(edof, eseff): + values[etopo-1] = values[etopo-1] + eleseff / elnodes + + evtemp = extractEldisp(edof, values) + ev = evtemp[:, range(0, elnodes*2, 2)] + + return ev + + +def beam2crd_old(ex, ey, ed, mag): + """ + ------------------------------------------------------------- + PURPOSE + Calculate the element continous displacements for a + number of identical 2D Bernoulli beam elements. + + INPUT: ex,ey, + ed, + mag + + OUTPUT: excd,eycd + ------------------------------------------------------------- + + LAST MODIFIED: P-E AUSTRELL 1993-10-15 + J Lindemann 2021-12-30 (Python) + + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + nie, ned = ed.shape + + excd = np.zeros([nie, 20]) + eycd = np.zeros([nie, 20]) + + for i in range(nie): + + b = np.array([ex[i, 1]-ex[i, 0], ey[i, 1]-ey[i, 0]]) + L = np.asscalar(np.sqrt(b@np.transpose(b))) + n = b/L + + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + d = ed[i, :] + dl = G @ d + + xl = np.linspace(0.0, L, 20) + one = np.ones(xl.shape) + + Cis = np.array([ + [-1.0, 1.0], + [L, 0.0] + ]) / L + + ds = np.array([dl[0], dl[3]]).reshape(2, 1) + + xl_one = np.transpose(np.vstack((xl, one))) + + ul = np.transpose(xl_one@Cis@ds) # [20x1][2] + + Cib = np.array([ + [12, 6*L, -12, 6*L], + [-6*L, -4*L**2, 6*L, -2*L**2], + [0, L**3, 0, 0], + [L**3, 0, 0, 0] + ])/L**3 + + db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) + vl = np.transpose(np.transpose( + np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) + + cld = np.vstack((ul, vl)) + A = np.array([ + [n[0], -n[1]], + [n[1], n[0]] + ]) + cd = A@cld + + # [2,1] x [1,20] + [2 x 1] x [1 x 20] + # [2 x 20] + [2 x 20] + + AA = A[:, 0].reshape(2, 1) + XL = xl.reshape(1, 20) + xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]])@one.reshape(1, 20) + + excd[i, :] = xyc[0, :]+mag*cd[0, :] + eycd[i, :] = xyc[1, :]+mag*cd[1, :] + + return excd, eycd + + +def beam2crd(ex=None, ey=None, ed=None, mag=None): + """ + ------------------------------------------------------------- + PURPOSE + Calculate the element continous displacements for a + number of identical 2D Bernoulli beam elements. + + INPUT: ex,ey, + ed, + mag + + OUTPUT: excd,eycd + ------------------------------------------------------------- + + LAST MODIFIED: P-E AUSTRELL 1993-10-15 + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + + nie, ned = ed.shape + + n_coords = 21 + + excd = np.zeros([nie, n_coords]) + eycd = np.zeros([nie, n_coords]) + + for i in range(nie): + b = np.array([ex[i, 1] - ex[i, 0], ey[i, 1] - ey[i, 0]]) + L = np.sqrt(b @ np.transpose(b)) + n = b / L + + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, - n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) + + d = np.transpose(ed[i, :]) + dl = G @ d + xl = np.transpose(np.linspace(0, L, n_coords)) + one = np.ones(xl.shape) + + Cis = np.array([ + [-1, 1], + [L, 0] + ]) / L + + ds = np.array([dl[0], dl[3]]).reshape(2, 1) + xl_one = np.transpose(np.vstack((xl, one))) + ul = np.transpose(xl_one@Cis@ds) # [20x1][2] + + Cib = np.array([ + [12, 6 * L, - 12, 6 * L], + [- 6 * L, - 4 * L ** 2, 6 * L, - 2 * L ** 2], + [0, L ** 3, 0, 0], + [L ** 3, 0, 0, 0] + ]) / L ** 3 + + db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) + vl = np.transpose(np.transpose( + np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) + + cld = np.vstack((ul, vl)) + A = np.array([ + [n[0], -n[1]], + [n[1], n[0]] + ]) + cd = A@cld + + # [2,1] x [1,20] + [2 x 1] x [1 x 20] + # [2 x 20] + [2 x 20] + + AA = A[:, 0].reshape(2, 1) + XL = xl.reshape(1, n_coords) + xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]] + )@one.reshape(1, n_coords) + + excd[i, :] = xyc[0, :]+mag*cd[0, :] + eycd[i, :] = xyc[1, :]+mag*cd[1, :] + + return excd, eycd \ No newline at end of file diff --git a/calfem/vis_mpl.py b/calfem/vis_mpl.py index 888f181..b000c13 100644 --- a/calfem/vis_mpl.py +++ b/calfem/vis_mpl.py @@ -1581,127 +1581,288 @@ def eldisp2(ex, ey, ed, plotpar=[2, 1, 1], sfac=None): # hold off # %--------------------------end-------------------------------- -def secforce2(ex, ey, es, plotpar=None, sfac=None, eci = None): - """ - -------------------------------------------------------------------------- - PURPOSE: - Draw section force diagram for a two dimensional bar or beam element. - INPUT: - ex = [ x1 x2 ] - ey = [ y1 y2 ] element node coordinates. +def dispbeam2(ex, ey, edi, plotpar=[2, 1, 1], sfac=None): + """ + dispbeam2(ex,ey,edi,plotpar,sfac) + [sfac]=dispbeam2(ex,ey,edi) + [sfac]=dispbeam2(ex,ey,edi,plotpar) +------------------------------------------------------------------------ + PURPOSE + Draw the displacement diagram for a two dimensional beam element. + + INPUT: ex = [ x1 x2 ] + ey = [ y1 y2 ] element node coordinates. + + edi = [ u1 v1; + u2 v2; + .....] matrix containing the displacements + in Nbr evaluation points along the beam. + + plotpar=[linetype, linecolour, nodemark] + + linetype=1 -> solid linecolour=1 -> black + 2 -> dashed 2 -> blue + 3 -> dotted 3 -> magenta + 4 -> red + nodemark=0 -> no mark + 1 -> circle + 2 -> star + 3 -> point + + sfac = [scalar] scale factor for displacements. + + Rem. Default if sfac and plotpar is left out is auto magnification + and dashed black lines with circles at nodes -> plotpar=[1 1 1] +------------------------------------------------------------------------ + + LAST MODIFIED: O Dahlblom 2015-11-18 + O Dahlblom 2023-01-31 (Python) - es = [ S1; - S2; - ... ] vector containing the section force - in Nbr evaluation points along the element. + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University +------------------------------------------------------------------------ + """ + if ex.shape != ey.shape: + raise ValueError("Check size of ex, ey dimensions.") - plotpar=[linecolour, elementcolour] + rows, cols = edi.shape + if cols != 2: + raise ValueError("Check size of edi dimension.") + Nbr = rows + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + nxX=dx/L + nyX=dy/L + n = np.array([nxX, nyX]) + + line_color, line_style, node_color, node_style = pltstyle2(plotpar) + + if sfac is None: + sfac=(0.1*L)/(np.max(abs(edi))) + + eci = np.arange(0., L+L/(Nbr-1), L/(Nbr-1)).reshape(Nbr,1) + + edi1=edi*sfac +# From local x-coordinates to global coordinates of the beam element. + A = np.zeros(2*Nbr).reshape(Nbr,2) + A[0,0] = ex[0] + A[0,1] = ey[0] + for i in range(1, Nbr): + A[i,0]=A[0,0]+eci[i]*n[0] + A[i,1]=A[0,1]+eci[i]*n[1] + + for i in range(0, Nbr): + A[i,0]=A[i,0]+edi1[i,0]*n[0]-edi1[i,1]*n[1] + A[i,1]=A[i,1]+edi1[i,0]*n[1]+edi1[i,1]*n[0] + xc=np.array(A[:,0]) + yc=np.array(A[:,1]) + + plt.plot(xc,yc, color=line_color, linewidth=1) + + A1=np.array([A[0,0], A[Nbr-1,0]]).reshape(1,2) + A2=np.array([A[0,1], A[Nbr-1,1]]).reshape(1,2) + draw_node_circles(A1, A2, color=node_color, + filled=False, marker_type=node_style) - linecolour=1 -> black elementcolour=1 -> black - 2 -> blue 2 -> blue - 3 -> magenta 3 -> magenta - 4 -> red 4 -> red - sfac = [scalar] scale factor for section force diagrams. +def secforce2(ex, ey, es, plotpar=[2, 1], sfac=None, eci=None): + """ + secforce2(ex,ey,es,plotpar,sfac) + secforce2(ex,ey,es,plotpar,sfac,eci) + [sfac]=secforce2(ex,ey,es) + [sfac]=secforce2(ex,ey,es,plotpar) +-------------------------------------------------------------------------- + PURPOSE: + Draw section force diagram for a two dimensional bar or beam element. + + INPUT: ex = [ x1 x2 ] + ey = [ y1 y2 ] element node coordinates. + + es = [ S1; + S2; + ... ] vector containing the section force + in Nbr evaluation points along the element. + + plotpar=[linecolour, elementcolour] + + linecolour=1 -> black elementcolour=1 -> black + 2 -> blue 2 -> blue + 3 -> magenta 3 -> magenta + 4 -> red 4 -> red + + sfac = [scalar] scale factor for section force diagrams. + + eci = [ x1; + x2; + ... ] local x-coordinates of the evaluation points (Nbr). + If not given, the evaluation points are assumed to be uniformly + distributed +-------------------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2019-12-16 + O Dahlblom 2023-01-31 (Python) - eci = [ x1; - x2; - ... ] local x-coordinates of the evaluation points (Nbr). - If not given, the evaluation points are assumed to be uniformly - distributed + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University +-------------------------------------------------------------------------- """ + if ex.shape != ey.shape: + raise ValueError("Check size of ex, ey dimensions.") - if ex.shape == ey.shape: - if ex.ndim !=1: - nen = ex.shape[1] - else: - nen = ex.shape[0] + c=len(es) + Nbr=c - ex = ex.reshape(1, nen) - ey = ey.reshape(1, nen) - else: - raise ValueError("Check size of ex, ey dimensions.") + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + nxX=dx/L + nyX=dy/L + n = np.array([nxX, nyX]) - #bar2s returns a float - convert it to array - if isinstance(es, float): - es = np.array([es,es]).reshape(2,1) + if sfac is None: + sfac=(0.2*L)/max(abs(es)) - Nbr = es.shape[0] - b = np.array([ex[0,1]-ex[0,0],ey[0,1]-ey[0,0]]) - Length = np.sqrt(b@b) - n = (b/Length).reshape(1,len(b)) + if eci is None: + eci = np.arange(0., L+L/(Nbr-1), L/(Nbr-1)).reshape(Nbr,1) - if plotpar is None: - mpl_diagram_color = (0, 0, 1) # 'b' - mpl_elem_color = (0, 0, 0) # 'k' - elif len(plotpar) != 2: - raise ValueError('Check size of "plotpar" input argument!') + p1 = plotpar[0] + if p1 == 1: + line_color = (0, 0, 0) + elif p1 == 2: + line_color = (0, 0, 1) + elif p1 == 3: + line_color = (1, 0, 1) + elif p1 == 4: + line_color = (1, 0, 0) else: - p1, p2 = plotpar - if p1 == 1: - mpl_diagram_color = (0, 0, 0) # 'k' - elif p1 == 2: - mpl_diagram_color = (0, 0, 1) # 'b' - elif p1 == 3: - mpl_diagram_color = (1, 0, 1) # 'm' - elif p1 == 4: - mpl_diagram_color = (1, 0, 0) # 'r' - - if p2 == 1: - mpl_elem_color = (0, 0, 0) # 'k' - elif p2 == 2: - mpl_elem_color = (0, 0, 1) # 'b' - elif p2 == 3: - mpl_elem_color = (1, 0, 1) # 'm' - elif p2 == 4: - mpl_elem_color = (1, 0, 0) # 'r' - + raise ValueError("Invalid value for plotpar[1].") + line_style = 'solid' - if sfac is None: - sfac=(0.2*Length)/np.max(np.abs(es)) + p2 = plotpar[1] + if p2 == 1: + line_color1 = (0, 0, 0) + elif p2 == 2: + line_color1 = (0, 0, 1) + elif p2 == 3: + line_color1 = (1, 0, 1) + elif p2 == 4: + line_color1 = (1, 0, 0) + else: + raise ValueError("Invalid value for plotpar[1].") - if eci is None: - eci = np.linspace(0,Length,Nbr).reshape(Nbr,1) + a = len(eci) + if a != c: + raise ValueError("Check size of eci dimension.") + + es=es*sfac + +# From local x-coordinates to global coordinates of the element + A = np.zeros(2*Nbr).reshape(Nbr,2) + A[0,0] = ex[0] + A[0,1] = ey[0] + for i in range(Nbr): + A[i,0] = A[0,0]+eci[i]*n[0] + A[i,1] = A[0,1]+eci[i]*n[1] + + B=np.array(A) + +# Plot diagram + for i in range(0, Nbr): + A[i,0]=A[i,0]+es[i]*n[1] + A[i,1]=A[i,1]-es[i]*n[0] + + xc=np.array(A[:,0]) + yc=np.array(A[:,1]) + + plt.plot(xc,yc, color=line_color, linewidth=1) + +# Plot stripes in diagram + xs = np.zeros(2) + ys = np.zeros(2) + for i in range(Nbr): + xs[0]=B[i,0] + xs[1]=A[i,0] + ys[0]=B[i,1] + ys[1]=A[i,1] + print("i,xs,ys=") + print(i,xs,ys) + plt.plot(xs,ys, color=line_color, linewidth=1) +# Plot element + plt.plot(ex,ey, color=line_color1, linewidth=2) + + +def scalgraph2(sfac, magnitude, plotpar=2): + """ + scalgraph2(sfac, magnitude, plotpar) + scalgraph2(sfac, magnitude) + ------------------------------------------------------------- + PURPOSE + Draw a graphic scale - if es.shape[0] != eci.shape[0]: - raise ValueError("Check size of 'es' or 'eci' input argument!") + INPUT: sfac = [scalar] scale factor. - es *= sfac + magnitude = [Ref x y] The graphic scale has a length equivalent + to Ref and starts at coordinates (x,y). + If no coordinates are given the starting + point will be (0,-0.5). - # From local x-coordinates to global coordinates of the element - A = np.zeros([Nbr,2]) - A = [ex[0][0], ey[0][0]] + eci@n - Ax = np.zeros([Nbr-1,2]) - Ax[:,0] = A[:-1,0] - Ax[:,1] = A[1:,0] - Ay = np.zeros([Nbr-1,2]) - Ay[:,0] = A[:-1,1] - Ay[:,1] = A[1:,1] + plotpar=[linecolor] + linecolor=1 -> black + 2 -> blue + 3 -> magenta + 4 -> red + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2015-12-02 + O Dahlblom 2023-01-23 (Python) - Bx=np.copy(Ax) - By=np.copy(Ay) - for i in range(Nbr-1): - Ax[i,:] = [ Ax[i,0]+es[i]*n[0,1], Ax[i,1]+es[i+1]*n[0,1] ] - Ay[i,:] = [ Ay[i,0]-es[i]*n[0,0], Ay[i,1]-es[i+1]*n[0,0] ] + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + cols = len(magnitude) + if cols != 1 and cols != 3 : + raise ValueError("Check size of magnitude input argument.") + if cols == 1 : + N = magnitude + x = 0 + y = -0.5 + if cols == 3 : + N, x, y = magnitude + + print("x= y=") + print(x,y) + + L = N*sfac + print("L=") + print(L) + print("plotpar") + print(plotpar) + + if plotpar == 1: + line_color = (0, 0, 0) + elif plotpar == 2: + line_color = (0, 0, 1) + elif plotpar == 3: + line_color = (1, 0, 1) + elif plotpar == 4: + line_color = (1, 0, 0) + else: + raise ValueError("Invalid value for plotpar[1].") + print("x=") + print(x) + plt.plot([x, (x+L)],[y, y], color=line_color, linewidth=1) + plt.plot([x, x],[(y-L/20), (y+L/20)], color=line_color, linewidth=1) + plt.plot([(x+L), (x+L)],[(y-L/20), (y+L/20)], color=line_color, linewidth=1) + plt.text(x+L*1.1, (y-L/20), str(N)) - #plot diagram and its vertical stripes at the ends - plt.axis('equal') - draw_elements(Ax, Ay, color=mpl_diagram_color, - line_style='solid', filled=False, closed=False) - - draw_elements(np.array([ex[0][0], Ax[0,0]]).reshape(1,2), np.array([ey[0][0], Ay[0,0]]).reshape(1,2), color=mpl_diagram_color, - line_style='solid', filled=False, closed=False) - draw_elements(np.array([ex[0][1], Ax[-1,-1]]).reshape(1,2), np.array([ey[0][1], Ay[-1,-1]]).reshape(1,2), color=mpl_diagram_color, - line_style='solid', filled=False, closed=False) - - #plot stripes in diagram - for i in range(0,Nbr-2): - np.array([Bx[i,1], Ax[i,1]]).reshape(1,2), np.array([By[i,1], Ay[i,1]]).reshape(1,2) - draw_elements(np.array([Bx[i,1], Ax[i,1]]).reshape(1,2), np.array([By[i,1], Ay[i,1]]).reshape(1,2), color=mpl_diagram_color, - line_style='solid', filled=False, closed=False) - - #plot elements - draw_elements(ex, ey, color=mpl_elem_color, - line_style='solid', filled=False, closed=False) From d50c2697bce96318a4528faf326f193905b86c18 Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Fri, 17 Feb 2023 09:40:49 +0100 Subject: [PATCH 12/17] Added updated bar/beam examples. --- examples/exs_bar2.py | 70 ++++++++----- examples/exs_bar2_la.py | 7 +- examples/exs_bar2_lb.py | 107 +++++++++++++++++++ examples/exs_beam1.py | 115 +++++++++++--------- examples/exs_beam2.py | 214 +++++++++++++++++++++++--------------- examples/exs_beambar2.py | 146 +++++++++++++------------- examples/exs_flw_temp1.py | 92 ++++++++++++++++ 7 files changed, 513 insertions(+), 238 deletions(-) create mode 100644 examples/exs_bar2_lb.py create mode 100644 examples/exs_flw_temp1.py diff --git a/examples/exs_bar2.py b/examples/exs_bar2.py index dbf9cbd..c1d1e20 100644 --- a/examples/exs_bar2.py +++ b/examples/exs_bar2.py @@ -9,6 +9,7 @@ # REFERENCES # Ola Dahlblom 2004-09-07 # Jonas Lindemann 2009-01-25 +# Ola Dahlblom 2023-02-02 # ---------------------------------------------------------------- import numpy as np @@ -84,31 +85,44 @@ ed3 = cfc.extract_ed(edof[2, :], a) N3 = cfc.bar2s(ex3, ey3, ep3, ed3) -print("N1 = "+str(N1)) -print("N2 = "+str(N2)) -print("N3 = "+str(N3)) - -# ----- Draw deformed truss -------------------------------------- -cfv.figure(1,fig_size=(6,4)) -plotpar = [2,1,0] -cfv.eldraw2(ex1,ey1,plotpar) -cfv.eldraw2(ex2,ey2,plotpar) -cfv.eldraw2(ex3,ey3,plotpar) -sfac = cfv.scalfact2(ex1,ey1,ed1,0.1) -plotpar = [1,2,1] -cfv.eldisp2(ex1,ey1,ed1,plotpar,sfac) -cfv.eldisp2(ex2,ey2,ed2,plotpar,sfac) -cfv.eldisp2(ex3,ey3,ed3,plotpar,sfac) -cfv.plt.axis([-0.4, 2.0, -0.4, 1.4]) -cfv.title("Displacements") - -# ----- Draw normal force diagram --------------------------------- -cfv.figure(2,fig_size=(6,4)) -plotpar = [2,1] -sfac = cfv.scalfact2(ex1,ey1,N2,0.1) -cfv.secforce2(ex1,ey1,N1,plotpar,sfac) -cfv.secforce2(ex2,ey2,N2,plotpar,sfac) -cfv.secforce2(ex3,ey3,N3,plotpar,sfac) -cfv.plt.axis([-0.4, 2.0, -0.4, 1.4]) -cfv.title("Normal force") -cfv.showAndWait() \ No newline at end of file +print("N1 = ") +print(N1) +print("N2 = ") +print(N2) +print("N3 = ") +print(N3) + +# ----- Draw deformed frame --------------------------------------- + +plotpar = [2, 1, 0] +sfac = cfv.scalfact2(ex3, ey3, ed1, 0.1) +print("sfac=") +print(sfac) + +cfv.figure(1) +cfv.eldraw2(ex1, ey1, plotpar) +cfv.eldraw2(ex2, ey2, plotpar) +cfv.eldraw2(ex3, ey3, plotpar) + +plotpar = [1, 2, 1] +cfv.eldisp2(ex1, ey1, ed1, plotpar, sfac) +cfv.eldisp2(ex2, ey2, ed2, plotpar, sfac) +cfv.eldisp2(ex3, ey3, ed3, plotpar, sfac) +cfv.axis([-0.4, 2.0, -0.4, 1.4]) +plotpar1 = 2 +cfv.scalgraph2(sfac,[1e-3, 0, -0.3],plotpar1) +cfv.title('Displacements') + +# ----- Draw normal force diagram -------------------------------- + +plotpar = [2, 1] +sfac = cfv.scalfact2(ex1, ey1, N2[:,0], 0.1) +cfv.figure(2) +cfv.secforce2(ex1, ey1, N1[:,0], plotpar, sfac) +cfv.secforce2(ex2, ey2, N2[:,0], plotpar, sfac) +cfv.secforce2(ex3, ey3, N3[:,0], plotpar, sfac) +cfv.axis([-0.4, 2.0, -0.4, 1.4]) +cfv.scalgraph2(sfac,[5e4, 0, -0.3],plotpar1) +cfv.title('Normal force') + +cfv.showAndWait() diff --git a/examples/exs_bar2_la.py b/examples/exs_bar2_la.py index a1ef884..a774b0f 100644 --- a/examples/exs_bar2_la.py +++ b/examples/exs_bar2_la.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# example exs4a +# example exs_bar2_la # ---------------------------------------------------------------- # PURPOSE # Analysis of a plane truss using loops. @@ -11,6 +11,7 @@ # K-G Olsson 1995-09-28 # O Dahlblom 2004-08-31 # J Lindemann 2009-01-25 +# O Dahlblom 2023-02-02 # ---------------------------------------------------------------- import numpy as np @@ -101,6 +102,8 @@ i = 0 for elx, ely, eld in zip(ex, ey, ed): - N[i] = cfc.bar2s(elx, ely, ep, eld) + es = cfc.bar2s(elx, ely, ep, eld) + N[i] = es[0] print("N%d = %g" % (i+1, N[i])) i += 1 + diff --git a/examples/exs_bar2_lb.py b/examples/exs_bar2_lb.py new file mode 100644 index 0000000..2fb3d3b --- /dev/null +++ b/examples/exs_bar2_lb.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# +# example exs_bar2_la +# ---------------------------------------------------------------- +# PURPOSE +# Analysis of a plane truss using loops and extraction of +# element coordinates from a global coordinate matrix. +# ---------------------------------------------------------------- + +# REFERENCES +# P-E Austrell 1994-03-08 +# K-G Olsson 1995-09-28 +# O Dahlblom 2004-08-31 +# J Lindemann 2009-01-25 +# O Dahlblom 2019-12-16 +# O Dahlblom 2023-02-02 +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc + +# ----- Topology matrix Edof ------------------------------------- + +edof = np.array([ + [1, 2, 5, 6], + [3, 4, 7, 8], + [5, 6, 9, 10], + [7, 8, 11, 12], + [7, 8, 5, 6], + [11, 12, 9, 10], + [3, 4, 5, 6], + [7, 8, 9, 10], + [1, 2, 7, 8], + [5, 6, 11, 12] +]) + +# ----- Stiffness matrix K and load vector f --------------------- + +K = np.zeros([12, 12]) +f = np.zeros([12, 1]) +f[10] = 0.5e6*np.sin(np.pi/6) +f[11] = -0.5e6*np.cos(np.pi/6) + +# ----- Element properties --------------------------------------- + +A = 25.0e-4 +E = 2.1e11 +ep = [E, A] + +#----- Global coordinates and topology -------------------------- + +coord = np.array([ + [0, 2], + [0, 0], + [2, 2], + [2, 0], + [4, 2], + [4, 0] +]) + +dof = np.array([ + [ 1, 2], + [ 3, 4], + [ 5, 6], + [ 7, 8], + [ 9, 10], + [11, 12] +]) + +# ----- Element coordinates -------------------------------------- + +ex, ey = cfc.coordxtr(edof, coord, dof,2) + +# ----- Create element stiffness matrices Ke and assemble into K - + +for elx, ely, eltopo in zip(ex, ey, edof): + Ke = cfc.bar2e(elx, ely, ep) + cfc.assem(eltopo, K, Ke) + +print("Stiffness matrix K:") +print(K) + +# ----- Solve the system of equations ---------------------------- + +bc = np.array([1, 2, 3, 4]) +a, r = cfc.solveq(K, f, bc) + +print("Displacements a:") +print(a) + +print("Reaction forces r:") +print(r) + +# ----- Element forces ------------------------------------------- + +ed = cfc.extract_ed(edof, a) +N = np.zeros([edof.shape[0]]) + +print("Element forces:") + +i = 0 +for elx, ely, eld in zip(ex, ey, ed): + es = cfc.bar2s(elx, ely, ep, eld) + N[i] = es[0] + print("N%d = %g" % (i+1, N[i])) + i += 1 + diff --git a/examples/exs_beam1.py b/examples/exs_beam1.py index fafe72d..4608101 100644 --- a/examples/exs_beam1.py +++ b/examples/exs_beam1.py @@ -1,87 +1,100 @@ # -*- coding: utf-8 -*- # -# example exs5 -# ---------------------------------------------------------------- -# PURPOSE +# example exs_beam1 +#---------------------------------------------------------------- +# PURPOSE # Analysis of a simply supported beam. -# ---------------------------------------------------------------- +#---------------------------------------------------------------- # REFERENCES -# Göran Sandberg 94-03-08 -# Karl-Gunnar Olsson 95-09-28 -# Ola Dahlblom 2004-09-21 +# Ola Dahlblom 2015-11-13 +# Ola Dahlblom 2019-12-11 +# Ola Dahlblom 2022-07-11 # ---------------------------------------------------------------- import numpy as np +import matplotlib.pyplot as plt import calfem.core as cfc +import calfem.utils as cfu import calfem.vis_mpl as cfv # ----- Topology ------------------------------------------------- edof = np.array([ - [1, 2, 3, 4], - [3, 4, 5, 6], + [1, 2, 3, 4], + [3, 4, 5, 6] ]) # ----- Stiffness matrix K and load vector f --------------------- -K = np.mat(np.zeros((6, 6))) -f = np.mat(np.zeros((6, 1))) -f[2] = -10000. +K = np.array(np.zeros((6, 6))) +f = np.array(np.zeros((6, 1))) +f[2] = -10e+3 -# ----- Element stiffness matrices ------------------------------ +# ----- Element stiffness and element load matrices ------------- -E = 2.1e11 +E = 210e9 I = 2510e-8 + ep = np.array([E, I]) -ex1 = np.array([0., 3.]) -ex2 = np.array([3., 9.]) +ex1 = np.array([0, 3]) +ex2 = np.array([3, 9]) +eq1 = np.array([0]) +eq2 = np.array([0]) + Ke1 = cfc.beam1e(ex1, ep) Ke2 = cfc.beam1e(ex2, ep) # ----- Assemble Ke into K --------------------------------------- -K = cfc.assem(edof[0,:], K, Ke1) -K = cfc.assem(edof[1,:], K, Ke2) +cfc.assem(edof[0, :], K, Ke1) +cfc.assem(edof[1, :], K, Ke2) -# ----- Solve the system of equations and compute support forces - +# ----- Solve the system of equations and compute reactions ------ bc = np.array([1, 5]) -(a, r) = cfc.solveq(K, f, bc) +a, r = cfc.solveq(K, f, bc) + +print("a = ") +print(a) +print("r = ") +print(r) # ----- Section forces ------------------------------------------- ed = cfc.extract_ed(edof, a) -es1, ed1, ec1 = cfc.beam1s(ex1, ep, ed[0, :], nep=10) -es2, ed2, ec2 = cfc.beam1s(ex2, ep, ed[1, :], nep=10) - -es = np.vstack(([0,0],es1,es2,[0,0])) -eD = np.vstack((0,ed1,ed2,0)) -ec = np.vstack((ex1[0],ec1+ex1[0],ec2+ex2[0],ex2[1])) - -# ----- Draw deformed beam ---------------------------------------- -cfv.figure(1,fig_size=(6,2.5)) -cfv.plt.plot([0, 9],[0,0],'b',linewidth=0.5) -cfv.plt.plot(ec,eD,'b') -cfv.plt.axis([-1,10,-0.03, 0.01]) -cfv.title("Displacements") - -# ----- Draw shear force diagram ---------------------------------- -cfv.figure(2,fig_size=(6,2.5)) -cfv.plt.plot([0, 9],[0,0],'b',linewidth=0.5) -cfv.plt.plot(ec,es[:,0],'b') -cfv.plt.axis([-1,10,-8000, 5000]) -cfv.title("Shear force") -cfv.gca().invert_yaxis() - -# ----- Draw bending moment diagram ------------------------------- -cfv.figure(3,fig_size=(6,2.5)) -cfv.plt.plot([0, 9],[0,0],'b',linewidth=0.5) -cfv.plt.plot(ec,es[:,1],'b') -cfv.plt.axis([-1,10,-5000, 25000]) -cfv.title("Bending moment") -cfv.gca().invert_yaxis() -cfv.showAndWait() +es1, ed1, ec1 = cfc.beam1s(ex1, ep, ed[0, :], eq1, nep=4) +es2, ed2, ec2 = cfc.beam1s(ex2, ep, ed[1, :], eq2, nep=7) + +print("es1 = ") +print(es1) +print("ed1 = ") +print(ed1) +print("es2 = ") +print(es2) +print("ed2 = ") +print(ed2) + +#----- Draw deformed beam --------------------------------------- + +cfv.figure(1) +plt.plot([0, 9],[0, 0], color=(0.8, 0.8, 0.8)) +plt.plot(np.concatenate(([0],ec1[:,0], 3+ec2[:,0],[9]), 0),np.concatenate(([0],ed1[:,0], ed2[:,0],[0]), 0), color=(0.0, 0.0, 0.0)) +cfv.title('displacements') + +#----- Draw shear force diagram---------------------------------- + +cfv.figure(2) +plt.plot([0, 9],[0, 0], color=(0.8, 0.8, 0.8)) +plt.plot(np.concatenate(([0],ec1[:,0], 3+ec2[:,0],[9]), 0),-np.concatenate(([0],es1[:,0], es2[:,0],[0]), 0)/1000, color=(0.0, 0.0, 0.0)) +cfv.title('shear force') + +#----- Draw moment diagram---------------------------------- + +cfv.figure(3) +plt.plot([0, 9],[0, 0], color=(0.8, 0.8, 0.8)) +plt.plot(np.concatenate(([0],ec1[:,0], 3+ec2[:,0],[9]), 0),-np.concatenate(([0],es1[:,1], es2[:,1],[0]), 0)/1000, color=(0.0, 0.0, 0.0)) +cfv.title('bending moment') -#------------------------ end ----------------------------------- \ No newline at end of file +cfv.showAndWait() diff --git a/examples/exs_beam2.py b/examples/exs_beam2.py index 98869ac..ad6594c 100644 --- a/examples/exs_beam2.py +++ b/examples/exs_beam2.py @@ -1,114 +1,158 @@ -# example exs6 +# -*- coding: utf-8 -*- +# +# example exs_beam2 # ---------------------------------------------------------------- # PURPOSE # Analysis of a plane frame. # ---------------------------------------------------------------- +# REFERENCES +# Göran Sandberg 94-03-08 +# Karl-Gunnar Olsson 95-09-28 +# Anders Olsson 99-03-01 +# Ola Dahlblom 2004-09-14 +# Ola Dahlblom 2019-12-16 +# Ola Dahlblom 2023-02-03 +# ---------------------------------------------------------------- + import numpy as np import calfem.core as cfc +import calfem.utils as cfu import calfem.vis_mpl as cfv - -#----- Topology ------------------------------------------------- +# ----- Topology ------------------------------------------------- edof = np.array([ - [4, 5, 6, 1, 2, 3], - [7, 8, 9, 10, 11, 12], - [4, 5, 6, 7, 8, 9] + [4, 5, 6, 1, 2, 3], + [7, 8, 9, 10, 11, 12], + [4, 5, 6, 7, 8, 9] ]) -#----- Stiffness matrix K and load vector f --------------------- +# ----- Stiffness matrix K and load vector f --------------------- -K = np.zeros([12,12]) -f = np.zeros([12,1]) -f[3,0] = 2e3 +K = np.array(np.zeros((12, 12))) +f = np.array(np.zeros((12, 1))) +f[3] = 2.e+3 -#----- Element stiffness and element load matrices ------------- +# ----- Element stiffness and element load matrices ------------- -E=200e9 -A1=2e-3 -A2=6e-3 -I1=1.6e-5 -I2=5.4e-5 +E = 200.e9 +A1 = 2.e-3 +A2 = 6.e-3 +I1 = 1.6e-5 +I2 = 5.4e-5 ep1 = np.array([E, A1, I1]) ep3 = np.array([E, A2, I2]) +ex1 = np.array([0, 0]) +ex2 = np.array([6, 6]) +ex3 = np.array([0, 6]) +ey1 = np.array([4, 0]) +ey2 = np.array([4, 0]) +ey3 = np.array([4, 4]) +eq1 = np.array([0, 0]) +eq2 = np.array([0, 0]) +eq3 = np.array([0, -10e+3]) -ex1 = np.array([0.,0.]) -ey1 = np.array([4.,0.]) -ex2 = np.array([6.,6.]) -ey2 = np.array([4.,0.]) -ex3 = np.array([0.,6.]) -ey3 = np.array([4.,4.]) +Ke1 = cfc.beam2e(ex1, ey1, ep1) +Ke2 = cfc.beam2e(ex2, ey2, ep1) +Ke3, fe3 = cfc.beam2e(ex3, ey3, ep3, eq3) -eq1 = np.array([0.,0.]) -eq2 = np.array([0.,0.]) -eq3 = np.array([0.,-10e3]) +# ----- Assemble Ke into K --------------------------------------- -Ke1 = cfc.beam2e(ex1,ey1,ep1) -Ke2 = cfc.beam2e(ex2,ey2,ep1) -Ke3, fe3 = cfc.beam2e(ex3,ey3,ep3,eq3) +cfc.assem(edof[0, :], K, Ke1) +cfc.assem(edof[1, :], K, Ke2) +cfc.assem(edof[2, :], K, Ke3, f, fe3) -#----- Assemble Ke into K --------------------------------------- +# ----- Solve the system of equations and compute reactions ------ -K = cfc.assem(edof[0,:],K,Ke1) -K = cfc.assem(edof[1,:],K,Ke2) -K, f = cfc.assem(edof[2,:],K,Ke3,f,fe3) - -#----- Solve the system of equations and compute reactions ------ bc = np.array([1, 2, 3, 10, 11]) a, r = cfc.solveq(K, f, bc) -#----- Section forces ------------------------------------------- +print("a = ") +print(a) +print("r = ") +print(r) + +# ----- Section forces ------------------------------------------- + ed = cfc.extract_ed(edof, a) -es1, edi1, eci1 = cfc.beam2s(ex1,ey1,ep1,ed[0,:],eq1,21) -es2, edi2, eci2 = cfc.beam2s(ex2,ey2,ep1,ed[1,:],eq2,21) -es3, edi3, eci3 = cfc.beam2s(ex3,ey3,ep3,ed[2,:],eq3,21) - -#----- Draw deformed frame --------------------------------------- -cfv.figure(1,fig_size=(6,4)) -plotpar=[2,1,0] -cfv.eldraw2(ex1,ey1,plotpar) -cfv.eldraw2(ex2,ey2,plotpar) -cfv.eldraw2(ex3,ey3,plotpar) -sfac=cfv.scalfact2(ex3,ey3,edi3,0.1) -plotpar=[1,2,1] -cfv.eldisp2(ex1,ey1,ed[0,:],plotpar,sfac) -cfv.eldisp2(ex2,ey2,ed[1,:],plotpar,sfac) -cfv.eldisp2(ex3,ey3,ed[2,:],plotpar,sfac) -cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) -cfv.title("Displacements") - - -#----- Draw normal force diagram -------------------------------- -cfv.figure(2,fig_size=(6,4)) -plotpar=[2,1] -sfac=cfv.scalfact2(ex1,ey1,es1[:,0],0.2) -cfv.secforce2(ex1,ey1,es1[:,0],plotpar,sfac) -cfv.secforce2(ex2,ey2,es2[:,0],plotpar,sfac) -cfv.secforce2(ex3,ey3,es3[:,0],plotpar,sfac) -cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) -cfv.title("Normal force") - -#----- Draw shear force diagram --------------------------------- -cfv.figure(3,fig_size=(6,4)) -plotpar=[2,1] -sfac=cfv.scalfact2(ex3,ey3,es3[:,1],0.2) -cfv.secforce2(ex1,ey1,es1[:,1],plotpar,sfac) -cfv.secforce2(ex2,ey2,es2[:,1],plotpar,sfac) -cfv.secforce2(ex3,ey3,es3[:,1],plotpar,sfac) -cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) -cfv.title("Shear force") - -#----- Draw moment diagram -------------------------------------- -cfv.figure(4,fig_size=(6,4)) -plotpar=[2,1] -sfac=cfv.scalfact2(ex3,ey3,es3[:,2],0.2) -cfv.secforce2(ex1,ey1,es1[:,2],plotpar,sfac) -cfv.secforce2(ex2,ey2,es2[:,2],plotpar,sfac) -cfv.secforce2(ex3,ey3,es3[:,2],plotpar,sfac) -cfv.plt.axis([-1.5, 7.5, -0.5, 5.5]) -cfv.title("Bending moment") -cfv.showAndWait() -#------------------------ end ----------------------------------- \ No newline at end of file +es1, edi1, ec1 = cfc.beam2s(ex1, ey1, ep1, ed[0, :], eq1, nep=21) +es2, edi2, ec2 = cfc.beam2s(ex2, ey2, ep1, ed[1, :], eq2, nep=21) +es3, edi3, ec3 = cfc.beam2s(ex3, ey3, ep3, ed[2, :], eq3, nep=21) + +print("es1 = ") +print(es1) +print("edi1 = ") +print(edi1) +print("es2 = ") +print(es2) +print("edi2 = ") +print(edi2) +print("es3 = ") +print(es3) +print("edi3 = ") +print(edi3) + +# ----- Draw deformed frame --------------------------------------- + +plotpar = [2, 1, 0] +sfac = cfv.scalfact2(ex3, ey3, edi3, 0.1) +print("sfac=") +print(sfac) + +cfv.figure(1) +cfv.eldraw2(ex1, ey1, plotpar) +cfv.eldraw2(ex2, ey2, plotpar) +cfv.eldraw2(ex3, ey3, plotpar) + +plotpar = [1, 2, 1] +cfv.dispbeam2(ex1, ey1, edi1, plotpar, sfac) +cfv.dispbeam2(ex2, ey2, edi2, plotpar, sfac) +cfv.dispbeam2(ex3, ey3, edi3, plotpar, sfac) +cfv.axis([-1.5, 7.5, -0.5, 5.5]) +plotpar1 = 2 +cfv.scalgraph2(sfac,[1e-2, 0.5, 0],plotpar1); +cfv.title('Displacements') + +# ----- Draw normal force diagram -------------------------------- + +plotpar = [2, 1] +sfac = cfv.scalfact2(ex1, ey1, es1[:,0], 0.2) +cfv.figure(2) +cfv.secforce2(ex1, ey1, es1[:,0], plotpar, sfac) +cfv.secforce2(ex2, ey2, es2[:,0], plotpar, sfac) +cfv.secforce2(ex3, ey3, es3[:,0], plotpar, sfac) +cfv.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.scalgraph2(sfac,[3e4, 1.5, 0],plotpar1) +cfv.title('Normal force') + +# ----- Draw shear force diagram --------------------------------- + +plotpar = [2, 1] +sfac = cfv.scalfact2(ex3, ey3, es3[:,1], 0.2) +cfv.figure(3) +cfv.secforce2(ex1, ey1, es1[:,1], plotpar, sfac) +cfv.secforce2(ex2, ey2, es2[:,1], plotpar, sfac) +cfv.secforce2(ex3, ey3, es3[:,1], plotpar, sfac) +cfv.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.scalgraph2(sfac,[3e4, 0.5, 0],plotpar1) +cfv.title('Shear force') + +# ----- Draw moment diagram -------------------------------------- + +plotpar = [2, 1] +sfac = cfv.scalfact2(ex3, ey3, es3[:,2], 0.2) +print("sfac=") +print(sfac) + +cfv.figure(4) +cfv.secforce2(ex1, ey1, es1[:,2], plotpar, sfac) +cfv.secforce2(ex2, ey2, es2[:,2], plotpar, sfac) +cfv.secforce2(ex3, ey3, es3[:,2], plotpar, sfac) +cfv.axis([-1.5, 7.5, -0.5, 5.5]) +cfv.scalgraph2(sfac,[3e4, 0.5, 0],plotpar1) +cfv.title('Moment') + +cfv.showAndWait() \ No newline at end of file diff --git a/examples/exs_beambar2.py b/examples/exs_beambar2.py index 5514923..70633c4 100644 --- a/examples/exs_beambar2.py +++ b/examples/exs_beambar2.py @@ -1,17 +1,18 @@ # -*- coding: utf-8 -*- # -# example exs7 +# example exs_beam2 # ---------------------------------------------------------------- # PURPOSE -# Set up a frame, consisting of both beams and bars, and -# illustrate the calculations by use of graphics functions. +# Analysis of a combined beam and bar structure. # ---------------------------------------------------------------- # REFERENCES -# P-A Hansson 1994-01-20 -# K-G Olsson 1995-09-28 -# O Dahlblom 2004-10-07 -# J Lindemann 2021-12-29 (Python version) +# Ola Dahlblom 2015-11-16 +# Ola Dahlblom 2019-12-19 +# Ola Dahlblom 2023-02-02 +# Copyright (c) Division of Structural Mechanics and +# Division of Solid Mechanics. +# Lund University # ---------------------------------------------------------------- import numpy as np @@ -19,92 +20,93 @@ import calfem.utils as cfu import calfem.vis_mpl as cfv -np.set_printoptions(precision=3, suppress=True) +#np.set_printoptions(precision=3, suppress=True) -# ----- System matrices ------------------------------------------ +# ----- Topology ------------------------------------------------- -K = np.zeros((18, 18)) -f = np.zeros((18, 1)) - -f[12] = 1 - -coord = np.array([ - [0., 0.], - [1., 0.], - [0., 1.], - [1., 1.], - [0., 2.], - [1., 2.] +edof1 = np.array([ + [1, 2, 3, 4, 5, 6], + [4, 5, 6, 7, 8, 9], + [7, 8, 9, 10, 11, 12] ]) -dof = np.array([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - [10, 11, 12], - [13, 14, 15], - [16, 17, 18] +edof2 = np.array([ + [13, 14, 4, 5], + [13, 14, 7, 8] ]) -# ----- Element properties, topology and coordinates ------------- +# ----- Stiffness matrix K and load vector f --------------------- -ep1 = [1, 1, 1] -edof1 = np.array([ - [1, 2, 3, 7, 8, 9], - [7, 8, 9, 13, 14, 15], - [4, 5, 6, 10, 11, 12], - [10, 11, 12, 16, 17, 18], - [7, 8, 9, 10, 11, 12], - [13, 14, 15, 16, 17, 18] -]) +K = np.array(np.zeros((14, 14))) +f = np.array(np.zeros((14, 1))) -ex1, ey1 = cfc.coordxtr(edof1, coord, dof, 2) +# ----- Element stiffness and element load matrices ------------- -ep2 = [1, 1] -edof2 = np.array([ - [1, 2, 10, 11], - [7, 8, 16, 17], - [7, 8, 4, 5], - [13, 14, 10, 11] -]) +E = 200.e9 +A1 = 4.e-3 +I1 = 5.4e-5 +A2 = 1.e-3 -ex2, ey2 = cfc.coordxtr(edof2, coord, dof, 2) +ep1 = np.array([E, A1, I1]) +ep4 = np.array([E, A2]) -# ----- Draw the fe-mesh as a check of the model ----------------- +eq1 = np.array([0, 0]) +eq2 = np.array([0, -10e+3]) -cfv.figure(1) -cfv.eldraw2(ex1, ey1, [1, 3, 1]) -cfv.eldraw2(ex2, ey2, [1, 2, 1]) +ex1 = np.array([0, 2]) +ex2 = np.array([2, 4]) +ex3 = np.array([4, 6]) +ex4 = np.array([0, 2]) +ex5 = np.array([0, 4]) +ey1 = np.array([2, 2]) +ey2 = np.array([2, 2]) +ey3 = np.array([2, 2]) +ey4 = np.array([0, 2]) +ey5 = np.array([0, 2]) -# ----- Create and assemble element matrices --------------------- +Ke1 = cfc.beam2e(ex1, ey1, ep1) +Ke2, fe2 = cfc.beam2e(ex2, ey2, ep1, eq2) +Ke3, fe3 = cfc.beam2e(ex3, ey3, ep1, eq2) +Ke4 = cfc.bar2e(ex4, ey4, ep4) +Ke5 = cfc.bar2e(ex5, ey5, ep4) -for elx, ely, eltopo in zip(ex1, ey1, edof1): - Ke = cfc.beam2e(elx, ely, ep1) - K = cfc.assem(eltopo, K, Ke) +# ----- Assemble Ke into K --------------------------------------- -for elx, ely, eltopo in zip(ex2, ey2, edof2): - Ke = cfc.bar2e(elx, ely, ep2) - K = cfc.assem(eltopo, K, Ke) +cfc.assem(edof1[0, :], K, Ke1) +cfc.assem(edof1[1, :], K, Ke2, f, fe2) +cfc.assem(edof1[2, :], K, Ke3, f, fe3) +cfc.assem(edof2[0, :], K, Ke4) +cfc.assem(edof2[1, :], K, Ke5) -# ----- Solve equation system ------------------------------------ +# ----- Solve the system of equations and compute reactions ------ -bc = np.array([1, 2, 3, 4, 5, 6]) +bc = np.array([1, 2, 3, 13, 14]) a, r = cfc.solveq(K, f, bc) -# ---- Extract element displacements and display the deformed mesh - +print("a = ") +print(a) +print("r = ") +print(r) + +# ----- Section forces ------------------------------------------- ed1 = cfc.extract_ed(edof1, a) ed2 = cfc.extract_ed(edof2, a) -sfac = cfv.scalfact2(ex1, ey1, ed1, 0.1) - -cfv.figure(2) -cfv.eldraw2(ex1, ey1) -cfv.eldraw2(ex2, ey2) -cfv.eldisp2(ex1, ey1, ed1, [2, 1, 1], sfac) -cfv.eldisp2(ex2, ey2, ed2, [2, 1, 1], sfac) - -cfv.show_and_wait() - +es1, _, _ = cfc.beam2s(ex1, ey1, ep1, ed1[0, :], eq1, nep=11) +es2, _, _ = cfc.beam2s(ex2, ey2, ep1, ed1[1, :], eq2, nep=11) +es3, _, _ = cfc.beam2s(ex3, ey3, ep1, ed1[2, :], eq2, nep=11) +es4 = cfc.bar2s(ex4, ey4, ep4, ed2[0, :]) +es5 = cfc.bar2s(ex5, ey5, ep4, ed2[1, :]) + +print("es1 = ") +print(es1) +print("es2 = ") +print(es2) +print("es3 = ") +print(es3) +print("es4 = ") +print(es4) +print("es5 = ") +print(es5) -# -------------------------- end -------------------------------- diff --git a/examples/exs_flw_temp1.py b/examples/exs_flw_temp1.py new file mode 100644 index 0000000..b92c2e1 --- /dev/null +++ b/examples/exs_flw_temp1.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# +# example exs_flw_temp1 +#---------------------------------------------------------------- +# PURPOSE +# Analysis of one dimensional heat flow. +#---------------------------------------------------------------- + +# REFERENCES +# P-E Austrell 1994-03-08 +# K-G Olsson 1995-09-28 +# O Dahlblom 2004-09-07 +# O Dahlblom 2023-02-02 +# ---------------------------------------------------------------- + +import numpy as np +import calfem.core as cfc + +# ----- Topology ------------------------------------------------- + +edof = np.array([ + [1, 2], + [2, 3], + [3, 4], + [4, 5], + [5, 6] +]) + +# ----- Stiffness matrix K and load vector f --------------------- + +K = np.array(np.zeros((6, 6))) +f = np.array(np.zeros((6, 1))) +f[3] = 10 + +# ----- Element stiffness and element load matrices ------------- + +ep1 = 25 +ep2 = 24.3 +ep3 = 0.4 +ep4 = 17 +ep5 = 7.7 + +Ke1 = cfc.spring1e(ep1) +Ke2 = cfc.spring1e(ep2) +Ke3 = cfc.spring1e(ep3) +Ke4 = cfc.spring1e(ep4) +Ke5 = cfc.spring1e(ep5) + +# ----- Assemble Ke into K --------------------------------------- + +cfc.assem(edof[0, :], K, Ke1) +cfc.assem(edof[1, :], K, Ke2) +cfc.assem(edof[2, :], K, Ke3) +cfc.assem(edof[3, :], K, Ke4) +cfc.assem(edof[4, :], K, Ke5) + +# ----- Solve the system of equations ---------------------------- + +bc = np.array([1, 6]) +bcVal = np.array([-17, 20]) +a, r = cfc.solveq(K, f, bc, bcVal) + +print("a = ") +print(a) +print("r = ") +print(r) + +# ----- Section forces ------------------------------------------- + +ed1 = cfc.extract_ed(edof[0, :], a) +ed2 = cfc.extract_ed(edof[1, :], a) +ed3 = cfc.extract_ed(edof[2, :], a) +ed4 = cfc.extract_ed(edof[3, :], a) +ed5 = cfc.extract_ed(edof[4, :], a) + +q1 = cfc.spring1s(ep1, ed1) +q2 = cfc.spring1s(ep2, ed2) +q3 = cfc.spring1s(ep3, ed3) +q4 = cfc.spring1s(ep4, ed4) +q5 = cfc.spring1s(ep5, ed5) + +print("q1 = ") +print(q1) +print("q2 = ") +print(q2) +print("q3 = ") +print(q3) +print("q4 = ") +print(q4) +print("q5 = ") +print(q5) + From 18ff04bd12ded5b6a056c72c8635f02c5492797a Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Fri, 17 Feb 2023 09:42:58 +0100 Subject: [PATCH 13/17] Update core.py --- calfem/core.py | 9404 ++++++++++++++++++++++++++++-------------------- 1 file changed, 5428 insertions(+), 3976 deletions(-) diff --git a/calfem/core.py b/calfem/core.py index e85072e..2d5cf95 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -77,4807 +77,6259 @@ def info(msg): """Write ``msg`` to info log.""" cflog.info(" calfem.core: "+msg) +def spring1e(ep): + """ + Ke = spring1e(ep) + ------------------------------------------------------------- + PURPOSE + Compute element stiffness matrix for spring element. + + INPUT: ep = [k] spring stiffness or analog quantity + + OUTPUT: Ke : spring stiffness matrix, [2 x 2] + ------------------------------------------------------------- + LAST MODIFIED: P-E Austrell 1994-11-02 + O Dahlblom 2022-11-15 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + k = ep + Ke = k * np.array([ + [1, -1], + [-1, 1] + ]) -def flw2te(ex, ey, ep, D, eq=None): + return Ke + + +def spring1s(ep, ed): """ - Compute element stiffness (conductivity) matrix for a triangular field element. - - Parameters: + es = spring1s(ep, ed) + ------------------------------------------------------------- + PURPOSE + Compute element force in spring element (spring1e). - ex = [x1 x2 x3] - ey = [y1 y2 y3] element coordinates + INPUT: ep = [k] spring stiffness or analog quantity - ep = [t] element thickness + ed = [u1 u2] element displacement vector + + OUTPUT: es = [N] element force + ------------------------------------------------------------- - D = [kxx kxy; - kyx kyy] constitutive matrix - - eq heat supply per unit volume - - Returns: - - Ke element 'stiffness' matrix (3 x 3) + LAST MODIFIED: P-E AUSTRELL 1994-11-02 + O Dahlblom 2022-11-14 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + k = ep - fe element load vector (3 x 1) - + N = k*(ed[1]-ed[0]) + es = N + + return es + + +def bar1e(ex, ep, eq=None): """ - t = ep[0] - if eq == None: - eq = 0. + Ke = bar1e (ex, ep) + Ke, fe = bar1e(ex, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a onedimensional bar element. - exm = np.asmatrix(ex) - eym = np.asmatrix(ey) - C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) - B = np.matrix([ - [0., 1., 0.], - [0., 0., 1.] - ])*C.I - A = 0.5*np.linalg.det(C) + INPUT: ex = [x1 x2] element node coordinates - Ke = B.T*D*B*t*A - fe = np.matrix([[1., 1., 1.]]).T*eq*A*t/3 + ep = [E A] element properties; + E: Young's modulus + A: cross section area + ka: axial spring stiffness - if eq == 0.: + eq = [qX] distributed load + + OUTPUT: Ke : bar stiffness matrix [2 x 2] + fe : element load vector [2 x 1] (if eq!=None) + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2015-10-22 + O Dahlblom 2022-11-14 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A = ep + DEA=E*A + + qX=0. + if not eq is None: + qX=eq[0] + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + Ke = DEA/L*np.array([ + [1, -1], + [-1, 1] + ]) + + fe = qX*L*np.array([1/2, 1/2]).reshape(2,1) + + if eq is None: return Ke else: return Ke, fe -def flw2ts(ex, ey, D, ed): - """ - Compute flows or corresponding quantities in the triangular field element. - - Parameters: - - ex = [x1 x2 x3] - ey = [y1 y2 y3] element coordinates - - D = [kxx kxy - kyx kyy] constitutive matrix - - ed =[u1 u2 u3] u1,u2,u3: nodal values - .. .. ..; - - Returns: - - es=[ qx qy ] - ... ..] element flows - - et=[ gx gy ] - ... ..] element gradients - +def bar1s(ex, ep, ed, eq=None, nep=None): """ + es = bar1s(ex, ep, ed) + es = bar1s(ex, ep, ed, eq) + es, edi, eci = bar1s(ex, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute section forces in one dimensional bar element - if len(ex.shape) > 1: - qs = np.zeros([ex.shape[0], 2]) - qt = np.zeros([ex.shape[0], 2]) - row = 0 - for exr, eyr, edr in zip(ex, ey, ed): - exm = np.asmatrix(exr) - eym = np.asmatrix(eyr) - edm = np.asmatrix(edr) - C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) - B = np.matrix([ - [0., 1., 0.], - [0., 0., 1.] - ])*C.I + INPUT: ex = [x1 x2] element node coordinates - qs[row, :] = (-D*B*edm.T).T - qt[row, :] = (B*edm.T).T - row += 1 + ep = [E A] element properties, + E: Young's modulus + A: cross section area + + ed = [u1 u2] element displacement vector - return qs, qt - else: - exm = np.asmatrix(ex) - eym = np.asmatrix(ey) - edm = np.asmatrix(ed) - C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) - B = np.matrix([ - [0., 1., 0.], - [0., 0., 1.] - ])*C.I + eq = [qX] distributed load - qs = -D*B*edm.T - qt = B*edm.T + nep : number of evaluation points ( default=2 ) - return qs.T, qt.T + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- -def flw2qe(ex, ey, ep, D, eq=None): + LAST MODIFIED: O Dahlblom 2021-02-25 + O Dahlblom 2022-11-14 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - Compute element stiffness (conductivity) matrix for a triangular field element. - - Parameters: - - ex = [x1, x2, x3, x4] - ey = [y1, y2, y3, y4] element coordinates - - ep = [t] element thickness + E, A = ep + DEA=E*A + + qX=0. + if not eq is None: + qX=eq[0] + + ne=2 + if nep != None: + ne=nep + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + a1 = ed.reshape(2,1) + + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + + C1a = C1 @ a1 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) + + N = DEA*du + es = N + edi=u + eci=X - D = [[kxx, kxy], - [kyx, kyy]] constitutive matrix - - eq heat supply per unit volume - - Returns: - - Ke element 'stiffness' matrix (4 x 4) + if nep == None: + return es + else: + return es, edi, eci - fe element load vector (4 x 1) - + +def bar1we(ex, ep, eq=None): """ - xc = sum(ex)/4. - yc = sum(ey)/4. + Ke = bar1we (ex, ep) + Ke, fe = bar1we(ex, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a onedimensional bar element with + axial springs. - K = np.zeros((5, 5)) - f = np.zeros((5, 1)) + INPUT: ex = [x1 x2] element node coordinates - if eq == None: - k1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D) - K = assem(np.array([1, 2, 5]), K, k1) - k1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D) - K = assem(np.array([2, 3, 5]), K, k1) - k1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D) - K = assem(np.array([3, 4, 5]), K, k1) - k1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D) - K = assem(np.array([4, 1, 5]), K, k1) - else: - k1, f1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D, eq) - K, f = assem(np.array([1, 2, 5]), K, k1, f, f1) - k1, f1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D, eq) - K, f = assem(np.array([2, 3, 5]), K, k1, f, f1) - k1, f1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D, eq) - K, f = assem(np.array([3, 4, 5]), K, k1, f, f1) - k1, f1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D, eq) - K, f = assem(np.array([4, 1, 5]), K, k1, f, f1) - Ke1, fe1 = statcon(K, f, np.array([5])) + ep = [E A kX] element properties; + E: Young's modulus + A: cross section area + kX: axial spring stiffness - Ke = Ke1 - fe = fe1 + eq = [qX] distributed load + + OUTPUT: Ke : bar stiffness matrix [2 x 2] + fe : element load vector [2 x 1] (if eq!=None) + ------------------------------------------------------------- - if eq == None: + LAST MODIFIED: O Dahlblom 2015-12-17 + O Dahlblom 2022-10-19 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, kX = ep + DEA = E*A; + + qX = 0. + if not eq is None: + qX = eq[0] + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + K1 = DEA/L*np.array([ + [1, -1], + [-1, 1] + ]) + + K2 = kX*L/6*np.array([ + [2, 1], + [1, 2] + ]) + + Ke = K1+K2 + + fe = qX*L*np.array([1/2, 1/2]).reshape(2,1) + + if eq is None: return Ke else: return Ke, fe -def flw2qs(ex, ey, ep, D, ed, eq=None): +def bar1ws(ex, ep, ed, eq=None, nep=None): """ - Compute flows or corresponding quantities in the - quadrilateral field element. - - Parameters: - - ex = [x1, x2, x3, x4] - ey = [y1, y2, y3, y4] element coordinates - - ep = [t] element thickness + es = bar1ws(ex, ep, ed) + es = bar1ws(ex, ep, ed, eq) + es, edi, eci = bar1ws(ex, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute section forces in one dimensional bar element - D = [[kxx, kxy], - [kyx, kyy]] constitutive matrix + INPUT: ex = [x1 x2] element node coordinates - ed = [[u1, u2, u3, u4], - [.., .., .., ..]] u1,u2,u3,u4: nodal values - - eq heat supply per unit volume - - Returns: - - es = [[qx, qy], - [.., ..]] element flows + ep = [E A kX] element properties, + E: Young's modulus + A: cross section area + kX: axial spring stiffness + + ed = [u1 u2] element displacement vector - et = [[gx, gy], - [.., ..]] element gradients - - """ - K = np.zeros((5, 5)) - f = np.zeros((5, 1)) + eq = [qX] distributed load - xm = sum(ex)/4 - ym = sum(ey)/4 + nep : number of evaluation points ( default=2 ) - if eq == None: - q = 0 - else: - q = eq + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] - En = np.array([ - [1, 2, 5], - [2, 3, 5], - [3, 4, 5], - [4, 1, 5] - ]) - ex1 = np.array([ex[0], ex[1], xm]) - ey1 = np.array([ey[0], ey[1], ym]) - ex2 = np.array([ex[1], ex[2], xm]) - ey2 = np.array([ey[1], ey[2], ym]) - ex3 = np.array([ex[2], ex[3], xm]) - ey3 = np.array([ey[2], ey[3], ym]) - ex4 = np.array([ex[3], ex[0], xm]) - ey4 = np.array([ey[3], ey[0], ym]) + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- - if eq == None: - k1 = flw2te(ex1, ey1, ep, D) - K = assem(En[0], K, k1) - k1 = flw2te(ex2, ey2, ep, D) - K = assem(En[1], K, k1) - k1 = flw2te(ex3, ey3, ep, D) - K = assem(En[2], K, k1) - k1 = flw2te(ex4, ey4, ep, D) - K = assem(En[3], K, k1) + LAST MODIFIED: O Dahlblom 2021-02-25 + O Dahlblom 2022-11-14 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, kX = ep + DEA = E*A + + qX = 0. + if not eq is None: + qX = eq[0] + + ne = 2 + if nep != None: + ne = nep + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + a1 = ed.reshape(2,1) + + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + + C1a = C1 @ a1 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + if DEA != 0: + u = u +kX/DEA*np.concatenate(((X**2-L*X)/2, (X**3-L**2*X)/6),1) @ C1a-(X**2-L*X)*qX/(2*DEA) + du = du +kX/DEA*np.concatenate(((2*X-L)/2, (3*X**2-L**2)/6),1) @ C1a-(2*X-L)*qX/(2*DEA) + + N = DEA*du + es = N + edi = u + eci = X + + if nep == None: + return es else: - k1, f1 = flw2te(ex1, ey1, ep, D, q) - K, f = assem(En[0], K, k1, f, f1) - k1, f1 = flw2te(ex2, ey2, ep, D, q) - K, f = assem(En[1], K, k1, f, f1) - k1, f1 = flw2te(ex3, ey3, ep, D, q) - K, f = assem(En[2], K, k1, f, f1) - k1, f1 = flw2te(ex4, ey4, ep, D, q) - K, f = assem(En[3], K, k1, f, f1) + return es, edi, eci - if ed.ndim == 1: - ed = np.array([ed]) - ni, nj = np.shape(ed) +def bar2e(ex, ey, ep, eq=None): + """ + Ke = bar2e(ex, ey, ep) + Ke, fe = bar2e(ex, ey, ep, eq) + ---------------------------------------------------------------------- + PURPOSE + Compute the element stiffness matrix for two dimensional bar element. + + INPUT: ex = [x1 x2] element node coordinates - a = np.zeros((5, ni)) - for i in range(ni): - a[np.ix_(range(5), [i])], r = np.asarray( - solveq(K, f, np.arange(1, 5), ed[i])) + ey = [y1 y2] element node coordinates - s1, t1 = flw2ts(ex1, ey1, D, a[np.ix_(En[0, :]-1, np.arange(ni))].T) - s2, t2 = flw2ts(ex2, ey2, D, a[np.ix_(En[1, :]-1, np.arange(ni))].T) - s3, t3 = flw2ts(ex3, ey3, D, a[np.ix_(En[2, :]-1, np.arange(ni))].T) - s4, t4 = flw2ts(ex4, ey4, D, a[np.ix_(En[3, :]-1, np.arange(ni))].T) + ep = [E A] element properties; + E: Young's modulus + A: cross section area - es = (s1+s2+s3+s4)/4. - et = (t1+t2+t3+t4)/4. + eq = [qX] distributed load + + OUTPUT: Ke : bar stiffness matrix [4 x 4] + fe : element load vector [4 x 1] (if eq!=None) + ------------------------------------------------------------- - return es, et + LAST MODIFIED: O Dahlblom 2015-10-20 + O Dahlblom 2022-11-16 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A = ep + DEA = E*A + qX = 0. + if not eq is None: + qX=eq[0] + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + Kle = DEA/L*np.array([ + [1, -1], + [-1, 1] + ]) -def flw2i4e(ex, ey, ep, D, eq=None): + fle = qX*L*np.array([1/2, 1/2]).reshape(2,1) + + nxX=dx/L + nyX=dy/L + G = np.array([ + [nxX, nyX, 0, 0], + [ 0, 0, nxX, nyX] + ]) + + Ke = G.T @ Kle @ G + fe = G.T @ fle + + if eq is None: + return Ke + else: + return Ke, fe + + +def bar2s(ex, ey, ep, ed, eq=None, nep=None): """ - Compute element stiffness (conductivity) - matrix for 4 node isoparametric field element + es = bar2s(ex, ey, ep, ed) + es = bar2s(ex, ey, ep, ed, eq) + es, edi, eci = bar2s(ex, ey, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute normal force in two dimensional bar element. + + INPUT: ex = [x1 x2] element node coordinates - Parameters: - - ex = [x1 x2 x3 x4] element coordinates - ey = [y1 y2 y3 y4] + ey = [y1 y2] element node coordinates - ep = [t ir] thickness and integration rule + ep = [E A] element properties, + E: Young's modulus + A: cross section area + + ed = [u1 ... u4] element displacement vector - D = [[kxx kxy], - [kyx kyy]] constitutive matrix + eq = [qX] distributed load - eq heat supply per unit volume + nep : number of evaluation points ( default=2 ) - Returns: - Ke element 'stiffness' matrix (4 x 4) - fe element load vector (4 x 1) + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] + + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2015-12-04 + O Dahlblom 2022-11-16 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - t = ep[0] - ir = ep[1] - ngp = ir*ir + E, A = ep + DEA = E*A + + qX = 0. + if not eq is None: + qX = eq[0] + + ne = 2 + if nep != None: + ne=nep - if eq == None: - q = 0 - else: - q = eq + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.mat([g1, g1]) - w = np.mat([w1, w1]) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-g1, -g1], - [g1, -g1], - [-g1, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w1, w1], - [w1, w1], - [w1, w1] - ]) - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat([ - [-g1, -g1], - [-g2, -g1], - [g1, -g1], - [-g1, g2], - [g2, g2], - [g1, g2], - [-g1, g1], - [g2, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w2, w1], - [w1, w1], - [w1, w2], - [w2, w2], - [w1, w2], - [w1, w1], - [w2, w1], - [w1, w1] - ]) + nxX = dx/L + nyX = dy/L + + G = np.array([ + [nxX, nyX, 0, 0], + [ 0, 0, nxX, nyX] + ]) + + a1 = G @ ed.reshape(4,1) + + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + + C1a = C1 @ a1 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) + + N = DEA*du + es = N + edi = u + eci = X + + if nep == None: + return es else: - info("Used number of integration points not implemented") - wp = np.multiply(w[:, 0], w[:, 1]) + return es, edi, eci - xsi = gp[:, 0] - eta = gp[:, 1] - r2 = ngp*2 - N = np.multiply((1-xsi), (1-eta))/4. - N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) - N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) - N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) +def bar2ge(ex, ey, ep, QX): + """ + Ke = bar2ge(ex, ey, ep, QX) + ---------------------------------------------------------------------- + PURPOSE + Compute element stiffness matrix for two dimensional geometric + nonlinear bar element. + + INPUT: ex = [x1 x2] element node coordinates - dNr = np.mat(np.zeros((r2, 4))) - dNr[0:r2:2, 0] = -(1-eta)/4. - dNr[0:r2:2, 1] = (1-eta)/4. - dNr[0:r2:2, 2] = (1+eta)/4. - dNr[0:r2:2, 3] = -(1+eta)/4. - dNr[1:r2+1:2, 0] = -(1-xsi)/4. - dNr[1:r2+1:2, 1] = -(1+xsi)/4. - dNr[1:r2+1:2, 2] = (1+xsi)/4. - dNr[1:r2+1:2, 3] = (1-xsi)/4. + ey = [y1 y2] element node coordinates - Ke1 = np.mat(np.zeros((4, 4))) - fe1 = np.mat(np.zeros((4, 1))) - JT = dNr*np.mat([ex, ey]).T + ep = [E A] element properties; + E: Young's modulus + A: cross section area - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinant == 0") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() - fe1 = fe1+N[i, :].T*detJ*wp[i] + QX: axial force in the bar + + OUTPUT: Ke : bar stiffness matrix [4 x 4] + ------------------------------------------------------------- - if eq == None: - return Ke1*t - else: - return Ke1*t, fe1*t*eq + LAST MODIFIED: O Dahlblom 2015-12-17 + O Dahlblom 2022-11-16 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A = ep + DEA = E*A + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + K0le = DEA/L*np.array([ + [ 1, 0, -1, 0], + [ 0, 0, 0, 0], + [-1, 0, 1, 0], + [ 0, 0, 0, 0] + ]) + + Ksle = QX/L*np.array([ + [ 0, 0, 0, 0], + [ 0, 1, 0, -1], + [ 0, 0, 0, 0], + [ 0, -1, 0, 1] + ]) + Kle = K0le + Ksle -def flw2i4s(ex, ey, ep, D, ed): + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + + G = np.array([ + [nxX, nyX, 0, 0], + [nxY, nyY, 0, 0], + [ 0, 0, nxX, nyX], + [ 0, 0, nxY, nyY] + ]) + + Ke = G.T @ Kle @ G + + return Ke + + +def bar2gs(ex, ey, ep, ed, nep=None): """ - Compute flows or corresponding quantities in the - 4 node isoparametric element. + es, QX, edi, eci = bar2s(ex, ey, ep, ed) + es, QX, edi, eci = bar2s(ex, ey, ep, ed, nep) + ------------------------------------------------------------- + PURPOSE + Compute normal force in two dimensional bar element (bar2ge). - Parameters: - - ex = [x1 x2 x3 x4] element coordinates - ey = [y1 y2 y3 y4] + INPUT: ex = [x1 x2] element node coordinates - ep = [t ir] thickness and integration rule + ey = [y1 y2] element node coordinates - D = [[kxx kxy], - [kyx kyy]] constitutive matrix + ep = [E A] element properties, + E: Young's modulus + A: cross section area + + ed = [u1 ... u4] element displacement vector - ed = [u1, u2, u3, u4] u1,u2,u3,u4: nodal values + nep : number of evaluation points ( default=2 ) - Returns: - es = [[qx, qy], - [.., ..]] element flows + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + QX: axial force - et = [[qx, qy], - [... ..]] element gradients + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] - eci=[[ix1, iy1], Gauss point location vector - [... ...], nint: number of integration points - [ix(nint), iy(nint)] + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2015-10-20 + O Dahlblom 2022-11-16 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - t = ep[0] - ir = ep[1] - ngp = ir*ir + E, A = ep + DEA = E*A + + ne=2 + if nep != None: + ne=nep + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.mat([g1, g1]) - w = np.mat([w1, w1]) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-g1, -g1], - [g1, -g1], - [-g1, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w1, w1], - [w1, w1], - [w1, w1] - ]) - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat([ - [-g1, -g1], - [-g2, -g1], - [g1, -g1], - [-g1, g2], - [g2, g2], - [g1, g2], - [-g1, g1], - [g2, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w2, w1], - [w1, w1], - [w1, w2], - [w2, w2], - [w1, w2], - [w1, w1], - [w2, w1], - [w1, w1] - ]) + G = np.array([ + [nxX, nyX, 0, 0], + [nxY, nyY, 0, 0], + [ 0, 0, nxX, nyX], + [ 0, 0, nxY, nyY] + ]) + + edl = G @ ed.reshape(4,1) + a1 = np.array([ + edl[0], + edl[2] + ]) + + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + N = DEA*du + QX = N[0] + es = N + edi=u + eci=X + + if nep == None: + return es, QX else: - info("Used number of integration points not implemented") - wp = np.multiply(w[:, 0], w[:, 1]) + return es, QX, edi, eci - xsi = gp[:, 0] - eta = gp[:, 1] - r2 = ngp*2 - N = np.multiply((1-xsi), (1-eta))/4. - N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) - N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) - N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) +def bar3e(ex, ey, ez, ep, eq=None): + """ + Ke = bar2e(ex, ey, ez, ep) + Ke, fe = bar2e(ex, ey, ez, ep, eq) + ---------------------------------------------------------------------- + PURPOSE + Compute the element stiffness matrix for three dimensional bar element. + + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] + ez = [z1 z2] - dNr = np.mat(np.zeros((r2, 4))) - dNr[0:r2:2, 0] = -(1-eta)/4. - dNr[0:r2:2, 1] = (1-eta)/4. - dNr[0:r2:2, 2] = (1+eta)/4. - dNr[0:r2:2, 3] = -(1+eta)/4. - dNr[1:r2+1:2, 0] = -(1-xsi)/4. - dNr[1:r2+1:2, 1] = -(1+xsi)/4. - dNr[1:r2+1:2, 2] = (1+xsi)/4. - dNr[1:r2+1:2, 3] = (1-xsi)/4. + ep = [E A] element properties; + E: Young's modulus + A: cross section area - eci = N*np.mat([ex, ey]).T - if ed.ndim == 1: - ed = np.array([ed]) + eq = [qX] distributed load + + OUTPUT: Ke : bar stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- - red, ced = np.shape(ed) - JT = dNr*np.mat([ex, ey]).T + LAST MODIFIED: O Dahlblom 2015-10-19 + O Dahlblom 2022-11-18 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A = ep + DEA=E*A - es = np.mat(np.zeros((ngp*red, 2))) - et = np.mat(np.zeros((ngp*red, 2))) - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinatn == 0") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - p1 = -D*B*ed.T - p2 = B*ed.T - es[i:ngp*red:ngp, :] = p1.T - et[i:ngp*red:ngp, :] = p2.T + qX=0. + if not eq is None: + qX=eq[0] + + x1, x2 = ex + y1, y2 = ey + z1, z2 = ez + dx = x2-x1 + dy = y2-y1 + dz = z2-z1 + L = np.sqrt(dx*dx+dy*dy+dz*dz) + + Kle = DEA/L*np.array([ + [1, -1], + [-1, 1] + ]) - return es, et, eci + fle = qX*L*np.array([1/2, 1/2]).reshape(2,1) + + nxX=dx/L + nyX=dy/L + nzX=dz/L + G = np.array([ + [nxX, nyX, nzX, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, nzX] + ]) + + Ke = G.T @ Kle @ G + fe = G.T @ fle + + if eq is None: + return Ke + else: + return Ke, fe -def flw2i8e(ex, ey, ep, D, eq=None): +def bar3s(ex, ey, ez, ep, ed, eq=None, nep=None): """ - Compute element stiffness (conductivity) - matrix for 8 node isoparametric field element. - - Parameters: + es = bar3s(ex, ey, ez, ep, ed) + es = bar3s(ex, ey, ez, ep, ed, eq) + es, edi, eci = bar3s(ex, ey, ez, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute normal force in three dimensional bar element. - ex = [x1, ..., x8] element coordinates - ey = [y1, ..., y8] - - ep = [t, ir] thickness and integration rule + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] + ez = [z1 z2] - D = [[kxx, kxy], - [kyx, kyy]] constitutive matrix + ep = [E A] element properties, + E: Young's modulus + A: cross section area + + ed = [u1 ... u4] element displacement vector - eq heat supply per unit volume + eq = [qX] distributed load - Returns: - - Ke element 'stiffness' matrix (8 x 8) - fe element load vector (8 x 1) + nep : number of evaluation points ( default=2 ) + + OUTPUT: es = [N1 ; section forces, local directions, in + N2 ; nep points along the beam, dim(es)= nep x 1 + ...] + + edi = [u1 ; element displacements, local directions, + u2 ; in n points along the bar, dim(edi)= nep x 1 + ...] + + eci = [x1; evaluation points on the local x-axis, + x2; (x1=0 and xn=L) + ...] + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2021-09-01 + O Dahlblom 2022-11-18 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - t = ep[0] - ir = ep[1] - ngp = ir*ir + E, A = ep + DEA = E*A + + qX = 0. + if not eq is None: + qX = eq[0] + + ne = 2 + if nep != None: + ne = nep - if eq == None: - q = 0 - else: - q = eq + x1, x2 = ex + y1, y2 = ey + z1, z2 = ez + dx = x2-x1 + dy = y2-y1 + dz = z2-z1 + L = np.sqrt(dx*dx+dy*dy+dz*dz) - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.mat([g1, g1]) - w = np.mat([w1, w1]) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-g1, -g1], - [g1, -g1], - [-g1, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w1, w1], - [w1, w1], - [w1, w1] - ]) - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat([ - [-g1, -g1], - [-g2, -g1], - [g1, -g1], - [-g1, g2], - [g2, g2], - [g1, g2], - [-g1, g1], - [g2, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w2, w1], - [w1, w1], - [w1, w2], - [w2, w2], - [w1, w2], - [w1, w1], - [w2, w1], - [w1, w1] - ]) + nxX = dx/L + nyX = dy/L + nzX =dz/L + + G = np.array([ + [nxX, nyX, nzX, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, nzX] + ]) + + a1 = G @ ed.reshape(6,1) + + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + + C1a = C1 @ a1 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) + + N = DEA*du + es = N + edi=u + eci=X + + if nep == None: + return es else: - info("Used number of integration points not implemented") - wp = np.multiply(w[:, 0], w[:, 1]) + return es, edi, eci + - xsi = gp[:, 0] - eta = gp[:, 1] - r2 = ngp*2 +def beam1e(ex, ep, eq=None): + """ + Ke = beam1e(ex, ep) + Ke, fe = beam1e(ex, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a one dimensional beam element. - N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. - N = np.append(N, np.multiply( - np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) - N = np.append(N, np.multiply( - np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) - N = np.append(N, np.multiply( - np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) - N = np.append(N, np.multiply( - (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) - N = np.append(N, np.multiply( - (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) - N = np.append(N, np.multiply( - (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) - N = np.append(N, np.multiply( - (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) + INPUT: ex = [x1 x2] element node coordinates - dNr = np.mat(np.zeros((r2, 8))) - dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + - np.multiply((1-xsi), (1-eta)))/4. - dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - - np.multiply((1+xsi), (1-eta)))/4. - dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - - np.multiply((1+xsi), (1+eta)))/4. - dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + - np.multiply((1-xsi), (1+eta)))/4. - dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) - dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. - dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) - dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. - dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + - np.multiply((1-xsi), (1-eta)))/4. - dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + - np.multiply((1+xsi), (1-eta)))/4. - dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - - np.multiply((1+xsi), (1+eta)))/4. - dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - - np.multiply((1-xsi), (1+eta)))/4. - dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. - dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) - dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. - dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) + ep = [E I] element properties; + E: Young's modulus + I: moment of inertia - Ke1 = np.mat(np.zeros((8, 8))) - fe1 = np.mat(np.zeros((8, 1))) - JT = dNr*np.mat([ex, ey]).T + eq = [qY] distributed load + + OUTPUT: Ke : beam stiffness matrix [4 x 4] + fe : element load vector [4 x 1] (if eq!=None) + ------------------------------------------------------------- - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobideterminanten lika med noll!") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() - fe1 = fe1+N[i, :].T*detJ*wp[i] + LAST MODIFIED: O Dahlblom 2019-01-09 + O Dahlblom 2022-10-25 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, I = ep + DEI = E*I - if eq != None: - return Ke1*t, fe1*t*q + qY = 0. + if not eq is None: + qY = eq[0] + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + Ke = DEI/L**3*np.array([ + [12, 6*L, -12, 6*L], + [6*L, 4*L**2, -6*L, 2*L**2], + [-12, -6*L, 12, -6*L], + [6*L, 2*L**2, -6*L, 4*L**2] + ]) + + fe = qY*np.array([L/2, L**2/12, L/2, -L**2/12]).reshape(4,1) + + if eq is None: + return Ke else: - return Ke1*t + return Ke, fe -def flw2i8s(ex, ey, ep, D, ed): +def beam1s(ex, ep, ed, eq=None, nep=None): """ - Compute flows or corresponding quantities in the - 8 node isoparametric element. - - Parameters: - - ex = [x1,x2,x3....,x8] element coordinates - ey = [y1,y2,y3....,y8] + es = beam1s(ex, ep, ed) + es = beam1s(ex, ep, ed, eq) + es, ed, ec = beam1s(ex, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute section forces in one dimensional beam element (beam1e). - ep = [t,ir] thickness and integration rule + INPUT ex = [x1 x2] element node coordinates - D = [[kxx,kxy], - [kyx,kyy]] constitutive matrix + ep = [E I] element properties, + E: Young's modulus + I: moment of inertia + + ed = [u1 ... u4] element displacements - ed = [u1,....,u8] u1,....,u8: nodal values + eq = [qy] distributed loads, local directions - Returns: - es = [[qx,qy], - [..,..]] element flows + nep : number of evaluation points ( default=2 ) - et = [[qx,qy], - [..,..]] element gradients + OUTPUT: es = [V1 M1 ; section forces, local directions, in + V2 M2 ; nep points along the beam, dim(es)= nep x 2 + ......] + + edi = [v1 ; element displacements, local directions, + v2 ; in nep points along the beam, dim(edi)= nep x 1 + ....] - eci=[[ix1,iy1], Gauss point location vector - [...,...], nint: number of integration points - [ix(nint),iy(nint)]] + eci = [x1; evaluation points on the local x-axis + x2; + ..] + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2021-09-01 + O Dahlblom 2022-10-25 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - t = ep[0] - ir = ep[1] - ngp = ir*ir + + E, I = ep + DEI = E*I + + qY=0. + + if not eq is None: + qY = eq[0] + + ne = 2 + if nep != None: + ne = nep + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + a2 = ed.reshape(4,1) + + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a +# dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + + if DEI != 0: + v = v+(X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) +# dv = dv+(2*X**3 - 3*L*X**2 + L**2*X)*qY/(12*DEI) + d2v = d2v+(6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v+(2*X - L*one)*qY/(2*DEI) + + M = DEI*d2v + V = -DEI*d3v + es = np.concatenate((V, M), 1) + edi = v + eci = X - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.mat([g1, g1]) - w = np.mat([w1, w1]) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-g1, -g1], - [g1, -g1], - [-g1, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w1, w1], - [w1, w1], - [w1, w1] - ]) - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat([ - [-g1, -g1], - [-g2, -g1], - [g1, -g1], - [-g1, g2], - [g2, g2], - [g1, g2], - [-g1, g1], - [g2, g1], - [g1, g1] - ]) - w = np.mat([ - [w1, w1], - [w2, w1], - [w1, w1], - [w1, w2], - [w2, w2], - [w1, w2], - [w1, w1], - [w2, w1], - [w1, w1] - ]) + if nep == None: + return es else: - info("Used number of integration points not implemented") - wp = np.multiply(w[:, 0], w[:, 1]) + return es, edi, eci + - xsi = gp[:, 0] - eta = gp[:, 1] - r2 = ngp*2 +def beam1we(ex, ep, eq=None): + """ + Ke = beam1we(ex, ep) + Ke, fe = beam1we(ex, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a one dimensional beam element + on elastic foundation. - N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. - N = np.append(N, np.multiply( - np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) - N = np.append(N, np.multiply( - np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) - N = np.append(N, np.multiply( - np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) - N = np.append(N, np.multiply( - (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) - N = np.append(N, np.multiply( - (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) - N = np.append(N, np.multiply( - (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) - N = np.append(N, np.multiply( - (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) + INPUT: ex = [x1 x2] element node coordinates - dNr = np.mat(np.zeros((r2, 8))) - dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + - np.multiply((1-xsi), (1-eta)))/4. - dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - - np.multiply((1+xsi), (1-eta)))/4. - dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - - np.multiply((1+xsi), (1+eta)))/4. - dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + - np.multiply((1-xsi), (1+eta)))/4. - dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) - dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. - dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) - dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. - dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + - np.multiply((1-xsi), (1-eta)))/4. - dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + - np.multiply((1+xsi), (1-eta)))/4. - dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - - np.multiply((1+xsi), (1+eta)))/4. - dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - - np.multiply((1-xsi), (1+eta)))/4. - dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. - dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) - dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. - dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) + ep = [E I kY] element properties; + E: Young's modulus + I: moment of inertia + kY: transversal found. stiffness - eci = N*np.mat([ex, ey]).T - if ed.ndim == 1: - ed = np.array([ed]) - red, ced = np.shape(ed) - JT = dNr*np.mat([ex, ey]).T + eq = [qY] distributed load - es = np.mat(np.zeros((ngp*red, 2))) - et = np.mat(np.zeros((ngp*red, 2))) + OUTPUT: Ke: beam stiffness matrix [4 x 4] + fe: element load vector [4 x 1] (if eq!=None) + ------------------------------------------------------------- - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinant == 0") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - p1 = -D*B*ed.T - p2 = B*ed.T - es[i:ngp*red:ngp, :] = p1.T - et[i:ngp*red:ngp, :] = p2.T + LAST MODIFIED: O Dahlblom 2016-02-17 + O Dahlblom 2022-10-18 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, I, kY =ep + DEI = E*I; - return es, et, eci + qY = 0 + if not eq is None: + qY = eq[0] + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + K0 = DEI/L**3*np.array([ + [12, 6*L, -12, 6*L], + [6*L, 4*L**2, -6*L, 2*L**2], + [-12, -6*L, 12, -6*L], + [6*L, 2*L**2, -6*L, 4*L**2] + ]) + + Ks = kY*L/420*np.array([ + [156, 22*L, 54, -13*L], + [22*L, 4*L**2, 13*L, -3*L**2], + [54, 13*L, 156, -22*L], + [-13*L, -3*L**2, -22*L, 4*L**2] + ]) + + Ke = K0+Ks + + fe = qY*np.array([L/2, L**2/12, L/2, -L**2/12]).reshape(4,1) + if eq is None: + return Ke + else: + return Ke, fe -def flw3i8e(ex, ey, ez, ep, D, eq=None): +def beam1ws(ex, ep, ed, eq=None, nep=None): """ - Compute element stiffness (conductivity) - matrix for 8 node isoparametric field element. - - Parameters: - - ex = [x1,x2,x3,...,x8] - ey = [y1,y2,y3,...,y8] element coordinates - ez = [z1,z2,z3,...,z8] + es = beam1ws(ex, ep, ed) + es = beam1ws(ex, ep, ed, eq) + es, ed, ec = beam1ws(ex, ep, ed, eq, nep) + ------------------------------------------------------------- + PURPOSE + Compute section forces in one dimensional beam element + on elastic foundation (beam1we). - ep = [ir] Ir: Integration rule + INPUT: ex = [x1 x2] element node coordinates - D = [[kxx,kxy,kxz], - [kyx,kyy,kyz], - [kzx,kzy,kzz]] constitutive matrix + ep = [E I kY] element properties, + E: Young's modulus + I: moment of inertia + kY: transversal foundation stiffness - eq heat supply per unit volume + ed = [u1 ... u4] element displacements + + eq = [qy] distributed loads, local directions - Output: + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [V1 M1 ; section forces, local directions, in + V2 M2 ; nep points along the beam, dim(es)= n x 2 + ......] + + edi = [v1 ; element displacements, local directions, + v2 ; in nep points along the beam, dim(edi)= n x 1 + ...] - Ke element 'stiffness' matrix (8 x 8) - fe element load vector (8 x 1) + eci = [x1 ; evaluation points on the local x-axis + x2 ; + ...] + + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2021-09-01 + O Dahlblom 2022-10-18 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ - ir = ep[0] - ngp = ir*ir*ir + E, I, kY = ep + DEI = E*I + + qY = 0. + + if not eq is None: + qY = eq[0] + + ne = 2 + if nep != None: + ne = nep + + x1, x2 = ex + dx = x2-x1 + L = abs(dx) + + a2 = ed.reshape(4,1) + + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + + if DEI != 0: + v = v - kY/DEI*np.concatenate(( + (X**4 - 2*L*X**3 + L**2*X**2)/24, + (X**5 - 3*L**2*X**3 + 2*L**3*X**2)/120, + (X**6 - 4*L**3*X**3 + 3*L**4*X**2)/360, + (X**7 - 5*L**4*X**3 + 4*L**5*X**2)/840), 1) @ C2a + \ + (X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) + d2v = d2v - kY/DEI*np.concatenate(( + (6*X**2 - 6*L*X + L**2*one)/12, + (10*X**3 - 9*L**2*X + 2*L**3*one)/60, + (5*X**4 - 4*L**3*X + L**4*one)/60, + (21*X**5 - 15*L**4*X + 4*L**5*one)/420),1) @ C2a + \ + (6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v - kY/DEI*np.concatenate(( + (2*X - L*one)/2, + (10*X**2 - 3*L**2)/20, + (5*X**3 - L**3*one)/15, + (7*X**4 - L**4*one)/28), 1) @ C2a + \ + (2*X - L*one)*qY/(2*DEI) + M = DEI*d2v + V = -DEI*d3v + es = np.concatenate((V, M), 1) + edi = v + eci = X - if eq == None: - q = 0 + if nep == None: + return es else: - q = eq + return es, edi, eci + - if ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-1, -1, -1], - [1, -1, -1], - [1, 1, -1], - [-1, 1, -1], - [-1, -1, 1], - [1, -1, 1], - [1, 1, 1], - [-1, 1, 1] - ])*g1 - w = np.mat(np.ones((8, 3)))*w1 - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat(np.zeros((27, 3))) - w = np.mat(np.zeros((27, 3))) - I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) - I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) - gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 - gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] - I1 = abs(I1) - I2 = abs(I2) - w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 - w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] - I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) - I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) - gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 - gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] - I1 = abs(I1) - I2 = abs(I2) - w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 - w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] - I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) - I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) - I3 = abs(I1) - gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 - gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] - w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 - w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] - else: - info("Used number of integration points not implemented") - return +def beam2e(ex, ey, ep, eq=None): + """ + Ke = beam2e(ex, ey, ep) + Ke, fe = beam2e(ex, ey, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a two dimensional beam element. - wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] - xsi = gp[:, 0] - eta = gp[:, 1] - zet = gp[:, 2] - r2 = ngp*3 + ep = [E A I] element properties; + E: Young's modulus + A: Cross section area + I: moment of inertia - N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1-eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1+eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1+eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1-eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1-eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1+eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1+eta)), (1+zet))/8., axis=1) + eq = [qX qY] distributed loads, local directions + + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- - dNr = np.mat(np.zeros((r2, 8))) - dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) - dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) - dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) - dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) - dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) - dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) - dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) - dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) - dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) - dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) - dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) - dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) - dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) - dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) - dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) - dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) - dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) - dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) - dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) - dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) - dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) - dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) - dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) - dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) - dNr = dNr/8. + LAST MODIFIED: O Dahlblom 2015-08-17 + O Dahlblom 2022-11-21 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I + + qX = 0. + qY = 0. + if not eq is None: + qX, qY = eq + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + Kle = np.array([ + [ DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI/L**3, 6*DEI/L**2, 0., -12*DEI/L**3, 6*DEI/L**2], + [ 0., 6*DEI/L**2, 4*DEI/L, 0., -6*DEI/L**2, 2*DEI/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI/L**3, -6*DEI/L**2, 0., 12*DEI/L**3, -6*DEI/L**2], + [ 0., 6*DEI/L**2, 2*DEI/L, 0., -6*DEI/L**2, 4*DEI/L] + ]) - Ke1 = np.mat(np.zeros((8, 8))) - fe1 = np.mat(np.zeros((8, 1))) - JT = dNr*np.mat([ex, ey, ez]).T + fle = L*np.array([qX/2, qY/2, qY*L/12, qX/2, qY/2, -qY*L/12]).reshape(6,1) - for i in range(ngp): - indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinant == 0") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() - fe1 = fe1+N[i, :].T*detJ*wp[i] + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) - if eq != None: - return Ke1, fe1*q + Ke = G.T @ Kle @ G + fe = G.T @ fle + + if eq is None: + return Ke else: - return Ke1 + return Ke, fe -def flw3i8s(ex, ey, ez, ep, D, ed): +def beam2s(ex, ey, ep, ed, eq=None, nep=None): """ - Compute flows or corresponding quantities in the - 8 node (3-dim) isoparametric field element. - - Parameters: + es = beam2s(ex, ey, ep, ed) + es = beam2s(ex, ey, ep, ed, eq) + es, edi, eci = beam2s(ex, ey, ep, ed, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Compute section forces in two dimensional beam element (beam2e). - ex = [x1,x2,x3,...,x8] - ey = [y1,y2,y3,...,y8] element coordinates - ez = [z1,z2,z3,...,z8] + INPUT: ex = [x1 x2] + ey = [y1 y2] element node coordinates - ep = [ir] Ir: Integration rule + ep = [E A I] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia - D = [[kxx,kxy,kxz], - [kyx,kyy,kyz], - [kzx,kzy,kzz]] constitutive matrix + ed = [u1 ... u6] element displacements - ed = [[u1,....,u8], element nodal values - [..,....,..]] + eq = [qx qy] distributed loads, local directions - Output: + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .....] - es = [[qx,qy,qz], - [..,..,..]] element flows(s) + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] - et = [[qx,qy,qz], element gradients(s) - [..,..,..]] + LAST MODIFIED: O Dahlblom 2021-09-08 + O Dahlblom 2022-11-21 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I + + qX = 0. + qY = 0. + if not eq is None: + qX, qY = eq + + ne=2 + if nep != None: + ne=nep + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) - eci = [[ix1,ix1,iz1], location vector - [...,...,...], nint: number of integration points - [ix(nint),iy(nint),iz(nint)]] + edl = G @ ed.reshape(6,1) + + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] + ]) + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a +# dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v=np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + if DEI != 0: + v = v+(X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) +# dv = dv+(2*X**3 - 3*L*X**2 + L**2*X)*qY/(12*DEI) + d2v = d2v+(6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v+(2*X - L*one)*qY/(2*DEI) + + N = DEA*du + M = DEI*d2v + V = -DEI*d3v + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v), 1) + eci = X + + if nep == None: + return es + else: + return es, edi, eci + +def beam2we(ex, ey, ep, eq=None): """ - ir = ep[0] - ngp = ir*ir*ir + Ke = beam2we(ex, ey, ep) + Ke, fe = beam2we(ex, ey, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a two dimensional beam element + on elastic foundation. - if ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-1, -1, -1], - [1, -1, -1], - [1, 1, -1], - [-1, 1, -1], - [-1, -1, 1], - [1, -1, 1], - [1, 1, 1], - [-1, 1, 1] - ])*g1 - w = np.mat(np.ones((8, 3)))*w1 - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat(np.zeros((27, 3))) - w = np.mat(np.zeros((27, 3))) - I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) - I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) - gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 - gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] - I1 = abs(I1) - I2 = abs(I2) - w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 - w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] - I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) - I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) - gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 - gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] - I1 = abs(I1) - I2 = abs(I2) - w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 - w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] - I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) - I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) - I3 = abs(I1) - gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 - gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] - w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 - w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] + + ep = [E,A,I,kX,kY] element properties; + E: Young's modulus + A: Cross section area + I: moment of inertia + kX: axial foundation stiffness + kY: transversal foundation stiffness + + eq = [qX qY] distributed loads, local directions + + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- + + LAST MODIFIED: O Dahlblom 2015-08-07 + O Dahlblom 2022-11-21 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I, kX, kY = ep + DEA = E*A + DEI = E*I + + qX = 0 + qY = 0 + if not eq is None: + qX, qY = eq + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + K0 = np.array([ + [ DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI/L**3, 6*DEI/L**2, 0., -12*DEI/L**3, 6*DEI/L**2], + [ 0., 6*DEI/L**2, 4*DEI/L, 0., -6*DEI/L**2, 2*DEI/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI/L**3, -6*DEI/L**2, 0., 12*DEI/L**3, -6*DEI/L**2], + [ 0., 6*DEI/L**2., 2*DEI/L, 0., -6*DEI/L**2, 4*DEI/L] + ]) + + Ks = L/420*np.array([ + [140*kX, 0, 0, 70*kX, 0, 0], + [0, 156*kY, 22*kY*L, 0, 54*kY, -13*kY*L], + [0, 22*kY*L, 4*kY*L**2, 0, 13*kY*L, -3*kY*L**2], + [70*kX, 0, 0, 140*kX, 0, 0], + [0, 54*kY, 13*kY*L, 0, 156*kY, -22*kY*L], + [0, -13*kY*L, -3*kY*L**2, 0, -22*kY*L, 4*kY*L**2] + ]) + + Kle = K0+Ks + + fle = L*np.array([qX/2, qY/2, qY*L/12, qX/2, qY/2, -qY*L/12]).reshape(6,1) + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + Ke = G.T @ Kle @ G + fe = G.T @ fle + + if eq is None: + return Ke else: - info("Used number of integration points not implemented") - return + return Ke, fe - wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) - xsi = gp[:, 0] - eta = gp[:, 1] - zet = gp[:, 2] - r2 = ngp*3 +def beam2ws(ex, ey, ep, ed, eq=None, nep=None): + """ + es = beam2ws(ex, ey, ep, ed) + es = beam2ws(ex, ey, ep, ed, eq) + es, edi, eci = beam2ws(ex, ey, ep, ed, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Compute section forces in a two dimensional beam element + on elastic foundation. - N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1-eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1+eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1+eta)), (1-zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1-eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1-eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1+xsi), (1+eta)), (1+zet))/8., axis=1) - N = np.append(N, np.multiply(np.multiply( - (1-xsi), (1+eta)), (1+zet))/8., axis=1) + INPUT: ex = [x1 x2] + ey = [y1 y2] element node coordinates - dNr = np.mat(np.zeros((r2, 8))) - dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) - dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) - dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) - dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) - dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) - dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) - dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) - dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) - dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) - dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) - dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) - dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) - dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) - dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) - dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) - dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) - dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) - dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) - dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) - dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) - dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) - dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) - dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) - dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) - dNr = dNr/8. - - eci = N*np.mat([ex, ey, ez]).T - if ed.ndim == 1: - ed = np.array([ed]) - red, ced = np.shape(ed) - JT = dNr*np.mat([ex, ey, ez]).T + ep = [E,A,I,kX,kY] element properties, + E: Young's modulus + A: cross section area + I: moment of inertia + kX: axial foundation stiffness + kY: transversal foundation stiffness - es = np.mat(np.zeros((ngp*red, 3))) - et = np.mat(np.zeros((ngp*red, 3))) - for i in range(ngp): - indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobideterminanten lika med noll!") - JTinv = np.linalg.inv(JT[indx-1, :]) - B = JTinv*dNr[indx-1, :] - p1 = -D*B*ed.T - p2 = B*ed.T - es[i:ngp*red:ngp, :] = p1.T - et[i:ngp*red:ngp, :] = p2.T + ed = [u1 ... u6] element displacements - return es, et, eci + eq = [qx qy] distributed loads, local directions + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .....] -def plante(ex, ey, ep, D, eq=None): - """ - Calculate the stiffness matrix for a triangular plane stress or plane strain element. - - Parameters: - - ex = [x1,x2,x3] element coordinates - ey = [y1,y2,y3] - - ep = [ptype,t] ptype: analysis type - t: thickness - - D constitutive matrix - - eq = [[bx], bx: body force x-dir - [by]] by: body force y-dir - - Returns: - - Ke element stiffness matrix (6 x 6) - fe equivalent nodal forces (6 x 1) (if eq is given) + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + ------------------------------------------------------------- + LAST MODIFIED: O Dahlblom 2022-09-30 + O Dahlblom 2022-11-21 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- """ + E, A, I, kX, kY = ep + DEA = E*A + DEI = E*I - ptype, t = ep - - bx = 0.0 - by = 0.0 - + qX = 0 + qY = 0 if not eq is None: - bx = eq[0] - by = eq[1] + qX, qY = eq + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + ne = 2 + if nep != None: + ne = nep - C = np.mat([ - [1, ex[0], ey[0], 0, 0, 0], - [0, 0, 0, 1, ex[0], ey[0]], - [1, ex[1], ey[1], 0, 0, 0], - [0, 0, 0, 1, ex[1], ey[1]], - [1, ex[2], ey[2], 0, 0, 0], - [0, 0, 0, 1, ex[2], ey[2]] + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] ]) - A = 0.5*np.linalg.det(np.mat([ - [1, ex[0], ey[0]], - [1, ex[1], ey[1]], - [1, ex[2], ey[2]] - ])) - - # --------- plane stress -------------------------------------- + edl = G @ ed.reshape(6,1) - if ptype == 1: - B = np.mat([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0] - ])*np.linalg.inv(C) + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] + ]) + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + if DEA != 0: + u = u +kX/DEA*np.concatenate(((X**2-L*X)/2, (X**3-L**2*X)/6),1) @ C1a-(X**2-L*X)*qX/(2*DEA) + du = du +kX/DEA*np.concatenate(((2*X-L)/2, (3*X**2-L**2)/6),1) @ C1a-(2*X-L)*qX/(2*DEA) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a +# dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + if DEI != 0: + v = v - kY/DEI*np.concatenate(( + (X**4 - 2*L*X**3 + L**2*X**2)/24, + (X**5 - 3*L**2*X**3 + 2*L**3*X**2)/120, + (X**6 - 4*L**3*X**3 + 3*L**4*X**2)/360, + (X**7 - 5*L**4*X**3 + 4*L**5*X**2)/840), 1) @ C2a + \ + (X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) + d2v = d2v - kY/DEI*np.concatenate(( + (6*X**2 - 6*L*X + L**2*one)/12, + (10*X**3 - 9*L**2*X + 2*L**3*one)/60, + (5*X**4 - 4*L**3*X + L**4*one)/60, + (21*X**5 - 15*L**4*X + 4*L**5*one)/420),1) @ C2a + \ + (6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v - kY/DEI*np.concatenate(( + (2*X - L*one)/2, + (10*X**2 - 3*L**2)/20, + (5*X**3 - L**3*one)/15, + (7*X**4 - L**4*one)/28), 1) @ C2a + \ + (2*X - L*one)*qY/(2*DEI) + + N = DEA*du + M = DEI*d2v + V = -DEI*d3v + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v), 1) + eci = X - colD = D.shape[1] + if nep == None: + return es + else: + return es, edi, eci + - if colD > 3: - Cm = np.linalg.inv(D) - Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) - else: - Dm = D +def beam2ge(ex, ey, ep, QX, eq=None): + """ + Ke = beam2ge(ex, ey, ep, QX) + Ke, fe = beam2ge(ex, ey, ep, QX, eq) + ------------------------------------------------------------- + PURPOSE + Compute the element stiffness matrix for a two dimensional + beam element with respect to geometric nonlinearity. + + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates - Ke = B.T*Dm*B*A*t - fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t + ep = [E, A, I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia - if eq is None: - return Ke - else: - return Ke, fe.T + QX axial force in the beam - #--------- plane strain -------------------------------------- + eq = [qY] distributed transverse load - elif ptype == 2: - B = np.mat([ - [0, 1, 0, 0, 0, 0, ], - [0, 0, 0, 0, 0, 1, ], - [0, 0, 1, 0, 1, 0, ] - ])*np.linalg.inv(C) + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- - colD = D.shape[1] + LAST MODIFIED: O Dahlblom 2015-12-17 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I - if colD > 3: - Dm = D[np.ix_((0, 1, 3), (0, 1, 3))] + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return else: - Dm = D + qY = eq[0] + else: + qY = 0 + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + K0le = np.array([ + [ DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI/L**3, 6*DEI/L**2, 0., -12*DEI/L**3, 6*DEI/L**2], + [ 0., 6*DEI/L**2, 4*DEI/L, 0., -6*DEI/L**2, 2*DEI/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI/L**3, -6*DEI/L**2, 0., 12*DEI/L**3, -6*DEI/L**2], + [ 0., 6*DEI/L**2, 2*DEI/L, 0., -6*DEI/L**2, 4*DEI/L] + ]) - Ke = B.T*Dm*B*A*t - fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t + Ksle = QX/(30*L)*np.array([ + [ 0., 0., 0., 0., 0., 0.], + [ 0., 36., 3*L, 0., -36., 3*L], + [ 0., 3*L, 4*L**2, 0., -3*L, -L**2], + [ 0., 0., 0., 0., 0., 0.], + [ 0., -36., -3*L, 0., 36., -3*L], + [ 0., 3*L, -L**2, 0., -3*L, 4*L**2] + ]) + + fle = qY*L*np.array([0, 1/2, L/12, 0, 1/2, -L/12]).reshape(6,1) - if eq == None: - return Ke - else: - return Ke, fe.T + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) + + Kle = K0le+Ksle + Ke = G.T @ Kle @ G + fe = G.T @ fle + if eq is None: + return Ke else: - info("Error ! Check first argument, ptype=1 or 2 allowed") - if eq == None: - return None - else: - return None, None + return Ke, fe -def plants(ex, ey, ep, D, ed): - """ - Calculate element normal and shear stress for a - triangular plane stress or plane strain element. - - INPUT: ex = [x1 x2 x3] element coordinates - ey = [y1 y2 y3] - - ep = [ptype t ] ptype: analysis type - t: thickness - - D constitutive matrix - - ed =[u1 u2 ...u6 element displacement vector - ...... ] one row for each element - - OUTPUT: es = [ sigx sigy [sigz] tauxy element stress matrix - ...... ] one row for each element - - et = [ epsx epsy [epsz] gamxy element strain matrix - ...... ] one row for each element +def beam2gs(ex, ey, ep, ed, QX, eq=None, nep=None): """ + es, QX = beam2gs(ex, ey, ep, ed, QX) + es, QX = beam2gs(ex, ey, ep, ed, QX, eq) + es, QX, edi, eci = beam2gs(ex, ey, ep, ed, QX, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Calculate section forces in a two dimensional nonlinear + beam element (beam2ge). - ptype = ep[0] + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates - if np.ndim(ex) == 1: - ex = np.array([ex]) - if np.ndim(ey) == 1: - ey = np.array([ey]) - if np.ndim(ed) == 1: - ed = np.array([ed]) + ep = [E, A, I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia - rowed = ed.shape[0] - rowex = ex.shape[0] + ed = [u1, ... ,u6] element displacement vector - # --------- plane stress -------------------------------------- + QX axial force - if ptype == 1: + eq = [qy] distributed transverse load - colD = D.shape[1] + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + QX axial force - if colD > 3: - Cm = np.linalg.inv(D) - Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) - else: - Dm = D + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .....] - incie = 0 + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + ------------------------------------------------------------- - if rowex == 1: - incie = 0 + LAST MODIFIED: O Dahlblom 2021-09-01 + O Dahlblom 2022-12-06 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I + + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return else: - incie = 1 + qY = eq[0] + else: + qY = 0 - et = np.zeros([rowed, colD]) - es = np.zeros([rowed, colD]) + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) - ie = 0 + ne = 2 + if nep != None: + ne = nep - for i in range(rowed): - C = np.matrix( - [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], - [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], - [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] - ) + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) - B = np.matrix([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) + edl = G @ ed.reshape(6,1) - ee = B*np.asmatrix(ed[ie, :]).T + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] + ]) + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a + dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + if DEI != 0: + v = v + QX/DEI*np.concatenate((zero, zero, (X**4-2*L*X**3+L**2*X**2)/12, (X**5-3*L**2*X**3+2*L**3*X**2)/20), 1) @ C2a + \ + (X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) + dv = dv + QX/DEI*np.concatenate((zero, zero, (2*X**3-3*L*X**2+L**2*X)/6, (5*X**4-9*L**2*X**2+4*L**3*X)/20), 1) @ C2a + \ + (2*X**3 - 3*L*X**2 + L**2*X)*qY/(12*DEI) + d2v = d2v + QX/DEI*np.concatenate((zero, zero, (6*X**2-6*L*X+L**2*one)/6, (10*X**3-9*L**2*X+2*L**3*one)/10), 1) @ C2a + \ + (6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v + QX/DEI*np.concatenate((zero, zero, (2*X-L*one), (30*X**2-9*L**2*one)/10), 1) @ C2a + \ + (2*X - L*one)*qY/(2*DEI) + + QX = DEA*du.item(0) + M = DEI*d2v + V = -DEI*d3v + N=QX+dv*V + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v), 1) + eci = X + + if nep == None: + return es, QX + else: + return es, QX, edi, eci - if colD > 3: - ss = np.zeros([colD, 1]) - ss[[0, 1, 3]] = Dm*ee - ee = Cm*ss - else: - ss = Dm*ee - - et[ie, :] = ee.T - es[ie, :] = ss.T - ie = ie + incie +def beam2gxe(ex, ey, ep, QX, eq=None): + """ + Ke = beam2gxe(ex, ey, ep, QX) + Ke, fe = beam2gxe(ex, ey, ep, QX, eq) + ------------------------------------------------------------- + PURPOSE + Compute the element stiffness matrix for a two dimensional + beam element with respect to geometric nonlinearity with exact solution. + + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates - return es, et + ep = [E, A, I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia - # --------- plane strain -------------------------------------- - elif ptype == 2: # Implementation by LAPM - colD = D.shape[1] - incie = 0 + QX axial force in the beam - if rowex == 1: - incie = 0 - else: - incie = 1 + eq distributed transverse load - et = np.zeros([rowed, colD]) - es = np.zeros([rowed, colD]) + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- - ie = 0 + LAST MODIFIED: O Dahlblom 2021-06-21 + O Dahlblom 2022-12-06 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I - ee = np.zeros([colD, 1]) + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return + else: + qY = eq[0] + else: + qY = 0 - for i in range(rowed): - C = np.matrix( - [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], - [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], - [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], - [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] - ) + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) - B = np.matrix([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) + eps = 1e-12 - e = B*np.asmatrix(ed[ie, :]).T + if QX < -eps*DEI/L**2: + kL = np.sqrt(-QX/DEI)*L + f1 = (kL/2)/np.tan(kL/2) + f2 = kL**2/(12*(1-f1)) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) + elif QX > eps*DEI/L**2: + kL = np.sqrt(QX/DEI)*L + f1 = (kL/2)/np.tanh(kL/2) + f2 = -(1/12.)*kL**2/(1-f1) + f3 = f1/4+3*f2/4 + f4 = -f1/2+3*f2/2 + f5 = f1*f2 + h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) + else: + f1 = f2 = f3 = f4 = f5 = h = 1 - if colD > 3: - ee[[0, 1, 3]] = e - else: - ee = e + Kle = np.array([ + [DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI*f5/L**3, 6*DEI*f2/L**2, 0., -12*DEI*f5/L**3, 6*DEI*f2/L**2], + [ 0., 6*DEI*f2/L**2, 4*DEI*f3/L, 0., -6*DEI*f2/L**2, 2*DEI*f4/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI*f5/L**3, -6*DEI*f2/L**2, 0., 12*DEI*f5/L**3, -6*DEI*f2/L**2], + [0., 6*DEI*f2/L**2, 2*DEI*f4/L, 0., -6*DEI*f2/L**2, 4*DEI*f3/L] + ]) - et[ie, :] = ee.T - es[ie, :] = (D*ee).T + fle = qY*L*np.array([0., 1/2., L*h/12, 0., 1/2., -L*h/12]).reshape(6,1) - ie = ie + incie + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) - return es, et + Ke = G.T @ Kle @ G + fe = G.T @ fle + if eq is None: + return Ke else: - print("Error ! Check first argument, ptype=1 or 2 allowed") - return None + return Ke, fe -def plantf(ex, ey, ep, es): +def beam2gxs(ex, ey, ep, ed, QX, eq=None, nep=None): """ - Compute internal element force vector in a triangular element - in plane stress or plane strain. + es, QX = beam2gxs(ex, ey, ep, ed, QX) + es, QX = beam2gxs(ex, ey, ep, ed, QX, eq) + es, QX, edi, eci = beam2gxs(ex, ey, ep, ed, QX, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Calculate section forces in a two dimensional nonlinear + beam element (beam2gxe). - Parameters: + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates - ex = [x1,x2,x3] node coordinates - ey = [y1,y2,y3] + ep = [E, A, I] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia - ep = [ptype,t] ptype: analysis type - t: thickness + ed = [u1, ... ,u6] element displacement vector - es = [[sigx,sigy,[sigz],tauxy] element stress matrix - [ ...... ]] one row for each element + QX axial force - OUTPUT: + eq = [qy] distributed transverse load - fe = [[f1],[f2],...,[f8]] internal force vector + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + QX axial force - """ + edi = [ u1 v1 element displacements, local directions, + u2 v2 in n points along the beam, dim(es)= n x 2 + .....] - ptype, t = ep + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + ------------------------------------------------------------- - colD = es.shape[1] + LAST MODIFIED: O Dahlblom 2021-09-17 + O Dahlblom 2022-12-06 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, A, I = ep + DEA = E*A + DEI = E*I - #--------- plane stress -------------------------------------- + if eq != None: + if np.size(eq) > 1: + error("eq should be a scalar !!!") + return + else: + qY = eq[0] + else: + qY = 0 - if ptype == 1: + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) - C = np.mat([ - [1, ex[0], ey[0], 0, 0, 0], - [0, 0, 0, 1, ex[0], ey[0]], - [1, ex[1], ey[1], 0, 0, 0], - [0, 0, 0, 1, ex[1], ey[1]], - [1, ex[2], ey[2], 0, 0, 0], - [0, 0, 0, 1, ex[2], ey[2]] - ]) + ne = 2 + if nep != None: + ne = nep - A = 0.5*np.linalg.det(np.mat([ - [1, ex[0], ey[0]], - [1, ex[1], ey[1]], - [1, ex[2], ey[2]] - ])) + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) - B = np.mat([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0] - ])*np.linalg.inv(C) + edl = G @ ed.reshape(6,1) - if colD > 3: - stress = np.asmatrix(es[np.ix_((0, 1, 3))]) - else: - stress = np.asmatrix(es) + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] + ]) - ef = (A*t*B.T*stress.T).T + eps = 1e-12 + + if QX < -eps*DEI/L**2: + k = np.sqrt(-QX/DEI) + kL = k*L + C2 = 1/(k*(-2*(1-np.cos(kL))+kL*np.sin(kL)))*np.array([ + [k*(kL*np.sin(kL)+np.cos(kL)-1), -kL*np.cos(kL)+np.sin(kL), -k*(1-np.cos(kL)), -np.sin(kL)+kL], + [-(k**2)*np.sin(kL), -k*(1-np.cos(kL)), (k**2)*np.sin(kL), -k*(1-np.cos(kL))], + [-k*(1-np.cos(kL)), kL*np.cos(kL)-np.sin(kL), k*(1-np.cos(kL)), np.sin(kL)-kL], + [k*np.sin(kL), (kL*np.sin(kL)+np.cos(kL)-1), -k*np.sin(kL), (1-np.cos(kL))] + ]) + + C2a = C2 @ a2 + v = np.concatenate((one, X, np.cos(k*X), np.sin(k*X)), 1) @ C2a + dv = np.concatenate((zero, one, -k*np.sin(k*X), k*np.cos(k*X)), 1) @ C2a + d2v = np.concatenate((zero, zero, -k**2*np.cos(k*X), -k**2*np.sin(k*X)), 1) @ C2a + d3v = np.concatenate((zero, zero, k**3*np.sin(k*X), -k**3*np.cos(k*X)), 1) @ C2a + if DEI != 0: + v = v+qY*L**4/(2*DEI)*((1+np.cos(kL))/(kL**3*np.sin(kL))*(-1+np.cos(k*X))+np.sin(k*X)/kL**3+X*(-1+X/L)/(kL**2*L)) + dv = dv+qY*L**3/(2*DEI)*((1+np.cos(kL))/(kL**2*np.sin(kL))*(-np.sin(k*X))+np.cos(k*X)/kL**2+(-1+2*X/L)/kL**2) + d2v = d2v+qY*L**2/(2*DEI)*((1+np.cos(kL))/(kL*np.sin(kL))*(-np.cos(k*X))-np.sin(k*X)/kL+2/(kL**2)) + d3v = d3v+qY*L/(2*DEI)*((1+np.cos(kL))/np.sin(kL)*(np.sin(k*X))-np.cos(k*X)) + elif QX > eps*DEI/L**2: + k = np.sqrt(QX/DEI) + kL = k*L + C2 = 1/(k*(-2*(1-np.cosh(kL))-kL*np.sinh(kL)))*np.array([ + [k*(-kL*np.sinh(kL)+np.cosh(kL)-1), -kL*np.cosh(kL)+np.sinh(kL), -k*(1-np.cosh(kL)), -np.sinh(kL)+kL], + [(k**2)*np.sinh(kL), -k*(1-np.cosh(kL)), -(k**2)*np.sinh(kL), -k*(1-np.cosh(kL))], + [-k*(1-np.cosh(kL)), kL*np.cosh(kL)-np.sinh(kL), k*(1-np.cosh(kL)), np.sinh(kL)-kL], + [-k*np.sinh(kL), (-kL*np.sinh(kL)+np.cosh(kL)-1), k*np.sinh(kL), (1-np.cosh(kL))] + ]) + C2a = C2 @ a2 + v = np.concatenate((one, X, np.cosh(k*X), np.sinh(k*X)), 1) @ C2a + dv = np.concatenate((zero, one, k*np.sinh(k*X), k*np.cosh(k*X)), 1) @ C2a + d2v = np.concatenate((zero, zero, k**2*np.cosh(k*X), k**2*np.sinh(k*X)), 1) @ C2a + d3v = np.concatenate((zero, zero, k**3*np.sinh(k*X), k**3*np.cosh(k*X)), 1) @ C2a + if DEI != 0: + v = v+qY*L**4/(2*DEI)*((1+np.cosh(kL))/(kL**3*np.sinh(kL))*(-1+np.cosh(k*X))-np.sinh(k*X)/kL**3+X*(1-X/L)/(kL**2*L)) + dv = dv+qY*L**3/(2*DEI)*((1+np.cosh(kL))/(kL**2*np.sinh(kL))*(np.sinh(k*X))-np.cosh(k*X)/kL**2+(1-2*X/L)/kL**2) + d2v = d2v+qY*L**2/(2*DEI)*((1+np.cosh(kL))/(kL*np.sinh(kL))*(np.cosh(k*X))-np.sinh(k*X)/kL-2/(kL**2)) + d3v = d3v+qY*L/(2*DEI)*((1+np.cosh(kL))/np.sinh(kL)*(np.sinh(k*X))-np.cosh(k*X)) + else: + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + C2a = C2 @ a2 + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a + dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + d2v = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + if DEI != 0: + v = v+(X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI) + dv = dv+(2*X**3 -3*L*X**2 +L**2*X)*qY/(12*DEI) + d2v = d2v +(6*X**2 - 6*L*X + L**2*one)*qY/(12*DEI) + d3v = d3v +(2*X - L*one)*qY/(2*DEI) + + QX = DEA*du.item(0) + M = DEI*d2v + V = -DEI*d3v + N=QX+dv*V + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v), 1) + eci = X + + if nep == None: + return es, QX + else: + return es, QX, edi, eci - return np.reshape(np.asarray(ef), 6) - #--------- plane strain -------------------------------------- +def beam2te(ex, ey, ep, eq=None): + """ + Ke = beam2te(ex, ey, ep) + Ke, fe = beam2te(ex, ey, ep, eq) + ------------------------------------------------------------- + PURPOSE + Compute the stiffness matrix for a two dimensional Timoshenko + beam element. + + INPUT: ex = [x1 x2] element node coordinates + ey = [y1 y2] + + ep = [E Gm A I ks] element properties; + E: Young's modulus + G: shear modulus + A: Cross section area + I: moment of inertia + ks: shear correction factor + + eq = [qX qY] distributed loads, local directions + + OUTPUT: Ke : element stiffness matrix [6 x 6] + fe : element load vector [6 x 1] (if eq!=None) + ------------------------------------------------------------- - elif ptype == 2: + LAST MODIFIED: O Dahlblom 2021-11-05 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, Gm, A, I, ks = ep + DEA = E*A + DEI = E*I + DGAks = Gm*A*ks + + qX = 0. + qY = 0. + if not eq is None: + qX, qY = eq + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + m = (12*DEI)/(L**2*DGAks) + f1=1/(1+m) + f2=f1*(1+m/4) + f3=f1*(1-m/2) + + + Kle = np.array([ + [ DEA/L, 0., 0., -DEA/L, 0., 0.], + [ 0., 12*DEI*f1/L**3, 6*DEI*f1/L**2, 0., -12*DEI*f1/L**3, 6*DEI*f1/L**2], + [ 0., 6*DEI*f1/L**2, 4*DEI*f2/L, 0., -6*DEI*f1/L**2, 2*DEI*f3/L], + [-DEA/L, 0., 0., DEA/L, 0., 0.], + [ 0., -12*DEI*f1/L**3, -6*DEI*f1/L**2, 0., 12*DEI*f1/L**3, -6*DEI*f1/L**2], + [ 0., 6*DEI*f1/L**2, 2*DEI*f3/L, 0., -6*DEI*f1/L**2, 4*DEI*f2/L] + ]) - C = np.mat([ - [1, ex[0], ey[0], 0, 0, 0], - [0, 0, 0, 1, ex[0], ey[0]], - [1, ex[1], ey[1], 0, 0, 0], - [0, 0, 0, 1, ex[1], ey[1]], - [1, ex[2], ey[2], 0, 0, 0], - [0, 0, 0, 1, ex[2], ey[2]] - ]) + fle = L*np.array([qX/2, qY/2, qY*L/12, qX/2, qY/2, -qY*L/12]).reshape(6,1) - A = 0.5*np.linalg.det(np.mat([ - [1, ex[0], ey[0]], - [1, ex[1], ey[1]], - [1, ex[2], ey[2]] - ])) + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) - B = np.mat([ - [0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 1, 0] - ])*np.linalg.inv(C) + Ke = G.T @ Kle @ G + fe = G.T @ fle - if colD > 3: - stress = np.asmatrix(es[np.ix_((1, 2, 4))]) - else: - stress = np.asmatrix(es) + if eq is None: + return Ke + else: + return Ke, fe + - ef = (A*t*B.T*stress.T).T +def beam2ts(ex, ey, ep, ed, eq=None, nep=None): + """ + es = beam2ts(ex, ey, ep, ed) + es = beam2ts(ex, ey, ep, ed, eq) + es, edi, eci = beam2s(ex, ey, ep, ed, eq, nep) +--------------------------------------------------------------------- + PURPOSE + Compute section forces in two dimensional Timoshenko beam + element (beam2te). - return np.reshape(np.asarray(ef), 6) + INPUT: ex = [x1 x2] + ey = [y1 y2] element node coordinates - else: - info("Error ! Check first argument, ptype=1 or 2 allowed") - return None + ep = [E G A I ks] element properties, + E: Young's modulus + G: shear modulus + A: cross section area + I: moment of inertia + ks: shear correction factor + ed = [u1 ... u6] element displacements -def platre(ex, ey, ep, D, eq=None): - """ - Calculate the stiffness matrix for a rectangular plate element. - NOTE! Element sides must be parallel to the coordinate axis. - - Parameters: + eq = [qx qy] distributed loads, local directions - ex = [x1,x2,x3,x4] element coordinates - ey = [y1,y2,y3,y4] + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [ N1 V1 M1 section forces, local directions, in + N2 V2 M2 n points along the beam, dim(es)= n x 3 + ........] + + edi = [ u1 v1 teta1 element displacements, local directions, + u2 v2 teta2 in n points along the beam, dim(es)= n x 2 + ...........] + (Note! For Timoshenko beam element the rotation of the cross + section is not equal to dv/dx) + + eci = [ x1 local x-coordinates of the evaluation + x2 points, (x1=0 and xn=L) + ...] + ------------------------------------------------------------- - ep = [t] thicknes + LAST MODIFIED: O Dahlblom 2021-11-05 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, Gm, A, I, ks = ep + DEA = E*A + DEI = E*I + DGAks = Gm*A*ks + alpha=DEI/DGAks + + qX = 0. + qY = 0. + if not eq is None: + qX, qY = eq + + ne=2 + if nep != None: + ne=nep + + x1, x2 = ex + y1, y2 = ey + dx = x2-x1 + dy = y2-y1 + L = np.sqrt(dx*dx+dy*dy) + + nxX = dx/L + nyX = dy/L + nxY = -dy/L + nyY = dx/L + G = np.array([ + [nxX, nyX, 0, 0, 0, 0], + [nxY, nyY, 0, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0], + [ 0, 0, 0, nxX, nyX, 0], + [ 0, 0, 0, nxY, nyY, 0], + [ 0, 0, 0, 0, 0, 1] + ]) - D constitutive matrix for - plane stress + edl = G @ ed.reshape(6,1) - eq = [qz] load/unit area - Returns: + a1 = np.array([ + edl[0], + edl[3] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + + a2 = np.array([ + edl[1], + edl[2], + edl[4], + edl[5] + ]) + C2 = 1/(L**2+12*alpha)*np.array([ + [L**2+12*alpha, 0., 0., 0.], + [ -12*alpha/L, L**2+6*alpha, 12*alpha/L, -6*alpha], + [ -3., -2*L-6*alpha/L, 3., -L+6*alpha/L], + [ 2/L, 1., -2/L, 1.] + ]) + C2a = C2 @ a2 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + if DEA != 0: + u = u -(X**2-L*X)*qX/(2*DEA) + du = du -(2*X-L)*qX/(2*DEA) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a + dv = np.concatenate((zero, one, 2*X, 3*X**2), 1) @ C2a + theta = np.concatenate((zero, one, 2*X, 3*X**2+6*alpha), 1) @ C2a + dtheta=np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + if DEI != 0: + v = v+(X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEI)+(-X**2/2+L*X/2)*qY/DGAks + dv = dv+(2*X**3 - 3*L*X**2 + L**2*X)*qY/(12*DEI)+(-X+L/2)*qY/DGAks + theta = theta+(2*X**3-3*L*X**2+L**2*X)*qY/(12*DEI) + dtheta = dtheta+(6*X**2-6*L*X+L**2)*qY/(12*DEI) + + N = DEA*du + M = DEI*dtheta + V = DGAks*(dv-theta) + es = np.concatenate((N, V, M), 1) + edi = np.concatenate((u, v, theta), 1) + eci = X - Ke element stiffness matrix (12 x 12) - fe equivalent nodal forces (12 x 1) + if nep == None: + return es + else: + return es, edi, eci + +def beam2de(ex, ey, ep): """ - Lx = (ex[2]-ex[0]).astype(float) - Ly = (ey[2]-ey[0]).astype(float) - t = ep[0] + Ke, Me = beam2de(ex, ey, ep) + Ke, Me, Ce = beam2de(ex, ey, ep) + ------------------------------------------------------------- + PURPOSE + Calculate the stiffness matrix Ke, the mass matrix Me + and the damping matrix Ce for a 2D elastic Bernoulli + beam element. - D = t**3/12.*D + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates - A1 = Ly/(Lx**3) - A2 = Lx/(Ly**3) - A3 = 1/Lx/Ly - A4 = Ly/(Lx**2) - A5 = Lx/(Ly**2) - A6 = 1/Lx - A7 = 1/Ly - A8 = Ly/Lx - A9 = Lx/Ly + ep = [E,A,I,m,(a,b)] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + m: mass per unit length + a,b: damping coefficients, + Ce=aMe+bKe - C1 = 4*A1*D[0, 0]+4*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] - C2 = -4*A1*D[0, 0]+2*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] - C3 = 2*A1*D[0, 0]-4*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] - C4 = -2*A1*D[0, 0]-2*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] - C5 = 2*A5*D[1, 1]+A6*D[0, 1]+0.4*A6*D[2, 2] - C6 = 2*A4*D[0, 0]+A7*D[0, 1]+0.4*A7*D[2, 2] + OUTPUT: Ke element stiffness matrix (6 x 6) + Me element mass martix + Ce element damping matrix, optional + ------------------------------------------------------------- - C7 = 2*A5*D[1, 1]+0.4*A6*D[2, 2] - C8 = 2*A4*D[0, 0]+0.4*A7*D[2, 2] - C9 = A5*D[1, 1]-A6*D[0, 1]-0.4*A6*D[2, 2] - C10 = A4*D[0, 0]-A7*D[0, 1]-0.4*A7*D[2, 2] - C11 = A5*D[1, 1]-0.4*A6*D[2, 2] - C12 = A4*D[0, 0]-0.4*A7*D[2, 2] + LAST MODIFIED: K Persson 1995-08-23 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + b = np.array([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T @ b).item(0) + n = np.array(b/L).reshape(2,) - C13 = 4/3.*A9*D[1, 1]+8/15.*A8*D[2, 2] - C14 = 4/3.*A8*D[0, 0]+8/15.*A9*D[2, 2] - C15 = 2/3.*A9*D[1, 1]-8/15.*A8*D[2, 2] - C16 = 2/3.*A8*D[0, 0]-8/15.*A9*D[2, 2] - C17 = 2/3.*A9*D[1, 1]-2/15.*A8*D[2, 2] - C18 = 2/3.*A8*D[0, 0]-2/15.*A9*D[2, 2] - C19 = 1/3.*A9*D[1, 1]+2/15.*A8*D[2, 2] - C20 = 1/3.*A8*D[0, 0]+2/15.*A9*D[2, 2] - C21 = D[0, 1] + a = 0 + b = 0 + if np.size(ep) == 4: + E, A, I, m = ep + elif np.size(ep) == 6: + E, A, I, m, a, b = ep - Keq = np.mat(np.zeros((12, 12))) - Keq[0, 0:13] = C1, C5, -C6, C2, C9, -C8, C4, C11, -C12, C3, C7, -C10 - Keq[1, 1:13] = C13, -C21, C9, C15, 0, -C11, C19, 0, -C7, C17, 0 - Keq[2, 2:13] = C14, C8, 0, C18, C12, 0, C20, -C10, 0, C16 - Keq[3, 3:13] = C1, C5, C6, C3, C7, C10, C4, C11, C12 - Keq[4, 4:13] = C13, C21, -C7, C17, 0, -C11, C19, 0 - Keq[5, 5:13] = C14, C10, 0, C16, -C12, 0, C20 - Keq[6, 6:13] = C1, -C5, C6, C2, -C9, C8 - Keq[7, 7:13] = C13, -C21, -C9, C15, 0 - Keq[8, 8:13] = C14, -C8, 0, C18 - Keq[9, 9:13] = C1, -C5, -C6 - Keq[10, 10:13] = C13, C21 - Keq[11, 11] = C14 - Keq = Keq.T+Keq-np.diag(np.diag(Keq)) + print ("E, A, I, m, a, b, L") + print (E, A, I, m, a, b, L) - if eq != None: - q = eq - R1 = q*Lx*Ly/4 - R2 = q*Lx*Ly**2/24 - R3 = q*Ly*Lx**2/24 - feq = np.mat([R1, R2, -R3, R1, R2, R3, R1, -R2, R3, R1, -R2, -R3]) + Kle = np.array([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) - if eq != None: - return Keq, feq - else: - return Keq + Mle = m*L/420*np.array([ + [140, 0, 0, 70, 0, 0], + [0, 156, 22*L, 0, 54, -13*L], + [0, 22*L, 4*L**2, 0, 13*L, -3*L**2], + [70, 0, 0, 140, 0, 0], + [0, 54, 13*L, 0, 156, -22*L], + [0, -13*L, -3*L**2, 0, -22*L, 4*L**2] + ]) + Cle = a*Mle+b*Kle -def planqe(ex, ey, ep, D, eq=None): - """ - Calculate the stiffness matrix for a quadrilateral - plane stress or plane strain element. + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) - Parameters: - ex=[x1 x2 x3 x4] element coordinates - ey=[y1 y2 y3 y4] - - ep = [ptype, t] ptype: analysis type - t: element thickness + Ke = G.T @ Kle @ G + Me = G.T @ Mle @ G + Ce = G.T @ Cle @ G - D constitutive matrix + if np.size(ep) == 4: + return Ke, Me + elif np.size(ep) == 6: + return Ke, Me, Ce - eq = [bx; bx: body force in x direction - by] by: body force in y direction - OUTPUT: Ke : element stiffness matrix (8 x 8) - fe : equivalent nodal forces (row array) +def beam2ds(ex, ey, ep, ed, ev, ea): """ - K = np.zeros((10, 10)) - f = np.zeros((10, 1)) - - xm = sum(ex)/4. - ym = sum(ey)/4. + es = beam2ds(ex, ey, ep, ed, ev, ea) + ------------------------------------------------------------- + PURPOSE + Calculate the element forces for a number of identical + (nie) 2D Bernoulli beam elements in dynamic analysis. + + INPUT: ex = [x1, x2] + ey = [y1, y2] element node coordinates + + ep = [E,A,I,m,(a,b)] element properties; + E: Young's modulus + A: cross section area + I: moment of inertia + m: mass per unit length + a,b: damping coefficients, + Ce=aMe+bKe + + ed : element displacement matrix + + ev : element velocity matrix + + ea : element acceleration matrix + + OUTPUT: es : element forces in local directions, + = [-N1 -V1 -M1 N2 V2 M2; + ....... ......] ; dim(es)= nie x 6 + ------------------------------------------------------------- - b1 = eq if eq is not None else np.array([[0], [0]]) + LAST MODIFIED: K Persson 1995-08-23 + O Dahlblom 2022-12-08 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + b = np.array([ + [ex[1]-ex[0]], + [ey[1]-ey[0]] + ]) + L = np.sqrt(b.T @ b).item(0) + n = np.array(b/L).reshape(2,) - ke1, fe1 = plante(np.array([ex[0], ex[1], xm]), - np.array([ey[0], ey[1], ym]), ep, D, b1) - K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(np.array([ex[1], ex[2], xm]), - np.array([ey[1], ey[2], ym]), ep, D, b1) - K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(np.array([ex[2], ex[3], xm]), - np.array([ey[2], ey[3], ym]), ep, D, b1) - K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(np.array([ex[3], ex[0], xm]), - np.array([ey[3], ey[0], ym]), ep, D, b1) - K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) - Ke, fe = statcon(K, f, np.array([[9], [10]])) + a = 0 + b = 0 + if np.size(ep) == 4: + E, A, I, m = ep + elif np.size(ep) == 6: + E, A, I, m, a, b = ep - if eq == None: - return Ke - else: - return Ke, fe + Kle = np.array([ + [E*A/L, 0, 0, -E*A/L, 0, 0], + [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], + [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], + [-E*A/L, 0, 0, E*A/L, 0, 0], + [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], + [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] + ]) + Mle = m*L/420*np.array([ + [140, 0, 0, 70, 0, 0], + [0, 156, 22*L, 0, 54, -13*L], + [0, 22*L, 4*L**2, 0, 13*L, -3*L**2], + [70, 0, 0, 140, 0, 0], + [0, 54, 13*L, 0, 156, -22*L], + [0, -13*L, -3*L**2, 0, -22*L, 4*L**2] + ]) -def planqs(ex, ey, ep, D, ed, eq=None): - """ - Calculate element normal and shear stress for a quadrilateral - plane stress or plane strain element. - - Parameters: - ex = [x1 x2 x3 x4] element coordinates - ey = [y1 y2 y3 y4] - - ep = [ptype, t] ptype: analysis type - t: thickness - - D constitutive matrix - - ed = [u1 u2 ..u8] element displacement vector - - eq = [[bx] bx: body force in x direction - [by]] by: body force in y direction - - OUTPUT: es = [ sigx sigy (sigz) tauxy] element stress array - et = [ epsx epsy (epsz) gamxy] element strain array - """ + Cle = a*Mle+b*Kle - if ex.shape != (4,) or ey.shape != (4,) or ed.shape != (8,): - raise ValueError( - 'Error ! PLANQS: only one element at the time (ex, ey, ed must be a row arrays)') + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) - K = np.zeros((10, 10)) - f = np.zeros((10, 1)) + nie, ned = ed.shape + es = np.array(np.zeros((nie, 6))) + for i in range(nie): + d = ed[i,:].reshape(6,1) + v = ev[i,:].reshape(6,1) + a = ea[i,:].reshape(6,1) + es[i,:] = (Kle @ G @ d + Cle @ G @ v + Mle @ G @ a).T + +# [nie,ned]=size(ed); +# for i=1:nie +# d=ed(i,:)'; +# v=ev(i,:)'; +# a=ea(i,:)'; +# es(i,:)=(Kle*G*d+Cle*G*v+Mle*G*a)'; - xm = sum(ex)/4. - ym = sum(ey)/4. + return es - b1 = eq if eq is not None else np.array([[0], [0]]) - ex1 = np.array([ex[0], ex[1], xm]) - ey1 = np.array([ey[0], ey[1], ym]) - ex2 = np.array([ex[1], ex[2], xm]) - ey2 = np.array([ey[1], ey[2], ym]) - ex3 = np.array([ex[2], ex[3], xm]) - ey3 = np.array([ey[2], ey[3], ym]) - ex4 = np.array([ex[3], ex[0], xm]) - ey4 = np.array([ey[3], ey[0], ym]) +def beam3e(ex, ey, ez, eo, ep, eq=None): + """ + Ke = beam3e(ex, ey, ez, eo, ep) + Ke, fe = beam3e(ex, ey, ez, eo, ep, eq) + ------------------------------------------------------------- + PURPOSE + Calculate the stiffness matrix for a 3D elastic Bernoulli + beam element. - ke1, fe1 = plante(ex1, ey1, ep, D, b1) - K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(ex2, ey2, ep, D, b1) - K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(ex3, ey3, ep, D, b1) - K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) - ke1, fe1 = plante(ex4, ey4, ep, D, b1) - K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) + INPUT: ex = [x1 x2] + ey = [y1 y2] + ez = [z1 z2] element node coordinates - A1 = 0.5 * \ - np.linalg.det( - np.hstack([np.ones((3, 1)), np.mat(ex1).T, np.mat(ey1).T])) - A2 = 0.5 * \ - np.linalg.det( - np.hstack([np.ones((3, 1)), np.mat(ex2).T, np.mat(ey2).T])) - A3 = 0.5 * \ - np.linalg.det( - np.hstack([np.ones((3, 1)), np.mat(ex3).T, np.mat(ey3).T])) - A4 = 0.5 * \ - np.linalg.det( - np.hstack([np.ones((3, 1)), np.mat(ex4).T, np.mat(ey4).T])) - Atot = A1+A2+A3+A4 + eo = [xz yz zz] orientation of local z-axis - a, _ = solveq(K, f, np.array(range(1, 9)), ed) + ep = [E G A Iy Iz Kv] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + Iy: Moment of inertia, local y-axis + Iz: Moment of inertia, local z-axis + Kv: Saint-Venant's torsion constant -# ni = ed.shape[0] -# a = np.mat(empty((10,ni))) -# for i in range(ni): -# a[:,i] = solveq(K, f, np.array(range(1,9)), ed[i,:])[0] -# #a = np.hstack([a, solveq(K, f, np.hstack([matrix(range(1,9)).T, ed[i,:].T]) ) ]) + eq = [qX qY qZ qW] distributed loads, local directions + + OUTPUT: Ke : element stiffness matrix [12 x 12] - s1, t1 = plants(ex1, ey1, ep, D, np.hstack([a[[0, 1, 2, 3, 8, 9], :].T])) - s2, t2 = plants(ex2, ey2, ep, D, np.hstack([a[[2, 3, 4, 5, 8, 9], :].T])) - s3, t3 = plants(ex3, ey3, ep, D, np.hstack([a[[4, 5, 6, 7, 8, 9], :].T])) - s4, t4 = plants(ex4, ey4, ep, D, np.hstack([a[[6, 7, 0, 1, 8, 9], :].T])) + fe : element load vector [12 x 1] (if eq!=None) + ------------------------------------------------------------- - es = (s1*A1+s2*A2+s3*A3+s4*A4)/Atot - et = (t1*A1+t2*A2+t3*A3+t4*A4)/Atot + LAST MODIFIED: O Dahlblom 2015-10-19 + O Dahlblom 2022-11-21 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + E, Gs, A, Iy, Iz, Kv = ep + DEA = E*A + DEIz = E*Iz + DEIy = E*Iy + DGK = Gs*Kv + + qX = 0. + qY = 0. + qZ = 0. + qW = 0. + if not eq is None: + qX, qY, qZ, qW = eq + + x1, x2 = ex + y1, y2 = ey + z1, z2 = ez + dx = x2-x1 + dy = y2-y1 + dz = z2-z1 + L = np.sqrt(dx*dx+dy*dy+dz*dz) + + a = DEA/L + b = 12*DEIz/L**3 + c = 6*DEIz/L**2 + d = 12*DEIy/L**3 + e = 6*DEIy/L**2 + f = DGK/L + g = 2*DEIy/L + h = 2*DEIz/L + + Kle = np.array([ + [a, 0, 0, 0, 0, 0, -a, 0, 0, 0, 0, 0], + [0, b, 0, 0, 0, c, 0, -b, 0, 0, 0, c], + [0, 0, d, 0, -e, 0, 0, 0, -d, 0, -e, 0], + [0, 0, 0, f, 0, 0, 0, 0, 0, -f, 0, 0], + [0, 0, -e, 0, 2*g, 0, 0, 0, e, 0, g, 0], + [0, c, 0, 0, 0, 2*h, 0, -c, 0, 0, 0, h], + [-a, 0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0], + [0, -b, 0, 0, 0, -c, 0, b, 0, 0, 0, -c], + [0, 0, -d, 0, e, 0, 0, 0, d, 0, e, 0], + [0, 0, 0, -f, 0, 0, 0, 0, 0, f, 0, 0], + [0, 0, -e, 0, g, 0, 0, 0, e, 0, 2*g, 0], + [0, c, 0, 0, 0, h, 0, -c, 0, 0, 0, 2*h] + ]) - # [0] because these are 1-by-3 arrays and we want row arrays out. - return es[0], et[0] + fle = L/2*np.array([qX, qY, qZ, qW, -qZ*L/6, qY*L/6, + qX, qY, qZ, qW, qZ*L/6, -qY*L/6]).reshape(12,1) - -def plani4e(ex, ey, ep, D, eq=None): - """ - Calculate the stiffness matrix for a 4 node isoparametric - element in plane strain or plane stress. - - Parameters: - ex = [x1 ... x4] element coordinates. Row array - ey = [y1 ... y4] - - ep =[ptype, t, ir] ptype: analysis type - t : thickness - ir: integration rule + n1 = np.array([dx, dy, dz])/L - D constitutive matrix + lc = np.sqrt(eo @ eo.T) + eo1= np.array(eo/lc) + n2a = np.cross(eo1,n1) + n2al = np.sqrt(n2a @ n2a.T) + n2=n2a/n2al - eq = [bx; by] bx: body force in x direction - by: body force in y direction - Any array with 2 elements acceptable + n3 = np.cross(n1,n2) - Returns: - Ke : element stiffness matrix (8 x 8) - fe : equivalent nodal forces (8 x 1) - """ - ptype = ep[0] - t = ep[1] - ir = ep[2] - ngp = ir*ir - if eq == None: - q = np.zeros((2, 1)) - else: - q = np.reshape(eq, (2, 1)) -#--------- gauss points -------------------------------------- - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.mat([g1, g1]) - w = np.mat([w1, w1]) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.mat([ - [-g1, -g1], - [g1, -g1], - [-g1, g1], - [g1, g1]]) - w = np.mat([ - [w1, w1], - [w1, w1], - [w1, w1], - [w1, w1]]) - elif ir == 3: - g1 = 0.774596669241483 - g2 = 0. - w1 = 0.555555555555555 - w2 = 0.888888888888888 - gp = np.mat([ - [-g1, -g1], - [-g2, -g1], - [g1, -g1], - [-g1, g2], - [g2, g2], - [g1, g2], - [-g1, g1], - [g2, g1], - [g1, g1]]) - w = np.mat([ - [w1, w1], - [w2, w1], - [w1, w1], - [w1, w2], - [w2, w2], - [w1, w2], - [w1, w1], - [w2, w1], - [w1, w1]]) - else: - info("Used number of integrat ion points not implemented") - wp = np.multiply(w[:, 0], w[:, 1]) - xsi = gp[:, 0] - eta = gp[:, 1] - r2 = ngp*2 - # Shape Functions - N = np.multiply((1-xsi), (1-eta))/4. - N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) - N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) - N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + G = np.array([ + [n1[0], n1[1], n1[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n2[0], n2[1], n2[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n3[0], n3[1], n3[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n1[0], n1[1], n1[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n2[0], n2[1], n2[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n3[0], n3[1], n3[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n1[0], n1[1], n1[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n2[0], n2[1], n2[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n3[0], n3[1], n3[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n1[0], n1[1], n1[2]], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n2[0], n2[1], n2[2]], + [0, 0, 0, 0, 0, 0, + 0, 0, 0, n3[0], n3[1], n3[2]] + ]) - dNr = np.mat(np.zeros((r2, 4))) - dNr[0:r2:2, 0] = -(1-eta)/4. - dNr[0:r2:2, 1] = (1-eta)/4. - dNr[0:r2:2, 2] = (1+eta)/4. - dNr[0:r2:2, 3] = -(1+eta)/4. - dNr[1:r2+1:2, 0] = -(1-xsi)/4. - dNr[1:r2+1:2, 1] = -(1+xsi)/4. - dNr[1:r2+1:2, 2] = (1+xsi)/4. - dNr[1:r2+1:2, 3] = (1-xsi)/4. + print("G=") + print(G) -# - Ke1 = np.mat(np.zeros((8, 8))) - fe1 = np.mat(np.zeros((8, 1))) - JT = dNr*np.mat([ex, ey]).T - # --------- plane stress -------------------------------------- - if ptype == 1: - colD = np.shape(D)[0] - if colD > 3: - Cm = np.linalg.inv(D) - Dm = np.linalg.inv(Cm[np.ix_([0, 1, 3], [0, 1, 3])]) - else: - Dm = D -# - B = np.matrix(np.zeros((3, 8))) - N2 = np.matrix(np.zeros((2, 8))) - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobi determinant equal or less than zero!") - JTinv = np.linalg.inv(JT[indx-1, :]) - dNx = JTinv*dNr[indx-1, :] -# - index_array_even = np.array([0, 2, 4, 6]) - index_array_odd = np.array([1, 3, 5, 7]) -# - counter = 0 - for index in index_array_even: - B[0, index] = dNx[0, counter] - B[2, index] = dNx[1, counter] - N2[0, index] = N[i, counter] - counter = counter+1 -# - counter = 0 - for index in index_array_odd: - B[1, index] = dNx[1, counter] - B[2, index] = dNx[0, counter] - N2[1, index] = N[i, counter] - counter = counter+1 -# - Ke1 = Ke1+B.T*Dm*B*detJ*wp[i].item()*t - fe1 = fe1 + N2.T * q * detJ * wp[i].item() * t + Ke = G.T @ Kle @ G + fe = G.T @ fle - return Ke1, fe1 -#--------- plane strain -------------------------------------- - elif ptype == 2: - # - colD = np.shape(D)[0] - if colD > 3: - Dm = D[np.ix_([0, 1, 3], [0, 1, 3])] - else: - Dm = D -# - B = np.matrix(np.zeros((3, 8))) - N2 = np.matrix(np.zeros((2, 8))) - for i in range(ngp): - indx = np.array([2*(i+1)-1, 2*(i+1)]) - detJ = np.linalg.det(JT[indx-1, :]) - if detJ < 10*np.finfo(float).eps: - info("Jacobideterminant equal or less than zero!") - JTinv = np.linalg.inv(JT[indx-1, :]) - dNx = JTinv*dNr[indx-1, :] -# - index_array_even = np.array([0, 2, 4, 6]) - index_array_odd = np.array([1, 3, 5, 7]) -# - counter = 0 - for index in index_array_even: - # - B[0, index] = dNx[0, counter] - B[2, index] = dNx[1, counter] - N2[0, index] = N[i, counter] -# - counter = counter+1 -# - counter = 0 - for index in index_array_odd: - B[1, index] = dNx[1, counter] - B[2, index] = dNx[0, counter] - N2[1, index] = N[i, counter] - counter = counter+1 -# - Ke1 = Ke1 + B.T * Dm * B * detJ * np.asscalar(wp[i]) * t - fe1 = fe1+N2.T*q*detJ*np.asscalar(wp[i])*t - return Ke1, fe1 + if eq is None: + return Ke else: - info("Error ! Check first argument, ptype=1 or 2 allowed") + return Ke, fe -def soli8e(ex, ey, ez, ep, D, eqp=None): +def beam3s(ex, ey, ez, eo, ep, ed, eq=None, nep=None): """ - Ke=soli8e(ex,ey,ez,ep,D) - [Ke,fe]=soli8e(ex,ey,ez,ep,D,eq) + es = beam3s(ex, ey, ez, eo, ep, ed) + es = beam3s(ex, ey, ez, eo, ep, ed, eq) + es, edi, eci = beam3s(ex, ey, ez, eo, ep, ed, eq, nep) ------------------------------------------------------------- PURPOSE - Calculate the stiffness matrix for a 8 node (brick) - isoparametric element. + Calculate the variation of the section forces and displacements + along a three-dimensional beam element. - INPUT: ex = [x1 x2 x3 ... x8] - ey = [y1 y2 y3 ... y8] element coordinates - ez = [z1 z2 z3 ... z8] + INPUT: ex = [x1 x2] + ey = [y1 y2] + ez = [z1 z2] element node coordinates - ep = [ir] ir integration rule + eo = [xz yz zz] orientation of local z-axis - D constitutive matrix + ep = [E G A Iy Iz Kv] element properties + E: Young's modulus + G: Shear modulus + A: Cross section area + Iy: Moment of inertia, local y-axis + Iz: Moment of inertia, local z-axis + Kv: Saint-Venant's torsion constant - eq = [bx; by; bz] bx: body force in x direction - by: body force in y direction - bz: body force in z direction + ed = [u1 ... u12] element displacements + + eq = [qX qY qZ qW] distributed loads, local directions + + nep number of evaluation points ( default=2 ) + + OUTPUT: es = [[N1,Vy1,Vz1,T1,My1,Mz1], section forces in n points along + [N2,Vy2,Vz2,T2,My2,Mz2], the local x-axis + [..,...,...,..,...,...], + [Nn,Vyn,Vzn,Tn,Myn,Mzn]] + + edi = [[u1,v1,w1,fi1], displacements in n points along + [u2,v2,w2,fi2], the local x-axis + [..,..,..,...], + [un,vn,wn,fin]] + + eci = [[x1], local x-coordinates of the evaluation + [x2], points + [..], + [xn]] - OUTPUT: Ke : element stiffness matrix - fe : equivalent nodal forces ------------------------------------------------------------- - LAST MODIFIED: M Ristinmaa 1995-10-25 - J Lindemann 2022-01-24 (Python version) + LAST MODIFIED: O Dahlblom 2015-10-19 + O Dahlblom 2022-11-23 (Python version) Copyright (c) Division of Structural Mechanics and Division of Solid Mechanics. Lund University ------------------------------------------------------------- """ - ir = ep[0] - ngp = ir*ir*ir + E, Gs, A, Iy, Iz, Kv = ep + DEA = E*A + DEIz = E*Iz + DEIy = E*Iy + DGK = Gs*Kv + + qX = 0. + qY = 0. + qZ = 0. + qW = 0. + if not eq is None: + qX, qY, qZ, qW = eq - if eqp == None: - eq = np.zeros((3, 1)) - else: - eq = eqp + ne = 2 + if nep != None: + ne = nep - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.array([g1, g1, g1]).reshape(1, 3) - w = np.array([w1, w1, w1]).reshape(1, 3) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.zeros((8, 3)) - w = np.zeros((8, 3)) - gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 - w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 - w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 - w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + x1, x2 = ex + y1, y2 = ey + z1, z2 = ez + dx = x2-x1 + dy = y2-y1 + dz = z2-z1 + L = np.sqrt(dx*dx+dy*dy+dz*dz) + n1 = np.array([dx, dy, dz])/L + + lc = np.sqrt(eo @ eo.T) + eo1= np.array(eo/lc) + n2a = np.cross(eo1,n1) + n2al = np.sqrt(n2a @ n2a.T) + n2=n2a/n2al + + n3 = np.cross(n1,n2) + + G = np.array([ + [n1[0], n1[1], n1[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n2[0], n2[1], n2[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [n3[0], n3[1], n3[2], 0, 0, 0, + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n1[0], n1[1], n1[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n2[0], n2[1], n2[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, n3[0], n3[1], n3[2], + 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n1[0], n1[1], n1[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n2[0], n2[1], n2[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, + n3[0], n3[1], n3[2], 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n1[0], n1[1], n1[2]], + [0, 0, 0, 0, 0, 0, 0, + 0, 0, n2[0], n2[1], n2[2]], + [0, 0, 0, 0, 0, 0, + 0, 0, 0, n3[0], n3[1], n3[2]] + ]) + + edl = G @ ed.reshape(12,1) + + a1 = np.array([ + edl[0], + edl[6] + ]) + C1 = np.array([ + [1., 0.], + [-1/L, 1/L] + ]) + C1a = C1 @ a1 + + a2 = np.array([ + edl[1], + edl[5], + edl[7], + edl[11] + ]) + C2 = np.array([ + [1., 0., 0., 0.], + [0., 1., 0., 0.], + [-3/L**2, -2/L, 3/L**2, -1/L], + [2/L**3, 1/L**2, -2/L**3, 1/L**2] + ]) + C2a = C2 @ a2 + + a3 = np.array([ + edl[2], + -edl[4], + edl[8], + -edl[10] + ]) + C3 = C2 + C3a = C3 @ a3 + + a4 = np.array([ + edl[3], + edl[9] + ]) + C4 = C1 + C4a = C4 @ a4 + + X = np.arange(0., L+L/(ne-1), L/(ne-1)).reshape(ne,1) + zero = np.zeros(ne).reshape(ne,1) + one = np.ones(ne).reshape(ne,1) + + u = np.concatenate((one, X), 1) @ C1a + du = np.concatenate((zero, one), 1) @ C1a + if DEA != 0: + u = u-(X**2-L*X)*qX/(2*DEA) + du = du-(2*X-L)*qX/(2*DEA) + + v = np.concatenate((one, X, X**2, X**3), 1) @ C2a + d2v=np.concatenate((zero, zero, 2*one, 6*X), 1) @ C2a + d3v = np.concatenate((zero, zero, zero, 6*one), 1) @ C2a + if DEIz != 0: + v = v+(X**4 - 2*L*X**3 + L**2*X**2)*qY/(24*DEIz) + d2v = d2v+(6*X**2 - 6*L*X + L**2*one)*qY/(12*DEIz) + d3v = d3v+(2*X - L*one)*qY/(2*DEIz) + + w = np.concatenate((one, X, X**2, X**3), 1) @ C3a + d2w = np.concatenate((zero, zero, 2*one, 6*X), 1) @ C3a + d3w = np.concatenate((zero, zero, zero, 6*one), 1) @ C3a + if DEIy != 0: + w = w+(X**4 - 2*L*X**3 + L**2*X**2)*qZ/(24*DEIy) + d2w = d2w+(6*X**2 - 6*L*X + L**2*one)*qZ/(12*DEIy) + d3w = d3w+(2*X - L*one)*qZ/(2*DEIy) + + fi = np.concatenate((one, X), 1) @ C4a + dfi = np.concatenate((zero, one), 1) @ C4a + if DGK != 0: + fi = fi-(X**2-L*X)*qW/(2*DGK) + dfi = dfi-(2*X-L)*qW/(2*DGK) + N = DEA*du + Mz = DEIz*d2v + Vy = -DEIz*d3v + My = -DEIy*d2w + Vz = -DEIy*d3w + T = DGK*dfi + es = np.concatenate((N, Vy, Vz, T, My, Mz), 1) + edi = np.concatenate((u, v, w, fi), 1) + eci = X + + if nep == None: + return es else: - g1 = 0.774596669241483, - g2 = 0.0 - w1 = 0.555555555555555 - w2 = 0.888888888888888 + return es, edi, eci + - gp = np.zeros((27, 3)) - w = np.zeros((27, 3)) +def flw2te(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) matrix for a triangular field element. + + Parameters: + + ex = [x1 x2 x3] + ey = [y1 y2 y3] element coordinates + + ep = [t] element thickness - I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) - I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) + D = [kxx kxy; + kyx kyy] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (3 x 3) - gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 - gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] + fe element load vector (3 x 1) + + """ + t = ep[0] + if eq == None: + eq = 0. - I1 = np.abs(I1) - I2 = np.abs(I2) + exm = np.asmatrix(ex) + eym = np.asmatrix(ey) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I + A = 0.5*np.linalg.det(C) - w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 - w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] + Ke = B.T*D*B*t*A + fe = np.matrix([[1., 1., 1.]]).T*eq*A*t/3 - I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) - I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) + if eq == 0.: + return Ke + else: + return Ke, fe - gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 - gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] - I1 = np.abs(I1) - I2 = np.abs(I2) +def flw2ts(ex, ey, D, ed): + """ + Compute flows or corresponding quantities in the triangular field element. + + Parameters: + + ex = [x1 x2 x3] + ey = [y1 y2 y3] element coordinates + + D = [kxx kxy + kyx kyy] constitutive matrix + + ed =[u1 u2 u3] u1,u2,u3: nodal values + .. .. ..; + + Returns: + + es=[ qx qy ] + ... ..] element flows + + et=[ gx gy ] + ... ..] element gradients + + """ - w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 - w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] + if len(ex.shape) > 1: + qs = np.zeros([ex.shape[0], 2]) + qt = np.zeros([ex.shape[0], 2]) + row = 0 + for exr, eyr, edr in zip(ex, ey, ed): + exm = np.asmatrix(exr) + eym = np.asmatrix(eyr) + edm = np.asmatrix(edr) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I - I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) - I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) - I3 = np.abs(I1) + qs[row, :] = (-D*B*edm.T).T + qt[row, :] = (B*edm.T).T + row += 1 - gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 - gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] + return qs, qt + else: + exm = np.asmatrix(ex) + eym = np.asmatrix(ey) + edm = np.asmatrix(ed) + C = np.asmatrix(np.hstack([np.ones((3, 1)), exm.T, eym.T])) + B = np.matrix([ + [0., 1., 0.], + [0., 0., 1.] + ])*C.I - w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 - w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] + qs = -D*B*edm.T + qt = B*edm.T - wp = w[:, 0]*w[:, 1]*w[:, 2] + return qs.T, qt.T - xsi = gp[:, 0] - eta = gp[:, 1] - zet = gp[:, 2] - r2 = ngp*3 - N = np.zeros((ngp, 8)) - dNr = np.zeros((r2, 8)) +def flw2qe(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) matrix for a triangular field element. + + Parameters: + + ex = [x1, x2, x3, x4] + ey = [y1, y2, y3, y4] element coordinates + + ep = [t] element thickness - N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 - N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 - N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 - N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 - N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 - N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 - N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 - N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + eq heat supply per unit volume + + Returns: + + Ke element 'stiffness' matrix (4 x 4) - dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) - dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) - dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) - dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) - dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) - dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) - dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) - dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) - dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) - dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) - dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) - dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) - dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) - dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) - dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) - dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) - dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) - dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) - dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) - dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) - dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) - dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) - dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) - dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) + fe element load vector (4 x 1) + + """ + xc = sum(ex)/4. + yc = sum(ey)/4. - dNr = dNr/8.0 + K = np.zeros((5, 5)) + f = np.zeros((5, 1)) - Ke = np.zeros((24, 24)) - fe = np.zeros((24, 1)) + if eq == None: + k1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D) + K = assem(np.array([1, 2, 5]), K, k1) + k1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D) + K = assem(np.array([2, 3, 5]), K, k1) + k1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D) + K = assem(np.array([3, 4, 5]), K, k1) + k1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D) + K = assem(np.array([4, 1, 5]), K, k1) + else: + k1, f1 = flw2te([ex[0], ex[1], xc], [ey[0], ey[1], yc], ep, D, eq) + K, f = assem(np.array([1, 2, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[1], ex[2], xc], [ey[1], ey[2], yc], ep, D, eq) + K, f = assem(np.array([2, 3, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[2], ex[3], xc], [ey[2], ey[3], yc], ep, D, eq) + K, f = assem(np.array([3, 4, 5]), K, k1, f, f1) + k1, f1 = flw2te([ex[3], ex[0], xc], [ey[3], ey[0], yc], ep, D, eq) + K, f = assem(np.array([4, 1, 5]), K, k1, f, f1) + Ke1, fe1 = statcon(K, f, np.array([5])) - ex = np.asarray(ex).reshape((8, 1)) - ey = np.asarray(ey).reshape((8, 1)) - ez = np.asarray(ez).reshape((8, 1)) + Ke = Ke1 + fe = fe1 - JT = dNr@np.concatenate((ex, ey, ez), axis=1) + if eq == None: + return Ke + else: + return Ke, fe - eps = np.finfo(float).eps - for i in range(ngp): - indx = [i*3, i*3+1, i*3+2] - detJ = np.linalg.det(JT[indx, :]) - if detJ < 10*eps: - print('Jacobideterminant equal or less than zero!') - JTinv = np.linalg.inv(JT[indx, :]) - dNx = JTinv@dNr[indx, :] - - B = np.zeros((6, 24)) - N2 = np.zeros((3, 24)) - - B[0, 0:24:3] = dNx[0, :] - B[1, 1:25:3] = dNx[1, :] - B[2, 2:26:3] = dNx[2, :] - B[3, 0:24:3] = dNx[1, :] - B[3, 1:25:3] = dNx[0, :] - B[4, 0:24:3] = dNx[2, :] - B[4, 2:26:3] = dNx[0, :] - B[5, 1:25:3] = dNx[2, :] - B[5, 2:26:3] = dNx[1, :] - - N2[0, 0:24:3] = N[i, :] - N2[1, 1:25:3] = N[i, :] - N2[2, 2:26:3] = N[i, :] - - Ke = Ke + (np.transpose(B)@D@B)*detJ*wp[i] - fe = fe + (np.transpose(N2)@eq)*detJ*wp[i] - - if eqp != None: - return Ke, fe - else: - return Ke - - -def soli8s(ex, ey, ez, ep, D, ed): +def flw2qs(ex, ey, ep, D, ed, eq=None): """ - [es,et]=soli8s(ex,ey,ez,ep,D,ed) - ------------------------------------------------------------- - PURPOSE - Calculate element normal and shear stress for a - 8 node (brick) isoparametric element. + Compute flows or corresponding quantities in the + quadrilateral field element. - INPUT: ex = [x1 x2 x3 ... x8] - ey = [y1 y2 y3 ... y8] element coordinates - ez = [z1 z2 z3 ... z8] + Parameters: - ep = [Ir] Ir: integration rule + ex = [x1, x2, x3, x4] + ey = [y1, y2, y3, y4] element coordinates - D constitutive matrix + ep = [t] element thickness + + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + ed = [[u1, u2, u3, u4], + [.., .., .., ..]] u1,u2,u3,u4: nodal values - ed = [u1 u2 ..u24] element displacement vector - - OUTPUT: es = [ sigx sigy sigz sigxy sigyz sigxz ; - ...... ... ] - element stress matrix, one row for each - integration point + eq heat supply per unit volume + + Returns: + + es = [[qx, qy], + [.., ..]] element flows - es = [ eps epsy epsz epsxy epsyz epsxz ; - ...... ... ] - element strain matrix, one row for each - integration point - ------------------------------------------------------------- + et = [[gx, gy], + [.., ..]] element gradients - LAST MODIFIED: M Ristinmaa 1995-10-25 - J Lindemann 2022-02-23 (Python version) - - Copyright (c) Division of Structural Mechanics and - Division of Solid Mechanics. - Lund University - ------------------------------------------------------------- """ + K = np.zeros((5, 5)) + f = np.zeros((5, 1)) - ir = ep[0] - ngp = ir*ir*ir - - ir = ep[0] - ngp = ir*ir*ir + xm = sum(ex)/4 + ym = sum(ey)/4 - if ir == 1: - g1 = 0.0 - w1 = 2.0 - gp = np.array([g1, g1, g1]).reshape(1, 3) - w = np.array([w1, w1, w1]).reshape(1, 3) - elif ir == 2: - g1 = 0.577350269189626 - w1 = 1 - gp = np.zeros((8, 3)) - w = np.zeros((8, 3)) - gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 - w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 - w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 - gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 - w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + if eq == None: + q = 0 else: - g1 = 0.774596669241483, - g2 = 0.0 - w1 = 0.555555555555555 - w2 = 0.888888888888888 - - gp = np.zeros((27, 3)) - w = np.zeros((27, 3)) - - I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) - I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) + q = eq - gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 - gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] + En = np.array([ + [1, 2, 5], + [2, 3, 5], + [3, 4, 5], + [4, 1, 5] + ]) + ex1 = np.array([ex[0], ex[1], xm]) + ey1 = np.array([ey[0], ey[1], ym]) + ex2 = np.array([ex[1], ex[2], xm]) + ey2 = np.array([ey[1], ey[2], ym]) + ex3 = np.array([ex[2], ex[3], xm]) + ey3 = np.array([ey[2], ey[3], ym]) + ex4 = np.array([ex[3], ex[0], xm]) + ey4 = np.array([ey[3], ey[0], ym]) - I1 = np.abs(I1) - I2 = np.abs(I2) + if eq == None: + k1 = flw2te(ex1, ey1, ep, D) + K = assem(En[0], K, k1) + k1 = flw2te(ex2, ey2, ep, D) + K = assem(En[1], K, k1) + k1 = flw2te(ex3, ey3, ep, D) + K = assem(En[2], K, k1) + k1 = flw2te(ex4, ey4, ep, D) + K = assem(En[3], K, k1) + else: + k1, f1 = flw2te(ex1, ey1, ep, D, q) + K, f = assem(En[0], K, k1, f, f1) + k1, f1 = flw2te(ex2, ey2, ep, D, q) + K, f = assem(En[1], K, k1, f, f1) + k1, f1 = flw2te(ex3, ey3, ep, D, q) + K, f = assem(En[2], K, k1, f, f1) + k1, f1 = flw2te(ex4, ey4, ep, D, q) + K, f = assem(En[3], K, k1, f, f1) - w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 - w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] + if ed.ndim == 1: + ed = np.array([ed]) - I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) - I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) + ni, nj = np.shape(ed) - gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 - gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] + a = np.zeros((5, ni)) + for i in range(ni): + a[np.ix_(range(5), [i])], r = np.asarray( + solveq(K, f, np.arange(1, 5), ed[i])) - I1 = np.abs(I1) - I2 = np.abs(I2) + s1, t1 = flw2ts(ex1, ey1, D, a[np.ix_(En[0, :]-1, np.arange(ni))].T) + s2, t2 = flw2ts(ex2, ey2, D, a[np.ix_(En[1, :]-1, np.arange(ni))].T) + s3, t3 = flw2ts(ex3, ey3, D, a[np.ix_(En[2, :]-1, np.arange(ni))].T) + s4, t4 = flw2ts(ex4, ey4, D, a[np.ix_(En[3, :]-1, np.arange(ni))].T) - w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 - w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] + es = (s1+s2+s3+s4)/4. + et = (t1+t2+t3+t4)/4. - I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) - I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) - I3 = np.abs(I1) + return es, et - gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 - gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] - w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 - w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] +def flw2i4e(ex, ey, ep, D, eq=None): + """ + Compute element stiffness (conductivity) + matrix for 4 node isoparametric field element - wp = w[:, 0]*w[:, 1]*w[:, 2] + Parameters: + + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] - xsi = gp[:, 0] - eta = gp[:, 1] - zet = gp[:, 2] - r2 = ngp*3 + ep = [t ir] thickness and integration rule - N = np.zeros((ngp, 8)) - dNr = np.zeros((r2, 8)) + D = [[kxx kxy], + [kyx kyy]] constitutive matrix - N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 - N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 - N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 - N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 - N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 - N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 - N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 - N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 + eq heat supply per unit volume - dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) - dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) - dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) - dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) - dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) - dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) - dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) - dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) - dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) - dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) - dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) - dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) - dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) - dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) - dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) - dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) - dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) - dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) - dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) - dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) - dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) - dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) - dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) - dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) + Returns: + Ke element 'stiffness' matrix (4 x 4) + fe element load vector (4 x 1) - dNr = dNr/8.0 + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir - ex = np.asarray(ex).reshape((8, 1)) - ey = np.asarray(ey).reshape((8, 1)) - ez = np.asarray(ez).reshape((8, 1)) + if eq == None: + q = 0 + else: + q = eq - JT = dNr@np.concatenate((ex, ey, ez), axis=1) - - eps = np.finfo(float).eps - - eci = N@np.concatenate((ex, ey, ez), axis=1) - et = np.zeros((ngp, 6)) - es = np.zeros((ngp, 6)) - - ed = ed.reshape(1, 24) - - for i in range(ngp): - indx = [i*3, i*3+1, i*3+2] - detJ = np.linalg.det(JT[indx, :]) - if detJ < 10*eps: - print('Jacobideterminant equal or less than zero!') - JTinv = np.linalg.inv(JT[indx, :]) - dNx = JTinv@dNr[indx, :] + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) - B = np.zeros((6, 24)) - N2 = np.zeros((3, 24)) + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 - B[0, 0:24:3] = dNx[0, :] - B[1, 1:25:3] = dNx[1, :] - B[2, 2:26:3] = dNx[2, :] - B[3, 0:24:3] = dNx[1, :] - B[3, 1:25:3] = dNx[0, :] - B[4, 0:24:3] = dNx[2, :] - B[4, 2:26:3] = dNx[0, :] - B[5, 1:25:3] = dNx[2, :] - B[5, 2:26:3] = dNx[1, :] + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) - N2[0, 0:24:3] = N[i, :] - N2[1, 1:25:3] = N[i, :] - N2[2, 2:26:3] = N[i, :] + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. - # [6x24] x [24,1] - ee = B@np.transpose(ed) + Ke1 = np.mat(np.zeros((4, 4))) + fe1 = np.mat(np.zeros((4, 1))) + JT = dNr*np.mat([ex, ey]).T - et[i, :] = ee.reshape(6,) - es[i, :] = (D@ee).reshape(6,) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] - return et, es, eci + if eq == None: + return Ke1*t + else: + return Ke1*t, fe1*t*eq -def assem(edof, K, Ke, f=None, fe=None): +def flw2i4s(ex, ey, ep, D, ed): """ - Assemble element matrices Ke ( and fe ) into the global - stiffness matrix K ( and the global force vector f ) - according to the topology matrix edof. + Compute flows or corresponding quantities in the + 4 node isoparametric element. Parameters: - - edof dof topology array - K the global stiffness matrix - Ke element stiffness matrix - f the global force vector - fe element force vector - Output parameters: - - K the new global stiffness matrix - f the new global force vector - fe element force vector - - """ + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] - if edof.ndim == 1: - idx = edof-1 - K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke - if (not f is None) and (not fe is None): - f[np.ix_(idx)] = f[np.ix_(idx)] + fe - else: - for row in edof: - idx = row-1 - K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke - if (not f is None) and (not fe is None): - f[np.ix_(idx)] = f[np.ix_(idx)] + fe + ep = [t ir] thickness and integration rule - if f is None: - return K - else: - return K, f + D = [[kxx kxy], + [kyx kyy]] constitutive matrix + ed = [u1, u2, u3, u4] u1,u2,u3,u4: nodal values -def solveq(K, f, bcPrescr, bcVal=None): - """ - Solve static FE-equations considering boundary conditions. - - Parameters: - - K global stiffness matrix, dim(K)= nd x nd - f global load vector, dim(f)= nd x 1 - - bcPrescr 1-dim integer array containing prescribed dofs. - bcVal 1-dim float array containing prescribed values. - If not given all prescribed dofs are assumed 0. - Returns: - - a solution including boundary values - Q reaction force vector - dim(a)=dim(Q)= nd x 1, nd : number of dof's - - """ - - nDofs = K.shape[0] - nPdofs = bcPrescr.shape[0] + es = [[qx, qy], + [.., ..]] element flows - if bcVal is None: - bcVal = np.zeros([nPdofs], 'd') + et = [[qx, qy], + [... ..]] element gradients - bc = np.ones(nDofs, 'bool') - bcDofs = np.arange(nDofs) + eci=[[ix1, iy1], Gauss point location vector + [... ...], nint: number of integration points + [ix(nint), iy(nint)] - bc[np.ix_(bcPrescr-1)] = False - bcDofs = bcDofs[bc] + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir - fsys = f[bcDofs]-K[np.ix_((bcDofs), (bcPrescr-1))] * \ - np.asmatrix(bcVal).reshape(nPdofs, 1) - asys = np.linalg.solve(K[np.ix_((bcDofs), (bcDofs))], fsys) + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) - a = np.zeros([nDofs, 1]) - a[np.ix_(bcPrescr-1)] = np.asmatrix(bcVal).reshape(nPdofs, 1) - a[np.ix_(bcDofs)] = asys + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 - Q = K*np.asmatrix(a)-f + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) - return (np.asmatrix(a), Q) + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. + + eci = N*np.mat([ex, ey]).T + if ed.ndim == 1: + ed = np.array([ed]) + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey]).T -def spsolveq(K, f, bcPrescr, bcVal=None): + es = np.mat(np.zeros((ngp*red, 2))) + et = np.mat(np.zeros((ngp*red, 2))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinatn == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + + return es, et, eci + + +def flw2i8e(ex, ey, ep, D, eq=None): """ - Solve static FE-equations considering boundary conditions. + Compute element stiffness (conductivity) + matrix for 8 node isoparametric field element. Parameters: - K global stiffness matrix, dim(K)= nd x nd - f global load vector, dim(f)= nd x 1 - - bcPrescr 1-dim integer array containing prescribed dofs. - bcVal 1-dim float array containing prescribed values. - If not given all prescribed dofs are assumed 0. + ex = [x1, ..., x8] element coordinates + ey = [y1, ..., y8] + ep = [t, ir] thickness and integration rule + + D = [[kxx, kxy], + [kyx, kyy]] constitutive matrix + + eq heat supply per unit volume + Returns: - a solution including boundary values - Q reaction force vector - dim(a)=dim(Q)= nd x 1, nd : number of dof's - + Ke element 'stiffness' matrix (8 x 8) + fe element load vector (8 x 1) + """ + t = ep[0] + ir = ep[1] + ngp = ir*ir - nDofs = K.shape[0] - nPdofs = bcPrescr.shape[0] + if eq == None: + q = 0 + else: + q = eq - if bcVal is None: - bcVal = np.zeros([nPdofs], 'd') + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) + else: + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) - bc = np.ones(nDofs, 'bool') - bcDofs = np.arange(nDofs) + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 - bc[np.ix_(bcPrescr-1)] = False - bcDofs = bcDofs[bc] + N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) + N = np.append(N, np.multiply( + (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) + N = np.append(N, np.multiply( + (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) - bcVal_m = np.asmatrix(bcVal).reshape(nPdofs, 1) + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - + np.multiply((1+xsi), (1-eta)))/4. + dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + + np.multiply((1-xsi), (1+eta)))/4. + dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) + dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. + dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) + dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. + dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + + np.multiply((1+xsi), (1-eta)))/4. + dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - + np.multiply((1-xsi), (1+eta)))/4. + dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) + dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) - info("Preparing system matrix...") + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey]).T - mask = np.ones(K.shape[0], dtype=bool) - mask[bcDofs] = False + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminanten lika med noll!") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] - info("step 1... converting K->CSR") - Kcsr = K.asformat("csr") - info("step 2... Kt") - #Kt1 = K[bcDofs] - #Kt = Kt1[:,bcPrescr] - Kt = K[np.ix_((bcDofs), (bcPrescr-1))] - info("step 3... fsys") - fsys = f[bcDofs]-Kt*bcVal_m - info("step 4... Ksys") - Ksys1 = Kcsr[bcDofs] - Ksys = Ksys1[:, bcDofs] - #Ksys = Kcsr[np.ix_((bcDofs),(bcDofs))] - info("done...") + if eq != None: + return Ke1*t, fe1*t*q + else: + return Ke1*t - info("Solving system...") - asys = dsolve.spsolve(Ksys, fsys) - info("Reconstructing full a...") - a = np.zeros([nDofs, 1]) - a[np.ix_(bcPrescr-1)] = bcVal_m - a[np.ix_(bcDofs)] = np.asmatrix(asys).transpose() +def flw2i8s(ex, ey, ep, D, ed): + """ + Compute flows or corresponding quantities in the + 8 node isoparametric element. + + Parameters: + + ex = [x1,x2,x3....,x8] element coordinates + ey = [y1,y2,y3....,y8] - a_m = np.asmatrix(a) - Q = K*a_m-f - info("done...") - return (a_m, Q) + ep = [t,ir] thickness and integration rule + D = [[kxx,kxy], + [kyx,kyy]] constitutive matrix -def eigen(K,M,b=None): - """ - Solve the generalized eigenvalue problem - |K-LM|X = 0, considering boundary conditions + ed = [u1,....,u8] u1,....,u8: nodal values - Parameters: + Returns: + es = [[qx,qy], + [..,..]] element flows - K global stiffness matrix, dim(K) = ndof x ndof - M global mass matrix, dim(M) = ndof x ndof - b boundary condition vector, dim(b) = nbc x 1 + et = [[qx,qy], + [..,..]] element gradients - Returns: + eci=[[ix1,iy1], Gauss point location vector + [...,...], nint: number of integration points + [ix(nint),iy(nint)]] - L eigenvalue vector, dim(L) = (ndof-nbc) x 1 - X eigenvectors, dim(X) = ndof x (ndof-nbc) """ - nd, _ = K.shape - if b is not None: - fdof = np.setdiff1d(np.arange(nd), b-1) - D, X1 = eig(K[np.ix_(fdof,fdof)], M[np.ix_(fdof,fdof)]) - D = np.real(D) - nfdof, _ = X1.shape - for j in range(nfdof): - mnorm = np.sqrt(X1[:,j].T@M[np.ix_(fdof,fdof)]@X1[:,j]) - X1[:,j] /= mnorm - s_order = np.argsort(D) - L = np.sort(D) - X2 = np.zeros(X1.shape) - for ind,j in enumerate(s_order): - X2[:,ind] = X1[:,j] - X = np.zeros((nd,nfdof)) - X[fdof,:] = X2 - return L, X + t = ep[0] + ir = ep[1] + ngp = ir*ir + + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1] + ]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1] + ]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1] + ]) else: - D, X1 = eig(K, M) - D = np.real(D) - for j in range(nd): - mnorm = np.sqrt(X1[:,j].T@M@X1[:,j]) - X1[:,j] /= mnorm - s_order = np.argsort(D) - L = np.sort(D) - X = np.copy(X1) - for ind,j in enumerate(s_order): - X[:,ind] = X1[:,j] - return L, X + info("Used number of integration points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 -def gfunc(G,dt): - """ - Form vector with function values at equally spaced - points by linear interpolation + N = np.multiply(np.multiply(-(1-xsi), (1-eta)), (1+xsi+eta))/4. + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1-eta)), (1-xsi+eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1+xsi), (1+eta)), (1-xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + np.multiply(-(1-xsi), (1+eta)), (1+xsi-eta))/4., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1-eta))/2., axis=1) + N = np.append(N, np.multiply( + (1+xsi), (1-np.multiply(eta, eta)))/2., axis=1) + N = np.append(N, np.multiply( + (1-np.multiply(xsi, xsi)), (1+eta))/2., axis=1) + N = np.append(N, np.multiply( + (1-xsi), (1-np.multiply(eta, eta)))/2., axis=1) - Parameters: + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:2, 0] = -(-np.multiply((1-eta), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[0:r2:2, 1] = -(np.multiply((1-eta), (1-xsi+eta)) - + np.multiply((1+xsi), (1-eta)))/4. + dNr[0:r2:2, 2] = -(np.multiply((1+eta), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[0:r2:2, 3] = -(-np.multiply((1+eta), (1+xsi-eta)) + + np.multiply((1-xsi), (1+eta)))/4. + dNr[0:r2:2, 4] = -np.multiply(xsi, (1-eta)) + dNr[0:r2:2, 5] = (1-np.multiply(eta, eta))/2. + dNr[0:r2:2, 6] = -np.multiply(xsi, (1+eta)) + dNr[0:r2:2, 7] = -(1-np.multiply(eta, eta))/2. + dNr[1:r2+1:2, 0] = -(-np.multiply((1-xsi), (1+xsi+eta)) + + np.multiply((1-xsi), (1-eta)))/4. + dNr[1:r2+1:2, 1] = -(-np.multiply((1+xsi), (1-xsi+eta)) + + np.multiply((1+xsi), (1-eta)))/4. + dNr[1:r2+1:2, 2] = -(np.multiply((1+xsi), (1-xsi-eta)) - + np.multiply((1+xsi), (1+eta)))/4. + dNr[1:r2+1:2, 3] = -(np.multiply((1-xsi), (1+xsi-eta)) - + np.multiply((1-xsi), (1+eta)))/4. + dNr[1:r2+1:2, 4] = -(1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 5] = -np.multiply(eta, (1+xsi)) + dNr[1:r2+1:2, 6] = (1-np.multiply(xsi, xsi))/2. + dNr[1:r2+1:2, 7] = -np.multiply(eta, (1-xsi)) - G = [t_i, g_i] t_i: time i, g_i: g(t_i) - dim(G) = np x 2, np = number of points - dt time step + eci = N*np.mat([ex, ey]).T + if ed.ndim == 1: + ed = np.array([ed]) + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey]).T - Returns: + es = np.mat(np.zeros((ngp*red, 2))) + et = np.mat(np.zeros((ngp*red, 2))) - t 1-D vector with equally spaced time points - g 1-D vector with corresponding function values - """ - ti = np.arange(G[0,0],G[-1,0]+dt,dt) - g1 = np.interp(ti,G[:,0],G[:,1]) - return ti, g1 + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T + return es, et, eci -def step1(K,C,f,a0,bc,ip,times,dofs): - """ - Algorithm for dynamic solution of first-order - FE equations considering boundary conditions. +def flw3i8e(ex, ey, ez, ep, D, eq=None): + """ + Compute element stiffness (conductivity) + matrix for 8 node isoparametric field element. + Parameters: + + ex = [x1,x2,x3,...,x8] + ey = [y1,y2,y3,...,y8] element coordinates + ez = [z1,z2,z3,...,z8] - K conductivity matrix, dim(K) = ndof x ndof - C capacity matrix, dim(C) = ndof x ndof - f load vector, dim(f) = ndof x (nstep + 1), - If dim(f) = ndof x 1, the values are kept constant - during time integration - a0 initial vector a(0), dim(a0) = ndof x 1 - bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) - where nbc = number of prescribed degrees of freedom (either constant or time-dependent) - The first column contains the numbers of the prescribed degrees of freedom - and the subsequent columns contain the time history. - If dim(bc) = nbc x 2, the values from the second column are kept constant - during time integration - ip array [dt, tottime, alpha], where - dt is the size of the time increment, - tottime is the total time, - alpha is time integration constant. - Frequently used values of alpha are: - alpha=0: forward difference; forward Euler, - alpha=1/2: trapezoidal rule; Crank-Nicholson - alpha=1: backward difference; backward Euler - times array [t(i) ...] of times at which output should be written to a and da - dofs array [dof(i) ...] of degree of freedom numbers for which history output - should be written to ahist and dahist - - Returns: + ep = [ir] Ir: Integration rule - modelhist dictionary containing solution history for the whole model at following keys: - modelhist['a'] constains values of a at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes - modelhist['da'] constains values of da at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes - dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': - dofhist['a'] constains time history of a at the dofs specified in 'dofs' - dim(dofhist['ahist']) = ndof x (nstep + 1) - dofhist['da'] constains time history of daat the dofs specified in 'dofs' - dim(dofhist['dahist']) = ndof x (nstep + 1) - """ - ndof, _ = K.shape - dt, tottime, alpha = ip - a1 = (1-alpha)*dt - a2 = alpha*dt + D = [[kxx,kxy,kxz], + [kyx,kyy,kyz], + [kzx,kzy,kzz]] constitutive matrix - nstep = 1 - if np.array(f).any(): - _, ncf = f.shape - if ncf>1: - nstep = ncf-1 + eq heat supply per unit volume - if np.array(bc).any(): - _, ncb = bc.shape - if ncb>2: - nstep = ncb-2 - bound = 1 - if not np.array(bc).any(): - bound = 0 + Output: - ns = int(tottime/dt) - if (ns < nstep or nstep==1): - nstep=ns + Ke element 'stiffness' matrix (8 x 8) + fe element load vector (8 x 1) - tf = np.zeros((ndof,nstep+1)) - if np.array(f).any(): - if ncf==1: - tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) - if ncf>1: - tf = np.copy(f) + """ + ir = ep[0] + ngp = ir*ir*ir - modelhist = {} - sa=0 - if not np.array(times).any(): - ntimes=0 - sa=1 - modelhist['a'] = np.zeros((ndof,nstep+1)) - modelhist['da'] = np.zeros((ndof,nstep+1)) + if eq == None: + q = 0 else: - ntimes = len(times) - if ntimes: - sa=2 - modelhist['a'] = np.zeros((ndof,ntimes)) - modelhist['da'] = np.zeros((ndof,ntimes)) + q = eq - dofhist = {} - if np.array(dofs).all(): - ndofs = len(dofs) - if ndofs: - dofhist['a'] = np.zeros((ndofs,nstep+1)) - dofhist['da'] = np.zeros((ndofs,nstep+1)) + if ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-1, -1, -1], + [1, -1, -1], + [1, 1, -1], + [-1, 1, -1], + [-1, -1, 1], + [1, -1, 1], + [1, 1, 1], + [-1, 1, 1] + ])*g1 + w = np.mat(np.ones((8, 3)))*w1 + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat(np.zeros((27, 3))) + w = np.mat(np.zeros((27, 3))) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) + gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] + I1 = abs(I1) + I2 = abs(I2) + w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) + gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] + I1 = abs(I1) + I2 = abs(I2) + w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) + I3 = abs(I1) + gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 + gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] + w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 + w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] else: - ndofs=0 + info("Used number of integration points not implemented") + return - itime = 0 + wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) - # Calculate initial second time derivative d2a0 - da0 = np.linalg.solve(C,tf[:,0].reshape(-1,1) - K@a0) - # Save initial values - if sa==1: - modelhist['a'][:,0] = a0.ravel() - modelhist['da'][:,0] = da0.ravel() - elif sa==2: - if times[itime]==0: - modelhist['a'][:,itime] = a0.ravel() - modelhist['da'][:,itime] = da0.ravel() - itime += 1 + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 - if ndofs: - dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() - dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1+zet))/8., axis=1) - # Reduce matrices due to bcs - tempa = np.zeros((ndof,1)) - tempda = np.zeros((ndof,1)) - fdof=np.arange(1,ndof+1).astype(int) - if bound: - nrb, ncb = bc.shape - if ncb==2: - pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) - pda = np.zeros((nrb,nstep+1)) - elif ncb>2: - pa = np.copy(bc[:,1:]) - pda1 = (pa[:,1]-pa[:,0])/dt - pdarest = (pa[:,1:] - pa[:,0:-1])/dt - pda = np.hstack((pda1.reshape(-1,1),pdarest)) - pdof = np.copy(bc[:,0]).astype(int) - fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 - pdof -= 1 #adjusting for indexing starting from 0 - Keff = C[np.ix_(fdof,fdof)] + a2*K[np.ix_(fdof,fdof)] - else: - fdof -= 1 #adjusting for indexing starting from 0 - Keff = C + a2*K + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) + dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) + dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) + dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) + dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) + dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) + dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) + dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) + dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) + dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) + dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) + dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) + dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) + dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) + dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) + dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) + dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) + dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) + dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) + dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) + dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) + dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) + dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) + dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) + dNr = dNr/8. - L, U = lu(Keff,permute_l=True) - anew = a0[np.ix_(fdof)] - danew = da0[np.ix_(fdof)] + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey, ez]).T - # Iterate over time steps - for j in range(1,nstep+1): - time = dt*j - aold = np.copy(anew) - daold = np.copy(danew) - apred = aold + a1*daold - if not bound: - reff = tf[:,j].reshape(-1,1) - K@apred - else: - pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) - reff = tf[np.ix_(fdof),j].reshape(-1,1) - K[np.ix_(fdof,fdof)]@apred - pdeff - y = np.linalg.solve(L,reff) - danew = np.linalg.solve(U,y) - anew = apred + a2*danew - # Save to modelhist and dofhist - if bound: - tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) - tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) - tempa[np.ix_(fdof)] = anew - tempda[np.ix_(fdof)] = danew - if sa==1: - modelhist['a'][:,j] = tempa.ravel() - modelhist['da'][:,j] = tempda.ravel() - elif sa==2: - if ntimes and itime < ntimes: - if time >= times[itime]: - modelhist['a'][:,itime] = tempa.ravel() - modelhist['da'][:,itime] = tempda.ravel() - itime += 1 - if ndofs: - dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() - dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + for i in range(ngp): + indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant == 0") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + Ke1 = Ke1+B.T*D*B*detJ*wp[i].item() + fe1 = fe1+N[i, :].T*detJ*wp[i] - return modelhist, dofhist + if eq != None: + return Ke1, fe1*q + else: + return Ke1 -def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): +def flw3i8s(ex, ey, ez, ep, D, ed): """ - Algorithm for dynamic solution of second-order - FE equations considering boundary conditions. - + Compute flows or corresponding quantities in the + 8 node (3-dim) isoparametric field element. + Parameters: + + ex = [x1,x2,x3,...,x8] + ey = [y1,y2,y3,...,y8] element coordinates + ez = [z1,z2,z3,...,z8] - K global stiffness matrix, dim(K) = ndof x ndof - C global damping matrix, dim(C) = ndof x ndof - If there is no damping in the system, simply set C=[] - M global mass matrix, dim(M) = ndof x ndof - f global load vector, dim(f) = ndof x (nstep + 1), - If dim(f) = ndof x 1, the values are kept constant - during time integration - a0 initial displacement vector a(0), dim(a0) = ndof x 1 - da0 initial velocity vector v(0), dim(da0) = ndof x 1 - bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) - where nbc = number of prescribed degrees of freedom (either constant or time-dependent) - The first column contains the numbers of the prescribed degrees of freedom - and the subsequent columns contain the time history. - If dim(bc) = nbc x 2, the values from the second column are kept constant - during time integration - ip array [dt, tottime, alpha, delta], where - dt is the size of the time increment, - tottime is the total time, - alpha and delta are time integration constants for the Newmark family of methods. - Frequently used values of alpha and delta are: - alpha=1/4, delta=1/2: average acceleration (trapezoidal) rule, - alpha=1/6, delta=1/2: linear acceleration - alpha=0, delta=1/2: central difference - times array [t(i) ...] of times at which output should be written to a, da and d2a - dofs array [dof(i) ...] of degree of freedom numbers for which history output - should be written to ahist, dahist and d2ahist + ep = [ir] Ir: Integration rule - Returns: + D = [[kxx,kxy,kxz], + [kyx,kyy,kyz], + [kzx,kzy,kzz]] constitutive matrix - modelhist dictionary containing solution history for the whole model at following keys: - modelhist['a'] constains displacement values at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes - modelhist['da'] constains velocity values at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes - modelhist['d2a'] constains acceleration values at all timesteps, - alternatively at times specified in 'times' - dim(modelhist['d2a']) = ndof x (nstep + 1) or ndof x ntimes - dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': - dofhist['a'] constains displacement time history at the dofs specified in 'dofs' - dim(dofhist['ahist']) = ndof x (nstep + 1) - dofhist['da'] constains velocity time history at the dofs specified in 'dofs' - dim(dofhist['dahist']) = ndof x (nstep + 1) - dofhist['d2a'] constains acceleration time history at the dofs specified in 'dofs' - dim(dofhist['d2ahist']) = ndof x (nstep + 1) - """ - ndof, _ = K.shape - if not np.array(C).any(): - C = np.zeros((ndof,ndof)) - dt, tottime, alpha, delta = ip - b1 = dt*dt*0.5*(1-2*alpha) - b2 = (1-delta)*dt - b3 = delta*dt - b4 = alpha*dt*dt + ed = [[u1,....,u8], element nodal values + [..,....,..]] - nstep = 1 - if np.array(f).any(): - _, ncf = f.shape - if ncf>1: - nstep = ncf-1 + Output: - if np.array(bc).any(): - _, ncb = bc.shape - if ncb>2: - nstep = ncb-2 - bound = 1 - if not np.array(bc).any(): - bound = 0 + es = [[qx,qy,qz], + [..,..,..]] element flows(s) - ns = int(tottime/dt) - if (ns < nstep or nstep==1): - nstep=ns + et = [[qx,qy,qz], element gradients(s) + [..,..,..]] - tf = np.zeros((ndof,nstep+1)) - if np.array(f).any(): - if ncf==1: - tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) - if ncf>1: - tf = np.copy(f) + eci = [[ix1,ix1,iz1], location vector + [...,...,...], nint: number of integration points + [ix(nint),iy(nint),iz(nint)]] - modelhist = {} - sa=0 - if not np.array(times).any(): - ntimes=0 - sa=1 - modelhist['a'] = np.zeros((ndof,nstep+1)) - modelhist['da'] = np.zeros((ndof,nstep+1)) - modelhist['d2a'] = np.zeros((ndof,nstep+1)) - else: - ntimes = len(times) - if ntimes: - sa=2 - modelhist['a'] = np.zeros((ndof,ntimes)) - modelhist['da'] = np.zeros((ndof,ntimes)) - modelhist['d2a'] = np.zeros((ndof,ntimes)) + """ + ir = ep[0] + ngp = ir*ir*ir - dofhist = {} - if np.array(dofs).all(): - ndofs = len(dofs) - if ndofs: - dofhist['a'] = np.zeros((ndofs,nstep+1)) - dofhist['da'] = np.zeros((ndofs,nstep+1)) - dofhist['d2a'] = np.zeros((ndofs,nstep+1)) + if ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-1, -1, -1], + [1, -1, -1], + [1, 1, -1], + [-1, 1, -1], + [-1, -1, 1], + [1, -1, 1], + [1, 1, 1], + [-1, 1, 1] + ])*g1 + w = np.mat(np.ones((8, 3)))*w1 + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat(np.zeros((27, 3))) + w = np.mat(np.zeros((27, 3))) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]) + gp[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 0] + I1 = abs(I1) + I2 = abs(I2) + w[:, 0] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 0] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 0] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) + gp[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*g1 + gp[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*g2+gp[:, 1] + I1 = abs(I1) + I2 = abs(I2) + w[:, 1] = np.mat([I1, I1, I1]).reshape(27, 1)*w1 + w[:, 1] = np.mat([I2, I2, I2]).reshape(27, 1)*w2+w[:, 1] + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]) + I3 = abs(I1) + gp[:, 2] = np.mat([I1, I2, I3]).reshape(27, 1)*g1 + gp[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*g2+gp[:, 2] + w[:, 2] = np.mat([I3, I2, I3]).reshape(27, 1)*w1 + w[:, 2] = np.mat([I2, I3, I2]).reshape(27, 1)*w2+w[:, 2] else: - ndofs=0 + info("Used number of integration points not implemented") + return - itime = 0 + wp = np.multiply(np.multiply(w[:, 0], w[:, 1]), w[:, 2]) - # Calculate initial second time derivative d2a0 - d2a0 = np.linalg.solve(M,tf[:,0].reshape(-1,1) - C@da0 - K@a0) - # Save initial values - if sa==1: - modelhist['a'][:,0] = a0.ravel() - modelhist['da'][:,0] = da0.ravel() - modelhist['d2a'][:,0] = d2a0.ravel() - elif sa==2: - if times[itime]==0: - modelhist['a'][:,itime] = a0.ravel() - modelhist['da'][:,itime] = da0.ravel() - modelhist['d2a'][:,itime] = d2a0.ravel() - itime += 1 + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 - if ndofs: - dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() - dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() - dofhist['d2a'][:,0] = d2a0[np.ix_(dofs-1)].ravel() + N = np.multiply(np.multiply((1-xsi), (1-eta)), (1-zet))/8. + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1-zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1-eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1+xsi), (1+eta)), (1+zet))/8., axis=1) + N = np.append(N, np.multiply(np.multiply( + (1-xsi), (1+eta)), (1+zet))/8., axis=1) - # Reduce matrices due to bcs - tempa = np.zeros((ndof,1)) - tempda = np.zeros((ndof,1)) - tempd2a = np.zeros((ndof,1)) - fdof=np.arange(1,ndof+1).astype(int) - if bound: - nrb, ncb = bc.shape - if ncb==2: - pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) - pda = np.zeros((nrb,nstep+1)) - elif ncb>2: - pa = np.copy(bc[:,1:]) - pda1 = (pa[:,1]-pa[:,0])/dt - pdarest = (pa[:,1:] - pa[:,0:-1])/dt - pda = np.hstack((pda1.reshape(-1,1),pdarest)) - pdof = np.copy(bc[:,0]).astype(int) - fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 - pdof -= 1 #adjusting for indexing starting from 0 - Keff = M[np.ix_(fdof,fdof)] + b3*C[np.ix_(fdof,fdof)] +b4*K[np.ix_(fdof,fdof)] - else: - fdof -= 1 #adjusting for indexing starting from 0 - Keff = M + b3*C + b4*K + dNr = np.mat(np.zeros((r2, 8))) + dNr[0:r2:3, 0] = np.multiply(-(1-eta), (1-zet)) + dNr[0:r2:3, 1] = np.multiply((1-eta), (1-zet)) + dNr[0:r2:3, 2] = np.multiply((1+eta), (1-zet)) + dNr[0:r2:3, 3] = np.multiply(-(1+eta), (1-zet)) + dNr[0:r2:3, 4] = np.multiply(-(1-eta), (1+zet)) + dNr[0:r2:3, 5] = np.multiply((1-eta), (1+zet)) + dNr[0:r2:3, 6] = np.multiply((1+eta), (1+zet)) + dNr[0:r2:3, 7] = np.multiply(-(1+eta), (1+zet)) + dNr[1:r2+1:3, 0] = np.multiply(-(1-xsi), (1-zet)) + dNr[1:r2+1:3, 1] = np.multiply(-(1+xsi), (1-zet)) + dNr[1:r2+1:3, 2] = np.multiply((1+xsi), (1-zet)) + dNr[1:r2+1:3, 3] = np.multiply((1-xsi), (1-zet)) + dNr[1:r2+1:3, 4] = np.multiply(-(1-xsi), (1+zet)) + dNr[1:r2+1:3, 5] = np.multiply(-(1+xsi), (1+zet)) + dNr[1:r2+1:3, 6] = np.multiply((1+xsi), (1+zet)) + dNr[1:r2+1:3, 7] = np.multiply((1-xsi), (1+zet)) + dNr[2:r2+2:3, 0] = np.multiply(-(1-xsi), (1-eta)) + dNr[2:r2+2:3, 1] = np.multiply(-(1+xsi), (1-eta)) + dNr[2:r2+2:3, 2] = np.multiply(-(1+xsi), (1+eta)) + dNr[2:r2+2:3, 3] = np.multiply(-(1-xsi), (1+eta)) + dNr[2:r2+2:3, 4] = np.multiply((1-xsi), (1-eta)) + dNr[2:r2+2:3, 5] = np.multiply((1+xsi), (1-eta)) + dNr[2:r2+2:3, 6] = np.multiply((1+xsi), (1+eta)) + dNr[2:r2+2:3, 7] = np.multiply((1-xsi), (1+eta)) + dNr = dNr/8. - L, U = lu(Keff,permute_l=True) - anew = a0[np.ix_(fdof)] - danew = da0[np.ix_(fdof)] - d2anew = d2a0[np.ix_(fdof)] + eci = N*np.mat([ex, ey, ez]).T + if ed.ndim == 1: + ed = np.array([ed]) + red, ced = np.shape(ed) + JT = dNr*np.mat([ex, ey, ez]).T - # Iterate over time steps - for j in range(1,nstep+1): - time = dt*j - aold = np.copy(anew) - daold = np.copy(danew) - d2aold = np.copy(d2anew) - apred = aold + dt*daold + b1*d2aold - dapred = daold + b2*d2aold - if not bound: - reff = tf[:,j].reshape(-1,1) - C@dapred - K@apred - else: - pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) - reff = tf[np.ix_(fdof),j].reshape(-1,1) - C[np.ix_(fdof,fdof)]@dapred - K[np.ix_(fdof,fdof)]@apred - pdeff - y = np.linalg.solve(L,reff) - d2anew = np.linalg.solve(U,y) - anew = apred + b4*d2anew - danew = dapred + b3*d2anew - # Save to modelhist and dofhist - if bound: - tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) - tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) - tempa[np.ix_(fdof)] = anew - tempda[np.ix_(fdof)] = danew - tempd2a[np.ix_(fdof)] = d2anew - if sa==1: - modelhist['a'][:,j] = tempa.ravel() - modelhist['da'][:,j] = tempda.ravel() - modelhist['d2a'][:,j] = tempd2a.ravel() - elif sa==2: - if ntimes and itime < ntimes: - if time >= times[itime]: - modelhist['a'][:,itime] = tempa.ravel() - modelhist['da'][:,itime] = tempda.ravel() - modelhist['d2a'][:,itime] = tempd2a.ravel() - itime += 1 - if ndofs: - dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() - dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() - dofhist['d2a'][:,j] = tempd2a[np.ix_(dofs-1)].ravel() + es = np.mat(np.zeros((ngp*red, 3))) + et = np.mat(np.zeros((ngp*red, 3))) + for i in range(ngp): + indx = np.array([3*(i+1)-2, 3*(i+1)-1, 3*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminanten lika med noll!") + JTinv = np.linalg.inv(JT[indx-1, :]) + B = JTinv*dNr[indx-1, :] + p1 = -D*B*ed.T + p2 = B*ed.T + es[i:ngp*red:ngp, :] = p1.T + et[i:ngp*red:ngp, :] = p2.T - return modelhist, dofhist + return es, et, eci -def extract_eldisp(edof, a): +def plante(ex, ey, ep, D, eq=None): """ - Extract element displacements from the global displacement - vector according to the topology matrix edof. + Calculate the stiffness matrix for a triangular plane stress or plane strain element. Parameters: - a the global displacement vector - edof dof topology array - - Returns: + ex = [x1,x2,x3] element coordinates + ey = [y1,y2,y3] + + ep = [ptype,t] ptype: analysis type + t: thickness + + D constitutive matrix - ed: element displacement array + eq = [[bx], bx: body force x-dir + [by]] by: body force y-dir + + Returns: - """ - - ed = None - - if edof.ndim == 1: - nDofs = len(edof) - ed = np.zeros([nDofs]) - idx = edof-1 - ed[:] = a[np.ix_(idx)].T - else: - nElements = edof.shape[0] - nDofs = edof.shape[1] - ed = np.zeros([nElements, nDofs]) - i = 0 - for row in edof: - idx = row-1 - ed[i, :] = a[np.ix_(idx)].T - i += 1 - - return ed + Ke element stiffness matrix (6 x 6) + fe equivalent nodal forces (6 x 1) (if eq is given) + """ -extractEldisp = extract_eldisp -extract_ed = extract_eldisp + ptype, t = ep + bx = 0.0 + by = 0.0 -def statcon(K, f, cd): - """ - Condensation of static FE-equations according to the vector cd. + if not eq is None: + bx = eq[0] + by = eq[1] - Parameters: - - K global stiffness matrix, dim(K) = nd x nd - f global load vector, dim(f)= nd x 1 + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) - cd vector containing dof's to be eliminated - dim(cd)= nc x 1, nc: number of condensed dof's - Returns: - - K1 condensed stiffness matrix, - dim(K1)= (nd-nc) x (nd-nc) - f1 condensed load vector, dim(f1)= (nd-nc) x 1 - """ - nd, nd = np.shape(K) - cd = (cd-1).flatten() + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) - aindx = np.arange(nd) - aindx = np.delete(aindx, cd, 0) - bindx = cd + # --------- plane stress -------------------------------------- - Kaa = np.mat(K[np.ix_(aindx, aindx)]) - Kab = np.mat(K[np.ix_(aindx, bindx)]) - Kbb = np.mat(K[np.ix_(bindx, bindx)]) + if ptype == 1: + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) - fa = np.mat(f[aindx]) - fb = np.mat(f[bindx]) + colD = D.shape[1] - K1 = Kaa-Kab*Kbb.I*Kab.T - f1 = fa-Kab*Kbb.I*fb + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) + else: + Dm = D - return K1, f1 + Ke = B.T*Dm*B*A*t + fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t + if eq is None: + return Ke + else: + return Ke, fe.T -def c_mul(a, b): - return eval(hex((np.long(a) * b) & 0xFFFFFFFF)[:-1]) + #--------- plane strain -------------------------------------- + elif ptype == 2: + B = np.mat([ + [0, 1, 0, 0, 0, 0, ], + [0, 0, 0, 0, 0, 1, ], + [0, 0, 1, 0, 1, 0, ] + ])*np.linalg.inv(C) -def dofHash(dof): - if len(dof) == 1: - return dof[0] - value = 0x345678 - for item in dof: - value = c_mul(1000003, value) ^ hash(item) - value = value ^ len(dof) - if value == -1: - value = -2 - return value + colD = D.shape[1] + if colD > 3: + Dm = D[np.ix_((0, 1, 3), (0, 1, 3))] + else: + Dm = D -def create_dofs(nCoords, nDof): - """ - Create dof array [nCoords x nDof] - """ - return np.arange(nCoords*nDof).reshape(nCoords, nDof)+1 + Ke = B.T*Dm*B*A*t + fe = A/3*np.mat([bx, by, bx, by, bx, by]).T*t + if eq == None: + return Ke + else: + return Ke, fe.T -createdofs = create_dofs + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + if eq == None: + return None + else: + return None, None -def coordxtr(edof, coords, dofs, nen=-1): +def plants(ex, ey, ep, D, ed): """ - Create element coordinate matrices ex, ey, ez from edof - coord and dofs matrices. + Calculate element normal and shear stress for a + triangular plane stress or plane strain element. - Parameters: + INPUT: ex = [x1 x2 x3] element coordinates + ey = [y1 y2 y3] - edof [nel x (nen * nnd)], nnd = number of node dofs - coords [ncoords x ndims], ndims = node dimensions - dofs [ncoords x nnd] - - Returns: + ep = [ptype t ] ptype: analysis type + t: thickness - ex if ndims = 1 - ex, ey if ndims = 2 - ex, ey, ez if ndims = 3 + D constitutive matrix + + ed =[u1 u2 ...u6 element displacement vector + ...... ] one row for each element + + OUTPUT: es = [ sigx sigy [sigz] tauxy element stress matrix + ...... ] one row for each element + + et = [ epsx epsy [epsz] gamxy element strain matrix + ...... ] one row for each element """ - # Create dictionary with dof indices - - dofDict = {} - nDofs = np.size(dofs, 1) - nElements = np.size(edof, 0) - n_element_dofs = np.size(edof, 1) - nDimensions = np.size(coords, 1) - nElementDofs = np.size(edof, 1) + ptype = ep[0] - if nen == -1: - nElementNodes = int(nElementDofs/nDofs) - else: - nElementNodes = nen + if np.ndim(ex) == 1: + ex = np.array([ex]) + if np.ndim(ey) == 1: + ey = np.array([ey]) + if np.ndim(ed) == 1: + ed = np.array([ed]) - if nElementNodes*nDofs != n_element_dofs: - nDofs = nElementNodes*nDofs - n_element_dofs - user_warning( - "dofs/edof mismatch. Using %d dofs per node when indexing." % nDofs) + rowed = ed.shape[0] + rowex = ex.shape[0] - idx = 0 - for dof in dofs: - #dofDict[dofHash(dof)] = idx - dofDict[hash(tuple(dof[0:nDofs]))] = idx - idx += 1 + # --------- plane stress -------------------------------------- - # Loop over edof and extract element coords + if ptype == 1: - ex = np.zeros((nElements, nElementNodes)) - ey = np.zeros((nElements, nElementNodes)) - ez = np.zeros((nElements, nElementNodes)) + colD = D.shape[1] - elementIdx = 0 - for etopo in edof: - for i in range(nElementNodes): - i0 = i*nDofs - i1 = i*nDofs+nDofs-1 - dof = [] - if i0 == i1: - dof = [etopo[i*nDofs]] - else: - dof = etopo[i*nDofs:(i*nDofs+nDofs)] + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_((0, 1, 3), (0, 1, 3))]) + else: + Dm = D - nodeCoord = coords[dofDict[hash(tuple(dof[0:nDofs]))]] + incie = 0 - if nDimensions >= 1: - ex[elementIdx, i] = nodeCoord[0] - if nDimensions >= 2: - ey[elementIdx, i] = nodeCoord[1] - if nDimensions >= 3: - ez[elementIdx, i] = nodeCoord[2] + if rowex == 1: + incie = 0 + else: + incie = 1 - elementIdx += 1 + et = np.zeros([rowed, colD]) + es = np.zeros([rowed, colD]) - if nDimensions == 1: - return ex + ie = 0 - if nDimensions == 2: - return ex, ey + for i in range(rowed): + C = np.matrix( + [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], + [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], + [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] + ) - if nDimensions == 3: - return ex, ey, ez + B = np.matrix([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) + ee = B*np.asmatrix(ed[ie, :]).T -coord_extract = coordxtr + if colD > 3: + ss = np.zeros([colD, 1]) + ss[[0, 1, 3]] = Dm*ee + ee = Cm*ss + else: + ss = Dm*ee + + et[ie, :] = ee.T + es[ie, :] = ss.T + ie = ie + incie -def hooke(ptype, E, v): + return es, et + + # --------- plane strain -------------------------------------- + elif ptype == 2: # Implementation by LAPM + colD = D.shape[1] + incie = 0 + + if rowex == 1: + incie = 0 + else: + incie = 1 + + et = np.zeros([rowed, colD]) + es = np.zeros([rowed, colD]) + + ie = 0 + + ee = np.zeros([colD, 1]) + + for i in range(rowed): + C = np.matrix( + [[1, ex[ie, 0], ey[ie, 0], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 0], ey[ie, 0]], + [1, ex[ie, 1], ey[ie, 1], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 1], ey[ie, 1]], + [1, ex[ie, 2], ey[ie, 2], 0, 0, 0], + [0, 0, 0, 1, ex[ie, 2], ey[ie, 2]]] + ) + + B = np.matrix([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0]])*np.linalg.inv(C) + + e = B*np.asmatrix(ed[ie, :]).T + + if colD > 3: + ee[[0, 1, 3]] = e + else: + ee = e + + et[ie, :] = ee.T + es[ie, :] = (D*ee).T + + ie = ie + incie + + return es, et + + else: + print("Error ! Check first argument, ptype=1 or 2 allowed") + return None + + +def plantf(ex, ey, ep, es): """ - Calculate the material matrix for a linear - elastic and isotropic material. - + Compute internal element force vector in a triangular element + in plane stress or plane strain. + Parameters: - - ptype= 1: plane stress - 2: plane strain - 3: axisymmetry - 4: three dimensional - - E Young's modulus - v Poissons const. - - Returns: - - D material matrix - + + ex = [x1,x2,x3] node coordinates + ey = [y1,y2,y3] + + ep = [ptype,t] ptype: analysis type + t: thickness + + es = [[sigx,sigy,[sigz],tauxy] element stress matrix + [ ...... ]] one row for each element + + OUTPUT: + + fe = [[f1],[f2],...,[f8]] internal force vector + """ + ptype, t = ep + + colD = es.shape[1] + + #--------- plane stress -------------------------------------- + if ptype == 1: - D = E*np.matrix( - [[1, v, 0], - [v, 1, 0], - [0, 0, (1-v)/2]] - )/(1-v**2) + + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) + + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) + + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) + + if colD > 3: + stress = np.asmatrix(es[np.ix_((0, 1, 3))]) + else: + stress = np.asmatrix(es) + + ef = (A*t*B.T*stress.T).T + + return np.reshape(np.asarray(ef), 6) + + #--------- plane strain -------------------------------------- + elif ptype == 2: - D = E/(1+v)*np.matrix( - [[1-v, v, v, 0], - [v, 1-v, v, 0], - [v, v, 1-v, 0], - [0, 0, 0, (1-2*v)/2]] - )/(1-2*v) - elif ptype == 3: - D = E/(1+v)*np.matrix( - [[1-v, v, v, 0], - [v, 1-v, v, 0], - [v, v, 1-v, 0], - [0, 0, 0, (1-2*v)/2]] - )/(1-2*v) - elif ptype == 4: - D = E*np.matrix( - [[1-v, v, v, 0, 0, 0], - [v, 1-v, v, 0, 0, 0], - [v, v, 1-v, 0, 0, 0], - [0, 0, 0, (1-2*v)/2, 0, 0], - [0, 0, 0, 0, (1-2*v)/2, 0], - [0, 0, 0, 0, 0, (1-2*v)/2]] - )/(1+v)/(1-2*v) - else: - info("ptype not supported.") - return D + C = np.mat([ + [1, ex[0], ey[0], 0, 0, 0], + [0, 0, 0, 1, ex[0], ey[0]], + [1, ex[1], ey[1], 0, 0, 0], + [0, 0, 0, 1, ex[1], ey[1]], + [1, ex[2], ey[2], 0, 0, 0], + [0, 0, 0, 1, ex[2], ey[2]] + ]) + A = 0.5*np.linalg.det(np.mat([ + [1, ex[0], ey[0]], + [1, ex[1], ey[1]], + [1, ex[2], ey[2]] + ])) -def effmises(es, ptype): + B = np.mat([ + [0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 1, 0] + ])*np.linalg.inv(C) + + if colD > 3: + stress = np.asmatrix(es[np.ix_((1, 2, 4))]) + else: + stress = np.asmatrix(es) + + ef = (A*t*B.T*stress.T).T + + return np.reshape(np.asarray(ef), 6) + + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + return None + + +def platre(ex, ey, ep, D, eq=None): """ - Calculate effective von mises stresses. + Calculate the stiffness matrix for a rectangular plate element. + NOTE! Element sides must be parallel to the coordinate axis. Parameters: - - es - - ptype= 1: plane stress - 2: plane strain - 3: axisymmetry - 4: three dimensional - - es = [[sigx,sigy,[sigz],tauxy] element stress matrix - [ ...... ]] one row for each element - + + ex = [x1,x2,x3,x4] element coordinates + ey = [y1,y2,y3,y4] + + ep = [t] thicknes + + D constitutive matrix for + plane stress + + eq = [qz] load/unit area Returns: - - eseff = [eseff_0 .. eseff_nel-1] - + + Ke element stiffness matrix (12 x 12) + fe equivalent nodal forces (12 x 1) + """ + Lx = (ex[2]-ex[0]).astype(float) + Ly = (ey[2]-ey[0]).astype(float) + t = ep[0] - nel = np.size(es, 0) - escomps = np.size(es, 1) + D = t**3/12.*D + + A1 = Ly/(Lx**3) + A2 = Lx/(Ly**3) + A3 = 1/Lx/Ly + A4 = Ly/(Lx**2) + A5 = Lx/(Ly**2) + A6 = 1/Lx + A7 = 1/Ly + A8 = Ly/Lx + A9 = Lx/Ly + + C1 = 4*A1*D[0, 0]+4*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] + C2 = -4*A1*D[0, 0]+2*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] + C3 = 2*A1*D[0, 0]-4*A2*D[1, 1]-2*A3*D[0, 1]-5.6*A3*D[2, 2] + C4 = -2*A1*D[0, 0]-2*A2*D[1, 1]+2*A3*D[0, 1]+5.6*A3*D[2, 2] + C5 = 2*A5*D[1, 1]+A6*D[0, 1]+0.4*A6*D[2, 2] + C6 = 2*A4*D[0, 0]+A7*D[0, 1]+0.4*A7*D[2, 2] + + C7 = 2*A5*D[1, 1]+0.4*A6*D[2, 2] + C8 = 2*A4*D[0, 0]+0.4*A7*D[2, 2] + C9 = A5*D[1, 1]-A6*D[0, 1]-0.4*A6*D[2, 2] + C10 = A4*D[0, 0]-A7*D[0, 1]-0.4*A7*D[2, 2] + C11 = A5*D[1, 1]-0.4*A6*D[2, 2] + C12 = A4*D[0, 0]-0.4*A7*D[2, 2] + + C13 = 4/3.*A9*D[1, 1]+8/15.*A8*D[2, 2] + C14 = 4/3.*A8*D[0, 0]+8/15.*A9*D[2, 2] + C15 = 2/3.*A9*D[1, 1]-8/15.*A8*D[2, 2] + C16 = 2/3.*A8*D[0, 0]-8/15.*A9*D[2, 2] + C17 = 2/3.*A9*D[1, 1]-2/15.*A8*D[2, 2] + C18 = 2/3.*A8*D[0, 0]-2/15.*A9*D[2, 2] + C19 = 1/3.*A9*D[1, 1]+2/15.*A8*D[2, 2] + C20 = 1/3.*A8*D[0, 0]+2/15.*A9*D[2, 2] + C21 = D[0, 1] + + Keq = np.mat(np.zeros((12, 12))) + Keq[0, 0:13] = C1, C5, -C6, C2, C9, -C8, C4, C11, -C12, C3, C7, -C10 + Keq[1, 1:13] = C13, -C21, C9, C15, 0, -C11, C19, 0, -C7, C17, 0 + Keq[2, 2:13] = C14, C8, 0, C18, C12, 0, C20, -C10, 0, C16 + Keq[3, 3:13] = C1, C5, C6, C3, C7, C10, C4, C11, C12 + Keq[4, 4:13] = C13, C21, -C7, C17, 0, -C11, C19, 0 + Keq[5, 5:13] = C14, C10, 0, C16, -C12, 0, C20 + Keq[6, 6:13] = C1, -C5, C6, C2, -C9, C8 + Keq[7, 7:13] = C13, -C21, -C9, C15, 0 + Keq[8, 8:13] = C14, -C8, 0, C18 + Keq[9, 9:13] = C1, -C5, -C6 + Keq[10, 10:13] = C13, C21 + Keq[11, 11] = C14 + Keq = Keq.T+Keq-np.diag(np.diag(Keq)) + + if eq != None: + q = eq + R1 = q*Lx*Ly/4 + R2 = q*Lx*Ly**2/24 + R3 = q*Ly*Lx**2/24 + + feq = np.mat([R1, R2, -R3, R1, R2, R3, R1, -R2, R3, R1, -R2, -R3]) + + if eq != None: + return Keq, feq + else: + return Keq + + +def planqe(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a quadrilateral + plane stress or plane strain element. + + Parameters: + ex=[x1 x2 x3 x4] element coordinates + ey=[y1 y2 y3 y4] + + ep = [ptype, t] ptype: analysis type + t: element thickness + + D constitutive matrix + + eq = [bx; bx: body force in x direction + by] by: body force in y direction + + OUTPUT: Ke : element stiffness matrix (8 x 8) + fe : equivalent nodal forces (row array) + """ + K = np.zeros((10, 10)) + f = np.zeros((10, 1)) + + xm = sum(ex)/4. + ym = sum(ey)/4. + + b1 = eq if eq is not None else np.array([[0], [0]]) + + ke1, fe1 = plante(np.array([ex[0], ex[1], xm]), + np.array([ey[0], ey[1], ym]), ep, D, b1) + K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[1], ex[2], xm]), + np.array([ey[1], ey[2], ym]), ep, D, b1) + K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[2], ex[3], xm]), + np.array([ey[2], ey[3], ym]), ep, D, b1) + K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(np.array([ex[3], ex[0], xm]), + np.array([ey[3], ey[0], ym]), ep, D, b1) + K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) + Ke, fe = statcon(K, f, np.array([[9], [10]])) + + if eq == None: + return Ke + else: + return Ke, fe + + +def planqs(ex, ey, ep, D, ed, eq=None): + """ + Calculate element normal and shear stress for a quadrilateral + plane stress or plane strain element. + + Parameters: + ex = [x1 x2 x3 x4] element coordinates + ey = [y1 y2 y3 y4] + + ep = [ptype, t] ptype: analysis type + t: thickness + + D constitutive matrix + + ed = [u1 u2 ..u8] element displacement vector + + eq = [[bx] bx: body force in x direction + [by]] by: body force in y direction + + OUTPUT: es = [ sigx sigy (sigz) tauxy] element stress array + et = [ epsx epsy (epsz) gamxy] element strain array + """ + + if ex.shape != (4,) or ey.shape != (4,) or ed.shape != (8,): + raise ValueError( + 'Error ! PLANQS: only one element at the time (ex, ey, ed must be a row arrays)') + + K = np.zeros((10, 10)) + f = np.zeros((10, 1)) + + xm = sum(ex)/4. + ym = sum(ey)/4. + + b1 = eq if eq is not None else np.array([[0], [0]]) + + ex1 = np.array([ex[0], ex[1], xm]) + ey1 = np.array([ey[0], ey[1], ym]) + ex2 = np.array([ex[1], ex[2], xm]) + ey2 = np.array([ey[1], ey[2], ym]) + ex3 = np.array([ex[2], ex[3], xm]) + ey3 = np.array([ey[2], ey[3], ym]) + ex4 = np.array([ex[3], ex[0], xm]) + ey4 = np.array([ey[3], ey[0], ym]) + + ke1, fe1 = plante(ex1, ey1, ep, D, b1) + K, f = assem(np.array([1, 2, 3, 4, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex2, ey2, ep, D, b1) + K, f = assem(np.array([3, 4, 5, 6, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex3, ey3, ep, D, b1) + K, f = assem(np.array([5, 6, 7, 8, 9, 10]), K, ke1, f, fe1) + ke1, fe1 = plante(ex4, ey4, ep, D, b1) + K, f = assem(np.array([7, 8, 1, 2, 9, 10]), K, ke1, f, fe1) + + A1 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex1).T, np.mat(ey1).T])) + A2 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex2).T, np.mat(ey2).T])) + A3 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex3).T, np.mat(ey3).T])) + A4 = 0.5 * \ + np.linalg.det( + np.hstack([np.ones((3, 1)), np.mat(ex4).T, np.mat(ey4).T])) + Atot = A1+A2+A3+A4 + + a, _ = solveq(K, f, np.array(range(1, 9)), ed) + +# ni = ed.shape[0] +# a = np.mat(empty((10,ni))) +# for i in range(ni): +# a[:,i] = solveq(K, f, np.array(range(1,9)), ed[i,:])[0] +# #a = np.hstack([a, solveq(K, f, np.hstack([matrix(range(1,9)).T, ed[i,:].T]) ) ]) + + s1, t1 = plants(ex1, ey1, ep, D, np.hstack([a[[0, 1, 2, 3, 8, 9], :].T])) + s2, t2 = plants(ex2, ey2, ep, D, np.hstack([a[[2, 3, 4, 5, 8, 9], :].T])) + s3, t3 = plants(ex3, ey3, ep, D, np.hstack([a[[4, 5, 6, 7, 8, 9], :].T])) + s4, t4 = plants(ex4, ey4, ep, D, np.hstack([a[[6, 7, 0, 1, 8, 9], :].T])) + + es = (s1*A1+s2*A2+s3*A3+s4*A4)/Atot + et = (t1*A1+t2*A2+t3*A3+t4*A4)/Atot + + # [0] because these are 1-by-3 arrays and we want row arrays out. + return es[0], et[0] + + +def plani4e(ex, ey, ep, D, eq=None): + """ + Calculate the stiffness matrix for a 4 node isoparametric + element in plane strain or plane stress. + + Parameters: + ex = [x1 ... x4] element coordinates. Row array + ey = [y1 ... y4] + + ep =[ptype, t, ir] ptype: analysis type + t : thickness + ir: integration rule + + D constitutive matrix + + eq = [bx; by] bx: body force in x direction + by: body force in y direction + Any array with 2 elements acceptable + + Returns: + Ke : element stiffness matrix (8 x 8) + fe : equivalent nodal forces (8 x 1) + """ + ptype = ep[0] + t = ep[1] + ir = ep[2] + ngp = ir*ir + if eq == None: + q = np.zeros((2, 1)) + else: + q = np.reshape(eq, (2, 1)) +#--------- gauss points -------------------------------------- + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.mat([g1, g1]) + w = np.mat([w1, w1]) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.mat([ + [-g1, -g1], + [g1, -g1], + [-g1, g1], + [g1, g1]]) + w = np.mat([ + [w1, w1], + [w1, w1], + [w1, w1], + [w1, w1]]) + elif ir == 3: + g1 = 0.774596669241483 + g2 = 0. + w1 = 0.555555555555555 + w2 = 0.888888888888888 + gp = np.mat([ + [-g1, -g1], + [-g2, -g1], + [g1, -g1], + [-g1, g2], + [g2, g2], + [g1, g2], + [-g1, g1], + [g2, g1], + [g1, g1]]) + w = np.mat([ + [w1, w1], + [w2, w1], + [w1, w1], + [w1, w2], + [w2, w2], + [w1, w2], + [w1, w1], + [w2, w1], + [w1, w1]]) + else: + info("Used number of integrat ion points not implemented") + wp = np.multiply(w[:, 0], w[:, 1]) + xsi = gp[:, 0] + eta = gp[:, 1] + r2 = ngp*2 + # Shape Functions + N = np.multiply((1-xsi), (1-eta))/4. + N = np.append(N, np.multiply((1+xsi), (1-eta))/4., axis=1) + N = np.append(N, np.multiply((1+xsi), (1+eta))/4., axis=1) + N = np.append(N, np.multiply((1-xsi), (1+eta))/4., axis=1) + + dNr = np.mat(np.zeros((r2, 4))) + dNr[0:r2:2, 0] = -(1-eta)/4. + dNr[0:r2:2, 1] = (1-eta)/4. + dNr[0:r2:2, 2] = (1+eta)/4. + dNr[0:r2:2, 3] = -(1+eta)/4. + dNr[1:r2+1:2, 0] = -(1-xsi)/4. + dNr[1:r2+1:2, 1] = -(1+xsi)/4. + dNr[1:r2+1:2, 2] = (1+xsi)/4. + dNr[1:r2+1:2, 3] = (1-xsi)/4. + +# + Ke1 = np.mat(np.zeros((8, 8))) + fe1 = np.mat(np.zeros((8, 1))) + JT = dNr*np.mat([ex, ey]).T + # --------- plane stress -------------------------------------- + if ptype == 1: + colD = np.shape(D)[0] + if colD > 3: + Cm = np.linalg.inv(D) + Dm = np.linalg.inv(Cm[np.ix_([0, 1, 3], [0, 1, 3])]) + else: + Dm = D +# + B = np.matrix(np.zeros((3, 8))) + N2 = np.matrix(np.zeros((2, 8))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobi determinant equal or less than zero!") + JTinv = np.linalg.inv(JT[indx-1, :]) + dNx = JTinv*dNr[indx-1, :] +# + index_array_even = np.array([0, 2, 4, 6]) + index_array_odd = np.array([1, 3, 5, 7]) +# + counter = 0 + for index in index_array_even: + B[0, index] = dNx[0, counter] + B[2, index] = dNx[1, counter] + N2[0, index] = N[i, counter] + counter = counter+1 +# + counter = 0 + for index in index_array_odd: + B[1, index] = dNx[1, counter] + B[2, index] = dNx[0, counter] + N2[1, index] = N[i, counter] + counter = counter+1 +# + Ke1 = Ke1+B.T*Dm*B*detJ*wp[i].item()*t + fe1 = fe1 + N2.T * q * detJ * wp[i].item() * t + + return Ke1, fe1 +#--------- plane strain -------------------------------------- + elif ptype == 2: + # + colD = np.shape(D)[0] + if colD > 3: + Dm = D[np.ix_([0, 1, 3], [0, 1, 3])] + else: + Dm = D +# + B = np.matrix(np.zeros((3, 8))) + N2 = np.matrix(np.zeros((2, 8))) + for i in range(ngp): + indx = np.array([2*(i+1)-1, 2*(i+1)]) + detJ = np.linalg.det(JT[indx-1, :]) + if detJ < 10*np.finfo(float).eps: + info("Jacobideterminant equal or less than zero!") + JTinv = np.linalg.inv(JT[indx-1, :]) + dNx = JTinv*dNr[indx-1, :] +# + index_array_even = np.array([0, 2, 4, 6]) + index_array_odd = np.array([1, 3, 5, 7]) +# + counter = 0 + for index in index_array_even: + # + B[0, index] = dNx[0, counter] + B[2, index] = dNx[1, counter] + N2[0, index] = N[i, counter] +# + counter = counter+1 +# + counter = 0 + for index in index_array_odd: + B[1, index] = dNx[1, counter] + B[2, index] = dNx[0, counter] + N2[1, index] = N[i, counter] + counter = counter+1 +# + Ke1 = Ke1 + B.T * Dm * B * detJ * np.asscalar(wp[i]) * t + fe1 = fe1+N2.T*q*detJ*np.asscalar(wp[i])*t + return Ke1, fe1 + else: + info("Error ! Check first argument, ptype=1 or 2 allowed") + + +def soli8e(ex, ey, ez, ep, D, eqp=None): + """ + Ke=soli8e(ex,ey,ez,ep,D) + [Ke,fe]=soli8e(ex,ey,ez,ep,D,eq) + ------------------------------------------------------------- + PURPOSE + Calculate the stiffness matrix for a 8 node (brick) + isoparametric element. + + INPUT: ex = [x1 x2 x3 ... x8] + ey = [y1 y2 y3 ... y8] element coordinates + ez = [z1 z2 z3 ... z8] + + ep = [ir] ir integration rule + + D constitutive matrix + + eq = [bx; by; bz] bx: body force in x direction + by: body force in y direction + bz: body force in z direction + + OUTPUT: Ke : element stiffness matrix + fe : equivalent nodal forces + ------------------------------------------------------------- + + LAST MODIFIED: M Ristinmaa 1995-10-25 + J Lindemann 2022-01-24 (Python version) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + ir = ep[0] + ngp = ir*ir*ir + + if eqp == None: + eq = np.zeros((3, 1)) + else: + eq = eqp - eseff = np.zeros([nel]) + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.array([g1, g1, g1]).reshape(1, 3) + w = np.array([w1, w1, w1]).reshape(1, 3) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.zeros((8, 3)) + w = np.zeros((8, 3)) + gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 + w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 + w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 + w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + else: + g1 = 0.774596669241483, + g2 = 0.0 + w1 = 0.555555555555555 + w2 = 0.888888888888888 - if ptype == 1: - sigxx = es[:, 0] - sigyy = es[:, 1] - sigxy = es[:, 2] - eseff = np.sqrt(sigxx*sigxx+sigyy*sigyy-sigxx*sigyy+3*sigxy*sigxy) - return eseff + gp = np.zeros((27, 3)) + w = np.zeros((27, 3)) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) -def stress2nodal(eseff, edof): - """ - Convert element effective stresses to nodal effective - stresses. - - Parameters: - - eseff = [eseff_0 .. eseff_nel-1] - edof = [dof topology array] - - Returns: - - ev: element value array [[ev_0_0 ev_0_1 ev_0_nen-1 ] - .. - ev_nel-1_0 ev_nel-1_1 ev_nel-1_nen-1] - - """ + gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] - values = np.zeros(edof.max()) - elnodes = int(np.size(edof, 1) / 2) + I1 = np.abs(I1) + I2 = np.abs(I2) - for etopo, eleseff in zip(edof, eseff): - values[etopo-1] = values[etopo-1] + eleseff / elnodes + w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] - evtemp = extractEldisp(edof, values) - ev = evtemp[:, range(0, elnodes*2, 2)] + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) - return ev + gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] + I1 = np.abs(I1) + I2 = np.abs(I2) -def beam2crd_old(ex, ey, ed, mag): - """ - ------------------------------------------------------------- - PURPOSE - Calculate the element continous displacements for a - number of identical 2D Bernoulli beam elements. - - INPUT: ex,ey, - ed, - mag - - OUTPUT: excd,eycd - ------------------------------------------------------------- + w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] - LAST MODIFIED: P-E AUSTRELL 1993-10-15 - J Lindemann 2021-12-30 (Python) + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) + I3 = np.abs(I1) - Copyright (c) Division of Structural Mechanics and - Division of Solid Mechanics. - Lund University - ------------------------------------------------------------- - """ - nie, ned = ed.shape + gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 + gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] - excd = np.zeros([nie, 20]) - eycd = np.zeros([nie, 20]) + w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 + w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] - for i in range(nie): + wp = w[:, 0]*w[:, 1]*w[:, 2] - b = np.array([ex[i, 1]-ex[i, 0], ey[i, 1]-ey[i, 0]]) - L = np.asscalar(np.sqrt(b@np.transpose(b))) - n = b/L + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 - G = np.array([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + N = np.zeros((ngp, 8)) + dNr = np.zeros((r2, 8)) - d = ed[i, :] - dl = G @ d + N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 + N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 + N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 + N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 + N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 + N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 + N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 + N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 - xl = np.linspace(0.0, L, 20) - one = np.ones(xl.shape) + dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) + dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) + dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) + dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) + dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) + dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) + dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) + dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) + dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) + dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) + dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) + dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) + dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) + dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) + dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) + dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) + dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) + dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) + dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) + dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) + dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) + dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) + dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) + dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) - Cis = np.array([ - [-1.0, 1.0], - [L, 0.0] - ]) / L + dNr = dNr/8.0 - ds = np.array([dl[0], dl[3]]).reshape(2, 1) + Ke = np.zeros((24, 24)) + fe = np.zeros((24, 1)) - xl_one = np.transpose(np.vstack((xl, one))) + ex = np.asarray(ex).reshape((8, 1)) + ey = np.asarray(ey).reshape((8, 1)) + ez = np.asarray(ez).reshape((8, 1)) - ul = np.transpose(xl_one@Cis@ds) # [20x1][2] + JT = dNr@np.concatenate((ex, ey, ez), axis=1) - Cib = np.array([ - [12, 6*L, -12, 6*L], - [-6*L, -4*L**2, 6*L, -2*L**2], - [0, L**3, 0, 0], - [L**3, 0, 0, 0] - ])/L**3 + eps = np.finfo(float).eps - db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) - vl = np.transpose(np.transpose( - np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) + for i in range(ngp): + indx = [i*3, i*3+1, i*3+2] + detJ = np.linalg.det(JT[indx, :]) + if detJ < 10*eps: + print('Jacobideterminant equal or less than zero!') + JTinv = np.linalg.inv(JT[indx, :]) + dNx = JTinv@dNr[indx, :] - cld = np.vstack((ul, vl)) - A = np.array([ - [n[0], -n[1]], - [n[1], n[0]] - ]) - cd = A@cld + B = np.zeros((6, 24)) + N2 = np.zeros((3, 24)) - # [2,1] x [1,20] + [2 x 1] x [1 x 20] - # [2 x 20] + [2 x 20] + B[0, 0:24:3] = dNx[0, :] + B[1, 1:25:3] = dNx[1, :] + B[2, 2:26:3] = dNx[2, :] + B[3, 0:24:3] = dNx[1, :] + B[3, 1:25:3] = dNx[0, :] + B[4, 0:24:3] = dNx[2, :] + B[4, 2:26:3] = dNx[0, :] + B[5, 1:25:3] = dNx[2, :] + B[5, 2:26:3] = dNx[1, :] - AA = A[:, 0].reshape(2, 1) - XL = xl.reshape(1, 20) - xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]])@one.reshape(1, 20) + N2[0, 0:24:3] = N[i, :] + N2[1, 1:25:3] = N[i, :] + N2[2, 2:26:3] = N[i, :] - excd[i, :] = xyc[0, :]+mag*cd[0, :] - eycd[i, :] = xyc[1, :]+mag*cd[1, :] + Ke = Ke + (np.transpose(B)@D@B)*detJ*wp[i] + fe = fe + (np.transpose(N2)@eq)*detJ*wp[i] - return excd, eycd + if eqp != None: + return Ke, fe + else: + return Ke -def beam2crd(ex=None, ey=None, ed=None, mag=None): +def soli8s(ex, ey, ez, ep, D, ed): """ + [es,et]=soli8s(ex,ey,ez,ep,D,ed) ------------------------------------------------------------- - PURPOSE - Calculate the element continous displacements for a - number of identical 2D Bernoulli beam elements. + PURPOSE + Calculate element normal and shear stress for a + 8 node (brick) isoparametric element. - INPUT: ex,ey, - ed, - mag + INPUT: ex = [x1 x2 x3 ... x8] + ey = [y1 y2 y3 ... y8] element coordinates + ez = [z1 z2 z3 ... z8] - OUTPUT: excd,eycd - ------------------------------------------------------------- + ep = [Ir] Ir: integration rule + + D constitutive matrix + + ed = [u1 u2 ..u24] element displacement vector + + OUTPUT: es = [ sigx sigy sigz sigxy sigyz sigxz ; + ...... ... ] + element stress matrix, one row for each + integration point - LAST MODIFIED: P-E AUSTRELL 1993-10-15 - Copyright (c) Division of Structural Mechanics and + es = [ eps epsy epsz epsxy epsyz epsxz ; + ...... ... ] + element strain matrix, one row for each + integration point + ------------------------------------------------------------- + + LAST MODIFIED: M Ristinmaa 1995-10-25 + J Lindemann 2022-02-23 (Python version) + + Copyright (c) Division of Structural Mechanics and Division of Solid Mechanics. Lund University ------------------------------------------------------------- """ - nie, ned = ed.shape - - n_coords = 21 + ir = ep[0] + ngp = ir*ir*ir - excd = np.zeros([nie, n_coords]) - eycd = np.zeros([nie, n_coords]) + ir = ep[0] + ngp = ir*ir*ir - for i in range(nie): - b = np.array([ex[i, 1] - ex[i, 0], ey[i, 1] - ey[i, 0]]) - L = np.sqrt(b @ np.transpose(b)) - n = b / L + if ir == 1: + g1 = 0.0 + w1 = 2.0 + gp = np.array([g1, g1, g1]).reshape(1, 3) + w = np.array([w1, w1, w1]).reshape(1, 3) + elif ir == 2: + g1 = 0.577350269189626 + w1 = 1 + gp = np.zeros((8, 3)) + w = np.zeros((8, 3)) + gp[:, 0] = np.array([-1, 1, 1, -1, -1, 1, 1, -1])*g1 + w[:, 0] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 1] = np.array([-1, -1, 1, 1, -1, -1, 1, 1])*g1 + w[:, 1] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + gp[:, 2] = np.array([-1, -1, -1, -1, 1, 1, 1, 1])*g1 + w[:, 2] = np.array([1, 1, 1, 1, 1, 1, 1, 1])*w1 + else: + g1 = 0.774596669241483, + g2 = 0.0 + w1 = 0.555555555555555 + w2 = 0.888888888888888 - G = np.array([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, - n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + gp = np.zeros((27, 3)) + w = np.zeros((27, 3)) - d = np.transpose(ed[i, :]) - dl = G @ d - xl = np.transpose(np.linspace(0, L, n_coords)) - one = np.ones(xl.shape) + I1 = np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]).reshape(1, 9) + I2 = np.array([0, -1, 0, 0, 1, 0, 0, 1, 0]).reshape(1, 9) - Cis = np.array([ - [-1, 1], - [L, 0] - ]) / L + gp[:, 0] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 0] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 0] - ds = np.array([dl[0], dl[3]]).reshape(2, 1) - xl_one = np.transpose(np.vstack((xl, one))) - ul = np.transpose(xl_one@Cis@ds) # [20x1][2] + I1 = np.abs(I1) + I2 = np.abs(I2) - Cib = np.array([ - [12, 6 * L, - 12, 6 * L], - [- 6 * L, - 4 * L ** 2, 6 * L, - 2 * L ** 2], - [0, L ** 3, 0, 0], - [L ** 3, 0, 0, 0] - ]) / L ** 3 + w[:, 0] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 0] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 0] - db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) - vl = np.transpose(np.transpose( - np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) + I1 = np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]).reshape(1, 9) - cld = np.vstack((ul, vl)) - A = np.array([ - [n[0], -n[1]], - [n[1], n[0]] - ]) - cd = A@cld + gp[:, 1] = np.concatenate((I1, I1, I1), axis=1)*g1 + gp[:, 1] = np.concatenate((I2, I2, I2), axis=1)*g2 + gp[:, 1] - # [2,1] x [1,20] + [2 x 1] x [1 x 20] - # [2 x 20] + [2 x 20] + I1 = np.abs(I1) + I2 = np.abs(I2) - AA = A[:, 0].reshape(2, 1) - XL = xl.reshape(1, n_coords) - xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]] - )@one.reshape(1, n_coords) + w[:, 1] = np.concatenate((I1, I1, I1), axis=1)*w1 + w[:, 1] = np.concatenate((I2, I2, I2), axis=1)*w2 + w[:, 1] - excd[i, :] = xyc[0, :]+mag*cd[0, :] - eycd[i, :] = xyc[1, :]+mag*cd[1, :] + I1 = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1]).reshape(1, 9) + I2 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0]).reshape(1, 9) + I3 = np.abs(I1) - return excd, eycd + gp[:, 2] = np.concatenate((I1, I2, I3), axis=1)*g1 + gp[:, 2] = np.concatenate((I2, I3, I2), axis=1)*g2 + gp[:, 2] -# ----------------------------------------------------------------- -# ----------------------------------------------------------------- -# ----------------------------------------------------------------- -# ----------------------------------------------------------------- + w[:, 2] = np.concatenate((I3, I2, I3), axis=1)*w1 + w[:, 2] = np.concatenate((I2, I3, I2), axis=1)*w2 + w[:, 2] -def _spring1e(ep): - """ - Compute element stiffness matrix for spring element. - - :param float ep: spring stiffness or analog quantity (ep = k). - :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 - """ - k = ep - return np.mat([[k, -k], [-k, k]], 'd') + wp = w[:, 0]*w[:, 1]*w[:, 2] + xsi = gp[:, 0] + eta = gp[:, 1] + zet = gp[:, 2] + r2 = ngp*3 -def _spring1s(ep, ed): - """ - Compute element force in spring element (spring1e). - - :param float ep: spring stiffness or analog quantity - :param list ed: element displacements [d0, d1] - :return float es: element force [N] - """ - k = ep - return k*(ed[1]-ed[0]) + N = np.zeros((ngp, 8)) + dNr = np.zeros((r2, 8)) + N[:, 0] = (1-xsi)*(1-eta)*(1-zet)/8 + N[:, 1] = (1+xsi)*(1-eta)*(1-zet)/8 + N[:, 2] = (1+xsi)*(1+eta)*(1-zet)/8 + N[:, 3] = (1-xsi)*(1+eta)*(1-zet)/8 + N[:, 4] = (1-xsi)*(1-eta)*(1+zet)/8 + N[:, 5] = (1+xsi)*(1-eta)*(1+zet)/8 + N[:, 6] = (1+xsi)*(1+eta)*(1+zet)/8 + N[:, 7] = (1-xsi)*(1+eta)*(1+zet)/8 -def _bar1e(ep): - """ - Compute element stiffness matrix for spring element. - - :param ep float: spring stiffness or analog quantity - :return mat Ke: stiffness matrix, dim(Ke)= 2 x 2 - """ - k = ep - return np.mat([[k, -k], [-k, k]], 'd') + dNr[0:r2+1:3, 0] = -(1-eta)*(1-zet) + dNr[0:r2+1:3, 1] = (1-eta)*(1-zet) + dNr[0:r2+1:3, 2] = (1+eta)*(1-zet) + dNr[0:r2+1:3, 3] = -(1+eta)*(1-zet) + dNr[0:r2+1:3, 4] = -(1-eta)*(1+zet) + dNr[0:r2+1:3, 5] = (1-eta)*(1+zet) + dNr[0:r2+1:3, 6] = (1+eta)*(1+zet) + dNr[0:r2+1:3, 7] = -(1+eta)*(1+zet) + dNr[1:r2+2:3, 0] = -(1-xsi)*(1-zet) + dNr[1:r2+2:3, 1] = -(1+xsi)*(1-zet) + dNr[1:r2+2:3, 2] = (1+xsi)*(1-zet) + dNr[1:r2+2:3, 3] = (1-xsi)*(1-zet) + dNr[1:r2+2:3, 4] = -(1-xsi)*(1+zet) + dNr[1:r2+2:3, 5] = -(1+xsi)*(1+zet) + dNr[1:r2+2:3, 6] = (1+xsi)*(1+zet) + dNr[1:r2+2:3, 7] = (1-xsi)*(1+zet) + dNr[2:r2+3:3, 0] = -(1-xsi)*(1-eta) + dNr[2:r2+3:3, 1] = -(1+xsi)*(1-eta) + dNr[2:r2+3:3, 2] = -(1+xsi)*(1+eta) + dNr[2:r2+3:3, 3] = -(1-xsi)*(1+eta) + dNr[2:r2+3:3, 4] = (1-xsi)*(1-eta) + dNr[2:r2+3:3, 5] = (1+xsi)*(1-eta) + dNr[2:r2+3:3, 6] = (1+xsi)*(1+eta) + dNr[2:r2+3:3, 7] = (1-xsi)*(1+eta) + dNr = dNr/8.0 -def _bar1s(ep, ed): - """ - Compute element force in spring element (spring1e). - - :param float ep: spring stiffness or analog quantity - :param list ed: element displacements [d0, d1] - :return float es: element force - """ - k = ep - return k*(ed[1]-ed[0]) + ex = np.asarray(ex).reshape((8, 1)) + ey = np.asarray(ey).reshape((8, 1)) + ez = np.asarray(ez).reshape((8, 1)) + JT = dNr@np.concatenate((ex, ey, ez), axis=1) -def _bar2e(ex, ey, ep): - """ - Compute the element stiffness matrix for two dimensional bar element. + eps = np.finfo(float).eps - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: [E, A]: E - Young's modulus, A - Cross section area - :return mat Ke: stiffness matrix, [4 x 4] - """ - E = ep[0] - A = ep[1] - - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - - Kle = np.mat([[1., -1.], [-1., 1.]])*E*A/L - - n = np.asarray(b.T/L).reshape(2,) - - G = np.mat([ - [n[0], n[1], 0., 0.], - [0., 0., n[0], n[1]] - ]) - - return G.T*Kle*G + eci = N@np.concatenate((ex, ey, ez), axis=1) + et = np.zeros((ngp, 6)) + es = np.zeros((ngp, 6)) + ed = ed.reshape(1, 24) -def _bar2g(ex, ey, ep, N): - """ - Compute element stiffness matrix for two dimensional geometric - nonlinear bar element. - - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :param float N: normal force - :return mat Ke: stiffness matrix [4 x 4] - """ - E = ep[0] - A = ep[1] + for i in range(ngp): + indx = [i*3, i*3+1, i*3+2] + detJ = np.linalg.det(JT[indx, :]) + if detJ < 10*eps: + print('Jacobideterminant equal or less than zero!') + JTinv = np.linalg.inv(JT[indx, :]) + dNx = JTinv@dNr[indx, :] - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) + B = np.zeros((6, 24)) + N2 = np.zeros((3, 24)) - L = np.sqrt(b.T*b).item() + B[0, 0:24:3] = dNx[0, :] + B[1, 1:25:3] = dNx[1, :] + B[2, 2:26:3] = dNx[2, :] + B[3, 0:24:3] = dNx[1, :] + B[3, 1:25:3] = dNx[0, :] + B[4, 0:24:3] = dNx[2, :] + B[4, 2:26:3] = dNx[0, :] + B[5, 1:25:3] = dNx[2, :] + B[5, 2:26:3] = dNx[1, :] - n = np.asarray(b.T/L).reshape(2,) + N2[0, 0:24:3] = N[i, :] + N2[1, 1:25:3] = N[i, :] + N2[2, 2:26:3] = N[i, :] - G = np.mat([ - [n[0], n[1], 0., 0.], - [-n[1], n[0], 0., 0.], - [0., 0., n[0], n[1]], - [0., 0., -n[1], n[0]] - ]) + # [6x24] x [24,1] + ee = B@np.transpose(ed) - Kle = E*A/L*np.mat([ - [1, 0, -1, 0], - [0, 0, 0, 0], - [-1, 0, 1, 0], - [0, 0, 0, 0] - ])+N/L*np.mat([ - [0, 0, 0, 0], - [0, 1, 0, -1], - [0, 0, 0, 0], - [0, -1, 0, 1] - ]) + et[i, :] = ee.reshape(6,) + es[i, :] = (D@ee).reshape(6,) - return G.T*Kle*G + return et, es, eci -def _bar2s(ex, ey, ep, ed): +def assem(edof, K, Ke, f=None, fe=None): """ - Compute normal force in two dimensional bar element. + Assemble element matrices Ke ( and fe ) into the global + stiffness matrix K ( and the global force vector f ) + according to the topology matrix edof. + + Parameters: + + edof dof topology array + K the global stiffness matrix + Ke element stiffness matrix + f the global force vector + fe element force vector + + Output parameters: + + K the new global stiffness matrix + f the new global force vector + fe element force vector - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :param list ed: element displacements [u1, u2, u3, u4] - :return float N: element foce [N] """ - E = ep[0] - A = ep[1] - - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - - #Kle = np.mat([[1.,-1.],[-1.,1.]])*E*A/L - n = np.asarray(b.T/L).reshape(2,) - - G = np.mat([ - [n[0], n[1], 0., 0.], - [0., 0., n[0], n[1]] - ]) + if edof.ndim == 1: + idx = edof-1 + K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke + if (not f is None) and (not fe is None): + f[np.ix_(idx)] = f[np.ix_(idx)] + fe + else: + for row in edof: + idx = row-1 + K[np.ix_(idx, idx)] = K[np.ix_(idx, idx)] + Ke + if (not f is None) and (not fe is None): + f[np.ix_(idx)] = f[np.ix_(idx)] + fe - u = np.asmatrix(ed).T - N = E*A/L*np.mat([[-1., 1.]])*G*u - return N.item() + if f is None: + return K + else: + return K, f -def _bar2gs(ex, ey, ep, ed): +def solveq(K, f, bcPrescr, bcVal=None): """ - Calculate section forces in a two dimensional geometric - nonlinear bar element (bar2g). + Solve static FE-equations considering boundary conditions. + Parameters: - ex = [x1 x2] element node coordinates - ey = [y1 y2] - - ep = [E A] element properties; - E: Young's modulus - A: cross section area - - ed = [u1 ... u4] element displacement vector - + + K global stiffness matrix, dim(K)= nd x nd + f global load vector, dim(f)= nd x 1 + + bcPrescr 1-dim integer array containing prescribed dofs. + bcVal 1-dim float array containing prescribed values. + If not given all prescribed dofs are assumed 0. + Returns: - es = [N1; - N2 ] section forces, local directions - - QX: axial force - - edi = [ u1 ; element displacements, local directions, - u2 ; in n points along the bar, dim(es)= n x 1 - ...] - - eci = [ x1 ; local x-coordinates of the evaluation - x2 ; points, (x1=0 and xn=L) - ...] + + a solution including boundary values + Q reaction force vector + dim(a)=dim(Q)= nd x 1, nd : number of dof's + """ - EA = ep[0]*ep[1] - ne = 2 - - dx = ex[1] - ex[0] - dy = ey[1] - ey[0] - L = np.sqrt(dx**2 + dy**2) - - n = [dx/L, dy/L, -dy/L, dx/L] - G = np.array([ - [n[0], n[1], 0., 0.], - [n[2], n[3], 0., 0.], - [0., 0., n[0], n[1]], - [0., 0., n[2], n[3]] - ]) - - edl = G@ed.reshape(-1,1) - a1 = np.array([edl[0], edl[2]]).reshape(-1,1) - - C1 = np.array([[1., 0.,], - [-1/L, 1/L]]) - C1a = C1@a1 - x = np.linspace(0,L,ne).reshape(-1,1) - zero = np.zeros(x.shape) - one = np.ones(x.shape) - - u = np.concatenate((one, x),axis=1)@C1a - du = np.concatenate((zero, one),axis=1)@C1a - - N = EA*du - return N, N[0].item(), u, x + nDofs = K.shape[0] + nPdofs = bcPrescr.shape[0] + if bcVal is None: + bcVal = np.zeros([nPdofs], 'd') -def _bar3e(ex, ey, ez, ep): - """ - Compute element stiffness matrix for three dimensional bar element. - - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ez: element z coordinates [z1, z2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :return mat Ke: stiffness matrix, [6 x 6] - """ - E = ep[0] - A = ep[1] + bc = np.ones(nDofs, 'bool') + bcDofs = np.arange(nDofs) - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() + bc[np.ix_(bcPrescr-1)] = False + bcDofs = bcDofs[bc] - n = np.asarray(b.T/L).reshape(3) + fsys = f[bcDofs]-K[np.ix_((bcDofs), (bcPrescr-1))] * \ + np.asmatrix(bcVal).reshape(nPdofs, 1) + asys = np.linalg.solve(K[np.ix_((bcDofs), (bcDofs))], fsys) - G = np.mat([ - [n[0], n[1], n[2], 0., 0., 0.], - [0., 0., 0., n[0], n[1], n[2]] - ]) + a = np.zeros([nDofs, 1]) + a[np.ix_(bcPrescr-1)] = np.asmatrix(bcVal).reshape(nPdofs, 1) + a[np.ix_(bcDofs)] = asys - Kle = E*A/L*np.mat([ - [1, -1], - [-1, 1] - ]) + Q = K*np.asmatrix(a)-f - return G.T*Kle*G + return (np.asmatrix(a), Q) -def _bar3s(ex, ey, ez, ep, ed): +def spsolveq(K, f, bcPrescr, bcVal=None): """ - Compute normal force in three dimensional bar element. + Solve static FE-equations considering boundary conditions. + + Parameters: + + K global stiffness matrix, dim(K)= nd x nd + f global load vector, dim(f)= nd x 1 + + bcPrescr 1-dim integer array containing prescribed dofs. + bcVal 1-dim float array containing prescribed values. + If not given all prescribed dofs are assumed 0. + + Returns: + + a solution including boundary values + Q reaction force vector + dim(a)=dim(Q)= nd x 1, nd : number of dof's - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ez: element z coordinates [z1, z2] - :param list ep: element properties [E, A], E - Young's modulus, A - Cross section area - :param list ed: element displacements [u1, ..., u6] - :return float N: normal force """ - E = ep[0] - A = ep[1] - - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(3) + nDofs = K.shape[0] + nPdofs = bcPrescr.shape[0] - G = np.mat([ - [n[0], n[1], n[2], 0., 0., 0.], - [0., 0., 0., n[0], n[1], n[2]] - ]) + if bcVal is None: + bcVal = np.zeros([nPdofs], 'd') - #Kle = E*A/L*np.mat([ - # [ 1,-1], - # [-1, 1] - #]) + bc = np.ones(nDofs, 'bool') + bcDofs = np.arange(nDofs) - u = np.asmatrix(ed).T - N = E*A/L*np.mat([[-1., 1.]])*G*u + bc[np.ix_(bcPrescr-1)] = False + bcDofs = bcDofs[bc] - return N.item() + bcVal_m = np.asmatrix(bcVal).reshape(nPdofs, 1) -def _beam1e(ex, ep, eq=None): - """ - Compute the stiffness matrix for a one dimensional beam element. + info("Preparing system matrix...") - :param list ex: element x coordinates [x1, x2] - :param list ep: element properties [E, I], E - Young's modulus, I - Moment of inertia - :param float eq: distributed load [qy] - :return mat Ke: element stiffness matrix [4 x 4] - :return mat fe: element load vector [4 x 1] (if eq!=None) - """ - L = ex[1]-ex[0] + mask = np.ones(K.shape[0], dtype=bool) + mask[bcDofs] = False - E = ep[0] - I = ep[1] + info("step 1... converting K->CSR") + Kcsr = K.asformat("csr") + info("step 2... Kt") + #Kt1 = K[bcDofs] + #Kt = Kt1[:,bcPrescr] + Kt = K[np.ix_((bcDofs), (bcPrescr-1))] + info("step 3... fsys") + fsys = f[bcDofs]-Kt*bcVal_m + info("step 4... Ksys") + Ksys1 = Kcsr[bcDofs] + Ksys = Ksys1[:, bcDofs] + #Ksys = Kcsr[np.ix_((bcDofs),(bcDofs))] + info("done...") - qy = 0. - if eq: - qy = eq + info("Solving system...") + asys = dsolve.spsolve(Ksys, fsys) - Ke = E*I/(L**3) * np.mat([ - [12, 6*L, -12, 6*L], - [6*L, 4*L**2, -6*L, 2*L**2], - [-12, -6*L, 12, -6*L], - [6*L, 2*L**2, -6*L, 4*L**2] - ]) + info("Reconstructing full a...") + a = np.zeros([nDofs, 1]) + a[np.ix_(bcPrescr-1)] = bcVal_m + a[np.ix_(bcDofs)] = np.asmatrix(asys).transpose() - fe = qy*np.mat([L/2, L**2/12, L/2, -L**2/12]).T + a_m = np.asmatrix(a) + Q = K*a_m-f + info("done...") + return (a_m, Q) - if eq is None: - return Ke - else: - return Ke, fe -def _beam1s(ex, ep, ed, eq=None, nep=None): +def eigen(K,M,b=None): """ - Compute section forces in one dimensional beam element (beam1e). + Solve the generalized eigenvalue problem + |K-LM|X = 0, considering boundary conditions Parameters: - ex = [x1 x2] element node coordinates - - ep = [E I] element properties, - E: Young's modulus - I: moment of inertia - - ed = [u1 ... u4] element displacements - - eq = qy distributed load, local directions - - nep number of evaluation points ( default=2 ) + K global stiffness matrix, dim(K) = ndof x ndof + M global mass matrix, dim(M) = ndof x ndof + b boundary condition vector, dim(b) = nbc x 1 Returns: - es = [ V1 M1 section forces, local directions, in - V2 M2 n points along the beam, dim(es)= n x 2 - .........] - - edi = [ v1 element displacements, local directions, - v2 in n points along the beam, dim(es)= n x 1 - .......] - - eci = [ x1 local x-coordinates of the evaluation - x2 points, (x1=0 and xn=L) - ...] - + L eigenvalue vector, dim(L) = (ndof-nbc) x 1 + X eigenvectors, dim(X) = ndof x (ndof-nbc) """ - EI = ep[0]*ep[1] - L = ex[1]-ex[0] - - qy = 0. - - if eq: - qy = eq - - ne = 2 - - if nep != None: - ne = nep - - Cinv = np.mat([ - [1, 0, 0, 0], - [0, 1, 0, 0], - [-3/(L**2), -2/L, 3/(L**2), -1/L], - [2/(L**3), 1/(L**2), -2/(L**3), 1/(L**2)] - ]) - - Ca = (Cinv@ed).T - - x = np.asmatrix(np.linspace(0., L, nep)).T - zero = np.asmatrix(np.zeros([len(x)])).T - one = np.asmatrix(np.ones([len(x)])).T - - v = np.concatenate((one, x, np.power(x, 2), np.power(x, 3)), 1)@Ca \ - + qy/(24*EI)*(np.power(x,4) - 2*L*np.power(x,3) + (L**2)*np.power(x,2)) - d2v = np.concatenate((zero, zero, 2*one, 6*x), 1)@Ca \ - + qy/(12*EI)*(6*np.power(x,2) - 6*L*x + L**2) - d3v = np.concatenate((zero, zero, zero, 6*one), 1)@Ca + qy/(2*EI)*(2*x - L) - - M = EI*d2v - V = -EI*d3v - edi = v - eci = x - es = np.concatenate((V, M), 1) - - return (es, edi, eci) - + nd, _ = K.shape + if b is not None: + fdof = np.setdiff1d(np.arange(nd), b-1) + D, X1 = eig(K[np.ix_(fdof,fdof)], M[np.ix_(fdof,fdof)]) + D = np.real(D) + nfdof, _ = X1.shape + for j in range(nfdof): + mnorm = np.sqrt(X1[:,j].T@M[np.ix_(fdof,fdof)]@X1[:,j]) + X1[:,j] /= mnorm + s_order = np.argsort(D) + L = np.sort(D) + X2 = np.zeros(X1.shape) + for ind,j in enumerate(s_order): + X2[:,ind] = X1[:,j] + X = np.zeros((nd,nfdof)) + X[fdof,:] = X2 + return L, X + else: + D, X1 = eig(K, M) + D = np.real(D) + for j in range(nd): + mnorm = np.sqrt(X1[:,j].T@M@X1[:,j]) + X1[:,j] /= mnorm + s_order = np.argsort(D) + L = np.sort(D) + X = np.copy(X1) + for ind,j in enumerate(s_order): + X[:,ind] = X1[:,j] + return L, X -def _beam2e(ex, ey, ep, eq=None): - """ - Compute the stiffness matrix for a two dimensional beam element. - - :param list ex: element x coordinates [x1, x2] - :param list ey: element y coordinates [y1, y2] - :param list ep: element properties [E, A, I], E - Young's modulus, A - Cross section area, I - Moment of inertia - :param list eq: distributed loads, local directions [qx, qy] - :return mat Ke: element stiffness matrix [6 x 6] - :return mat fe: element stiffness matrix [6 x 1] (if eq!=None) +def gfunc(G,dt): """ + Form vector with function values at equally spaced + points by linear interpolation - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2,) - - E = ep[0] - A = ep[1] - I = ep[2] - - qx = 0. - qy = 0. - if not eq is None: - qx = eq[0] - qy = eq[1] - - Kle = np.mat([ - [E*A/L, 0., 0., -E*A/L, 0., 0.], - [0., 12*E*I/L**3., 6*E*I/L**2., 0., -12*E*I/L**3., 6*E*I/L**2.], - [0., 6*E*I/L**2., 4*E*I/L, 0., -6*E*I/L**2., 2*E*I/L], - [-E*A/L, 0., 0., E*A/L, 0., 0.], - [0., -12*E*I/L**3., -6*E*I/L**2., 0., 12*E*I/L**3., -6*E*I/L**2.], - [0., 6*E*I/L**2., 2*E*I/L, 0., -6*E*I/L**2., 4*E*I/L] - ]) - - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + Parameters: - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] - ]) + G = [t_i, g_i] t_i: time i, g_i: g(t_i) + dim(G) = np x 2, np = number of points + dt time step - Ke = G.T*Kle*G - fe = G.T*fle + Returns: - if eq is None: - return Ke - else: - return Ke, fe + t 1-D vector with equally spaced time points + g 1-D vector with corresponding function values + """ + ti = np.arange(G[0,0],G[-1,0]+dt,dt) + g1 = np.interp(ti,G[:,0],G[:,1]) + return ti, g1 -def _beam2s(ex, ey, ep, ed, eq=None, nep=None): +def step1(K,C,f,a0,bc,ip,times,dofs): """ - Compute section forces in two dimensional beam element (beam2e). - - Parameters: - - ex = [x1 x2] - ey = [y1 y2] element node coordinates - - ep = [E A I] element properties, - E: Young's modulus - A: cross section area - I: moment of inertia + Algorithm for dynamic solution of first-order + FE equations considering boundary conditions. - ed = [u1 ... u6] element displacements + Parameters: - eq = [qx qy] distributed loads, local directions + K conductivity matrix, dim(K) = ndof x ndof + C capacity matrix, dim(C) = ndof x ndof + f load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial vector a(0), dim(a0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha], where + dt is the size of the time increment, + tottime is the total time, + alpha is time integration constant. + Frequently used values of alpha are: + alpha=0: forward difference; forward Euler, + alpha=1/2: trapezoidal rule; Crank-Nicholson + alpha=1: backward difference; backward Euler + times array [t(i) ...] of times at which output should be written to a and da + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist and dahist - nep number of evaluation points ( default=2 ) - Returns: - - es = [ N1 V1 M1 section forces, local directions, in - N2 V2 M2 n points along the beam, dim(es)= n x 3 - .........] - - edi = [ u1 v1 element displacements, local directions, - u2 v2 in n points along the beam, dim(es)= n x 2 - .......] - eci = [ x1 local x-coordinates of the evaluation - x2 points, (x1=0 and xn=L) - ...] - + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains values of a at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains values of da at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains time history of a at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains time history of daat the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) """ - EA = ep[0]*ep[1] - EI = ep[0]*ep[2] - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2,) - - qx = 0. - qy = 0. - - if not eq is None: - qx = eq[0] - qy = eq[1] - - ne = 2 - - if nep != None: - ne = nep + ndof, _ = K.shape + dt, tottime, alpha = ip + a1 = (1-alpha)*dt + a2 = alpha*dt - C = np.mat([ - [0., 0., 0., 1., 0., 0.], - [0., 0., 0., 0., 0., 1.], - [0., 0., 0., 0., 1., 0.], - [L, 0., 0., 1., 0., 0.], - [0., L**3, L**2, 0., L, 1.], - [0., 3*L**2, 2*L, 0., 1., 0.] - ]) + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] - ]) + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 - M = np.ravel(C.I*(G*np.asmatrix(ed).T - - np.matrix([0., 0., 0., -qx*L**2/(2*EA), qy*L**4/(24*EI), qy*L**3/(6*EI)]).T)) - A = np.matrix([M[0], M[3]]).T - B = np.matrix([M[1], M[2], M[4], M[5]]).T - - x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T - zero = np.asmatrix(np.zeros([len(x)])).T - one = np.asmatrix(np.ones([len(x)])).T - - u = np.concatenate((x, one), 1)*A-np.power(x, 2)*qx/(2*EA) - du = np.concatenate((one, zero), 1)*A-x*qx/EA - v = np.concatenate((np.power(x, 3), np.power(x, 2), x, - one), 1)*B+np.power(x, 4)*qy/(24*EI) - d2v = np.concatenate((6*x, 2*one, zero, zero), 1) * \ - B+np.power(x, 2)*qy/(2*EI) - d3v = np.concatenate((6*one, zero, zero, zero), 1)*B+x*qy/EI - - N = EA*du - M = EI*d2v - V = -EI*d3v - edi = np.concatenate((u, v), 1) - eci = x - es = np.concatenate((N, V, M), 1) + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns - return (es, edi, eci) + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) -def _beam2t(ex, ey, ep, eq=None): - """ - Compute the stiffness matrix for a two dimensional elastic - Timoshenko beam element. - - Parameters: - - ex = [x1 x2] - ey = [y1 y2] element node coordinates - - ep = [E G A I ks] element properties - E: Young's modulus - G: Shear modulus - A: Cross section area - I: Moment of inertia - ks: Shear correction factor - - eq = [qx qy] distributed loads, local directions - - Returns: - - Ke element stiffness matrix (6 x 6) - - fe element load vector (6 x 1) - - """ + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2) + itime = 0 - E = ep[0] - Gm = ep[1] - A = ep[2] - I = ep[3] - ks = ep[4] + # Calculate initial second time derivative d2a0 + da0 = np.linalg.solve(C,tf[:,0].reshape(-1,1) - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + itime += 1 - qx = 0. - qy = 0. - if eq != None: - qx = eq[0] - qy = eq[1] - - m = (12/L**2)*(E*I/(Gm*A*ks)) - - Kle = E/(1+m)*np.mat([ - [A*(1+m)/L, 0., 0., -A*(1+m)/L, 0., 0.], - [0., 12*I/L**3., 6*I/L**2., 0., -12*I/L**3., 6*I/L**2.], - [0., 6*I/L**2., 4*I * - (1+m/4.)/L, 0., -6*I/L**2., 2*I*(1-m/2)/L], - [-A*(1+m)/L, 0., 0., - A*(1+m)/L, 0., 0.], - [0., -12*I/L**3., -6*I/L**2., - 0., 12*I/L**3., -6*I/L**2.], - [0., 6*I/L**2., 2*I * - (1-m/2)/L, 0., -6*I/L**2., 4*I*(1+m/4)/L] - ]) + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = C[np.ix_(fdof,fdof)] + a2*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = C + a2*K - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] - ]) + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] - Ke = G.T*Kle*G - fe = G.T*fle + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + apred = aold + a1*daold + if not bound: + reff = tf[:,j].reshape(-1,1) - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + danew = np.linalg.solve(U,y) + anew = apred + a2*danew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() - if eq == None: - return Ke - else: - return Ke, fe + return modelhist, dofhist -def _beam2ts(ex, ey, ep, ed, eq=None, nep=None): +def step2(K,C,M,f,a0,da0,bc,ip,times,dofs): """ - Compute section forces in two dimensional beam element (beam2e). - - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - - ep = [E,G,A,I,ks] element properties, - E: Young's modulus - G: shear modulus - A: cross section area - I: moment of inertia + Algorithm for dynamic solution of second-order + FE equations considering boundary conditions. - ed = [u1, ... ,u6] element displacements + Parameters: - eq = [qx, qy] distributed loads, local directions + K global stiffness matrix, dim(K) = ndof x ndof + C global damping matrix, dim(C) = ndof x ndof + If there is no damping in the system, simply set C=[] + M global mass matrix, dim(M) = ndof x ndof + f global load vector, dim(f) = ndof x (nstep + 1), + If dim(f) = ndof x 1, the values are kept constant + during time integration + a0 initial displacement vector a(0), dim(a0) = ndof x 1 + da0 initial velocity vector v(0), dim(da0) = ndof x 1 + bc boundary condition matrix, dim(bc) = nbc x (nstep + 2) + where nbc = number of prescribed degrees of freedom (either constant or time-dependent) + The first column contains the numbers of the prescribed degrees of freedom + and the subsequent columns contain the time history. + If dim(bc) = nbc x 2, the values from the second column are kept constant + during time integration + ip array [dt, tottime, alpha, delta], where + dt is the size of the time increment, + tottime is the total time, + alpha and delta are time integration constants for the Newmark family of methods. + Frequently used values of alpha and delta are: + alpha=1/4, delta=1/2: average acceleration (trapezoidal) rule, + alpha=1/6, delta=1/2: linear acceleration + alpha=0, delta=1/2: central difference + times array [t(i) ...] of times at which output should be written to a, da and d2a + dofs array [dof(i) ...] of degree of freedom numbers for which history output + should be written to ahist, dahist and d2ahist - nep number of evaluation points ( default=2 ) - Returns: - - es = [[N1,V1,M1], section forces, local directions, in - [N2,V2,M2], n points along the beam, dim(es)= n x 3 - ..........] - - edi = [[u1,v1,teta1], element displacements, local directions, - [u2,v2,teta2], and rotation of cross section at - .............] in n points along the beam, dim(es)= n x 2 - - (Note! Rotation of the cross section is not equal to dv/dx for Timoshenko beam element) - - eci = [[x1], local x-coordinates of the evaluation - [x2], points, (x1=0 and xn=L) - ....] - - """ - EA = ep[0]*ep[2] - EI = ep[0]*ep[3] - GAK = ep[1]*ep[2]*ep[4] - alfa = EI/GAK - - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b.T/L).reshape(2) - qx = 0. - qy = 0. - if eq != None: - qx = eq[0] - qy = eq[1] + modelhist dictionary containing solution history for the whole model at following keys: + modelhist['a'] constains displacement values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['a']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['da'] constains velocity values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['da']) = ndof x (nstep + 1) or ndof x ntimes + modelhist['d2a'] constains acceleration values at all timesteps, + alternatively at times specified in 'times' + dim(modelhist['d2a']) = ndof x (nstep + 1) or ndof x ntimes + dofhist dictionary containing solution history for the degrees of freedom selected in 'dofs': + dofhist['a'] constains displacement time history at the dofs specified in 'dofs' + dim(dofhist['ahist']) = ndof x (nstep + 1) + dofhist['da'] constains velocity time history at the dofs specified in 'dofs' + dim(dofhist['dahist']) = ndof x (nstep + 1) + dofhist['d2a'] constains acceleration time history at the dofs specified in 'dofs' + dim(dofhist['d2ahist']) = ndof x (nstep + 1) + """ + ndof, _ = K.shape + if not np.array(C).any(): + C = np.zeros((ndof,ndof)) + dt, tottime, alpha, delta = ip + b1 = dt*dt*0.5*(1-2*alpha) + b2 = (1-delta)*dt + b3 = delta*dt + b4 = alpha*dt*dt - ne = 2 + nstep = 1 + if np.array(f).any(): + _, ncf = f.shape + if ncf>1: + nstep = ncf-1 - if nep != None: - ne = nep + if np.array(bc).any(): + _, ncb = bc.shape + if ncb>2: + nstep = ncb-2 + bound = 1 + if not np.array(bc).any(): + bound = 0 - C = np.mat([ - [0., 0., 0., 1., 0., 0.], - [0., 0., 0., 0., 0., 1.], - [0., 6*alfa, 0., 0., 1., 0.], - [L, 0., 0., 1., 0., 0.], - [0., L**3, L**2, 0., L, 1.], - [0., 3*(L**2+2*alfa), 2*L, 0., 1., 0.] - ]) + ns = int(tottime/dt) + if (ns < nstep or nstep==1): + nstep=ns - G = np.mat([ - [n[0], n[1], 0., 0., 0., 0.], - [-n[1], n[0], 0., 0., 0., 0.], - [0., 0., 1., 0., 0., 0.], - [0., 0., 0., n[0], n[1], 0.], - [0., 0., 0., -n[1], n[0], 0.], - [0., 0., 0., 0., 0., 1.] - ]) + tf = np.zeros((ndof,nstep+1)) + if np.array(f).any(): + if ncf==1: + tf = f[:,0].reshape(-1,1)@np.ones((1,nstep+1)) + if ncf>1: + tf = np.copy(f) + + modelhist = {} + sa=0 + if not np.array(times).any(): + ntimes=0 + sa=1 + modelhist['a'] = np.zeros((ndof,nstep+1)) + modelhist['da'] = np.zeros((ndof,nstep+1)) + modelhist['d2a'] = np.zeros((ndof,nstep+1)) + else: + ntimes = len(times) + if ntimes: + sa=2 + modelhist['a'] = np.zeros((ndof,ntimes)) + modelhist['da'] = np.zeros((ndof,ntimes)) + modelhist['d2a'] = np.zeros((ndof,ntimes)) - M = np.ravel(C.I*(G*np.asmatrix(ed).T-np.mat([0., 0., 0., -qx*L**2/( - 2*EA), qy*L**4/(24*EI)-qy*L**2/(2*GAK), qy*L**3/(6*EI)]).T)) - C2 = np.mat([M[0], M[3]]).T - C4 = np.mat([M[1], M[2], M[4], M[5]]).T + dofhist = {} + if np.array(dofs).all(): + ndofs = len(dofs) + if ndofs: + dofhist['a'] = np.zeros((ndofs,nstep+1)) + dofhist['da'] = np.zeros((ndofs,nstep+1)) + dofhist['d2a'] = np.zeros((ndofs,nstep+1)) + else: + ndofs=0 - x = np.asmatrix(np.arange(0., L+L/(ne-1), L/(ne-1))).T - zero = np.asmatrix(np.zeros([len(x)])).T - one = np.asmatrix(np.ones([len(x)])).T + itime = 0 - u = np.concatenate((x, one), 1)*C2-qx/(2*EA)*np.power(x, 2) - du = np.concatenate((one, zero), 1)*C2-qx*x/EA + # Calculate initial second time derivative d2a0 + d2a0 = np.linalg.solve(M,tf[:,0].reshape(-1,1) - C@da0 - K@a0) + # Save initial values + if sa==1: + modelhist['a'][:,0] = a0.ravel() + modelhist['da'][:,0] = da0.ravel() + modelhist['d2a'][:,0] = d2a0.ravel() + elif sa==2: + if times[itime]==0: + modelhist['a'][:,itime] = a0.ravel() + modelhist['da'][:,itime] = da0.ravel() + modelhist['d2a'][:,itime] = d2a0.ravel() + itime += 1 - v = np.concatenate((np.power(x, 3), np.power(x, 2), x, one), 1) * \ - C4+qy/(24*EI)*np.np.power(x, 4)-qy/(2*GAK)*np.power(x, 2) - dv = np.concatenate((3*np.power(x, 2), 2*x, one, zero), - 1)*C4+qy*np.power(x, 3)/(6*EI)-qy*x/GAK + if ndofs: + dofhist['a'][:,0] = a0[np.ix_(dofs-1)].ravel() + dofhist['da'][:,0] = da0[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,0] = d2a0[np.ix_(dofs-1)].ravel() - teta = np.concatenate((3*(np.power(x, 2)+2*alfa*one), - 2*x, one, zero), 1)*C4+qy*np.power(x, 3)/(6*EI) - dteta = np.concatenate((6*x, 2*one, zero, zero), 1) * \ - C4+qy*np.power(x, 2)/(2*EI) + # Reduce matrices due to bcs + tempa = np.zeros((ndof,1)) + tempda = np.zeros((ndof,1)) + tempd2a = np.zeros((ndof,1)) + fdof=np.arange(1,ndof+1).astype(int) + if bound: + nrb, ncb = bc.shape + if ncb==2: + pa = bc[:,1].reshape(-1,1)@np.ones((1,nstep+1)) + pda = np.zeros((nrb,nstep+1)) + elif ncb>2: + pa = np.copy(bc[:,1:]) + pda1 = (pa[:,1]-pa[:,0])/dt + pdarest = (pa[:,1:] - pa[:,0:-1])/dt + pda = np.hstack((pda1.reshape(-1,1),pdarest)) + pdof = np.copy(bc[:,0]).astype(int) + fdof = np.setdiff1d(fdof,pdof).astype(int) - 1 + pdof -= 1 #adjusting for indexing starting from 0 + Keff = M[np.ix_(fdof,fdof)] + b3*C[np.ix_(fdof,fdof)] +b4*K[np.ix_(fdof,fdof)] + else: + fdof -= 1 #adjusting for indexing starting from 0 + Keff = M + b3*C + b4*K - N = EA*du - M = EI*dteta - V = GAK*(dv-teta) + L, U = lu(Keff,permute_l=True) + anew = a0[np.ix_(fdof)] + danew = da0[np.ix_(fdof)] + d2anew = d2a0[np.ix_(fdof)] - es = np.concatenate((N, V, M), 1) - edi = np.concatenate((u, v, teta), 1) - eci = x + # Iterate over time steps + for j in range(1,nstep+1): + time = dt*j + aold = np.copy(anew) + daold = np.copy(danew) + d2aold = np.copy(d2anew) + apred = aold + dt*daold + b1*d2aold + dapred = daold + b2*d2aold + if not bound: + reff = tf[:,j].reshape(-1,1) - C@dapred - K@apred + else: + pdeff = C[np.ix_(fdof,pdof)]@pda[:,j].reshape(-1,1) + K[np.ix_(fdof,pdof)]@pa[:,j].reshape(-1,1) + reff = tf[np.ix_(fdof),j].reshape(-1,1) - C[np.ix_(fdof,fdof)]@dapred - K[np.ix_(fdof,fdof)]@apred - pdeff + y = np.linalg.solve(L,reff) + d2anew = np.linalg.solve(U,y) + anew = apred + b4*d2anew + danew = dapred + b3*d2anew + # Save to modelhist and dofhist + if bound: + tempa[np.ix_(pdof)] = pa[:,j].reshape(-1,1) + tempda[np.ix_(pdof)] = pda[:,j].reshape(-1,1) + tempa[np.ix_(fdof)] = anew + tempda[np.ix_(fdof)] = danew + tempd2a[np.ix_(fdof)] = d2anew + if sa==1: + modelhist['a'][:,j] = tempa.ravel() + modelhist['da'][:,j] = tempda.ravel() + modelhist['d2a'][:,j] = tempd2a.ravel() + elif sa==2: + if ntimes and itime < ntimes: + if time >= times[itime]: + modelhist['a'][:,itime] = tempa.ravel() + modelhist['da'][:,itime] = tempda.ravel() + modelhist['d2a'][:,itime] = tempd2a.ravel() + itime += 1 + if ndofs: + dofhist['a'][:,j] = tempa[np.ix_(dofs-1)].ravel() + dofhist['da'][:,j] = tempda[np.ix_(dofs-1)].ravel() + dofhist['d2a'][:,j] = tempd2a[np.ix_(dofs-1)].ravel() - if nep != None: - return es, edi, eci - else: - return es + return modelhist, dofhist -def _beam2w(ex, ey, ep, eq=None): +def extract_eldisp(edof, a): """ - Compute the stiffness matrix for a two dimensional beam element - on elastic foundation. + Extract element displacements from the global displacement + vector according to the topology matrix edof. Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - - ep = [E,A,I,ka,kt] element properties, - E: Young's modulus - A: cross section area - I: moment of inertia - ka: axial foundation stiffness - kt: transversal foundation stiffness - - eq = [qx, qy] distributed loads, local directions - + + a the global displacement vector + edof dof topology array + Returns: - - Ke beam stiffness matrix (6 x 6) - - fe element load vector (6 x 1) + + ed: element displacement array + """ - b = np.mat([[ex[1]-ex[0]], [ey[1]-ey[0]]]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2) - - E, A, I, ka, kt = ep - qx = 0 - qy = 0 - if eq != None: - qx, qy = eq - - K1 = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], - [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], - [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] - ]) - - K2 = L/420*np.mat([ - [140*ka, 0, 0, 70*ka, 0, 0], - [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], - [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], - [70*ka, 0, 0, 140*ka, 0, 0], - [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], - [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] - ]) + ed = None - Kle = K1+K2 - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + if edof.ndim == 1: + nDofs = len(edof) + ed = np.zeros([nDofs]) + idx = edof-1 + ed[:] = a[np.ix_(idx)].T + else: + nElements = edof.shape[0] + nDofs = edof.shape[1] + ed = np.zeros([nElements, nDofs]) + i = 0 + for row in edof: + idx = row-1 + ed[i, :] = a[np.ix_(idx)].T + i += 1 - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + return ed - Ke = G.T*Kle*G - fe = G.T*fle - if eq != None: - return Ke, fe - else: - return Ke +extractEldisp = extract_eldisp +extract_ed = extract_eldisp -def _beam2ws(ex, ey, ep, ed, eq=None): +def statcon(K, f, cd): """ - Compute section forces in a two dimensional beam element - on elastic foundation. - - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - - ep = [E,A,I,ka,kt] element properties, - E: Young's modulus - A: cross section area - I: moment of inertia - ka: axial foundation stiffness - kt: transversal foundation stiffness - - ed = [u1, ... ,u6] element displacement vector + Condensation of static FE-equations according to the vector cd. - eq = [qx, qy] distributed loads, local directions + Parameters: + + K global stiffness matrix, dim(K) = nd x nd + f global load vector, dim(f)= nd x 1 + cd vector containing dof's to be eliminated + dim(cd)= nc x 1, nc: number of condensed dof's Returns: - - es = [[N1, V1, M1], - [N2, V2, M2]] element forces, local direction + + K1 condensed stiffness matrix, + dim(K1)= (nd-nc) x (nd-nc) + f1 condensed load vector, dim(f1)= (nd-nc) x 1 """ - if np.asmatrix(ed).shape[0] > 1: - error("Only one row is allowed in the ed matrix !!!") - return - - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) - - E, A, I, ka, kt = ep + nd, nd = np.shape(K) + cd = (cd-1).flatten() - qx = 0 - qy = 0 - if eq != None: - qx, qy = eq + aindx = np.arange(nd) + aindx = np.delete(aindx, cd, 0) + bindx = cd - K1 = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], - [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], - [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] - ]) + Kaa = np.mat(K[np.ix_(aindx, aindx)]) + Kab = np.mat(K[np.ix_(aindx, bindx)]) + Kbb = np.mat(K[np.ix_(bindx, bindx)]) - K2 = L/420*np.mat([ - [140*ka, 0, 0, 70*ka, 0, 0], - [0, 156*kt, 22*kt*L, 0, 54*kt, -13*kt*L], - [0, 22*kt*L, 4*kt*L**2, 0, 13*kt*L, -3*kt*L**2], - [70*ka, 0, 0, 140*ka, 0, 0], - [0, 54*kt, 13*kt*L, 0, 156*kt, -22*kt*L], - [0, -13*kt*L, -3*kt*L**2, 0, -22*kt*L, 4*kt*L**2] - ]) + fa = np.mat(f[aindx]) + fb = np.mat(f[bindx]) - Kle = K1+K2 - fle = L*np.mat([qx/2, qy/2, qy*L/12, qx/2, qy/2, -qy*L/12]).T + K1 = Kaa-Kab*Kbb.I*Kab.T + f1 = fa-Kab*Kbb.I*fb - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + return K1, f1 - P = Kle*G*np.asmatrix(ed).T-fle - es = np.mat([ - [-P[0, 0], -P[1, 0], -P[2, 0]], - [P[3, 0], P[4, 0], P[5, 0]] - ]) +def c_mul(a, b): + return eval(hex((np.long(a) * b) & 0xFFFFFFFF)[:-1]) - return es +def dofHash(dof): + if len(dof) == 1: + return dof[0] + value = 0x345678 + for item in dof: + value = c_mul(1000003, value) ^ hash(item) + value = value ^ len(dof) + if value == -1: + value = -2 + return value -def _beam2g(ex, ey, ep, N, eq=None): - """ - Compute the element stiffness matrix for a two dimensional - beam element with respect to geometric nonlinearity. - - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates - ep = [E,A,I] element properties; - E: Young's modulus - A: cross section area - I: moment of inertia +def create_dofs(nCoords, nDof): + """ + Create dof array [nCoords x nDof] + """ + return np.arange(nCoords*nDof).reshape(nCoords, nDof)+1 - N axial force in the beam - eq distributed transverse load +createdofs = create_dofs - Returns: - Ke element stiffness matrix (6 x 6) +def coordxtr(edof, coords, dofs, nen=-1): + """ + Create element coordinate matrices ex, ey, ez from edof + coord and dofs matrices. + + Parameters: + + edof [nel x (nen * nnd)], nnd = number of node dofs + coords [ncoords x ndims], ndims = node dimensions + dofs [ncoords x nnd] - fe element load vector (6 x 1) + Returns: + + ex if ndims = 1 + ex, ey if ndims = 2 + ex, ey, ez if ndims = 3 """ - if eq != None: - if np.size(eq) > 1: - error("eq should be a scalar !!!") - return - else: - q = eq[0] - else: - q = 0 - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) + # Create dictionary with dof indices - E, A, I = ep + dofDict = {} + nDofs = np.size(dofs, 1) + nElements = np.size(edof, 0) + n_element_dofs = np.size(edof, 1) + nDimensions = np.size(coords, 1) + nElementDofs = np.size(edof, 1) - rho = -N*L**2/(np.pi**2*E*I) + if nen == -1: + nElementNodes = int(nElementDofs/nDofs) + else: + nElementNodes = nen - kL = np.pi*np.sqrt(abs(rho))+np.finfo(float).eps + if nElementNodes*nDofs != n_element_dofs: + nDofs = nElementNodes*nDofs - n_element_dofs + user_warning( + "dofs/edof mismatch. Using %d dofs per node when indexing." % nDofs) - if rho > 0: - f1 = (kL/2)/np.tan(kL/2) - f2 = (1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) - elif rho < 0: - f1 = (kL/2)/np.tanh(kL/2) - f2 = -(1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) - else: - f1 = f2 = f3 = f4 = f5 = h = 1 + idx = 0 + for dof in dofs: + #dofDict[dofHash(dof)] = idx + dofDict[hash(tuple(dof[0:nDofs]))] = idx + idx += 1 - Kle = np.mat([ - [E*A/L, 0., 0., -E*A/L, 0., 0.], - [0., 12*E*I*f5/L**3., 6*E*I*f2/L**2., - 0., -12*E*I*f5/L**3., 6*E*I*f2/L**2.], - [0., 6*E*I*f2/L**2., 4*E*I*f3/L, - 0., -6*E*I*f2/L**2., 2*E*I*f4/L], - [-E*A/L, 0., 0., E*A/L, 0., 0.], - [0., -12*E*I*f5/L**3., -6*E*I*f2/L**2., - 0., 12*E*I*f5/L**3., -6*E*I*f2/L**2.], - [0., 6*E*I*f2/L**2., 2*E*I*f4/L, - 0., -6*E*I*f2/L**2., 4*E*I*f3/L] - ]) + # Loop over edof and extract element coords - fle = q*L*np.mat([0., 1/2., L*h/12, 0., 1/2., -L*h/12]).T + ex = np.zeros((nElements, nElementNodes)) + ey = np.zeros((nElements, nElementNodes)) + ez = np.zeros((nElements, nElementNodes)) - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + elementIdx = 0 + for etopo in edof: + for i in range(nElementNodes): + i0 = i*nDofs + i1 = i*nDofs+nDofs-1 + dof = [] + if i0 == i1: + dof = [etopo[i*nDofs]] + else: + dof = etopo[i*nDofs:(i*nDofs+nDofs)] - Ke = G.T*Kle*G - fe = G.T*fle + nodeCoord = coords[dofDict[hash(tuple(dof[0:nDofs]))]] - if eq != None: - return Ke, fe - else: - return Ke + if nDimensions >= 1: + ex[elementIdx, i] = nodeCoord[0] + if nDimensions >= 2: + ey[elementIdx, i] = nodeCoord[1] + if nDimensions >= 3: + ez[elementIdx, i] = nodeCoord[2] + elementIdx += 1 -def _beam2gs(ex, ey, ep, ed, N, eq=None): - """ - Calculate section forces in a two dimensional nonlinear - beam element. + if nDimensions == 1: + return ex - Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates + if nDimensions == 2: + return ex, ey - ep = [E,A,I] element properties; - E: Young's modulus - A: cross section area - I: moment of inertia + if nDimensions == 3: + return ex, ey, ez - ed = [u1, ... ,u6] element displacement vector - N axial force +coord_extract = coordxtr - eq = [qy] distributed transverse load +def hooke(ptype, E, v): + """ + Calculate the material matrix for a linear + elastic and isotropic material. + + Parameters: + + ptype= 1: plane stress + 2: plane strain + 3: axisymmetry + 4: three dimensional + + E Young's modulus + v Poissons const. + Returns: - - es = [[N1,V1,M1], element forces, local directions - [N2,V2,M2]] + + D material matrix + """ - if eq != None: - eq = eq[0] - else: - eq = 0 - - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) - - E, A, I = ep - - rho = -N*L**2/(np.pi**2*E*I) - eps = 2.2204e-16 - kL = np.pi*np.sqrt(abs(rho))+eps - - if rho > 0: - f1 = (kL/2)/np.tan(kL/2) - f2 = (1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = 6*(2/kL**2-(1+np.cos(kL))/(kL*np.sin(kL))) - elif rho < 0: - f1 = (kL/2)/np.tanh(kL/2) - f2 = -(1/12.)*kL**2/(1-f1) - f3 = f1/4+3*f2/4 - f4 = -f1/2+3*f2/2 - f5 = f1*f2 - h = -6*(2/kL**2-(1+np.cosh(kL))/(kL*np.sinh(kL))) + if ptype == 1: + D = E*np.matrix( + [[1, v, 0], + [v, 1, 0], + [0, 0, (1-v)/2]] + )/(1-v**2) + elif ptype == 2: + D = E/(1+v)*np.matrix( + [[1-v, v, v, 0], + [v, 1-v, v, 0], + [v, v, 1-v, 0], + [0, 0, 0, (1-2*v)/2]] + )/(1-2*v) + elif ptype == 3: + D = E/(1+v)*np.matrix( + [[1-v, v, v, 0], + [v, 1-v, v, 0], + [v, v, 1-v, 0], + [0, 0, 0, (1-2*v)/2]] + )/(1-2*v) + elif ptype == 4: + D = E*np.matrix( + [[1-v, v, v, 0, 0, 0], + [v, 1-v, v, 0, 0, 0], + [v, v, 1-v, 0, 0, 0], + [0, 0, 0, (1-2*v)/2, 0, 0], + [0, 0, 0, 0, (1-2*v)/2, 0], + [0, 0, 0, 0, 0, (1-2*v)/2]] + )/(1+v)/(1-2*v) else: - f1 = f2 = f3 = f4 = f5 = h = 1 + info("ptype not supported.") - Kle = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I*f5/L**3, 6*E*I*f2/L**2, - 0, -12*E*I*f5/L**3, 6*E*I*f2/L**2], - [0, 6*E*I*f2/L**2, 4*E*I*f3/L, 0, -6*E*I*f2/L**2, 2*E*I*f4/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I*f5/L**3, -6*E*I*f2/L**2, - 0, 12*E*I*f5/L**3, -6*E*I*f2/L**2], - [0, 6*E*I*f2/L**2, 2*E*I*f4/L, 0, -6*E*I*f2/L**2, 4*E*I*f3/L] - ]) + return D - fle = eq*L*np.mat([0, 1/2., L*h/12, 0, 1/2., -L*h/12]).T - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) +def effmises(es, ptype): + """ + Calculate effective von mises stresses. + + Parameters: + + es + + ptype= 1: plane stress + 2: plane strain + 3: axisymmetry + 4: three dimensional + + es = [[sigx,sigy,[sigz],tauxy] element stress matrix + [ ...... ]] one row for each element + + Returns: + + eseff = [eseff_0 .. eseff_nel-1] + + """ - u = np.asmatrix(ed).T - P = Kle*G*u-fle + nel = np.size(es, 0) + escomps = np.size(es, 1) - es = np.mat([ - [-P[0, 0], -P[1, 0], -P[2, 0]], - [P[3, 0], P[4, 0], P[5, 0]] - ]) + eseff = np.zeros([nel]) - return es + if ptype == 1: + sigxx = es[:, 0] + sigyy = es[:, 1] + sigxy = es[:, 2] + eseff = np.sqrt(sigxx*sigxx+sigyy*sigyy-sigxx*sigyy+3*sigxy*sigxy) + return eseff -def _beam2d(ex, ey, ep): +def stress2nodal(eseff, edof): """ - Calculate the stiffness matrix Ke, the mass matrix Me - and the damping matrix Ce for a 2D elastic Bernoulli - beam element. - + Convert element effective stresses to nodal effective + stresses. + Parameters: - - ex = [x1, x2] - ey = [y1, y2] element node coordinates + + eseff = [eseff_0 .. eseff_nel-1] + edof = [dof topology array] + + Returns: + + ev: element value array [[ev_0_0 ev_0_1 ev_0_nen-1 ] + .. + ev_nel-1_0 ev_nel-1_1 ev_nel-1_nen-1] + + """ - ep = [E,A,I,m,(a,b)] element properties; - E: Young's modulus - A: cross section area - I: moment of inertia - m: mass per unit length - a,b: damping coefficients, - Ce=aMe+bKe + values = np.zeros(edof.max()) + elnodes = int(np.size(edof, 1) / 2) + + for etopo, eleseff in zip(edof, eseff): + values[etopo-1] = values[etopo-1] + eleseff / elnodes + + evtemp = extractEldisp(edof, values) + ev = evtemp[:, range(0, elnodes*2, 2)] - Returns: + return ev - Ke element stiffness matrix (6 x 6) - Me element mass martix - Ce element damping matrix, optional + +def beam2crd_old(ex, ey, ed, mag): """ - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]] - ]) - L = np.sqrt(b.T*b).item() - n = np.asarray(b/L).reshape(2,) + ------------------------------------------------------------- + PURPOSE + Calculate the element continous displacements for a + number of identical 2D Bernoulli beam elements. + + INPUT: ex,ey, + ed, + mag + + OUTPUT: excd,eycd + ------------------------------------------------------------- - a = 0 - b = 0 - if np.size(ep) == 4: - E, A, I, m = ep - elif np.size(ep) == 6: - E, A, I, m, a, b = ep + LAST MODIFIED: P-E AUSTRELL 1993-10-15 + J Lindemann 2021-12-30 (Python) - Kle = np.mat([ - [E*A/L, 0, 0, -E*A/L, 0, 0], - [0, 12*E*I/L**3, 6*E*I/L**2, 0, -12*E*I/L**3, 6*E*I/L**2], - [0, 6*E*I/L**2, 4*E*I/L, 0, -6*E*I/L**2, 2*E*I/L], - [-E*A/L, 0, 0, E*A/L, 0, 0], - [0, -12*E*I/L**3, -6*E*I/L**2, 0, 12*E*I/L**3, -6*E*I/L**2], - [0, 6*E*I/L**2, 2*E*I/L, 0, -6*E*I/L**2, 4*E*I/L] - ]) + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ + nie, ned = ed.shape - Mle = m*L/420*np.mat([ - [140, 0, 0, 70, 0, 0], - [0, 156, 22*L, 0, 54, -13*L], - [0, 22*L, 4*L**2, 0, 13*L, -3*L**2], - [70, 0, 0, 140, 0, 0], - [0, 54, 13*L, 0, 156, -22*L], - [0, -13*L, -3*L**2, 0, -22*L, 4*L**2] - ]) + excd = np.zeros([nie, 20]) + eycd = np.zeros([nie, 20]) - Cle = a*Mle+b*Kle + for i in range(nie): - G = np.mat([ - [n[0], n[1], 0, 0, 0, 0], - [-n[1], n[0], 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0], - [0, 0, 0, n[0], n[1], 0], - [0, 0, 0, -n[1], n[0], 0], - [0, 0, 0, 0, 0, 1] - ]) + b = np.array([ex[i, 1]-ex[i, 0], ey[i, 1]-ey[i, 0]]) + L = np.asscalar(np.sqrt(b@np.transpose(b))) + n = b/L - Ke = G.T*Kle*G - Me = G.T*Mle*G - Ce = G.T*Cle*G + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, -n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) - if np.size(ep) == 4: - return Ke, Me - elif np.size(ep) == 6: - return Ke, Me, Ce + d = ed[i, :] + dl = G @ d + xl = np.linspace(0.0, L, 20) + one = np.ones(xl.shape) -def _beam3e(ex, ey, ez, eo, ep, eq=None): - """ - Calculate the stiffness matrix for a 3D elastic Bernoulli - beam element. - - Parameters: - - ex = [x1 x2] - ey = [y1 y2] - ez = [z1 z2] element node coordinates - - eo = [xz yz zz] orientation of local z axis - - ep = [E G A Iy Iz Kv] element properties - E: Young's modulus - G: Shear modulus - A: Cross section area - Iy: Moment of inertia, local y-axis - Iz: Moment of inertia, local z-axis - Kv: Saint-Venant's torsion constant - - eq = [qx qy qz qw] distributed loads + Cis = np.array([ + [-1.0, 1.0], + [L, 0.0] + ]) / L - Returns: + ds = np.array([dl[0], dl[3]]).reshape(2, 1) - Ke beam stiffness matrix (12 x 12) + xl_one = np.transpose(np.vstack((xl, one))) - fe equivalent nodal forces (12 x 1) + ul = np.transpose(xl_one@Cis@ds) # [20x1][2] - """ - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() - n1 = np.asarray(b.T/L).reshape(3,) + Cib = np.array([ + [12, 6*L, -12, 6*L], + [-6*L, -4*L**2, 6*L, -2*L**2], + [0, L**3, 0, 0], + [L**3, 0, 0, 0] + ])/L**3 - eo = np.asmatrix(eo) - lc = np.sqrt(eo*eo.T).item() - n3 = np.asarray(eo/lc).reshape(3,) + db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) + vl = np.transpose(np.transpose( + np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) - E, Gs, A, Iy, Iz, Kv = ep + cld = np.vstack((ul, vl)) + A = np.array([ + [n[0], -n[1]], + [n[1], n[0]] + ]) + cd = A@cld - qx = 0. - qy = 0. - qz = 0. - qw = 0. - if eq != None: - qx, qy, qz, qw = eq - - a = E*A/L - b = 12*E*Iz/L**3 - c = 6*E*Iz/L**2 - d = 12*E*Iy/L**3 - e = 6*E*Iy/L**2 - f = Gs*Kv/L - g = 2*E*Iy/L - h = 2*E*Iz/L - - Kle = np.mat([ - [a, 0, 0, 0, 0, 0, -a, 0, 0, 0, 0, 0], - [0, b, 0, 0, 0, c, 0, -b, 0, 0, 0, c], - [0, 0, d, 0, -e, 0, 0, 0, -d, 0, -e, 0], - [0, 0, 0, f, 0, 0, 0, 0, 0, -f, 0, 0], - [0, 0, -e, 0, 2*g, 0, 0, 0, e, 0, g, 0], - [0, c, 0, 0, 0, 2*h, 0, -c, 0, 0, 0, h], - [-a, 0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0], - [0, -b, 0, 0, 0, -c, 0, b, 0, 0, 0, -c], - [0, 0, -d, 0, e, 0, 0, 0, d, 0, e, 0], - [0, 0, 0, -f, 0, 0, 0, 0, 0, f, 0, 0], - [0, 0, -e, 0, g, 0, 0, 0, e, 0, 2*g, 0], - [0, c, 0, 0, 0, h, 0, -c, 0, 0, 0, 2*h] - ]) + # [2,1] x [1,20] + [2 x 1] x [1 x 20] + # [2 x 20] + [2 x 20] - fle = L/2*np.mat([qx, qy, qz, qw, -qz*L/6, qy*L/6, - qx, qy, qz, qw, qz*L/6, -qy*L/6]).T - - n2 = np.array([0., 0., 0.]) - n2[0] = n3[1]*n1[2]-n3[2]*n1[1] - n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] - n2[2] = n3[0]*n1[1]-n1[0]*n3[1] - - #An = np.append([n1,n2],[n3],0) - - G = np.mat([ - [n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], - [n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], - [n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0, 0, 0, 0], - [0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0, 0, 0, 0], - [0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, n1[0], n1[1], n1[2]], - [0, 0, 0, 0, 0, 0, 0, 0, 0, n2[0], n2[1], n2[2]], - [0, 0, 0, 0, 0, 0, 0, 0, 0, n3[0], n3[1], n3[2]] - ]) + AA = A[:, 0].reshape(2, 1) + XL = xl.reshape(1, 20) + xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]])@one.reshape(1, 20) - Ke = G.T*Kle*G - fe = G.T*fle + excd[i, :] = xyc[0, :]+mag*cd[0, :] + eycd[i, :] = xyc[1, :]+mag*cd[1, :] - if eq == None: - return Ke - else: - return Ke, fe + return excd, eycd -def _beam3s(ex, ey, ez, eo, ep, ed, eq=None, n=None): +def beam2crd(ex=None, ey=None, ed=None, mag=None): """ - Calculate the variation of the section forces and displacements - along a three-dimensional beam element. + ------------------------------------------------------------- + PURPOSE + Calculate the element continous displacements for a + number of identical 2D Bernoulli beam elements. - Parameters: - - ex = [x1 x2] element node coordinates - ey = [y1 y2] - ez = [z1 z2] + INPUT: ex,ey, + ed, + mag + + OUTPUT: excd,eycd + ------------------------------------------------------------- - eo = [xz yz zz] orientation of local z axis - - ep = [E G A Iy Iz Kv] element properties - E: Young's modulus - G: Shear modulus - A: Cross section area - Iy: Moment of inertia, local y-axis - Iz: Moment of inertia, local z-axis - Kv: Saint-Venant's torsion constant + LAST MODIFIED: P-E AUSTRELL 1993-10-15 + Copyright (c) Division of Structural Mechanics and + Division of Solid Mechanics. + Lund University + ------------------------------------------------------------- + """ - ed the element displacement vector from the - global coordinate system - - eq = [qx qy qz qw] the disibuted axial, transversal and - torsional loads + nie, ned = ed.shape - n the number of point in which displacements - and section forces are to be computed + n_coords = 21 - Returns: + excd = np.zeros([nie, n_coords]) + eycd = np.zeros([nie, n_coords]) - es = [[N1,Vy1,Vz1,T1,My1,Mz1], section forces in n points along - [N2,Vy2,Vz2,T2,My2,Mz2], the local x-axis - [..,...,...,..,...,...], - [Nn,Vyn,Vzn,Tn,Myn,Mzn]] + for i in range(nie): + b = np.array([ex[i, 1] - ex[i, 0], ey[i, 1] - ey[i, 0]]) + L = np.sqrt(b @ np.transpose(b)) + n = b / L - edi = [[u1,v1,w1,fi1], displacements in n points along - [u2,v2,w2,fi2], the local x-axis - [..,..,..,...], - [un,vn,wn,fin]] + G = np.array([ + [n[0], n[1], 0, 0, 0, 0], + [-n[1], n[0], 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0], + [0, 0, 0, n[0], n[1], 0], + [0, 0, 0, - n[1], n[0], 0], + [0, 0, 0, 0, 0, 1] + ]) - eci = [[x1], local x-coordinates of the evaluation - [x2], points - [..], - [xn]] + d = np.transpose(ed[i, :]) + dl = G @ d + xl = np.transpose(np.linspace(0, L, n_coords)) + one = np.ones(xl.shape) - """ - b = np.mat([ - [ex[1]-ex[0]], - [ey[1]-ey[0]], - [ez[1]-ez[0]] - ]) - L = np.sqrt(b.T*b).item() - n1 = np.asarray(b.T/L).reshape(3,) - - eo = np.asmatrix(eo) - lc = np.sqrt(eo*eo.T).item() - n3 = np.asarray(eo/lc).reshape(3,) - - EA = ep[0]*ep[2] - EIy = ep[0]*ep[3] - EIz = ep[0]*ep[4] - GKv = ep[1]*ep[5] - - qx = 0. - qy = 0. - qz = 0. - qw = 0. - if eq != None: - qx, qy, qz, qw = eq + Cis = np.array([ + [-1, 1], + [L, 0] + ]) / L - ne = 2 - if n != None: - ne = n + ds = np.array([dl[0], dl[3]]).reshape(2, 1) + xl_one = np.transpose(np.vstack((xl, one))) + ul = np.transpose(xl_one@Cis@ds) # [20x1][2] - n2 = np.array([0., 0., 0.]) - n2[0] = n3[1]*n1[2]-n3[2]*n1[1] - n2[1] = -n1[2]*n3[0]+n1[0]*n3[2] - n2[2] = n3[0]*n1[1]-n1[0]*n3[1] + Cib = np.array([ + [12, 6 * L, - 12, 6 * L], + [- 6 * L, - 4 * L ** 2, 6 * L, - 2 * L ** 2], + [0, L ** 3, 0, 0], + [L ** 3, 0, 0, 0] + ]) / L ** 3 - G = np.mat([ - [n1[0], n1[1], n1[2], 0, 0, 0, - 0, 0, 0, 0, 0, 0], - [n2[0], n2[1], n2[2], 0, 0, 0, - 0, 0, 0, 0, 0, 0], - [n3[0], n3[1], n3[2], 0, 0, 0, - 0, 0, 0, 0, 0, 0], - [0, 0, 0, n1[0], n1[1], n1[2], - 0, 0, 0, 0, 0, 0], - [0, 0, 0, n2[0], n2[1], n2[2], - 0, 0, 0, 0, 0, 0], - [0, 0, 0, n3[0], n3[1], n3[2], - 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, - n1[0], n1[1], n1[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, - n2[0], n2[1], n2[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, - n3[0], n3[1], n3[2], 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, - 0, 0, n1[0], n1[1], n1[2]], - [0, 0, 0, 0, 0, 0, 0, - 0, 0, n2[0], n2[1], n2[2]], - [0, 0, 0, 0, 0, 0, - 0, 0, 0, n3[0], n3[1], n3[2]] - ]) + db = np.array([dl[1], dl[2], dl[4], dl[5]]).reshape(4, 1) + vl = np.transpose(np.transpose( + np.vstack((xl**3/6, xl**2/2, xl, one)))@Cib@db) - u = G*np.asmatrix(ed).T-np.array([ # u is the local element displacement - [0], # vector minus the particular solution - [0], # to the beam's diff.eq:s - [0], - [0], - [0], - [0], - [-qx*L**2/(2*EA)], - [qy*L**4/(24*EIz)], - [qz*L**4/(24*EIy)], - [-qw*L**2/(2*GKv)], - [-qz*L**3/(6*EIy)], - [qy*L**3/(6*EIz)] - ]) + cld = np.vstack((ul, vl)) + A = np.array([ + [n[0], -n[1]], + [n[1], n[0]] + ]) + cd = A@cld - C = np.mat([ - [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], - [L, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], - [0, 0, L**3, L**2, L, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, L**3, L**2, L, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L, 1], - [0, 0, 0, 0, 0, 0, -3*L**2, -2*L, -1, 0, 0, 0], - [0, 0, 3*L**2, 2*L, 1, 0, 0, 0, 0, 0, 0, 0], - ]) + # [2,1] x [1,20] + [2 x 1] x [1 x 20] + # [2 x 20] + [2 x 20] - m = np.linalg.inv(C)*u - eci = np.zeros((ne, 1)) - es = np.zeros((ne, 6)) - edi = np.zeros((ne, 4)) - for i in np.arange(ne): - x = i*L/(ne-1) - eci[i, 0] = x - es[i, :] = (np.mat([ - [EA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, -6*EIz, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, -6*EIy, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GKv, 0], - [0, 0, 0, 0, 0, 0, -6*EIy*x, -2*EIy, 0, 0, 0, 0], - [0, 0, 6*EIz*x, 2*EIz, 0, 0, 0, 0, 0, 0, 0, 0] - ])*m+np.array([-qx*x, -qy*x, -qz*x, -qw*x, -qz*x**2/2, qy*x**2/2]).reshape(6, 1)).T - - edi[i, :] = (np.mat([ - [x, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, x**3, x**2, x, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, x**3, x**2, x, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x, 1] - ])*m+np.array([-qx*x**2/(2*EA), qy*x**4/(24*EIz), qz*x**4/(24*EIy), -qw*x**2/(2*GKv)]).reshape(4, 1)).T - - if n == None: - return es - else: - return es, edi, eci + AA = A[:, 0].reshape(2, 1) + XL = xl.reshape(1, n_coords) + xyc = AA@XL + np.array([[ex[i, 0]], [ey[i, 0]]] + )@one.reshape(1, n_coords) + + excd[i, :] = xyc[0, :]+mag*cd[0, :] + eycd[i, :] = xyc[1, :]+mag*cd[1, :] + + return excd, eycd + \ No newline at end of file From 197720fb4615fd1a843612e88f8d47fc555a1077 Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Fri, 17 Feb 2023 19:23:51 +0100 Subject: [PATCH 14/17] Merging changes from external updates --- calfem/vis_vedo.py | 2 +- examples/exd_beam2_m.py | 2 +- examples/exn_bar2g.py | 8 ++++---- examples/exn_bar2m.py | 5 ++++- examples/exn_beam2.py | 12 ++++++------ examples/exn_beam2_b.py | 13 +++++++------ examples/exv1.py | 2 +- examples/exv2.py | 2 +- examples/exv3.py | 2 +- examples/exv4.py | 4 ++-- 10 files changed, 28 insertions(+), 24 deletions(-) diff --git a/calfem/vis_vedo.py b/calfem/vis_vedo.py index 2f27b31..cd76fe4 100644 --- a/calfem/vis_vedo.py +++ b/calfem/vis_vedo.py @@ -16,7 +16,7 @@ import time from scipy.io import loadmat import calfem.core as cfc -import vis_vedo_utils as vdu +import calfem.vis_vedo_utils as vdu import vtk # Examples using this module: diff --git a/examples/exd_beam2_m.py b/examples/exd_beam2_m.py index 99be247..52fb35a 100644 --- a/examples/exd_beam2_m.py +++ b/examples/exd_beam2_m.py @@ -55,7 +55,7 @@ ep = np.array([ep1, ep1, ep2, ep2]) for elx, ely, eltopo, elprop in zip(ex, ey, edof, ep): - Ke, Me = cfc.beam2d(elx, ely, elprop) + Ke, Me = cfc.beam2de(elx, ely, elprop) cfc.assem(eltopo, K, Ke) cfc.assem(eltopo, M, Me) diff --git a/examples/exn_bar2g.py b/examples/exn_bar2g.py index d0ab094..629250e 100644 --- a/examples/exn_bar2g.py +++ b/examples/exn_bar2g.py @@ -42,8 +42,8 @@ f[4] = -10e6 f[5] = -0.2e6 - Ke1 = cfc.bar2g(ex1,ey1,ep1,QX1) - Ke2 = cfc.bar2g(ex2,ey2,ep2,QX2) + Ke1 = cfc.bar2ge(ex1,ey1,ep1,QX1) + Ke2 = cfc.bar2ge(ex2,ey2,ep2,QX2) K = cfc.assem(edof[0,:],K,Ke1) K=cfc.assem(edof[1,:],K,Ke2) bc = np.array([1,2,3,4]) @@ -52,8 +52,8 @@ Ed = cfc.extract_ed(edof,a) QX01 = QX1 - es1, QX1, ed1, _ = cfc.bar2gs(ex1,ey1,ep1,Ed[0,:]) - es2, QX2, ed2, _ = cfc.bar2gs(ex2,ey2,ep2,Ed[1,:]) + es1, QX1 = cfc.bar2gs(ex1,ey1,ep1,Ed[0,:]) + es2, QX2 = cfc.bar2gs(ex2,ey2,ep2,Ed[1,:]) if n>20: print("The solution does not converge") diff --git a/examples/exn_bar2m.py b/examples/exn_bar2m.py index 9e72afc..f9a5082 100644 --- a/examples/exn_bar2m.py +++ b/examples/exn_bar2m.py @@ -75,7 +75,10 @@ for j in range(3): ep = np.array([E[j], A[j]]) desj = cfc.bar2s(ex[j,:],ey[j,:],ep,ded[j,:]) - des[j,0] = desj + print('---') + print(desj) + print('---') + des[j,0] = desj[0] es += des for j in range(3): if abs(es[j,0]) >= Ns[j]: diff --git a/examples/exn_beam2.py b/examples/exn_beam2.py index 4a8ad3e..6650870 100644 --- a/examples/exn_beam2.py +++ b/examples/exn_beam2.py @@ -57,9 +57,9 @@ f = np.zeros([12,1]) f[3,0] = 10e3 - Ke1 = cfc.beam2g(ex1,ey1,ep1,QX1) - Ke2 = cfc.beam2g(ex2,ey2,ep1,QX2) - Ke3, fe3 = cfc.beam2g(ex3,ey3,ep3,QX3,eq3) + Ke1 = cfc.beam2ge(ex1,ey1,ep1,QX1) + Ke2 = cfc.beam2ge(ex2,ey2,ep1,QX2) + Ke3, fe3 = cfc.beam2ge(ex3,ey3,ep3,QX3,eq3) K = cfc.assem(edof[0,:],K,Ke1) K = cfc.assem(edof[1,:],K,Ke2) @@ -74,9 +74,9 @@ es1 = cfc.beam2gs(ex1,ey1,ep1,ed[0,:],QX1,eq1) es2 = cfc.beam2gs(ex2,ey2,ep1,ed[1,:],QX2,eq2) es3 = cfc.beam2gs(ex3,ey3,ep3,ed[2,:],QX3,eq3) - QX1 = es1[0,0] - QX2 = es2[0,0] - QX3 = es3[0,0] + QX1 = es1[1] + QX2 = es2[1] + QX3 = es3[1] if n==1: ed0 = ed diff --git a/examples/exn_beam2_b.py b/examples/exn_beam2_b.py index 471b301..0db602b 100644 --- a/examples/exn_beam2_b.py +++ b/examples/exn_beam2_b.py @@ -57,9 +57,9 @@ f = np.zeros([12,1]) f[3,0] = 10e3 - Ke1 = cfc.beam2g(ex1,ey1,ep1,QX1) - Ke2 = cfc.beam2g(ex2,ey2,ep1,QX2) - Ke3, fe3 = cfc.beam2g(ex3,ey3,ep3,QX3,eq3) + Ke1 = cfc.beam2ge(ex1,ey1,ep1,QX1) + Ke2 = cfc.beam2ge(ex2,ey2,ep1,QX2) + Ke3, fe3 = cfc.beam2ge(ex3,ey3,ep3,QX3,eq3) K = cfc.assem(edof[0,:],K,Ke1) K = cfc.assem(edof[1,:],K,Ke2) @@ -76,9 +76,10 @@ es1 = cfc.beam2gs(ex1,ey1,ep1,ed[0,:],QX1,eq1) es2 = cfc.beam2gs(ex2,ey2,ep1,ed[1,:],QX2,eq2) es3 = cfc.beam2gs(ex3,ey3,ep3,ed[2,:],QX3,eq3) - QX1 = es1[0,0] - QX2 = es2[0,0] - QX3 = es3[0,0] + + QX1 = es1[1] + QX2 = es2[1] + QX3 = es3[1] if n>20: print("The solution does not converge") diff --git a/examples/exv1.py b/examples/exv1.py index 9304a14..d624090 100644 --- a/examples/exv1.py +++ b/examples/exv1.py @@ -7,7 +7,7 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfv +import calfem.vis_vedo as cfv coord = np.array([ [0], diff --git a/examples/exv2.py b/examples/exv2.py index 82e2054..b9d4449 100644 --- a/examples/exv2.py +++ b/examples/exv2.py @@ -7,7 +7,7 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfv +import calfem.vis_vedo as cfv coord = np.array([ [0, 0, 0], diff --git a/examples/exv3.py b/examples/exv3.py index 879ec77..f0b2f91 100644 --- a/examples/exv3.py +++ b/examples/exv3.py @@ -7,7 +7,7 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfvv +import calfem.vis_vedo as cfv import calfem.geometry as cfg import calfem.mesh as cfm import calfem.utils as cfu diff --git a/examples/exv4.py b/examples/exv4.py index 1cbf6ec..ac63b9a 100644 --- a/examples/exv4.py +++ b/examples/exv4.py @@ -7,8 +7,8 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfv -import calfem.vedo_utils as cfvu +import calfem.vis_vedo as cfvv +import calfem.vis_vedo_utils as cfvu edof,coord,dof,a,ed,bc,f_dofs,Stress_tensors,vM_el,vM_n,lamb,eig = cfvv.import_mat('exv4',['edof','coord','dof','a','ed','bc','force_dofs','Stress_tensors','vM_el','vM_n','lambda','eig']) From 64bcfc740549b05c5bc82e780becddceb98dedf6 Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Tue, 19 Sep 2023 16:12:32 +0200 Subject: [PATCH 15/17] Fix for plantf --- calfem/core.py | 2 +- calfem_python_small.egg-info/SOURCES.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/calfem/core.py b/calfem/core.py index b4e58c0..6c71820 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -2923,7 +2923,7 @@ def plantf(ex, ey, ep, es): ])*np.linalg.inv(C) if colD > 3: - stress = np.asmatrix(es[np.ix_((1, 2, 4))]) + stress = np.asmatrix(es[np.ix_((0, 1, 3))]) else: stress = np.asmatrix(es) diff --git a/calfem_python_small.egg-info/SOURCES.txt b/calfem_python_small.egg-info/SOURCES.txt index 9c30548..8342635 100644 --- a/calfem_python_small.egg-info/SOURCES.txt +++ b/calfem_python_small.egg-info/SOURCES.txt @@ -12,6 +12,7 @@ calfem/core.py calfem/editor.py calfem/editor_resources.py calfem/editor_scene.py +calfem/editor_ui.py calfem/experimental.py calfem/geometry.py calfem/intvis.py From f0ea527a6572bcad70b2ba54630fe61fed28fe82 Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Sun, 8 Oct 2023 21:24:49 +0200 Subject: [PATCH 16/17] Update exv5.py --- examples/exv5.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/exv5.py b/examples/exv5.py index 54b32a6..b0ea62a 100644 --- a/examples/exv5.py +++ b/examples/exv5.py @@ -7,7 +7,7 @@ import numpy as np import calfem.core as cfc -import calfem.vedo as cfv +import calfem.vis_vedo as cfv # Adaptation of platre from version 3.4 for MATLAB # This function is not in the Python version currently From 2a1f05397ffc9056ebc3c2409848fc96b686ef87 Mon Sep 17 00:00:00 2001 From: Jonas Lindemann Date: Sun, 8 Oct 2023 21:41:18 +0200 Subject: [PATCH 17/17] Update core.py --- calfem/core.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/calfem/core.py b/calfem/core.py index 03e31de..a7da65e 100644 --- a/calfem/core.py +++ b/calfem/core.py @@ -2764,9 +2764,6 @@ def beam3e(ex, ey, ez, eo, ep, eq=None): 0, 0, 0, n3[0], n3[1], n3[2]] ]) - print("G=") - print(G) - Ke = G.T @ Kle @ G fe = G.T @ fle