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

FacetBasis.trace() #530

Merged
merged 34 commits into from
Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
79ab061
Start work on FacetBasis.trace
kinnala Dec 23, 2020
4a6523d
Make trace generic over different element types
kinnala Dec 23, 2020
5db3e67
Add ElementHex0 and tests for trace mesh
kinnala Dec 23, 2020
4fdce53
Extend docstring with return value
kinnala Dec 23, 2020
f40b086
Fix some types
kinnala Dec 23, 2020
1538195
Add comments and an exception if more than one interior DOF
kinnala Jan 1, 2021
a63fb66
Improve comments
kinnala Jan 1, 2021
961610a
Fix typing
kinnala Jan 2, 2021
eab15a0
Make FacetBasis.trace more DWIM
kinnala Jan 2, 2021
0424ab5
Add typing to the function handle argument
kinnala Jan 2, 2021
9ace134
Apply isort
kinnala Jan 2, 2021
d550bf9
Add changelog entries and fix typo
kinnala Jan 2, 2021
7ea82b7
Ignore mypy error and clarify comment
kinnala Jan 2, 2021
0092ca7
Add typing to silence mypy
kinnala Jan 2, 2021
b96743a
Add test case for the default target_elem
kinnala Jan 3, 2021
97eb6f8
Split FacetBasis.trace into two methods
kinnala Jan 3, 2021
30ca65a
Deprecate some asm() parameter types
kinnala Jan 5, 2021
f976251
Add a changelog entry
kinnala Jan 5, 2021
0afa4ff
ex18 as exx27, 30 #534
gdmcbain Jan 7, 2021
256ca58
Revert "ex18 as exx27, 30 #534"
gdmcbain Jan 7, 2021
6996d44
ex18 as exx27, 30 #534
gdmcbain Jan 7, 2021
55a0a75
copy quadrature from prior basis
gdmcbain Jan 7, 2021
c14e29c
Revert "copy quadrature from prior basis"
gdmcbain Jan 7, 2021
cfda62d
Revert "ex18 as exx27, 30 #534"
gdmcbain Jan 7, 2021
5c78912
ex18 as exx27, 30 #534
gdmcbain Jan 7, 2021
d902c4f
whitespace
gdmcbain Jan 7, 2021
a8699da
Merge pull request #535 from gdmcbain/asm-parameters-ex18
kinnala Jan 7, 2021
dfa488d
Merge pull request #534 from kinnala/deprecate-asm-parameters
kinnala Jan 7, 2021
1f5b532
Remove redundant second value
kinnala Jan 8, 2021
e209157
Fix flake8
kinnala Jan 8, 2021
f08abd7
Rename variable
kinnala Jan 8, 2021
835ca1b
Remove import
kinnala Jan 8, 2021
ebedc58
Fix typing
kinnala Jan 9, 2021
406e60a
Refactor part of _trace to Mesh
kinnala Jan 9, 2021
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
53 changes: 51 additions & 2 deletions skfem/assembly/basis/facet_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,59 @@ def default_parameters(self):
'h': self.mesh_parameters(),
'n': self.normals}

def global_coordinates(self) -> ndarray:
def global_coordinates(self) -> DiscreteField:
return DiscreteField(self.mapping.G(self.X, find=self.find))

def mesh_parameters(self) -> ndarray:
def mesh_parameters(self) -> DiscreteField:
return DiscreteField((np.abs(self.mapping.detDG(self.X, self.find))
** (1. / (self.mesh.dim() - 1.)))
if self.mesh.dim() != 1 else np.array([0.]))

def trace(self,
x: ndarray,
elem: Optional[Element] = None) -> Tuple[ndarray,
ndarray,
ndarray]:
"""Restrict solution to a boundary/interface mesh.

Parameters
----------
x
The solution vector.
elem
If given, perform L2 projection onto the new element before
restriction. L2 projection is performed on the boundary.

Returns
-------
p
The nodes of the trace mesh.
t
The elements of the trace mesh.
y
The new (projected and) restricted solution vector.

"""
from skfem.utils import project

cls = type(self)
fbasis = self if elem is None else cls(self.mesh,
elem,
facets=self.find,
quadrature=(self.X, self.W))
I = fbasis.get_dofs(self.find).all()
if len(I) == 0: # special case: no facet DOFs
if fbasis.dofs.interior_dofs.shape[0] > 1:
# no one-to-one restriction: requires interpolation
raise NotImplementedError
# special case: piecewise constant elem
I = fbasis.dofs.interior_dofs[:, self.tind].flatten()
y = x[I] if elem is None else project(x, self, fbasis, I=I)

