Exemplo n.º 1
0
def solve_eig(l, x_max, E0, x_num, tol):

    # Differential equation in standard form
    def f(t, y):
        return np.array(
            [y[1], (-2 / t + l * (l + 1) / t**2 - y[2]) * y[0], 0 * y[1]])

    # Boundary conditions
    def bc(ya, yb):
        return np.array([ya[0], yb[0], ya[1] - 1])

    # Create s interval
    x = np.linspace(tol, x_max, x_num)

    # Initial conditions from RK4
    y0 = de.rku4(lambda y, t: f(t, y), [0, 1, E0], x)

    # Solve BVP with solve_bvp
    sol = itg.solve_bvp(f, bc, x, y0.T, tol=tol)

    # Solve again using RK4
    #y_rk4 = de.rku4(lambda y, t:f(t, y), sol.y[:,0], s)
    #plt.plot(y_rk4[:,0], -y_rk4[:,1], label='Re:RK4')

    return sol
Exemplo n.º 2
0
def eig_shoot(g,
              a,
              b,
              lmd1,
              lmd2,
              t,
              adot=1,
              tol=10**(-8),
              max_itr=100,
              inf=False):
    '''Implements the shooting method to solve second order BVPs

    USAGE:
        y = shoot(g, a, b, lmd1, lmd2, t, tol, max_iter, inf)

    INPUT:
        g     - constructor function g(lmd) = f(y,t) which gives f for every lmd.
                f is the differential equation in the standard form dy/dt = f(y,t).
                Since we are solving a second-order boundary-value problem that has
                been transformed into a first order system, the function f should
                return a 1x2 array with the first entry equal to y and the second
                entry equal to y'.
        a     - solution value at the left boundary: a = y(t[0]).
        b     - solution value at the right boundary: b = y(t[n-1]).
        lmd1  - first initial estimate of eigenvalue.
        lmd2  - second initial estimate of eigenvalue.
        t     - array of n time values to determine y at.
        adot  - the derivative at the first boundary that you want to use.
        tol   - allowable tolerance on right boundary: | b - y[n-1] | < tol.
      max_itr - maximum number of iterations.
        inf   - set to True if we are working on a finite approximation of an
                infinite interval. This changes to method with which we update the
                eigenvalue approximations to binary search.

    OUTPUT:
        y     - array of normalized solution values corresponding to the values in
                the supplied array t.
        lmd   - solution eigenvalue corresponding to y

    NOTE:
        This function assumes that the second order BVP has been converted to
        a first order system of two equations.  The secant method is used to
        refine the values of lmd used for the initial value problems. If inf=True
        the method is changed to binary search.
    '''

    from diffeq import rku4

    n = len(t)  # Determine the size of the arrays we will generate

    # Compute solution to first initial value problem (IVP) with y'(a) = 1 and
    # lmd = lmd1. Because we are using the secant method to refine our estimates
    # of lmd, we don't really need all of the solution of the IVP, just the last
    # point of it -- this is saved in w1. w2 is, for now, an alias of w1

    y1 = rku4(g(lmd1), [a, adot], t)
    w1 = y1[n - 1, 0]
    w2 = w1

    print('%2d: lmd = %10.3e, error = %10.3e' % (0, lmd1, b - w1))

    # Begin the main loop.  We will compute the solution of a second IVP and
    # then use the both solutions to refine our estimate of lmd. This second
    # solution then replaces the first and a new 'second' solution is generated.
    # This process continues until we either solve the problem to within the
    # specified tolerance or we exceed the maximum number of allowable iterations.

    # Create iteration counter
    itr = 1

    print('inf')

    if inf == True:
        print(inf)

        y2 = rku4(g(lmd2), [a, adot], t)
        w2 = y2[n - 1, 0]

        # Check whether interval can be bisected
        if numpy.sign(w1 - b) == numpy.sign(w2 - b):
            print('\a**** ERROR ****')
            print('Interval of eigenvalues is not appropriate for bisection')

            break

        while numpy.abs(w2 - w1) > tol and itr < max_iter:

            # Calculate midpoint
            lmdm = (lmd2 + lmd1) / 2

            ym = rku4(g(lmdm), [a, adot], t)
            wm = ym[n - 1, 0]

            print('%2d: lmd = %10.3e, error = %10.3e' % (itr, lmdm, b - wm))

            if numpy.sign(wm - b) * numpy.sign(w1 - b) < 0:
                y2 = ym
            else:
                y1 = ym

            itr += 1

    else:

        while abs(b - w2) > tol and itr < max_itr:

            # Solve second initial value problem, using y'(a) = 1 and lmd = lmd2. We
            # need to retain the entire solution vector y since if y(t(n)) is close
            # enough to b for us to stop then the first column of y becomes our solution
            # vector.

            y2 = rku4(g(lmd2), [a, adot], t)
            w2 = y2[n - 1, 0]

            print('%2d: lmd = %10.3e, error = %10.3e' % (itr, lmd2, b - w2))

            # Compute the new approximations to the eigenvalue lmd. We compute lmd2
            # using a linear fit through (lmd1, w1) and (lmd2,w2) where w1 and w2 are
            # the estimates at t=b of the initial value problems solved above with. The
            # new value for lmd1 is the old value of lmd2.

            lmd1, lmd2 = (lmd2, lmd2 + (lmd2 - lmd1) / (w2 - w1) * (b - w2))
            w1 = w2

            # Update iteration counter
            itr += 1

    # All done. Check to see if we really solved the problem, and then return
    # the solution.

    if abs(b - w2) >= tol:
        print('\a**** ERROR ****')
        print('Maximum number of iterations (%d) exceeded' % max_itr)
        print('Returned values may not have desired accuracy')
        print('Error estimate of solution at the second endpoint is %e' %
              (b - w2))

    return y2[:, 0], lmd2
