def test_analytical(monitor, method, plot_mesh=False):
    """
    Check that the moved mesh matches that obtained previously.
    """
    fname = '_'.join([monitor.__name__, method])
    fpath = os.path.dirname(__file__)

    op = Options(approach='monge_ampere', r_adapt_rtol=1.0e-03, nonlinear_method=method)

    mesh = UnitSquareMesh(20, 20)
    orig_vol = assemble(Constant(1.0)*dx(domain=mesh))
    mm = MeshMover(mesh, monitor, op=op)
    mm.adapt()

    mesh.coordinates.assign(mm.x)
    vol = assemble(Constant(1.0)*dx(domain=mesh))
    assert np.allclose(orig_vol, vol), "Volume is not conserved!"

    if plot_mesh:
        import matplotlib.pyplot as plt
        fig, axes = plt.subplots(figsize=(5, 5))
        triplot(mesh, axes=axes, interior_kw={'linewidth': 0.1}, boundary_kw={'color': 'k'})
        axes.axis(False)
        savefig(fname, os.path.join(fpath, 'outputs'), extensions=['png'])

    if not os.path.exists(os.path.join(fpath, 'data', fname + '.npy')):
        np.save(os.path.join(fpath, 'data', fname), mm.x.dat.data)
        if not plot_mesh:
            pytest.xfail("Needed to set up the test. Please try again.")
    loaded = np.load(os.path.join(fpath, 'data', fname + '.npy'))
    assert np.allclose(mm.x.dat.data, loaded), "Mesh does not match data"
예제 #2
0
def test_combine_monitor(plot_mesh=False):
    """
    For monitor functions based on the sensors
    above, compare the meshes resulting from
    averaging and intersection (visually).

    In terms of testing, we just check for
    convergence and that volume is conserved.
    """
    alpha = Constant(10.0)  # Controls magnitude of arc
    beta = Constant(10.0)   # Controls width of arc

    def monitor1(mesh=None, x=None):
        x, y = x or SpatialCoordinate(mesh)
        return 1.0 + alpha*exp(-beta*abs(0.5 - x**2 - y**2))

    def monitor2(mesh=None, x=None):
        x, y = x or SpatialCoordinate(mesh)
        return 1.0 + alpha*exp(-beta*abs(0.5 - (1 - x)**2 - y**2))

    # Set parameters
    kwargs = {
        'approach': 'monge_ampere',
        'r_adapt_rtol': 1.0e-08,
        'nonlinear_method': 'relaxation',
    }
    op = Options(**kwargs)
    fpath = os.path.dirname(__file__)

    for mode in [1, 2, 'avg', 'int']:
        fname = {1: 'monitor1', 2: 'monitor2', 'avg': 'average', 'int': 'intersection'}[mode]
        monitor = monitor_combine(monitor1, monitor2, mode)

        # Create domain
        mesh = uniform_mesh(2, 100)
        orig_vol = assemble(Constant(1.0)*dx(domain=mesh))

        # Move the mesh and check for volume conservation
        mm = MeshMover(mesh, monitor, op=op)
        mm.adapt()
        mesh.coordinates.assign(mm.x)
        vol = assemble(Constant(1.0)*dx(domain=mesh))
        assert np.isclose(orig_vol, vol), "Volume is not conserved!"

        h = interpolate(CellSize(mesh), mm.P0).vector().gather()
        print("Combination method '{:s}':".format(fname))
        print("Minimum cell size = {:.4e}".format(h.min()))
        print("Maximum cell size = {:.4e}".format(h.max()))
        print("Mean cell size    = {:.4e}".format(np.mean(h)))

        # Plot mesh
        if plot_mesh:
            fig, axes = plt.subplots(figsize=(5, 5))
            triplot(mesh, axes=axes, interior_kw={'linewidth': 0.1}, boundary_kw={'color': 'k'})
            axes.axis(False)
            savefig(fname, os.path.join(fpath, 'outputs', op.approach), extensions=['png'])
            plt.close()
