Пример #1
0
def test_density_quotients_decomposition(dim):
    """
    As well as having an orthogonal eigendecomposition, an SPD matrix can also be
    decomposed as :math:`dVQV^T`, where :math:`d` is the so-called `density' and :math:`Q`
    are the `anisotropy coefficients'.

    This test computes such a decomposition and checks that it is valid.
    """
    mesh = uniform_mesh(dim, 20, l=2)
    P1_vec = VectorFunctionSpace(mesh, "CG", 1)
    P1_ten = TensorFunctionSpace(mesh, "CG", 1)

    # Recover Hessian metric for some arbitrary sensor
    f = prod([sin(pi*xi) for xi in SpatialCoordinate(mesh)])
    M = steady_metric(f, mesh=mesh, V=P1_ten, normalise=False, enforce_constraints=False)

    # Extract the eigendecomposition
    V = Function(P1_ten, name="Eigenvectors")
    Λ = Function(P1_vec, name="Eigenvalues")
    kernel = eigen_kernel(get_eigendecomposition, dim)
    op2.par_loop(kernel, P1_ten.node_set, V.dat(op2.RW), Λ.dat(op2.RW), M.dat(op2.READ))

    # Extract the density and anisotropy quotients
    d, Q = get_density_and_quotients(M)
    Λ.interpolate(as_vector([pow(d/Q[i], 2/dim) for i in range(dim)]))

    # Reassemble the matrix and check the two match
    dVQVT = Function(P1_ten, name="Reassembled matrix")
    kernel = eigen_kernel(set_eigendecomposition, dim)
    op2.par_loop(kernel, P1_ten.node_set, dVQVT.dat(op2.RW), V.dat(op2.READ), Λ.dat(op2.READ))
    assert np.allclose(M.dat.data, dVQVT.dat.data)
Пример #2
0
def test_eigendecomposition(dim):
    r"""
    Any symmetric matrix :math:`M` admits an orthogonal eigendecomposition
    :math:`M = V\Lambda V^T`, where :math:`\Lambda` is diagonal and :math:`V` is unitary.

    This test computes the eigendecomposition for a symmetric matrix and checks that
    it is valid.
    """
    mesh = uniform_mesh(dim, 20, l=2)
    P1_vec = VectorFunctionSpace(mesh, "CG", 1)
    P1_ten = TensorFunctionSpace(mesh, "CG", 1)

    # Recover Hessian metric for some arbitrary sensor
    f = prod([sin(pi*xi) for xi in SpatialCoordinate(mesh)])
    M = steady_metric(f, mesh=mesh, V=P1_ten, normalise=False, enforce_constraints=False)

    # Extract the eigendecomposition
    V = Function(P1_ten, name="Eigenvectors")
    Λ = Function(P1_vec, name="Eigenvalues")
    kernel = eigen_kernel(get_eigendecomposition, dim)
    op2.par_loop(kernel, P1_ten.node_set, V.dat(op2.RW), Λ.dat(op2.RW), M.dat(op2.READ))

    # Check eigenvectors are orthogonal
    VVT = interpolate(dot(V, transpose(V)), P1_ten)
    I = interpolate(Identity(dim), P1_ten)
    assert np.allclose(VVT.dat.data, I.dat.data)

    # Reassemble it and check the two match
    VΛVT = Function(P1_ten, name="Reassembled matrix")
    kernel = eigen_kernel(set_eigendecomposition, dim)
    op2.par_loop(kernel, P1_ten.node_set, VΛVT.dat(op2.RW), V.dat(op2.READ), Λ.dat(op2.READ))
    assert np.allclose(M.dat.data, VΛVT.dat.data)
 def density(mesh=None, x=None):
     """
     Adapt to the density of an L1-normalised
     Hessian metric for the sensor.
     """
     M = steady_metric(sensor(mesh, xy=x),
                       mesh=mesh,
                       op=op,
                       **hessian_kwargs)
     rho = get_density_and_quotients(M)[0]
     return 1.0 + alpha * rho / rho.vector().gather().max()
 def frobenius(mesh=None, x=None):
     """
     Adapt to the Frobenius norm of an L1-normalised
     Hessian metric for the sensor.
     """
     P1 = FunctionSpace(mesh, "CG", 1)
     M = steady_metric(sensor(mesh, xy=x),
                       mesh=mesh,
                       op=op,
                       **hessian_kwargs)
     M_F = local_frobenius_norm(M, space=P1)
     return 1.0 + alpha * M_F / interpolate(M_F, P1).vector().gather().max()
Пример #5
0
        0.1 * sin(50 * x) + atan(0.1 / (sin(5 * y) - 2 * x)),
        atan(0.1 / (sin(5 * y) - 2 * x)) + atan(0.5 / (sin(3 * y) - 7 * x))
    ][i]