Exemplo n.º 3
0
def shoot(f, a, b, z1, z2, t, tol):
    '''Implements the shooting method to solve second order BVPs

    USAGE:
        y = shoot(f, a, b, z1, z2, t, tol)

    INPUT:
        f     - function dy/dt = f(y,t).  Since we are solving a second-
                order boundary-value problem that has been transformed
                into a first order system, this function should return a
                1x2 array with the first entry equal to y and the second
                entry equal to y'.
        a     - solution value at the left boundary: a = y(t[0]).
        b     - solution value at the right boundary: b = y(t[n-1]).
        z1    - first initial estimate of y'(t[0]).
        z2    - second initial estimate of y'(t[0]).
        t     - array of n time values to determine y at.
        tol   - allowable tolerance on right boundary: | b - y[n-1] | < tol

    OUTPUT:
        y     - array of solution function values corresponding to the
                values in the supplied array t.

    NOTE:
        This function assumes that the second order BVP has been converted to
        a first order system of two equations.  The secant method is used to
        refine the initial values of y' used for the initial value problems.
    '''

    from diffeq import rku4

    max_iter = 100  # Maximum number of shooting iterations

    n = len(t)  # Determine the size of the arrays we will generate

    # Compute solution to first initial value problem (IVP) with y'(a) = z1.
    # Because we are using the secant method to refine our estimates of z =
    # y', we don't really need all the solution of the IVP, just the last
    # point of it -- this is saved in w1.

    y = rku4(f, [a, z1], t)
    w1 = y[n - 1, 0]

    print('%2d: z = %10.3e, error = %10.3e' % (0, z1, b - w1))

    # Begin the main loop.  We will compute the solution of a second IVP and
    # then use the both solutions to refine our estimate of y'(a).  This
    # second solution then replaces the first and a new 'second' solution is
    # generated.  This process continues until we either solve the problem to
    # within the specified tolerance or we exceed the maximum number of
    # allowable iterations.

    for i in range(max_iter):

        # Solve second initial value problem, using y'(a) = z2.  We need to
        # retain the entire solution vector y since if y(t(n)) is close enough
        # to b for us to stop then the first column of y becomes our solution
        # vector.

        y = rku4(f, [a, z2], t)
        w2 = y[n - 1, 0]

        print('%2d: z = %10.3e, error = %10.3e' % (i + 1, z2, b - w2))

        # Check to see if we are done...

        if abs(b - w2) < tol:
            break

        # Compute the new approximations to the initial value of the first
        # derivative.  We compute z2 using a linear fit through (z1,w1) and
        # (z2,w2) where w1 and w2 are the estimates at t=b of the initial
        # value problems solved above with y1'(a) = z1 and y2'(a) = z2.  The
        # new value for z1 is the old value of z2.

        #z1, z2 = ( z2, z1 + ( z2 - z1 ) / ( w2 - w1 ) * ( b - w1 ) )
        z1, z2 = (z2, z2 + (z2 - z1) / (w2 - w1) * (b - w2))
        w1 = w2

    # All done.  Check to see if we really solved the problem, and then return
    # the solution.

    if abs(b - w2) >= tol:
        print('\a**** ERROR ****')
        print('Maximum number of iterations (%d) exceeded' % max_iter)
        print('Returned values may not have desired accuracy')
        print('Error estimate of returned solution is %e' % (b - w2))

    return y[:, 0]