def __init__(self, c, funcgen_tol, funcgen_order):
     # c:  boundary coordinates, complex
     self.c = c
     self.cx = self.c.real.copy()
     self.cy = self.c.imag.copy()
     # get some useful boundary-related information
     self.n = self.c.size
     self.dt = 2 * np.pi / self.n
     self.ts = np.arange(self.n) * self.dt
     self.ik = np.fft.fftfreq(self.n, 1.0 / self.n)
     # get derivatives of this
     self.cp = fourier_derivative_1d(f=self.c, d=1, ik=self.ik)
     self.cpp = fourier_derivative_1d(f=self.c, d=2, ik=self.ik)
     # get direct fourier evaluator for this
     self.dirf_c = periodic_interp1d(self.c)
     self.dirf_cp = periodic_interp1d(self.cp)
     self.dirf_cpp = periodic_interp1d(self.cpp)
     # build function generator representations of these functions
     self.funcgen_c = FunctionGenerator(self.dirf_c,
                                        0,
                                        2 * np.pi,
                                        funcgen_tol,
                                        n=funcgen_order)
     self.funcgen_cp = FunctionGenerator(self.dirf_cp,
                                         0,
                                         2 * np.pi,
                                         funcgen_tol,
                                         n=funcgen_order)
     self.funcgen_cpp = FunctionGenerator(self.dirf_cpp,
                                          0,
                                          2 * np.pi,
                                          funcgen_tol,
                                          n=funcgen_order)
Пример #2
0
def compute_local_coordinates_nufft_old(cx,
                                        cy,
                                        x,
                                        y,
                                        newton_tol=1e-12,
                                        guess_ind=None,
                                        verbose=False,
                                        max_iterations=30):
    """
    Find using the coordinates:
    x = X + r n_x
    y = Y + r n_y
    """
    xshape = x.shape
    yshape = y.shape
    x = x.flatten()
    y = y.flatten()

    n = cx.shape[0]
    dt = 2 * np.pi / n
    ts = np.arange(n) * dt
    ik = 1j * np.fft.fftfreq(n, dt / (2 * np.pi))
    # tangent vectors
    xp = fourier_derivative_1d(f=cx, d=1, ik=ik, out='f')
    yp = fourier_derivative_1d(f=cy, d=1, ik=ik, out='f')
    # speed
    sp = np.sqrt(xp * xp + yp * yp)
    isp = 1.0 / sp
    # unit tangent vectors
    tx = xp * isp
    ty = yp * isp
    # unit normal vectors
    nx = ty
    ny = -tx
    # derivatives of the normal vector
    nxp = fourier_derivative_1d(f=nx, d=1, ik=ik, out='f')
    nyp = fourier_derivative_1d(f=ny, d=1, ik=ik, out='f')

    # interpolation routines for the necessary objects
    if have_better_fourier:

        def interp(f):
            return _interp2(f)
    else:

        def interp(f):
            return _interp(np.fft.fft(f), x.size)

    nx_i = interp(nx)
    ny_i = interp(ny)
    nxp_i = interp(nxp)
    nyp_i = interp(nyp)
    x_i = interp(cx)
    y_i = interp(cy)
    xp_i = interp(xp)
    yp_i = interp(yp)

    # functions for coordinate transform and its jacobian
    def f(t, r):
        x = x_i(t) + r * nx_i(t)
        y = y_i(t) + r * ny_i(t)
        return x, y

    def Jac(t, r):
        dxdt = xp_i(t) + r * nxp_i(t)
        dydt = yp_i(t) + r * nyp_i(t)
        dxdr = nx_i(t)
        dydr = ny_i(t)
        J = np.zeros((t.shape[0], 2, 2), dtype=float)
        J[:, 0, 0] = dxdt
        J[:, 0, 1] = dydt
        J[:, 1, 0] = dxdr
        J[:, 1, 1] = dydr
        return J.transpose((0, 2, 1))

    # brute force find of guess_inds if not provided (slow!)
    if guess_ind is None:
        xd = x - cx[:, None]
        yd = y - cy[:, None]
        dd = xd**2 + yd**2
        guess_ind = dd.argmin(axis=0)

    # get starting points (initial guess for t and r)
    t = ts[guess_ind]
    cxg = cx[guess_ind]
    cyg = cy[guess_ind]
    xdg = x - cxg
    ydg = y - cyg
    r = np.sqrt(xdg**2 + ydg**2)
    # how about we re-sign r?
    nxg = nx[guess_ind]
    nyg = ny[guess_ind]
    xcr1 = cxg + r * nxg
    ycr1 = cyg + r * nyg
    d1 = np.hypot(xcr1 - x, ycr1 - y)
    xcr2 = cxg - r * nxg
    ycr2 = cyg - r * nyg
    d2 = np.hypot(xcr2 - x, ycr2 - y)
    better2 = d1 > d2
    r[better2] *= -1

    # begin Newton iteration
    xo, yo = f(t, r)
    remx = xo - x
    remy = yo - y
    rem = np.abs(np.sqrt(remx**2 + remy**2)).max()
    if verbose:
        print('Newton tol: {:0.2e}'.format(rem))
    iteration = 0
    while rem > newton_tol:
        J = Jac(t, r)
        delt = -np.linalg.solve(J, np.column_stack([remx, remy]))
        line_factor = 1.0
        while True:
            t_new, r_new = t + line_factor * delt[:,
                                                  0], r + line_factor * delt[:,
                                                                             1]
            try:
                xo, yo = f(t_new, r_new)
                remx = xo - x
                remy = yo - y
                rem_new = np.sqrt(remx**2 + remy**2).max()
                testit = True
            except:
                testit = False
            if testit and ((rem_new < (1 - 0.5 * line_factor) * rem)
                           or line_factor < 1e-4):
                t = t_new
                # put theta back in [0, 2 pi]
                t[t < 0] += 2 * np.pi
                t[t > 2 * np.pi] -= 2 * np.pi
                r = r_new
                rem = rem_new
                break
            line_factor *= 0.5
        if verbose:
            print('Newton tol: {:0.2e}'.format(rem))
        iteration += 1
        if iteration > max_iterations:
            raise Exception(
                'Exceeded maximum number of iterations solving for coordinates .'
            )

    return t, r
