コード例 #1
0
ファイル: odt.py プロジェクト: ml-lab/optimesh
def nonlinear_optimization(
    X, cells, tol, max_num_steps, verbosity=1, step_filename_format=None
):
    """Optimal Delaunay Triangulation smoothing.

    This method minimizes the energy

        E = int_Omega |u_l(x) - u(x)| rho(x) dx

    where u(x) = ||x||^2, u_l is its piecewise linear nodal interpolation and
    rho is the density. Since u(x) is convex, u_l >= u everywhere and

        u_l(x) = sum_i phi_i(x) u(x_i)

    where phi_i is the hat function at x_i. With rho(x)=1, this gives

        E = int_Omega sum_i phi_i(x) u(x_i) - u(x)
          = 1/(d+1) sum_i ||x_i||^2 |omega_i| - int_Omega ||x||^2

    where d is the spatial dimension and omega_i is the star of x_i (the set of
    all simplices containing x_i).
    """
    import scipy.optimize

    # TODO remove this assertion and test
    # flat mesh
    assert X.shape[1] == 2

    mesh = MeshTri(X, cells, flat_cell_correction=None)

    if step_filename_format:
        mesh.save(
            step_filename_format.format(0),
            show_centroids=False,
            show_coedges=False,
            show_axes=False,
            nondelaunay_edge_color="k",
        )

    if verbosity > 0:
        print("Before:")
        extra_cols = ["energy: {:.5e}".format(energy(mesh))]
        print_stats(mesh, extra_cols=extra_cols)

    def f(x):
        mesh.update_interior_node_coordinates(x.reshape(-1, 2))
        return energy(mesh, uniform_density=True)

    # TODO put f and jac together
    def jac(x):
        mesh.update_interior_node_coordinates(x.reshape(-1, 2))

        grad = numpy.zeros(mesh.node_coords.shape)
        cc = mesh.cell_circumcenters
        for mcn in mesh.cells["nodes"].T:
            fastfunc.add.at(
                grad, mcn, ((mesh.node_coords[mcn] - cc).T * mesh.cell_volumes).T
            )
        gdim = 2
        grad *= 2 / (gdim + 1)
        return grad[mesh.is_interior_node, :2].flatten()

    def flip_delaunay(x):
        flip_delaunay.step += 1
        # Flip the edges
        mesh.update_interior_node_coordinates(x.reshape(-1, 2))
        mesh.flip_until_delaunay()

        if step_filename_format:
            mesh.save(
                step_filename_format.format(flip_delaunay.step),
                show_centroids=False,
                show_coedges=False,
                show_axes=False,
                nondelaunay_edge_color="k",
            )
        if verbosity > 1:
            print("\nStep {}:".format(flip_delaunay.step))
            print_stats(mesh, extra_cols=["energy: {}".format(f(x))])

        # mesh.show()
        # exit(1)
        return

    flip_delaunay.step = 0

    x0 = X[mesh.is_interior_node, :2].flatten()

    out = scipy.optimize.minimize(
        f,
        x0,
        jac=jac,
        method="CG",
        # method='newton-cg',
        tol=tol,
        callback=flip_delaunay,
        options={"maxiter": max_num_steps},
    )
    # Don't assert out.success; max_num_steps may be reached, that's fine.

    # One last edge flip
    mesh.update_interior_node_coordinates(out.x.reshape(-1, 2))
    mesh.flip_until_delaunay()

    if verbosity > 0:
        print("\nFinal ({} steps):".format(out.nit))
        extra_cols = ["energy: {:.5e}".format(energy(mesh))]
        print_stats(mesh, extra_cols=extra_cols)
        print()

    return mesh.node_coords, mesh.cells["nodes"]
コード例 #2
0
def runner(
    get_new_interior_points,
    X,
    cells,
    tol,
    max_num_steps,
    verbosity=1,
    step_filename_format=None,
    uniform_density=False,
):
    if X.shape[1] == 3:
        # create flat mesh
        assert numpy.all(abs(X[:, 2]) < 1.0e-15)
        X = X[:, :2]

    mesh = MeshTri(X, cells, flat_cell_correction=None)
    mesh.flip_until_delaunay()

    if step_filename_format:
        mesh.save(
            step_filename_format.format(0),
            show_centroids=False,
            show_coedges=False,
            show_axes=False,
            nondelaunay_edge_color="k",
        )

    if verbosity > 0:
        print("Before:")
        print_stats(mesh)

    k = 0
    while True:
        k += 1

        new_interior_points = get_new_interior_points(mesh)

        original_orient = mesh.signed_tri_areas > 0.0
        original_coords = mesh.node_coords[mesh.is_interior_node]

        # Step unless the orientation of any cell changes.
        alpha = 1.0
        while True:
            xnew = (1 - alpha) * original_coords + alpha * new_interior_points
            mesh.update_interior_node_coordinates(xnew)
            new_orient = mesh.signed_tri_areas > 0.0
            if numpy.all(original_orient == new_orient):
                break
            alpha /= 2

        mesh.flip_until_delaunay()

        if step_filename_format:
            mesh.save(
                step_filename_format.format(k),
                show_centroids=False,
                show_coedges=False,
                show_axes=False,
                nondelaunay_edge_color="k",
            )

        # Abort the loop if the update is small
        diff = mesh.node_coords[mesh.is_interior_node] - original_coords
        if numpy.all(numpy.einsum("ij,ij->i", diff, diff) < tol**2):
            break

        if k >= max_num_steps:
            break

        if verbosity > 1:
            print("\nstep {}:".format(k))
            print_stats(mesh)

    if verbosity > 0:
        print("\nFinal ({} steps):".format(k))
        print_stats(mesh)
        print()

    return mesh.node_coords, mesh.cells["nodes"]