op = DefaultOptions()
op.h_min = 1e-6
op.h_max = 0.1
op.num_adapt = 4
modes = ['target', 'p_norm', 'p_norm', 'p_norm']
orders = [None, 1, 2, None]
for op.normalisation, op.norm_order in zip(modes, orders):
    if op.normalisation == 'p_norm':
        normalisation = 'l-inf' if op.norm_order is None else 'l{:d}'.format(
            op.norm_order)
    else:
        normalisation = 'target'
    for i in range(4):
        for k in range(3):
            print("\nNormalisation {:s}  Sensor {:d}  Iteration {:d}".format(
                normalisation, i, k))
            op.target = pow(10, k)
            for j in range(op.num_adapt):
                if j == 0:
                    mesh = SquareMesh(40, 40, 2, 2)
                    mesh.coordinates.dat.data[:] -= [1, 1]
                mesh = adapt(mesh,
                             steady_metric(sensor(i, mesh), mesh=mesh, op=op))
            File('plots/normalisation_{:s}__sensor_{:d}__mesh_{:d}.pvd'.format(
                normalisation, i, k)).write(mesh.coordinates)
Пример #6
0
def recover_boundary_hessian(f, **kwargs):
    """
    Recover the Hessian of `f` on the domain boundary. That is, the Hessian in the direction
    tangential to the boundary. In two dimensions this gives a scalar field, whereas in three
    dimensions it gives a 2D field on the surface. The resulting field should only be considered on
    the boundary and is set arbitrarily to 1/h_max in the interior.

    :arg f: field which we seek the Hessian of.
    :kwarg op: `Options` class object providing max cell size value.
    :kwarg boundary_tag: physical ID for boundary segment
    :return: reconstructed boundary Hessian associated with `f`.
    """
    from adapt_utils.adapt.metric import steady_metric
    from adapt_utils.linalg import get_orthonormal_vectors

    kwargs.setdefault('op', Options())
    op = kwargs.get('op')
    op.print_debug("RECOVERY: Recovering Hessian on domain boundary...")
    mesh = kwargs.get('mesh', op.default_mesh)
    dim = mesh.topological_dimension()
    if dim not in (2, 3):
        raise ValueError("Dimensions other than 2D and 3D not considered.")

    # Solver parameters
    solver_parameters = op.hessian_solver_parameters['parts']
    if op.debug:
        solver_parameters['ksp_monitor'] = None
        solver_parameters['ksp_converged_reason'] = None

    # Function spaces
    P1 = FunctionSpace(mesh, "CG", 1)
    P1_ten = TensorFunctionSpace(mesh, "CG", 1)

    # Apply Gram-Schmidt to get tangent vectors
    n = FacetNormal(mesh)
    s = get_orthonormal_vectors(n)
    ns = as_vector([n, *s])

    # --- Solve tangent to boundary

    bcs = kwargs.get('bcs')
    assert bcs is None  # TODO
    boundary_tag = kwargs.get('boundary_tag', 'on_boundary')
    Hs, v = TrialFunction(P1), TestFunction(P1)
    l2_proj = [[Function(P1) for i in range(dim - 1)] for j in range(dim - 1)]
    h = Constant(1 / op.h_max**2)

    # Arbitrary value in domain interior
    a = v * Hs * dx
    L = v * h * dx

    # Hessian on boundary
    a_bc = v * Hs * ds
    nullspace = VectorSpaceBasis(constant=True)
    for j, s1 in enumerate(s):
        for i, s0 in enumerate(s):
            L_bc = -dot(s0, grad(v)) * dot(s1, grad(f)) * ds
            bbcs = None  # TODO?
            bcs = EquationBC(a_bc == L_bc,
                             l2_proj[i][j],
                             boundary_tag,
                             bcs=bbcs)
            solve(a == L,
                  l2_proj[i][j],
                  bcs=bcs,
                  nullspace=nullspace,
                  solver_parameters=solver_parameters)

    # --- Construct tensor field

    boundary_hessian = Function(P1_ten)
    if dim == 2:
        Hsub = abs(l2_proj[i][j])
        H = as_matrix([[h, 0], [0, Hsub]])
    else:
        Hsub = Function(TensorFunctionSpace(mesh, "CG", 1, shape=(2, 2)))
        Hsub.interpolate(
            as_matrix([[l2_proj[0][0], l2_proj[0][1]],
                       [l2_proj[1][0], l2_proj[1][1]]]))
        Hsub = steady_metric(H=Hsub,
                             normalise=False,
                             enforce_constraints=False,
                             op=op)
        H = as_matrix([[h, 0, 0], [0, Hsub[0, 0], Hsub[0, 1]],
                       [0, Hsub[1, 0], Hsub[1, 1]]])

    # Arbitrary value in domain interior
    sigma, tau = TrialFunction(P1_ten), TestFunction(P1_ten)
    a = inner(tau, sigma) * dx
    L = inner(tau, h * Identity(dim)) * dx

    # Boundary values imposed as in [Loseille et al. 2011]
    a_bc = inner(tau, sigma) * ds
    L_bc = inner(tau, dot(transpose(ns), dot(H, ns))) * ds
    bcs = EquationBC(a_bc == L_bc, boundary_hessian, boundary_tag)
    solve(a == L,
          boundary_hessian,
          bcs=bcs,
          solver_parameters=solver_parameters)
    return boundary_hessian