Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mortar methods generalizations and fixes #305

Merged
merged 36 commits into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7b998e4
Add MeshMortar and fix ex04
kinnala Jan 7, 2020
e5da7ce
Add doflocs to ElementHex1
kinnala Jan 7, 2020
326bc44
Clean up
kinnala Jan 7, 2020
77b7bed
Support more general directions and cases in MeshMortar
kinnala Jan 10, 2020
816de0f
Merge branch 'master' into mortar-methods-fix
kinnala Jan 11, 2020
b7f5037
Allow multiple inputs to MappingAffine.G
kinnala Jan 11, 2020
0e7e567
Refactor MeshMortar and MortarBasis
kinnala Jan 11, 2020
055236b
Allow element-wise inputs to detDG
kinnala Jan 13, 2020
8498fac
Further testing of the approach
kinnala Jan 13, 2020
ac485a5
Build mortar mappings instead of mortar meshes
kinnala Jan 13, 2020
40d259e
Change warning message
kinnala Jan 13, 2020
900a0f2
Remove ValueError on missing intorder
kinnala Jan 13, 2020
f7a642c
Fix shapes of the boundary mapping outputs
kinnala Jan 15, 2020
178ca57
Improve docstring
kinnala Jan 15, 2020
f6e626f
Add ElementQuadDG
kinnala Jan 15, 2020
0221a91
Merge branch 'master' into mortar-methods-fix
kinnala Jan 15, 2020
1aeb3e6
More generic example for ex04
kinnala Jan 15, 2020
d8a8eca
Rename MeshMortar to MortarPair
kinnala Jan 16, 2020
bd48e03
Remove references to MeshMortar
kinnala Jan 17, 2020
2a839f1
Create supermesh in the intersection of projected boundaries
kinnala Jan 17, 2020
a63cd5f
Avoid regenerating mesh at test suite
kinnala Jan 17, 2020
f732938
Add io for .json files
kinnala Jan 17, 2020
5dfa746
Add the ex04_mesh.json
kinnala Jan 17, 2020
fb91410
Rename skfem.importers to skfem.io
kinnala Jan 17, 2020
3a1afc4
Add changelog entry
kinnala Jan 17, 2020
5f31aa9
Make deprecation message better
kinnala Jan 17, 2020
e0ac052
Add changelog entry about mortaring
kinnala Jan 17, 2020
78e5246
Merge branch 'master' into mortar-methods-fix
kinnala Jan 18, 2020
f66c484
Use DeprecationWarning category
kinnala Jan 18, 2020
e42b20a
Improve dosctring
kinnala Jan 18, 2020
ac5e2f3
Improve docstring
kinnala Jan 18, 2020
da4416c
Merge branch 'master' into mortar-methods-fix
kinnala Jan 19, 2020
dbdd766
Add tests for MortarPair
kinnala Jan 19, 2020
b8ed693
Update changelog
kinnala Jan 19, 2020
531aea8
Add ex04 to docs and lots of small improvements
kinnala Jan 20, 2020
e556b8e
Add the definition of jump
kinnala Jan 20, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed
- Renamed skfem.importers to skfem.io.

### Added
- MortarBasis and MortarPair that support mortar methods in 2D.
- Serialization of meshes to json-files via skfem.io.json.
- ElementQuadDG for transforming H1 elements to DG elements.

## [0.4.1] - 2020-01-19

### Added
Expand Down
2 changes: 2 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ Defining a global basis

.. autoclass:: skfem.assembly.InteriorBasis

.. automethod:: skfem.assembly.InteriorBasis.refinterp

.. autoclass:: skfem.assembly.FacetBasis

Assembling matrices
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# -- Project information -----------------------------------------------------

project = 'scikit-fem'
copyright = '2018-2019, Tom Gustafsson, Geordie McBain'
copyright = '2018-20, Tom Gustafsson, Geordie McBain'
author = 'Tom Gustafsson, Geordie McBain'


Expand Down
11 changes: 6 additions & 5 deletions docs/learning.rst → docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ Poisson equation
examples/ex14.rst
examples/ex12.rst
examples/ex13.rst
examples/ex15.rst
examples/ex26.rst
examples/ex09.rst
examples/ex07.rst
examples/ex05.rst
examples/ex10.rst
examples/ex22.rst
examples/ex15.rst
examples/ex06.rst

Heat transfer
#############
Expand Down Expand Up @@ -51,11 +52,12 @@ Structural mechanics

