Commit 5e56a751 authored by Jeremy BLEYER's avatar Jeremy BLEYER

Added periodic homog example + changes in process files for including zip and notebooks

parent 7513fac1
......@@ -24,8 +24,9 @@ sys.path.insert(0, os.path.abspath('..'))
#sys.path.insert(0, os.path.abspath('../examples</'))
sys.path.append(os.getcwd())
import rstprocess
rstprocess.process()
import process_sources
process_sources.process()
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
......@@ -35,13 +36,17 @@ rstprocess.process()
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx',
'sphinx.ext.mathjax', 'sphinx.ext.napoleon']
'sphinx.ext.mathjax', 'sphinx.ext.napoleon', 'nbsphinx']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
source_parsers = {
'.md': 'recommonmark.parser.CommonMarkParser',
}
# The suffix of source filenames.
source_suffix = '.rst'#,'.txt']
source_suffix = ['.rst','.md']#,'.txt']
# The encoding of source files.
#source_encoding = 'utf-8-sig'
......@@ -58,9 +63,9 @@ copyright = u'2016, Jeremy Bleyer'
# built documents.
#
# The short X.Y version.
version = '1.0'
version = 'master'
# The full version, including alpha/beta/rc tags.
release = '1.0'
release = 'master'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......@@ -74,7 +79,7 @@ release = '1.0'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = ['_build', '**.ipynb_checkpoints']
# The reST default role (used for this markup: `text`) to use for all
# documents.
......@@ -186,6 +191,7 @@ html_static_path = ['_static']
# Output file base name for HTML help builder.
htmlhelp_basename = 'NumericaltoursofcontinuummechanicsusingFEniCSdoc'
html_short_title = "Numerical tours of continuum mechanics using FEniCS"
# -- Options for LaTeX output ---------------------------------------------
......@@ -204,7 +210,7 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'NumericaltoursofcontinuummechanicsusingFEniCS.tex', u'Numerical tours of continuum mechanics using FEniCS Documentation',
('index', 'NumericaltoursofcontinuummechanicsusingFEniCS.tex', u'Numerical tours of continuum mechanics using FEniCS',
u'Jeremy Bleyer', 'manual'),
]
......@@ -216,6 +222,7 @@ latex_documents = [
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
......@@ -234,7 +241,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'numericaltoursofcontinuummechanicsusingfenics', u'Numerical tours of continuum mechanics using FEniCS Documentation',
('index', 'numericaltoursofcontinuummechanicsusingfenics', u'Numerical tours of continuum mechanics using FEniCS',
[u'Jeremy Bleyer'], 1)
]
......@@ -248,7 +255,7 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'NumericaltoursofcontinuummechanicsusingFEniCS', u'Numerical tours of continuum mechanics using FEniCS Documentation',
('index', 'NumericaltoursofcontinuummechanicsusingFEniCS', u'Numerical tours of continuum mechanics using FEniCS',
u'Jeremy Bleyer', 'NumericaltoursofcontinuummechanicsusingFEniCS', 'One line description of project.',
'Miscellaneous'),
]
......@@ -264,3 +271,19 @@ texinfo_documents = [
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
#nbsphinx_prolog = """
#Go there: https://example.org/notebooks/{{ env.doc2path(env.docname, base=None) }}
#
#----
#"""
#{% set docname = env.doc2path(env.docname, base='doc') %}
nbsphinx_prolog = r"""
{% set docname = env.docname.split("/")[-1] %}
.. role:: raw-html(raw)
:format: html
.. nbinfo::
The corresponding files can be obtained from:
- Jupyter Notebook: :download:`{{docname+".ipynb"}}`
- Python script: :download:`{{docname+".py"}}`"""
\ No newline at end of file
.. Numerical tours of continuum mechanics using FEniCS documentation master file, created by
sphinx-quickstart on Wed Jun 8 21:25:10 2016.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Homogenization of heterogeneous materials
=========================================
Contents:
.. toctree::
:maxdepth: 1
demo/periodic_homog_elas/periodic_homog_elas.ipynb
......@@ -13,6 +13,7 @@ Contents:
intro
linear_problems
homogenization
nonlinear_problems
demo/reissner_mindlin/reissner_mindlin.rst
tips_and_tricks
......
......@@ -10,7 +10,7 @@ Contents:
.. toctree::
:maxdepth: 1
demo/nonlinear_materials/vonMises_plasticity.py.rst
demo/2D_plasticity/vonMises_plasticity.py.rst
......@@ -19,9 +19,11 @@
import sys
import os
import shutil
import zipfile
# extensions of files which must be copied with the demo when building docs
file_extensions = [".png",".gif", ".geo", ".xml", ".msh", ".pdf"]
zipfile_extensions = [".geo", ".msh", ".xml", ".py", ".ipynb"]
def process():
"""Copy demo rst files (C++ and Python) from the DOLFIN source tree
......@@ -36,7 +38,7 @@ def process():
# Directories to scan
subdirs = ["../examples"]
retval = os.getcwd()
# Iterate over subdirectories containing demos
for subdir in subdirs:
......@@ -55,28 +57,51 @@ def process():
if not os.path.isdir(version_path):
continue
# Build list of rst files in demo source directory
rst_files = [f for f in os.listdir(version_path) if os.path.splitext(f)[1] == ".rst" ]
# Create directory in documentation tree for demo
demo_dir = os.path.join('./demo/', demo, version)
demo_dir = os.path.join('./demo/', demo)
if not os.path.exists(demo_dir):
os.makedirs(demo_dir)
ipynb_files = [f for f in os.listdir(version_path) if f.endswith("ipynb") ]
for f in ipynb_files:
ff = os.path.join(path, f)
shutil.copy(ff, demo_dir)
ret = os.system("jupyter-nbconvert --to script %s --output %s" % (ff, os.path.join("../../doc",demo_dir, os.path.splitext(f)[0])))
if not ret == 0:
raise RuntimeError("Unable to convert ipynb file to a .py ({})".format(f))
# Build list of rst files in demo source directory
rst_files = [f for f in os.listdir(version_path) if f.endswith("rst") ]
# Copy rst files into documentation demo directory and process with Pylit
for f in rst_files:
shutil.copy(os.path.join(version_path, f), demo_dir)
# Run pylit on cpp.rst and py.rst files (file with 'double extensions')
if os.path.splitext(os.path.splitext(f)[0])[1] in (".py"):
if "py" in f.split("."):
rst_file = os.path.join(demo_dir, f)
command = pylit_parser + " " + rst_file
ret = os.system("python "+command)
if not ret == 0:
raise RuntimeError("Unable to convert rst file to a .py ({})".format(f))
tocopy_files = [f for f in os.listdir(version_path) if os.path.splitext(f)[1] in file_extensions ]
for f in tocopy_files:
source = os.path.join(version_path, f)
print("Copying {} to {}".format(source, demo_dir))
print("Copying {} to {}".format(source, demo_dir))
shutil.copy(source, demo_dir)
for f in ipynb_files + rst_files:
cwd = os.getcwd()
os.chdir(demo_dir)
files = os.listdir(".")
zip_files = []
for ff in files:
if any([ff.endswith(ext) for ext in zipfile_extensions]):
zip_files.append(ff)
with zipfile.ZipFile(f.split(".")[0]+".zip", 'w') as myzip:
for a in zip_files:
myzip.write(a, compress_type=zipfile.ZIP_DEFLATED)
os.chdir(cwd)
......@@ -2,28 +2,28 @@
.. _vonMisesPlasticity:
==================================================
Elasto-plastic analysis of a 2D von Mises material
Elasto-plastic analysis of a 2D von Mises material
==================================================
-------------
Introduction
-------------
This example is concerned with the incremental analysis of an elasto-plastic
This example is concerned with the incremental analysis of an elasto-plastic
von Mises material. The structure response is computed using an iterative
predictor-corrector return mapping algorithm embedded in a Newton-Raphson global
loop for restoring equilibrium. Due to the simple expression of the von Mises criterion,
the return mapping procedure is completely analytical (with linear isotropic
hardening). The corresponding file can be obtained from :download:`vonMises_plasticity.py`.
hardening). The corresponding sources can be obtained from :download:`vonMises_plasticity.zip`.
Another implementation of von Mises plasticity can also be found at
https://bitbucket.org/fenics-apps/fenics-solid-mechanics.
We point out that the 2D nature of the problem will impose keeping
track of the out-of-plane :math:`\varepsilon_{zz}^p` plastic strain and dealing with
representations of stress/strain states including the :math:`zz` component. Note
representations of stress/strain states including the :math:`zz` component. Note
also that are not concerned with the issue of volumetric locking induced by
incompressible plastic deformations since quadratic triangles in 2D is enough
to mitigate the locking phenomenon.
incompressible plastic deformations since quadratic triangles in 2D is enough
to mitigate the locking phenomenon.
The plastic strain evolution during the cylinder expansion will look like this:
......@@ -35,12 +35,12 @@ The plastic strain evolution during the cylinder expansion will look like this:
Problem position
-----------------
In FEniCS 2017.2, the FEniCS Form Compiler ``ffc`` now uses ``uflacs`` as a default
In FEniCS 2017.2, the FEniCS Form Compiler ``ffc`` now uses ``uflacs`` as a default
representation instead of the old ``quadrature`` representation. However, using
``Quadrature`` elements generates some bugs in this representation and we therefore
need to revert to the old representation. Deprecation warning messages are also disabled.
See `this post <https://www.allanswered.com/post/lknbq/assemble-quadrature-representation-vs-uflacs/>`_
and the corresponding `issue <https://bitbucket.org/fenics-project/ffc/issues/146/uflacs-generates-undefined-variable-for>`_
and the corresponding `issue <https://bitbucket.org/fenics-project/ffc/issues/146/uflacs-generates-undefined-variable-for>`_
for more information.::
from __future__ import print_function
......@@ -64,9 +64,9 @@ can also be related to a tangent elastic modulus :math:`E_t = \dfrac{EH}{E+H}`.
The considered problem is that of a plane strain hollow cylinder of internal (resp. external)
radius :math:`R_i` (resp. :math:`R_e`) under internal uniform pressure :math:`q`.
radius :math:`R_i` (resp. :math:`R_e`) under internal uniform pressure :math:`q`.
Only a quarter of cylinder is generated using ``Gmsh`` and converted to ``.xml`` format. ::
# elastic parameters
E = Constant(70e3)
nu = Constant(0.3)
......@@ -80,7 +80,7 @@ Only a quarter of cylinder is generated using ``Gmsh`` and converted to ``.xml``
mesh = Mesh("thick_cylinder.xml")
facets = MeshFunction("size_t", mesh, "thick_cylinder_facet_region.xml")
ds = Measure('ds')[facets]
Function spaces will involve a standard CG space for the displacement whereas internal
state variables such as plastic strains will be represented using a **Quadrature** element.
This choice will make it possible to express the complex non-linear material constitutive
......@@ -99,16 +99,16 @@ of Gauss points will be determined by the required degree of the Quadrature elem
W = FunctionSpace(mesh, We)
W0e = FiniteElement("Quadrature", mesh.ufl_cell(), degree=deg_stress, quad_scheme='default')
W0 = FunctionSpace(mesh, W0e)
.. note::
In older versions, it was possible to define Quadrature function spaces directly
using ``FunctionSpace(mesh, "Quadrature", 1)``. This is no longer the case since
FEniCS 2016.1 (see `this issue <https://bitbucket.org/fenics-project/dolfin/issues/757/functionspace-mesh-quadrature-1-broken-in>`_). Instead, Quadrature elements must first be defined
FEniCS 2016.1 (see `this issue <https://bitbucket.org/fenics-project/dolfin/issues/757/functionspace-mesh-quadrature-1-broken-in>`_). Instead, Quadrature elements must first be defined
by specifying the associated degree and quadrature scheme before defining the
associated FunctionSpace.
Various functions are defined to keep track of the current internal state and
currently computed increments::
......@@ -124,21 +124,21 @@ currently computed increments::
u_ = TestFunction(V)
Boundary conditions correspond to symmetry conditions on the bottom and left
parts (resp. numbered 1 and 3). Loading consists of a uniform pressure on the
parts (resp. numbered 1 and 3). Loading consists of a uniform pressure on the
internal boundary (numbered 4). It will be progressively increased from 0 to
:math:`q_{lim}=\dfrac{2}{\sqrt{3}}\sigma_0\log\left(\dfrac{R_e}{R_i}\right)`
which is the analytical collapse load for a perfectly-plastic material (no hardening)::
bc = [DirichletBC(V.sub(1), 0, facets, 1), DirichletBC(V.sub(0), 0, facets, 3)]
n = FacetNormal(mesh)
q_lim = float(2/sqrt(3)*ln(Re/Ri)*sig0)
loading = Expression("-q*t", q=q_lim, t=0, degree=2)
def F_ext(v):
return loading*dot(n, v)*ds(4)
-----------------------------
Constitutive relation update
-----------------------------
......@@ -147,7 +147,7 @@ Before writing the variational form, we now define some useful functions which
will enable performing the constitutive relation update using a return mapping
procedure. This step is quite classical in FEM plasticity for a von Mises criterion
with isotropic hardening and follow notations from [BON2014]_. First, the strain
tensor will be represented in a 3D fashion by appending zeros on the out-of-plane
tensor will be represented in a 3D fashion by appending zeros on the out-of-plane
components since, even if the problem is 2D, the plastic constitutive relation will
involve out-of-plane plastic strains. The elastic consitutive relation is also defined
and a function ``as_3D_tensor`` will enable to represent a 4 dimensional vector
......@@ -166,35 +166,35 @@ containing respectively :math:`xx, yy, zz` and :math:`xy` components as a 3D ten
[0, 0, X[2]]])
The return mapping procedure consists in finding a new stress :math:`\boldsymbol{\sigma}_{n+1}`
and internal variable :math:`p_{n+1}` state verifying the current plasticity condition
from a previous stress :math:`\boldsymbol{\sigma}_{n}` and internal variable :math:`p_n` state and
and internal variable :math:`p_{n+1}` state verifying the current plasticity condition
from a previous stress :math:`\boldsymbol{\sigma}_{n}` and internal variable :math:`p_n` state and
an increment of total deformation :math:`\Delta \boldsymbol{\varepsilon}`. An elastic
trial stress :math:`\boldsymbol{\sigma}_{\text{elas}} = \boldsymbol{\sigma}_{n} + \mathbf{C}\Delta \boldsymbol{\varepsilon}`
is first computed. The plasticity criterion is then evaluated with the previous plastic strain
:math:`f_{\text{elas}} = \sigma^{eq}_{\text{elas}} - \sigma_0 - H p_n` where
trial stress :math:`\boldsymbol{\sigma}_{\text{elas}} = \boldsymbol{\sigma}_{n} + \mathbf{C}\Delta \boldsymbol{\varepsilon}`
is first computed. The plasticity criterion is then evaluated with the previous plastic strain
:math:`f_{\text{elas}} = \sigma^{eq}_{\text{elas}} - \sigma_0 - H p_n` where
:math:`\sigma^{eq}_{\text{elas}} = \sqrt{\frac{3}{2}\boldsymbol{s}:\boldsymbol{s}}`
with the deviatoric elastic stress :math:`\boldsymbol{s} = \operatorname{dev}\boldsymbol{\sigma}_{\text{elas}}`.
If :math:`f_{\text{elas}} < 0`, no plasticity occurs during this time increment and
:math:`\Delta p,\Delta \boldsymbol{\varepsilon}^p =0`.
:math:`\Delta p,\Delta \boldsymbol{\varepsilon}^p =0`.
Otherwise, plasticity
occurs and the increment of plastic strain is given by :math:`\Delta p = \dfrac{f_{\text{elas}}}{3\mu+H}`.
Hence, both elastic and plastic evolution can be accounted for by defining the
plastic strain increment as follows:
plastic strain increment as follows:
.. math::
\Delta p = \dfrac{\langle f_{\text{elas}}\rangle_+}{3\mu+H}
where :math:`\langle \star \rangle_+` represents the positive part of :math:`\star`
and is obtained by function ``ppos``. Plastic evolution also requires the computation
of the normal vector to the final yield surface given by
of the normal vector to the final yield surface given by
:math:`\boldsymbol{n}_{\text{elas}} = \boldsymbol{s}/\sigma_{\text{elas}}^{eq}`. In the following,
this vector must be zero in case of elastic evolution. Hence, we multiply it by
this vector must be zero in case of elastic evolution. Hence, we multiply it by
:math:`\dfrac{\langle f_{\text{elas}}\rangle_+}{ f_{\text{elas}}}` to tackle
both cases in a single expression. The final stress state is corrected by the
plastic strain as follows :math:`\boldsymbol{\sigma}_{n+1} = \boldsymbol{\sigma}_{\text{elas}} -
\beta \boldsymbol{s}` with :math:`\beta = \dfrac{3\mu}{\sigma_{\text{elas}}^{eq}}\Delta p`.
It can be observed that the last term vanishes in case of elastic evolution so
both cases in a single expression. The final stress state is corrected by the
plastic strain as follows :math:`\boldsymbol{\sigma}_{n+1} = \boldsymbol{\sigma}_{\text{elas}} -
\beta \boldsymbol{s}` with :math:`\beta = \dfrac{3\mu}{\sigma_{\text{elas}}^{eq}}\Delta p`.
It can be observed that the last term vanishes in case of elastic evolution so
that the final stress is indeed the elastic predictor. ::
ppos = lambda x: (x+abs(x))/2.
......@@ -202,7 +202,7 @@ that the final stress is indeed the elastic predictor. ::
sig_n = as_3D_tensor(old_sig)
sig_elas = sig_n + sigma(deps)
s = dev(sig_elas)
sig_eq = sqrt(3/2.*inner(s, s))
sig_eq = sqrt(3/2.*inner(s, s))
f_elas = sig_eq - sig0 - H*old_p
dp = ppos(f_elas)/(3*mu+H)
n_elas = s/sig_eq*ppos(f_elas)/f_elas
......@@ -212,7 +212,7 @@ that the final stress is indeed the elastic predictor. ::
as_vector([n_elas[0, 0], n_elas[1, 1], n_elas[2, 2], n_elas[0, 1]]), \
beta, dp
.. note::
.. note::
We could have used conditionals to write more explicitly the difference
between elastic and plastic evolution.
......@@ -224,10 +224,10 @@ need to derive the algorithmic consistent tangent matrix given by:
\boldsymbol{n}_{\text{elas}} \otimes \boldsymbol{n}_{\text{elas}} - 2\mu\beta\mathbf{DEV}
where :math:`\mathbf{DEV}` is the 4th-order tensor associated with the deviatoric
operator (note that :math:`\mathbf{C}_{\text{tang}}^{\text{alg}}=\mathbf{C}` for
elastic evolution). Contrary to what is done in the FEniCS book, we do not store it as the components
of a 4th-order tensor but it will suffice keeping track of the normal vector and
the :math:`\beta` parameter related to the plastic strains. We instead define a function
operator (note that :math:`\mathbf{C}_{\text{tang}}^{\text{alg}}=\mathbf{C}` for
elastic evolution). Contrary to what is done in the FEniCS book, we do not store it as the components
of a 4th-order tensor but it will suffice keeping track of the normal vector and
the :math:`\beta` parameter related to the plastic strains. We instead define a function
computing the tangent stress :math:`\boldsymbol{\sigma}_\text{tang} = \mathbf{C}_{\text{tang}}^{\text{alg}}
\boldsymbol{\varepsilon}` as follows::
......@@ -242,26 +242,26 @@ Global problem and Newton-Raphson procedure
We are now in position to derive the global problem with its associated
Newton-Raphson procedure. Each iteration will require establishing equilibrium
by driving to zero the residual between the internal forces associated with the current
by driving to zero the residual between the internal forces associated with the current
stress state ``sig`` and the external force vector. Because we use Quadrature
elements a custom integration measure must be defined to match the quadrature
degree and scheme used by the Quadrature elements::
metadata = {"quadrature_degree": deg_stress, "quadrature_scheme": "default"}
dxm = dx(metadata=metadata)
a_Newton = inner(eps(v), sigma_tang(eps(u_)))*dxm
res = -inner(eps(u_), as_3D_tensor(sig))*dxm + F_ext(u_)
The consitutive update defined earlier will perform nonlinear operations on
The consitutive update defined earlier will perform nonlinear operations on
the stress and strain tensors. These nonlinear expressions must then be projected
back onto the associated Quadrature spaces. Since these fields are defined locally
in each cell (in fact only at their associated Gauss point), this projection can
be performed locally. For this reason, we define a ``local_project`` function
that use the ``LocalSolver`` to gain in efficiency (see also :ref:`TipsTricksProjection`)
for more details::
def local_project(v, V, u=None):
dv = TrialFunction(V)
v_ = TestFunction(V)
......@@ -279,17 +279,17 @@ for more details::
.. note::
We could have used the standard ``project`` if we are not interested in optimizing
the code. However, the use of Quadrature elements would have required telling
the code. However, the use of Quadrature elements would have required telling
``project`` to use an appropriate integration measure to solve the global :math:`L^2`
projection that occurs under the hood. This would have needed either redefining
projection that occurs under the hood. This would have needed either redefining
explicitly the projection associated forms (as we just did) or specifiying the
appropriate quadrature degree to the form compiler as follows
:code:`project(sig_, W, form_compiler_parameters={"quadrature_degree":deg_stress})`
Before defining the Newton-Raphson loop, we set up the output file and appropriate
FunctionSpace (here piecewise constant) and Function for output of the equivalent
FunctionSpace (here piecewise constant) and Function for output of the equivalent
plastic strain since XDMF output does not handle Quadrature elements::
file_results = XDMFFile("plasticity_results.xdmf")
file_results.parameters["flush_output"] = True
file_results.parameters["functions_share_mesh"] = True
......@@ -303,7 +303,7 @@ the list of load steps). A nonlinear discretization is adopted to refine the
load steps during the plastic evolution phase. At each time increment, the
system is assembled and the residual norm is computed. The incremental displacement
``Du`` is initialized to zero and the inner iteration loop performing the constitutive
update is initiated. Inside this loop, corrections ``du`` to the displacement
update is initiated. Inside this loop, corrections ``du`` to the displacement
increment are computed by solving the Newton system and the return mapping
update is performed using the current total strain increment ``deps``. The resulting
quantities are then projected onto their appropriate FunctionSpaces. The Newton
......@@ -338,21 +338,21 @@ the total displacement, stress and plastic strain states are updated ::
u.assign(u+Du)
sig_old.assign(sig)
p.assign(p+local_project(dp_, W0))
----------------
Post-processing
----------------
Inside the incremental loop, the displacement and plastic strains are exported
at each time increment, the plastic strain must first be projected onto the
previously defined DG FunctionSpace. We also monitor the value of the cylinder
previously defined DG FunctionSpace. We also monitor the value of the cylinder
displacement on the inner boundary. The load-displacement curve is then plotted::
file_results.write(u, t)
p_avg.assign(project(p, P0))
file_results.write(p_avg, t)
results[i+1, :] = (u(Ri, 0)[0], t)
import matplotlib.pyplot as plt
plt.plot(results[:, 0], results[:, 1], "-o")
plt.xlabel("Displacement of inner boundary")
......@@ -364,13 +364,13 @@ The load-displacement curve looks as follows:
.. image:: cylinder_expansion_load_displ.png
:scale: 20%
It can also be checked that the analytical limit load is also well reproduced
It can also be checked that the analytical limit load is also well reproduced
when considering a zero hardening modulus.
-----------
References
-----------
.. [BON2014] Marc Bonnet, Attilio Frangi, Christian Rey.
.. [BON2014] Marc Bonnet, Attilio Frangi, Christian Rey.
*The finite element method in solid mechanics.* McGraw Hill Education, pp.365, 2014
......@@ -12,10 +12,10 @@
Introduction
------------
In this first numerical tour, we will show how to compute a small strain solution for
In this first numerical tour, we will show how to compute a small strain solution for
a 2D isotropic linear elastic medium, either in plane stress or in plane strain,
in a tradtional displacement-based finite element formulation. The corresponding
file can be obtained from :download:`2D_elasticity.py`.Extension to 3D
in a tradtional displacement-based finite element formulation. The corresponding
file can be obtained from :download:`2D_elasticity.py`. Extension to 3D
is straightforward and an example can be found in the :ref:`ModalAnalysis` example.
We consider here the case of a cantilever beam modeled as a 2D medium of dimensions
......@@ -25,7 +25,7 @@ We also choose a criss-crossed structured mesh::
from __future__ import print_function
from fenics import *
L = 25.
H = 1.
Nx = 250
......@@ -37,10 +37,10 @@ Constitutive relation
---------------------
We now define the material parameters which are here given in terms of a Young's
modulus :math:`E` and a Poisson coefficient :math:`\nu`. In the following, we will
need to define the constitutive relation between the stress tensor :math:`\boldsymbol{\sigma}`
and the strain tensor :math:`\boldsymbol{\varepsilon}`. Let us recall
that the general expression of the linear elastic isotropic constitutive relation
modulus :math:`E` and a Poisson coefficient :math:`\nu`. In the following, we will
need to define the constitutive relation between the stress tensor :math:`\boldsymbol{\sigma}`
and the strain tensor :math:`\boldsymbol{\varepsilon}`. Let us recall
that the general expression of the linear elastic isotropic constitutive relation
for a 3D medium is given by:
.. math::
......@@ -52,61 +52,61 @@ for a natural (no prestress) initial state where the Lamé coefficients are give
.. math::
\lambda = \dfrac{E\nu}{(1+\nu)(1-2\nu)}, \quad \mu = \dfrac{E}{2(1+\nu)}
:label: Lame_coeff
In this demo, we consider a 2D model either in plane strain or in plane stress conditions.
In this demo, we consider a 2D model either in plane strain or in plane stress conditions.
Irrespective of this choice, we will work only with a 2D displacement vector :math:`\boldsymbol{u}=(u_x,u_y)`
and will subsequently define the strain operator ``eps`` as follows::
def eps(v):
return sym(grad(v))
which computes the 2x2 plane components of the symmetrized gradient tensor of
which computes the 2x2 plane components of the symmetrized gradient tensor of
any 2D vectorial field. In the plane strain case, the full 3D strain tensor is defined as follows:
.. math::
\boldsymbol{\varepsilon} = \begin{bmatrix} \varepsilon_{xx} & \varepsilon_{xy} & 0\\
\varepsilon_{xy} & \varepsilon_{yy} & 0 \\ 0 & 0 & 0\end{bmatrix}
so that the 2x2 plane part of the stress tensor is defined in the same way as for the 3D case
so that the 2x2 plane part of the stress tensor is defined in the same way as for the 3D case
(the out-of-plane stress component being given by :math:`\sigma_{zz}=\lambda(\varepsilon_{xx}+\varepsilon_{yy})`.
In the plane stress case, an out-of-plane strain component :math:`\varepsilon_{zz}`
In the plane stress case, an out-of-plane strain component :math:`\varepsilon_{zz}`
must be considered so that :math:`\sigma_{zz}=0`. Using this condition in the
3D constitutive relation, one has :math:`\varepsilon_{zz}=-\dfrac{\lambda}{\lambda+2\mu}(\varepsilon_{xx}+\varepsilon_{yy})`.
3D constitutive relation, one has :math:`\varepsilon_{zz}=-\dfrac{\lambda}{\lambda+2\mu}(\varepsilon_{xx}+\varepsilon_{yy})`.
Injecting into :eq:`constitutive_3D`, we have for the 2D plane stress relation:
.. math::
\boldsymbol{\sigma} = \lambda^* \text{tr}(\boldsymbol{\varepsilon})\mathbf{1} + 2\mu\boldsymbol{\varepsilon}
where :math:`\boldsymbol{\sigma}, \boldsymbol{\varepsilon}, \mathbf{1}` are 2D tensors and with
:math:`\lambda^* = \dfrac{2\lambda\mu}{\lambda+2\mu}`. Hence, the 2D constitutive relation
is identical to the plane strain case by changing only the value of the Lamé coefficient :math:`\lambda`.
:math:`\lambda^* = \dfrac{2\lambda\mu}{\lambda+2\mu}`. Hence, the 2D constitutive relation
is identical to the plane strain case by changing only the value of the Lamé coefficient :math:`\lambda`.
We can then have::
E = Constant(1e5)
nu = Constant(0.3)