# build connectivity for lower dimensional mesh
ix = self.mesh.facets[:, self.find]
ixuniq = np.unique(ix)
b = np.zeros(np.max(ix) + 1, dtype=np.int64)
b[ixuniq] = np.arange(len(ixuniq), dtype=np.int64)

return self.mesh.p[:, ixuniq], b[ix], y
4 changes: 3 additions & 1 deletion skfem/element/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@
from .element_tet import (ElementTetP0, ElementTetP1, ElementTetP2,
ElementTetRT0, ElementTetN0, ElementTetMini,
ElementTetCR)
from .element_hex import ElementHex1, ElementHex2, ElementHexS2 # noqa
from .element_hex import (ElementHex0, ElementHex1, ElementHex2,
ElementHexS2) # noqa
from .element_line import (ElementLineP0, ElementLineP1, ElementLineP2,
ElementLinePp, ElementLineHermite,
ElementLineMini) # noqa
Expand Down Expand Up @@ -95,6 +96,7 @@
"ElementTetN0",
"ElementTetMini",
"ElementTetCR",
"ElementHex0",
"ElementHex1",
"ElementHex2",
"ElementHexS2",
Expand Down
2 changes: 1 addition & 1 deletion skfem/element/element_hex/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Yadda"""
from .element_hex0 import ElementHex0 # noqa
from .element_hex1 import ElementHex1 # noqa
from .element_hex_s2 import ElementHexS2 # noqa
from .element_hex2 import ElementHex2 # noqa
20 changes: 20 additions & 0 deletions skfem/element/element_hex/element_hex0.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import numpy as np

from ..element_h1 import ElementH1
from ...mesh.mesh3d import MeshHex


class ElementHex0(ElementH1):
kinnala marked this conversation as resolved.
Show resolved Hide resolved

interior_dofs = 1
dim = 3
maxdeg = 0
dofnames = ['u']
doflocs = np.array([[.5, .5, .5]])
mesh_type = MeshHex

def lbasis(self, X, i):
if i == 0:
return np.ones(X.shape[1:]), np.zeros_like(X)
else:
self._index_error()
1 change: 1 addition & 0 deletions skfem/element/element_hex/element_hex1.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@


class ElementHex1(ElementH1):

nodal_dofs = 1
dim = 3
maxdeg = 3
Expand Down
40 changes: 37 additions & 3 deletions tests/test_basis.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
from unittest import TestCase

import pytest
import numpy as np
from numpy.testing import assert_allclose
from numpy.testing import assert_allclose, assert_almost_equal

from skfem import BilinearForm, asm, solve, condense, project
from skfem.mesh import MeshTri, MeshTet, MeshHex, MeshQuad, MeshLine
from skfem.assembly import InteriorBasis, FacetBasis, Dofs
from skfem.assembly import InteriorBasis, FacetBasis, Dofs, Functional
from skfem.element import (ElementVectorH1, ElementTriP2, ElementTriP1,
ElementTetP2, ElementHexS2, ElementHex2,
ElementQuad2, ElementLineP2)
ElementQuad2, ElementLineP2, ElementTriP0,
ElementLineP0, ElementQuad1, ElementQuad0,
ElementTetP1, ElementTetP0, ElementHex1,
ElementHex0)


class TestCompositeSplitting(TestCase):
Expand Down Expand Up @@ -178,3 +182,33 @@ class TestInterpolatorLine2(TestInterpolatorTet):
mesh_type = MeshLine
element_type = ElementLineP2
nrefs = 5


@pytest.mark.parametrize(
"mtype,bndmtype,e1,e2,e3",
[
(MeshTri, MeshLine, ElementTriP1(), ElementTriP0(), ElementLineP0()),
(MeshQuad, MeshLine, ElementQuad1(), ElementQuad0(), ElementLineP0()),
(MeshTet, MeshTri, ElementTetP1(), ElementTetP0(), ElementTriP0()),
(MeshHex, MeshQuad, ElementHex1(), ElementHex0(), ElementQuad0()),
]
)
def test_trace(mtype, bndmtype, e1, e2, e3):

m = mtype()
m.refine(3)

# use the boundary where last coordinate is zero
basis = FacetBasis(m, e1,
facets=m.facets_satisfying(lambda x: x[x.shape[0] - 1] == 0.0))
p, t, y = basis.trace(m.p[0], e2)

# drop the last coordinate to create trace mesh
nbasis = InteriorBasis(bndmtype(p[0:(p.shape[0] - 1)], t), e3)

@Functional
def integ(w):
return w['funy']

# integrate f(x) = x_1 over trace mesh
assert_almost_equal(integ.assemble(nbasis, funy=nbasis.interpolate(y)), .5)