.. toctree::

examples/ex03.rst
examples/ex11.rst
examples/ex08.rst
examples/ex02.rst
examples/ex21.rst
examples/ex04.rst
examples/ex11.rst
examples/ex03.rst
examples/ex08.rst

Others
######
Expand All @@ -64,4 +66,3 @@ Others

examples/ex23.rst
examples/ex16.rst
examples/ex06.rst
1 change: 1 addition & 0 deletions docs/examples/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
all: ex01_solution.png \
ex02_solution.png \
ex04_solution.png \
ex05_solution.png \
ex06_solution.png \
ex17_solution.png \
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/ex01.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@

@bilinear_form
def laplace(u, du, v, dv, w):
return du[0]*dv[0] + du[1]*dv[1]
return du[0] * dv[0] + du[1] * dv[1]

@linear_form
def load(v, dv, w):
return 1.0*v
return 1. * v

A = asm(laplace, basis)
b = asm(load, basis)
Expand Down
240 changes: 160 additions & 80 deletions docs/examples/ex04.py
Original file line number Diff line number Diff line change
@@ -1,133 +1,213 @@
"""
Author: kinnala

Solve a linearized contact problem between two linear elastic
bodies using the Nitsche's method.
"""

from skfem import *
from skfem.models.elasticity import linear_elasticity
import numpy as np

m = MeshTri()
m.refine(3)
M = MeshLine(np.linspace(0, 1, 6))
M = M*M
M = M._splitquads()
from skfem.io import from_meshio
from skfem.io.json import from_file, to_file


# create meshes
try:
m = from_file("docs/examples/ex04_mesh.json")
except FileNotFoundError:
from pygmsh import generate_mesh
from pygmsh.built_in import Geometry
geom = Geometry()
points = []
lines = []
points.append(geom.add_point([0., 0., 0.], .1))
points.append(geom.add_point([0., 1., 0.], .1))
points.append(geom.add_point([0.,-1., 0.], .1))
lines.append(geom.add_circle_arc(points[2], points[0], points[1]))
geom.add_physical(lines[-1], 'contact')
lines.append(geom.add_line(points[1], points[2]))
geom.add_physical(lines[-1], 'dirichlet')
geom.add_physical(geom.add_plane_surface(geom.add_line_loop(lines)), 'domain')
m = from_meshio(generate_mesh(geom, dim=2))
to_file(m, "docs/examples/ex04_mesh.json")

M = MeshLine(np.linspace(0, 1, 6)) * MeshLine(np.linspace(-1, 1, 10))
M.translate((1.0, 0.0))
M.refine()

map = MappingAffine(m)
Map = MappingAffine(M)
e1 = ElementTriP1()
e = ElementVectorH1(e1)

ib = InteriorBasis(m, e, map, 2)
Ib = InteriorBasis(M, e, Map, 2)
# define elements and bases
e1 = ElementTriP2()
e = ElementVectorH1(e1)

def rule(x, y):
return (x==1.0)
E1 = ElementQuad2()
E = ElementVectorH1(E1)

def param(x, y):
return y
ib = InteriorBasis(m, e, intorder=4)
Ib = InteriorBasis(M, E, intorder=4)

mortar = InterfaceMesh1D(m, M, rule, param)
mappings = MortarPair.init_2D(m, M,
m.boundaries['contact'],
M.facets_satisfying(lambda x: x[0] == 1.0),
np.array([0.0, 1.0]))

mb = {}
mortar_map = MappingAffine(mortar)
mb[0] = FacetBasis(mortar, e, mortar_map, 2, side=0)
mb[1] = FacetBasis(mortar, e, mortar_map, 2, side=1)
mb = [
MortarBasis(m, e, mapping = mappings[0], intorder=4),
MortarBasis(M, E, mapping = mappings[1], intorder=4),
]

# define bilinear forms
E1 = 1000.0
E2 = 1000.0

nu1 = 0.3
nu2 = 0.3

Mu1 = E1/(2.0*(1.0 + nu1))
Mu2 = E2/(2.0*(1.0 + nu2))
Mu1 = E1 / (2. * (1. + nu1))
Mu2 = E2 / (2. * (1. + nu2))

Lambda1 = E1*nu1/((1.0 + nu1)*(1.0 - 2.0*nu1))
Lambda2 = E2*nu2/((1.0 + nu2)*(1.0 - 2.0*nu2))
Lambda1 = E1 * nu1 / ((1. + nu1) * (1. - 2. * nu1))
Lambda2 = E2 * nu2 / ((1. + nu2) * (1. - 2. * nu2))

