File: test_solve_result_against_reference.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 (151 lines) | stat: -rwxr-xr-x 5,775 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
"""This file solves a simple reaction-diffusion problem and compares
the norm of the solution vector with a known solution (obtained when
running in serial). It is used for validating mesh partitioning and
parallel assembly/solve."""

# Copyright (C) 2009-2014 Anders Logg
#
# 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/>.
#
# Modified by Garth N. Wells, 2013

import pytest
import sys
from dolfin import *
from dolfin_utils.test import *

# Relative tolerance for regression test
tol = 1e-10

def compute_norm(mesh, degree):
    "Solve on given mesh file and degree of function space."

    # Create function space
    V = FunctionSpace(mesh, "Lagrange", degree)

    # Define variational problem
    v = TestFunction(V)
    u = TrialFunction(V)
    f = Expression("sin(x[0])", degree=degree)
    g = Expression("x[0]*x[1]", degree=degree)
    a = dot(grad(v), grad(u))*dx + v*u*dx
    L = v*f*dx - v*g*ds

    # Compute solution
    w = Function(V)
    solve(a == L, w)

    # Return norm of solution vector
    return w.vector().norm("l2")

def print_reference(results):
    "Print nicely formatted values for gluing into code as a reference"
    MPI.barrier(MPI.comm_world)
    if MPI.rank(MPI.comm_world) == 0:
        print("reference = {", end=' ')
        for (i, result) in enumerate(results):
            if i > 0:
                print("             ", end=' ')
            print("(\"%s\", %d): %.16g" % result, end=' ')
            if i < len(results) - 1:
                print(",")
            else:
                print("}")
    MPI.barrier(MPI.comm_world)

def check_results(results, reference, tol):
    "Compare results with reference"
    errors = []
    for (mesh_file, degree, norm) in results:
        if (mesh_file, degree) not in reference:
            errors.append((mesh_file, degree, None, None, None))
        else:
            ref = reference[(mesh_file, degree)]
            diff = abs(norm - ref) / abs(ref)
            if diff >= tol:
                errors.append((mesh_file, degree, norm, ref, diff))
    return errors

def print_errors(errors):
    MPI.barrier(MPI.comm_world)
    if MPI.rank(MPI.comm_world) == 0:
        print("Checking results")
        print("----------------")
        for (mesh_file, degree, norm, ref, diff) in errors:
            print("(%s, %d):\t" % (mesh_file, degree), end=' ')
            if diff is None:
                print("missing reference")
            else:
                print("*** ERROR", end=' ')
                print("(norm = %.16g, reference = %.16g, relative diff = %.16g)" % (norm, ref, diff))
    MPI.barrier(MPI.comm_world)

def test_computed_norms_against_references():
    # Reference values for norm of solution vector
    reference = { ("16x16 unit tri square", 1): 9.547454087328376 ,
                  ("16x16 unit tri square", 2): 18.42366670418269 ,
                  ("16x16 unit tri square", 3): 27.29583104732836 ,
                  ("16x16 unit tri square", 4): 36.16867128121694 ,
                  ("4x4x4 unit tet cube", 1): 12.23389289626038 ,
                  ("4x4x4 unit tet cube", 2): 28.96491629163837 ,
                  ("4x4x4 unit tet cube", 3): 49.97350551329799 ,
                  ("4x4x4 unit tet cube", 4): 74.49938266409099 ,
                  ("16x16 unit quad square", 1): 9.550848071820747 ,
                  ("16x16 unit quad square", 2): 18.423668706176354 ,
                  ("16x16 unit quad square", 3): 27.295831017251672 ,
                  ("16x16 unit quad square", 4): 36.168671281610855 ,
                  ("4x4x4 unit hex cube", 1): 12.151954087339782 ,
                  ("4x4x4 unit hex cube", 2): 28.965646690046885 ,
                  ("4x4x4 unit hex cube", 3): 49.97349423895635 ,
                  ("4x4x4 unit hex cube", 4): 74.49938136593539 }

    # Mesh files and degrees to check
    meshes = [(UnitSquareMesh(16, 16), "16x16 unit tri square"),
              (UnitCubeMesh(4, 4, 4),  "4x4x4 unit tet cube"),
              (UnitSquareMesh.create(16, 16, CellType.Type.quadrilateral), "16x16 unit quad square"),
              (UnitCubeMesh.create(4, 4, 4, CellType.Type.hexahedron), "4x4x4 unit hex cube")]
    degrees = [1, 2, 3, 4]

    # For MUMPS, increase estimated require memory increase. Typically
    # required for high order elements on small meshes in 3D
    if has_petsc():
        PETScOptions.set("mat_mumps_icntl_14", 40)

    # Iterate over test cases and collect results
    results = []
    for mesh in meshes:
        for degree in degrees:
            gc_barrier()
            norm = compute_norm(mesh[0], degree)
            results.append((mesh[1], degree, norm))

    # Change option back to default
    if has_petsc():
        PETScOptions.set("mat_mumps_icntl_14", 20)

    # Check results
    errors = check_results(results, reference, tol)

    # Print errors for debugging if they fail
    if errors:
        print_errors(errors)

    # Print results for use as reference
    if any(e[-1] is None for e in errors): # e[-1] is diff
        print_reference(results)

    # A passing test should have no errors
    assert len(errors) == 0 # See stdout for detailed norms and diffs.