File: test_local_assembler.py

package info (click to toggle)
dolfin 2018.1.0.post1-16
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 28,764 kB
  • sloc: xml: 104,040; cpp: 98,856; python: 22,511; makefile: 204; sh: 182
file content (156 lines) | stat: -rw-r--r-- 4,923 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"""Unit tests for local assembly"""

# Copyright (C) 2015 Tormod Landet
#
# This file is part of DOLFIN.
#
# DOLFIN is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DOLFIN is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with DOLFIN. If not, see <http://www.gnu.org/licenses/>.

import numpy
from dolfin import *
from dolfin_utils.test import set_parameters_fixture


ghost_mode = set_parameters_fixture("ghost_mode", ["shared_facet"])


def test_local_assembler_1D():
    mesh = UnitIntervalMesh(20)
    V = FunctionSpace(mesh, 'CG', 1)
    u = TrialFunction(V)
    v = TestFunction(V)
    c = Cell(mesh, 0)

    a_scalar = Constant(1)*dx(domain=mesh)
    a_vector = v*dx
    a_matrix = u*v*dx

    A_scalar = assemble_local(a_scalar, c)
    A_vector = assemble_local(a_vector, c)
    A_matrix = assemble_local(a_matrix, c)

    assert isinstance(A_scalar, float)
    assert near(A_scalar, 0.05)

    assert isinstance(A_vector, numpy.ndarray)
    assert A_vector.shape == (2,)
    assert near(A_vector[0], 0.025)
    assert near(A_vector[1], 0.025)

    assert isinstance(A_matrix, numpy.ndarray)
    assert A_matrix.shape == (2, 2)
    assert near(A_matrix[0, 0], 1/60)
    assert near(A_matrix[0, 1], 1/120)
    assert near(A_matrix[1, 0], 1/120)
    assert near(A_matrix[1, 1], 1/60)


def test_local_assembler_on_facet_integrals(ghost_mode):
    mesh = UnitSquareMesh(4, 4, 'right')
    Vcg = FunctionSpace(mesh, 'CG', 1)
    Vdg = FunctionSpace(mesh, 'DG', 0)
    Vdgt = FunctionSpace(mesh, 'DGT', 1)

    v = TestFunction(Vdgt)
    n = FacetNormal(mesh)

    # Initialize DG function "w" in discontinuous pattern
    w = Expression('(1.0 + pow(x[0], 2.2) + 1/(0.1 + pow(x[1], 3)))*300.0',
                   element=Vdg.ufl_element())

    # Define form that tests that the correct + and - values are used
    L = w('-')*v('+')*dS

    # Compile form. This is collective
    L = Form(L)

    # Get global cell 10. This will return a cell only on one of the
    # processes
    c = get_cell_at(mesh, 5/12, 1/3, 0)

    if c:
        # Assemble locally on the selected cell
        b_e = assemble_local(L, c)

        # Compare to values from phonyx (fully independent
        # implementation)
        b_phonyx = numpy.array([266.55210302, 266.55210302, 365.49000122,
                                365.49000122,          0.0,          0.0])
        error = sum((b_e - b_phonyx)**2)**0.5
        error = float(error)  # MPI.max does strange things to numpy.float64

    else:
        error = 0.0

    error = MPI.max(MPI.comm_world, float(error))
    assert error < 1e-8


def test_local_assembler_on_facet_integrals2(ghost_mode):
    mesh = UnitSquareMesh(4, 4)
    Vu = VectorFunctionSpace(mesh, 'DG', 1)
    Vv = FunctionSpace(mesh, 'DGT', 1)
    u = TrialFunction(Vu)
    v = TestFunction(Vv)
    n = FacetNormal(mesh)

    # Define form
    a = dot(u, n)*v*ds
    for R in '+-':
        a += dot(u(R), n(R))*v(R)*dS

    # Compile form. This is collective
    a = Form(a)

    # Get global cell 0. This will return a cell only on one of the
    # processes
    c = get_cell_at(mesh, 1/6, 1/12, 0)

    if c:
        A_e = assemble_local(a, c)
        A_correct = numpy.array([[0, 1/12, 1/24, 0, 0, 0],
                                 [0, 1/24, 1/12, 0, 0, 0],
                                 [-1/12, 0, -1/24, 1/12, 0, 1/24],
                                 [-1/24, 0, -1/12, 1/24, 0, 1/12],
                                 [0, 0, 0, -1/12, -1/24, 0],
                                 [0, 0, 0, -1/24, -1/12, 0]])
        error = ((A_e - A_correct)**2).sum()**0.5
        error = float(error)  # MPI.max does strange things to numpy.float64

    else:
        error = 0.0

    error = MPI.max(MPI.comm_world, float(error))
    assert error < 1e-16


def get_cell_at(mesh, x, y, z, eps=1e-3):
    """Return the cell with the given midpoint or None if not found. The
    function also checks that the cell is found on one of the
    processes when running in parallel to avoid that the above tests
    always suceed if the cell is not found on any of the processes.

    """
    found = None
    for cell in cells(mesh):
        mp = cell.midpoint()
        if abs(mp.x() - x) + abs(mp.y() - y) + abs(mp.y() - y) < eps:
            found = cell
            break

    # Make sure this cell is on at least one of the parallel processes
    marker = 1 if found is not None else 0
    assert MPI.max(MPI.comm_world, marker) == 1

    return found