Mu = Mu1
Lambda = Lambda1

weakform1 = linear_elasticity(Lambda=Lambda1, Mu=Mu1)
weakform2 = linear_elasticity(Lambda=Lambda2, Mu=Mu2)
weakform1 = linear_elasticity(Lambda=Lambda, Mu=Mu)
weakform2 = linear_elasticity(Lambda=Lambda, Mu=Mu)


alpha = 1
alpha = 1000
limit = 0.3

# assemble the stiffness matrices
K1 = asm(weakform1, ib)
K2 = asm(weakform2, Ib)
L = 0
K = [[K1, 0.], [0., K2]]
f = [None] * 2

def tr(T):
return T[0, 0] + T[1, 1]

def C(T):
return np.array([[2. * Mu * T[0, 0] + Lambda * tr(T), 2. * Mu * T[0, 1]],
[2. * Mu * T[1, 0], 2. * Mu * T[1, 1] + Lambda * tr(T)]])

def Eps(dw):
return np.array([[dw[0][0], .5 * (dw[0][1] + dw[1][0])],
[.5 * (dw[1][0] + dw[0][1]), dw[1][1]]])


# assemble the mortar matrices
for i in range(2):
for j in range(2):
@bilinear_form
def bilin_penalty(u, du, v, dv, w):
n = w.n
ju = (-1.0)**i*(u[0]*n[0] + u[1]*n[1])
jv = (-1.0)**j*(v[0]*n[0] + v[1]*n[1])

def tr(T):
return T[0, 0] + T[1, 1]

def C(T):
return np.array([[2*Mu*T[0, 0] + Lambda*tr(T), 2*Mu*T[0, 1]],
[2*Mu*T[1, 0], 2*Mu*T[1, 1] + Lambda*tr(T)]])

def Eps(dw):
return np.array([[dw[0][0], 0.5*(dw[0][1] + dw[1][0])],
[0.5*(dw[1][0] + dw[0][1]), dw[1][1]]])
mu = 0.5*(n[0]*C(Eps(du))[0, 0]*n[0] +\
n[0]*C(Eps(du))[0, 1]*n[1] +\
n[1]*C(Eps(du))[1, 0]*n[0] +\
n[1]*C(Eps(du))[1, 1]*n[1])
mv = 0.5*(n[0]*C(Eps(dv))[0, 0]*n[0] +\
n[0]*C(Eps(dv))[0, 1]*n[1] +\
n[1]*C(Eps(dv))[1, 0]*n[0] +\
n[1]*C(Eps(dv))[1, 1]*n[1])
ju = (-1.) ** i * (u[0] * n[0] + u[1] * n[1])
jv = (-1.) ** j * (v[0] * n[0] + v[1] * n[1])
mu = .5 * (n[0] * C(Eps(du))[0, 0] * n[0] +
n[0] * C(Eps(du))[0, 1] * n[1] +
n[1] * C(Eps(du))[1, 0] * n[0] +
n[1] * C(Eps(du))[1, 1] * n[1])
mv = .5 * (n[0] * C(Eps(dv))[0, 0] * n[0] +
n[0] * C(Eps(dv))[0, 1] * n[1] +
n[1] * C(Eps(dv))[1, 0] * n[0] +
n[1] * C(Eps(dv))[1, 1] * n[1])
h = w.h
return 1.0/(alpha*h)*ju*jv - mu*jv - mv*ju

L = asm(bilin_penalty, mb[i], mb[j]) + L

@linear_form
def load(v, dv, w):
return -50*v[1]

f1 = asm(load, ib)
f2 = np.zeros(K2.shape[0])
return ((1. / (alpha * h) * ju * jv - mu * jv - mv * ju)
* (np.abs(w.x[1]) <= limit))

K[j][i] += asm(bilin_penalty, mb[i], mb[j])

@linear_form
def lin_penalty(v, dv, w):
n = w.n
jv = (-1.) ** i * (v[0] * n[0] + v[1] * n[1])
mv = .5 * (n[0] * C(Eps(dv))[0, 0] * n[0] +
n[0] * C(Eps(dv))[0, 1] * n[1] +
n[1] * C(Eps(dv))[1, 0] * n[0] +
n[1] * C(Eps(dv))[1, 1] * n[1])
h = w.h
def gap(x):
return (1. - np.sqrt(1. - x[1] ** 2))
return ((1. / (alpha * h) * gap(w.x) * jv - gap(w.x) * mv)
* (np.abs(w.x[1]) <= limit))