예제 #3
0
파일: base.py 프로젝트: mc4117/adapt_utils
    def set_monitor_functions(self, monitors, bc=None, bbc=None):
        """
        Pass a monitor function to each mesh, thereby defining a `MeshMover` object which drives
        r-adaptation.

        This method is used under 'monge_ampere' and 'laplacian_smoothing' adaptation approaches.

        :arg monitors: a monitor function which takes one argument (the mesh) or a list thereof.
        :kwarg bc: boundary conditions to apply within the mesh movement algorithm.
        :kwarg bbc: boundary conditions to apply within EquationBC objects which appear in the mesh
            movement algorithm.
        """
        from adapt_utils.adapt.r import MeshMover

        # Sanitise input
        assert self.approach in ('monge_ampere', 'laplacian_smoothing')
        assert monitors is not None
        if callable(monitors):
            monitors = [monitors for mesh in self.meshes]

        # Create `MeshMover` objects which drive r-adaptation
        kwargs = {
            'method': self.approach,
            'bc': bc,
            'bbc': bbc,
            'op': self.op,
        }
        self.op.print_debug("MESH MOVEMENT: Creating MeshMover objects...")
        for i in range(self.num_meshes):
            assert monitors[i] is not None
            args = (Mesh(self.meshes[i].coordinates.copy(deepcopy=True)), monitors[i])
            self.mesh_movers[i] = MeshMover(*args, **kwargs)
예제 #4
0
def test_adjoint(monitor, nonlinear_method, ctrl, bnd, qoi):
    """
    Test replay and gradient for control `ctrl`, boundary condition `bnd` and quantity of
    interest `qoi`.
    """
    rtol = 1.0e-01
    maxiter = 100
    alpha = Constant(10.0)
    beta = Constant(200.0)
    gamma = Constant(0.15)
    if ctrl == 'alpha':
        init = 10.0
        control = Control(alpha)
    elif ctrl == 'beta':
        init = 200.0
        control = Control(beta)

    def ring(x=None, **kwargs):
        """
        An analytically defined monitor function which concentrates mesh density in
        a narrow ring within the unit square domain.
        """
        r = dot(x, x)
        return Constant(1.0) + alpha * pow(cosh(beta * (r - gamma)), -2)

    def bell(mesh=None, x=None):
        """
        An analytically defined monitor function which concentrates mesh density in
        a bell region within the unit square domain.
        """
        r = dot(x, x)
        return 1.0 + alpha * pow(cosh(0.5 * beta * r), -2)

    # Setup mesh
    with stop_annotating():
        mesh = UnitSquareMesh(20, 20)
        coords = mesh.coordinates.copy(deepcopy=True)
        coords.interpolate(coords - as_vector([0.5, 0.5]))
    mesh = Mesh(coords)

    # Setup boundary conditions
    if bnd == 'dirichlet':
        P1_vec = VectorFunctionSpace(mesh, "CG", 1)
        bc = DirichletBC(P1_vec, 0, 'on_boundary')
        bbc = []
    elif bnd == 'freeslip':
        bc, bbc = [], []
    else:
        bc, bbc = None, None

    # Move mesh
    mm = MeshMover(
        mesh,
        ring if monitor == 'ring' else bell,
        bc=bc,
        bbc=bbc,
        nonlinear_method=nonlinear_method,
    )
    mm.adapt(rtol=rtol, maxiter=maxiter)

    # Evaluate some functional
    J = assemble(qoi(mm.x))
    stop_annotating()

    # Test replay given same input
    Jhat = ReducedFunctional(J, control)
    c = Constant(init)
    JJ = Jhat(c)
    assert np.isclose(J, JJ), f"{J} != {JJ}"

    # Test replay given different input
    c = Constant(1.1 * init)
    JJ = Jhat(c)
    JJJ = Jhat(c)
    assert np.isclose(JJ, JJJ), f"{JJ} != {JJJ}"

    # Taylor test
    c = Constant(init)
    dc = Constant(1.0)
    minconv = taylor_test(Jhat, c, dc)
    assert minconv > 1.90, "Taylor test failed"
예제 #5
0
    fpath = os.path.join(fpath, initial_monitor_type)