Пример #3
0
def compute_local_coordinates_polyi_centering(cx,
                                              cy,
                                              x,
                                              y,
                                              gi,
                                              newton_tol=1e-12,
                                              verbose=None,
                                              max_iterations=30):
    """
    Find using the coordinates:
    x = X + r n_x
    y = Y + r n_y
    """
    xshape = x.shape
    x = x.flatten()
    y = y.flatten()
    gi = gi.flatten()
    xsize = x.size

    n = cx.shape[0]
    dt = 2 * np.pi / n
    ts = np.arange(n) * dt
    ik = 1j * np.fft.fftfreq(n, dt / (2 * np.pi))
    # tangent vectors
    xp = fourier_derivative_1d(f=cx, d=1, ik=ik, out='f')
    yp = fourier_derivative_1d(f=cy, d=1, ik=ik, out='f')
    # speed
    sp = np.sqrt(xp * xp + yp * yp)
    isp = 1.0 / sp
    # unit tangent vectors
    tx = xp * isp
    ty = yp * isp
    # unit normal vectors
    nx = ty
    ny = -tx

    # brute force find of guess_inds if not provided (slow!)
    guess_ind = np.empty(x.size, dtype=int)
    multi_guess_ind_finder_centering(cx, cy, x, y, guess_ind, gi, 10)

    # get starting points (initial guess for t and r)
    initial_ts = ts[guess_ind]

    # run the multi-newton solver
    t = _multi_newton(initial_ts, x, y, newton_tol, cx, cy, verbose,
                      max_iterations)

    # need to determine the sign now
    X, Y = np.zeros_like(x), np.zeros_like(x)
    XP, YP = np.zeros_like(x), np.zeros_like(x)
    multi_polyi_p(cx, t, X, XP)
    multi_polyi_p(cy, t, Y, YP)
    ISP = 1.0 / np.sqrt(XP * XP + YP * YP)
    NX = YP / ISP
    NY = -XP / ISP
    r = np.hypot(X - x, Y - y)
    xe1 = X + r * NX
    ye1 = Y + r * NY
    err1 = np.hypot(xe1 - x, ye1 - y)
    xe2 = X - r * NX
    ye2 = Y - r * NY
    err2 = np.hypot(xe2 - x, ye2 - y)
    sign = (err1 < err2).astype(int) * 2 - 1

    return t, r * sign