f[i] = asm(lin_penalty, mb[i])

import scipy.sparse
K = (scipy.sparse.bmat([[K1, None],[None, K2]]) + L).tocsr()
K = (scipy.sparse.bmat(K)).tocsr()


# set boundary conditions and solve
i1 = np.arange(K1.shape[0])
i2 = np.arange(K2.shape[0]) + K1.shape[0]

D1 = ib.get_dofs(lambda x, y: x==0.0).all()
D2 = Ib.get_dofs(lambda x, y: x==2.0).all()
D1 = ib.get_dofs(lambda x: x[0] == 0.0).all()
D2 = Ib.get_dofs(lambda x: x[0] == 2.0).all()

x = np.zeros(K.shape[0])

f = np.hstack((f1, f2))
f = np.hstack((f[0], f[1]))

x = np.zeros(K.shape[0])
D = np.concatenate((D1, D2 + ib.N))
I = np.setdiff1d(np.arange(K.shape[0]), D)

x[I] = solve(*condense(K, f, I=I))
x[ib.get_dofs(lambda x: x[0] == 0.0).nodal['u^1']] = 0.1
x[ib.get_dofs(lambda x: x[0] == 0.0).facet['u^1']] = 0.1

x = solve(*condense(K, f, I=I, x=x))


# create a displaced mesh
sf = 1

m.p[0, :] = m.p[0, :] + sf*x[i1][ib.nodal_dofs[0, :]]
m.p[1, :] = m.p[1, :] + sf*x[i1][ib.nodal_dofs[1, :]]
m.p[0, :] = m.p[0, :] + sf * x[i1][ib.nodal_dofs[0, :]]
m.p[1, :] = m.p[1, :] + sf * x[i1][ib.nodal_dofs[1, :]]

M.p[0, :] = M.p[0, :] + sf*x[i2][Ib.nodal_dofs[0, :]]
M.p[1, :] = M.p[1, :] + sf*x[i2][Ib.nodal_dofs[1, :]]
M.p[0, :] = M.p[0, :] + sf * x[i2][Ib.nodal_dofs[0, :]]
M.p[1, :] = M.p[1, :] + sf * x[i2][Ib.nodal_dofs[1, :]]

if __name__ == "__main__":

from skfem.visuals.matplotlib import draw, show
# post processing
s, S = {}, {}
e_dg = ElementTriDG(ElementTriP1())
E_dg = ElementQuadDG(ElementQuad1())

for itr in range(2):
for jtr in range(2):
@bilinear_form
def proj_cauchy(u, du, v, dv, w):
return C(Eps(du))[itr, jtr] * v

@bilinear_form
def mass(u, du, v, dv, w):
return u * v

ib_dg = InteriorBasis(m, e_dg, intorder=4)
Ib_dg = InteriorBasis(M, E_dg, intorder=4)

s[itr, jtr] = solve(asm(mass, ib_dg),
asm(proj_cauchy, ib, ib_dg) @ x[i1])
S[itr, jtr] = solve(asm(mass, Ib_dg),
asm(proj_cauchy, Ib, Ib_dg) @ x[i2])

s[2, 2] = nu1 * (s[0, 0] + s[1, 1])
S[2, 2] = nu2 * (S[0, 0] + S[1, 1])

vonmises1 = np.sqrt(.5 * ((s[0, 0] - s[1, 1]) ** 2 +
(s[1, 1] - s[2, 2]) ** 2 +
(s[2, 2] - s[0, 0]) ** 2 +
6. * s[0, 1]**2))

vonmises2 = np.sqrt(.5 * ((S[0, 0] - S[1, 1]) ** 2 +
(S[1, 1] - S[2, 2]) ** 2 +
(S[2, 2] - S[0, 0]) ** 2 +
6. * S[0, 1]**2))


if __name__ == "__main__":
from os.path import splitext
from sys import argv
from skfem.visuals.matplotlib import *

ax = draw(m)
ax = plot(ib_dg, vonmises1, shading='gouraud')
draw(m, ax=ax)
plot(Ib_dg, vonmises2, ax=ax, Nrefs=3, shading='gouraud')
draw(M, ax=ax)
show()
savefig(splitext(argv[0])[0] + '_solution.png')
Loading