fpath = os.path.join(fpath, monitor_type)
op = BoydOptions(approach='monge_ampere',
                 n=n_coarse,
                 fpath=fpath,
                 order=kwargs['order'])
op.update(kwargs)

# --- Initialise mesh

swp = AdaptiveProblem(op)

# Refine around equator and/or soliton
if initial_monitor is not None:
    mesh_mover = MeshMover(swp.meshes[0],
                           initial_monitor,
                           method='monge_ampere',
                           op=op)
    mesh_mover.adapt()
    mesh = Mesh(mesh_mover.x)
    op.__init__(mesh=mesh, **kwargs)
    swp.__init__(op, meshes=[mesh])

# --- Monitor function definitions


def elevation_norm_monitor(mesh, alpha=40.0, norm_type='H1', **kwargs):
    """
    Monitor function derived from the elevation `norm_type` norm.

    :kwarg alpha: controls the amplitude of the monitor function.
    """
def test_sensors(sensor, monitor_type, method, plot_mesh=False):
    alpha = Constant(5.0)
    hessian_kwargs = dict(enforce_constraints=False,
                          normalise=True,
                          noscale=True)
    pytest.xfail("FIXME")  # FIXME

    def shift_and_scale(mesh=None, x=None):
        """
        Adapt to the scaled and shifted sensor magnitude.
        """
        f = interpolate(abs(sensor(mesh, xy=x)), FunctionSpace(mesh, "CG", 1))
        return 1.0 + alpha * abs(sensor(mesh,
                                        xy=x)) / f.vector().gather().max()

    def gradient(mesh=None, x=None):
        """
        Adapt to a recovered gradient for the sensor.
        """
        g = recover_gradient(sensor(mesh, xy=x), mesh=mesh, op=op)
        gmax = g.vector().gather().max()
        return 1.0 + alpha * dot(g, g) / dot(gmax, gmax)

    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()

    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()

    rtol = 1.0e-03
    if monitor_type == 'shift_and_scale':
        monitor = shift_and_scale
    elif monitor_type == 'gradient':
        monitor = gradient
    elif monitor_type == 'frobenius':
        monitor = frobenius
    elif monitor_type == 'density':
        monitor = density
    else:
        raise ValueError(
            "Monitor function type {:s} not recognised.".format(monitor_type))

    # Set parameters
    kwargs = {
        'approach': 'monge_ampere',
        'r_adapt_rtol': rtol,
        'nonlinear_method': method,
        'normalisation': 'complexity',
        'norm_order': None,
    }
    op = Options(**kwargs)
    fname = '_'.join([sensor.__name__, monitor_type, method])
    fpath = os.path.dirname(__file__)

    # Create domain
    n = 100
    mesh = SquareMesh(n, n, 2)
    x, y = SpatialCoordinate(mesh)
    mesh.coordinates.interpolate(as_vector([x - 1, y - 1]))
    orig_vol = assemble(Constant(1.0) * dx(domain=mesh))

    # Move the mesh and check for volume conservation
    mm = MeshMover(mesh, monitor, op=op)
    mm.adapt()
    mesh.coordinates.assign(mm.x)
    vol = assemble(Constant(1.0) * dx(domain=mesh))
    assert np.isclose(orig_vol, vol), "Volume is not conserved!"

    # Plot mesh
    if plot_mesh:
        import matplotlib.pyplot as plt
        fig, axes = plt.subplots(figsize=(5, 5))
        triplot(mesh,
                axes=axes,
                interior_kw={'linewidth': 0.1},
                boundary_kw={'color': 'k'})
        axes.axis(False)
        savefig(fname,
                os.path.join(fpath, 'outputs', op.approach),
                extensions=['png'])
        plt.close()
        return

    # Save mesh coordinates to file
    if not os.path.exists(os.path.join(fpath, 'data', fname + '.npy')):
        np.save(os.path.join(fpath, 'data', fname), mm.x.dat.data)
        if not plot_mesh:
            pytest.xfail("Needed to set up the test. Please try again.")
    loaded = np.load(os.path.join(fpath, 'data', fname + '.npy'))
    assert np.allclose(mm.x.dat.data, loaded), "Mesh does not match data"