File: test_point_source.py

package info (click to toggle)
scifem 0.17.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,416 kB
  • sloc: python: 4,442; cpp: 323; sh: 16; makefile: 3
file content (111 lines) | stat: -rw-r--r-- 4,209 bytes parent folder | download | duplicates (3)
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
from mpi4py import MPI
import pytest
import dolfinx
import basix
import numpy as np
import ufl
from scifem import PointSource


def test_midpoint():
    """Check that adding point sources at all midpoints is equivalent of assembling
    the form ``v/abs(det(J))dx`` with a midpoint quadrature rule"""
    mesh = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, 2, 2)
    V = dolfinx.fem.functionspace(mesh, ("Lagrange", 1))
    tdim = mesh.topology.dim
    num_cells_local = mesh.topology.index_map(tdim).size_local
    midpoints = dolfinx.mesh.compute_midpoints(
        mesh, tdim, np.arange(num_cells_local, dtype=np.int32)
    )
    # Send all points from rank 0
    source_points = mesh.comm.gather(midpoints, root=0)
    if mesh.comm.rank == 0:
        source_points = np.vstack(source_points)
    else:
        source_points = np.empty((0, 3), dtype=midpoints.dtype)
    point_source = PointSource(V, source_points)
    np.testing.assert_allclose(point_source._cells, np.arange(num_cells_local, dtype=np.int32))
    np.testing.assert_allclose(point_source._points, midpoints)

    b = dolfinx.fem.Function(V)
    b.x.array[:] = 0
    point_source.apply_to_vector(b)
    b.x.scatter_reverse(dolfinx.la.InsertMode.add)
    b.x.scatter_forward()

    cell_geometry = basix.geometry(mesh.basix_cell())
    midpoint = (np.sum(cell_geometry, axis=0) / midpoints.shape[1]).reshape(
        -1, cell_geometry.shape[1]
    )

    b_ref = dolfinx.fem.Function(V)
    b_ref.x.array[:] = 0
    v = ufl.TestFunction(V)
    dx = ufl.Measure(
        "dx",
        domain=mesh,
        metadata={
            "quadrature_points": midpoint,
            "quadrature_weights": np.array([1.0]),
            "quadrature_rule": "custom",
        },
    )
    ref_L = dolfinx.fem.form(ufl.conj(v) / abs(ufl.JacobianDeterminant(mesh)) * dx)
    dolfinx.fem.assemble_vector(b_ref.x.array, ref_L)
    b_ref.x.scatter_reverse(dolfinx.la.InsertMode.add)
    b_ref.x.scatter_forward()

    np.testing.assert_allclose(b.x.array, b_ref.x.array)


def test_outside():
    mesh = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, 2, 2)
    V = dolfinx.fem.functionspace(mesh, ("Lagrange", 3))
    if mesh.comm.rank == 0:
        point = np.array([[1.1, 1.8, 0]])
    else:
        point = np.empty((0, 3), dtype=mesh.geometry.x.dtype)

    if MPI.COMM_WORLD.rank == 0:
        with pytest.raises(ValueError, match="Point source is outside the mesh"):
            ps = PointSource(V, point)
    else:
        # Can only catch this on a single rank with pytest as it is
        # the only one that sends in a point
        ps = PointSource(V, point)

    # Check if perturbing the mesh gets the point within
    mesh.geometry.x[:, :] *= 2
    b = dolfinx.fem.Function(V)
    ps = PointSource(V, point)
    ps.apply_to_vector(b, recompute=False)
    b.x.scatter_reverse(dolfinx.la.InsertMode.add)
    b.x.scatter_forward()

    # Check sanity of values in b
    bbtree = dolfinx.geometry.bb_tree(mesh, mesh.topology.dim)
    cell_candidates = dolfinx.geometry.compute_collisions_points(bbtree, point)
    cells = dolfinx.geometry.compute_colliding_cells(mesh, cell_candidates, point)
    # Only use evaluate for points on current processor
    # BUG: In DOLFINx 0.8.0, links(0) yields a too long array
    if cells.offsets[-1] > 0:
        cell = cells.links(0)[0]
        geom_dofs = mesh.geometry.dofmap[cell]
        ref_x = mesh.geometry.cmap.pull_back(point.reshape(-1, 3), mesh.geometry.x[geom_dofs])
        ref_values = V.ufl_element().tabulate(0, ref_x).flatten()
        b_nonzero = np.flatnonzero(b.x.array)
        dofs = V.dofmap.cell_dofs(cell)
        assert len(b_nonzero) == len(dofs)
        assert len(np.intersect1d(b_nonzero, dofs)) == len(dofs)
        b_contributions = b.x.array[dofs]
        np.testing.assert_allclose(ref_values, b_contributions)

    # Scale down geometry and check that re-computing raises an error
    mesh.geometry.x[:, :] /= 2
    ps.apply_to_vector(b, recompute=False)

    if MPI.COMM_WORLD.rank == 0:
        with pytest.raises(ValueError, match="Point source is outside the mesh"):
            ps.apply_to_vector(b, recompute=True)
    else:
        ps.apply_to_vector(b, recompute=True)