Пример #4
0
def compute_local_coordinates_nufft(cx,
                                    cy,
                                    x,
                                    y,
                                    newton_tol=1e-12,
                                    guess_ind=None,
                                    verbose=False,
                                    max_iterations=30):
    """
    Find using the coordinates:
    x = X + r n_x
    y = Y + r n_y
    """
    xshape = x.shape
    yshape = y.shape
    x = x.flatten()
    y = y.flatten()

    n = cx.shape[0]
    dt = 2 * np.pi / n
    ts = np.arange(n) * dt
    ik = 1j * np.fft.fftfreq(n, dt / (2 * np.pi))
    # tangent vectors
    xp = fourier_derivative_1d(f=cx, d=1, ik=ik, out='f')
    yp = fourier_derivative_1d(f=cy, d=1, ik=ik, out='f')
    xpp = fourier_derivative_1d(f=cx, d=2, ik=ik, out='f')
    ypp = fourier_derivative_1d(f=cy, d=2, ik=ik, out='f')
    # speed
    sp = np.sqrt(xp * xp + yp * yp)
    isp = 1.0 / sp
    # unit tangent vectors
    tx = xp * isp
    ty = yp * isp
    # unit normal vectors
    nx = ty
    ny = -tx
    # interpolation routines for the necessary objects
    if have_better_fourier:

        def interp(f):
            return _interp2(f)
    else:

        def interp(f):
            return _interp(f, x.size)

    nc_i = interp(nx + 1j * ny)
    c_i = interp(cx + 1j * cy)
    cp_i = interp(xp + 1j * yp)
    cpp_i = interp(xpp + 1j * ypp)

    # function for computing (d^2)_s and its derivative
    def f(t, x, y):
        C = c_i(t)
        X = C.real
        Y = C.imag
        Cp = cp_i(t)
        Xp = Cp.real
        Yp = Cp.imag
        return Xp * (X - x) + Yp * (Y - y), X, Y, Xp, Yp

    def fp(t, x, y, X, Y, Xp, Yp):
        Cpp = cpp_i(t)
        Xpp = Cpp.real
        Ypp = Cpp.imag
        return Xpp * (X - x) + Ypp * (Y - y) + Xp * Xp + Yp * Yp

    # brute force find of guess_inds if not provided (slow!)
    if guess_ind is None:
        guess_ind = np.empty(x.size, dtype=int)
        multi_guess_ind_finder(cx, cy, x, y, guess_ind)

    # get starting guess
    t = ts[guess_ind]

    # begin Newton iteration
    rem, X, Y, Xp, Yp = f(t, x, y)
    mrem = np.abs(rem).max()
    if verbose:
        print('Newton tol: {:0.2e}'.format(mrem))
    iteration = 0
    while mrem > newton_tol:
        J = fp(t, x, y, X, Y, Xp, Yp)
        delt = -rem / J
        line_factor = 1.0
        while True:
            t_new = t + line_factor * delt
            rem_new, X, Y, Xp, Yp = f(t_new, x, y)
            mrem_new = np.abs(rem_new).max()
            # try:
            #     rem_new, X, Y, Xp, Yp = f(t_new, x, y)
            #     mrem_new = np.abs(rem_new).max()
            #     testit = True
            # except:
            #     testit = False
            testit = True
            if testit and ((mrem_new < (1 - 0.5 * line_factor) * mrem)
                           or line_factor < 1e-4):
                t = t_new
                # put theta back in [0, 2 pi]
                t[t < 0] += 2 * np.pi
                t[t > 2 * np.pi] -= 2 * np.pi
                rem = rem_new
                mrem = mrem_new
                break
            line_factor *= 0.5
        if verbose:
            print('Newton tol: {:0.2e}'.format(mrem))
        iteration += 1
        if iteration > max_iterations:
            raise Exception(
                'Exceeded maximum number of iterations solving for coordinates .'
            )

    # need to determine the sign now
    C = c_i(t)
    X = C.real
    Y = C.imag
    if True:  # use nx, ny from guess_inds to determine sign
        NX = nx[guess_ind]
        NY = ny[guess_ind]
    else:  # interpolate to get these
        NC = nc_i(t)
        NX = NC.real
        NY = NC.imag
    r = np.hypot(X - x, Y - y)

    xe1 = X + r * NX
    ye1 = Y + r * NY
    err1 = np.hypot(xe1 - x, ye1 - y)
    xe2 = X - r * NX
    ye2 = Y - r * NY
    err2 = np.hypot(xe2 - x, ye2 - y)

    sign = (err1 < err2).astype(int) * 2 - 1

    return t, r * sign
Пример #5
0
def compute_local_coordinates_polyi_old(cx,
                                        cy,
                                        x,
                                        y,
                                        newton_tol=1e-12,
                                        guess_ind=None,
                                        verbose=False,
                                        max_iterations=30):
    """
    Find using the coordinates:
    x = X + r n_x
    y = Y + r n_y
    """
    xshape = x.shape
    x = x.flatten()
    y = y.flatten()
    xsize = x.size

    n = cx.shape[0]
    dt = 2 * np.pi / n
    ts = np.arange(n) * dt
    ik = 1j * np.fft.fftfreq(n, dt / (2 * np.pi))
    # tangent vectors
    xp = fourier_derivative_1d(f=cx, d=1, ik=ik, out='f')
    yp = fourier_derivative_1d(f=cy, d=1, ik=ik, out='f')
    # speed
    sp = np.sqrt(xp * xp + yp * yp)
    isp = 1.0 / sp
    # unit tangent vectors
    tx = xp * isp
    ty = yp * isp
    # unit normal vectors
    nx = ty
    ny = -tx
    # derivatives of the normal vector
    nxp = fourier_derivative_1d(f=nx, d=1, ik=ik, out='f')
    nyp = fourier_derivative_1d(f=ny, d=1, ik=ik, out='f')

    # brute force find of guess_inds if not provided (slow!)
    if guess_ind is None:
        xd = x - cx[:, None]
        yd = y - cy[:, None]
        dd = xd**2 + yd**2
        guess_ind = dd.argmin(axis=0)

    # get starting points (initial guess for t and r)
    initial_ts = ts[guess_ind]
    cxg = cx[guess_ind]
    cyg = cy[guess_ind]
    xdg = x - cxg
    ydg = y - cyg
    initial_rs = np.sqrt(xdg**2 + ydg**2)
    # how about we re-sign r?
    nxg = nx[guess_ind]
    nyg = ny[guess_ind]
    xcr1 = cxg + initial_rs * nxg
    ycr1 = cyg + initial_rs * nyg
    d1 = np.hypot(xcr1 - x, ycr1 - y)
    xcr2 = cxg - initial_rs * nxg
    ycr2 = cyg - initial_rs * nyg
    d2 = np.hypot(xcr2 - x, ycr2 - y)
    better2 = d1 > d2
    initial_rs[better2] *= -1

    # run the multi-newton solver
    all_t, all_r = _multi_newton_old(initial_ts, initial_rs, x, y, newton_tol,
                                     cx, cy, nx, ny, xp, yp, nxp, nyp, verbose,
                                     max_iterations)
    return all_t, all_r