Ejemplo n.º 1
0
    def solve_dae(self):
        
        #Get initial conditions vector
        self.init_conditions()

        #Instantiate reactor as DAE class
        self._rdae = ScikitsDAE(self._r)
                
        #Initial derivatives vector
        self.yd0 = np.zeros(len(self.y0))
        
        #Get list of differential and algebraic variables
        varlist = np.ones(len(self.y0))
           
        #Set algebraic variables
        varlist[self._rdae.p1:] = 0.0  
        
        #Instantiate the solver
        self.solver = ida.IDA(self._rdae.eval_dae, 
                              user_data = self._r,
                              atol = self.atol,
                              rtol = self.rtol,
                              order = self.order,
                              max_steps = self.max_steps,
                              linsolver = self.linsolver,
                              first_step_size = self.first_step_size,
                              max_step_size = self.max_step_size,
                              compute_initcond='yp0',
                              compute_initcond_t0 = 1e-06,
                              algebraic_vars_idx = np.where(varlist==0.0)[0],
                              exclude_algvar_from_error = self.exclude_algvar_from_error,
                              old_api=False)
        
        #Compute solution and return it along supplied axial coords.
        self.sol = self.solver.solve(self._z, self.y0, self.yd0)
        
        #If an error occurs
        if self.sol.errors.t != None:
            raise ValueError(self.sol.message,self.sol.errors.t)
    
        #Get solution vector
        self.values = self.sol.values.y
Ejemplo n.º 2
0
    lambdaval = 0.1
    #z0  =  array([x0, y0, 0., 0., lambdaval], np.float)
    #zp0 = array([0., 0., -lambdaval*x0, -lambdaval*y0-g, -g], np.float)
    z0 = [x0, y0, 0., 0., lambdaval]
    zp0 = [0., 0., -lambdaval * x0, -lambdaval * y0 - g, -g]


problem = SimpleOscillator()
time = problem.stop_t
nr = len(time)

# Variant 1: Solving the problem with the 'solve' method
solver = ida.IDA(res,
                 compute_initcond='yp0',
                 first_step_size=1e-18,
                 atol=1e-6,
                 rtol=1e-6,
                 algebraic_vars_idx=[4])

# strip unneeded return values from run_solver
_flag, t1, y1 = solver.solve(time, problem.z0, problem.zp0)[:3]

xt = y1[:, 0]
yt = y1[:, 1]

draw_graphs(1, t1, xt, yt)

# Variant 2: Solving the problem with the more versatile (but slower) method 'step'
problem.x0 = problem.x0 * 2
problem.y0 = problem.y0 * 2
problem.z0 = array([problem.x0, problem.y0, 0., 0., problem.lambdaval],
Ejemplo n.º 3
0
def main():
    """
    The main program: instantiate a problem, then use odes package to solve it
    """
    uinput = input("Solve as\n 1 = index 2 problem\n 2 = index 1 problem\n"
                " 3 = index 1 problem with jacobian\n 4 = info\n\n"
                "Answer (1,2,3 or 4) : ")
    jac = None
    if uinput == '1':
        problem = Doublependulum(type='index2')
        res = resindex2()
    elif uinput == '2':
        problem = Doublependulum(type='index1')
        res = resindex1()
    elif uinput == '3':
        problem = Doublependulum(type='index1_jac')
        res = resindex1()
        jac = jacindex1()
    else:
        print(__doc__)
        return

    z = [0]*(1+len(problem.stop_t)); zprime = [0]*(1+len(problem.stop_t))

    res.set_dblpend(problem)
    jfac = 1.
    if jac:
        jac.set_dblpend(problem)
        jfac = JACFAC

    solver = ida.IDA(res,
                compute_initcond='yp0',
                first_step_size=1e-18,
                atol=ATOL*jfac,
                rtol=RTOL*jfac,
                max_steps=1500,
                jacfn=jac,
                algebraic_vars_idx=problem.algvar_idx,
                exclude_algvar_from_error=problem.exclalg_err,
                )

    z[0] = np.empty(problem.neq, float)
    zprime[0] = np.empty(problem.neq, float)
    (flag, t0_init) = solver.init_step(0., problem.z0, problem.zprime0, z[0], zprime[0])
    realtime = [t0_init]
    #flag, rt = solver.step(t0_init, z[0], zprime[0])

    i=1
    error = False
    for time in problem.stop_t[1:]:
            #print 'at time', time
            z[i] = np.empty(problem.neq, float)
            zprime[i] = np.empty(problem.neq, float)
            flag, rt = solver.step(time, z[i], zprime[i])
            realtime += [rt]
            #print 'sol at ', time, z[i]

            i += 1
            if flag != 0:
                error = True
                print('Error in solver, breaking solution at time %g' % time)
                break

    fres = np.empty(problem.neq, float)
    res.evaluate(problem.stop_t[i-1], z[i-1], zprime[i-1], fres, None)
    print('last sol has residual: ', fres)

    nr = i
    x1t = asarray([z[i][0] for i in range(nr)])
    y1t = asarray([z[i][1] for i in range(nr)])
    x2t = asarray([z[i][2] for i in range(nr)])
    y2t = asarray([z[i][3] for i in range(nr)])
    xp1t = asarray([z[i][4] for i in range(nr)])
    yp1t = asarray([z[i][5] for i in range(nr)])
    xp2t = asarray([z[i][6] for i in range(nr)])
    yp2t = asarray([z[i][7] for i in range(nr)])
    energy = problem.m1*problem.g*y1t + \
                problem.m2*problem.g*y2t + \
                .5 *(problem.m1 * (xp1t**2 + yp1t**2)
                     + problem.m2 * (xp2t**2 + yp2t**2) )
    initenergy = energy[0]

    #solve the same with ddaspk
    if alsoddaspk:
        ddaspkz = empty((alen(problem.stop_t), problem.neq), float)
        ddaspkzprime = empty((alen(problem.stop_t), problem.neq), float)

        problem.set_res(res)
        ig = dae('ddaspk', problem.ddaspk_res)
        if jac:
            problem.set_jac(jac)
            ig.set_options(jacfn=problem.ddaspk_jac)
        #first compute the correct initial condition from the values of z0
        ig.set_options(
                        algebraic_vars_idx=problem.algvar_idx,
                        compute_initcond='yp0',
                        first_step=1e-18,
                        exclude_algvar_from_error=problem.exclalg_err,
                        atol=ATOL, rtol=RTOL, max_steps=1500)
        tinit = ig.init_step(0., problem.z0, problem.zprime0, ddaspkz[0], ddaspkzprime[0])

        print('ddaspk started from z0 = ', problem.z0)
        print('ddaspk initial condition calculated, [z,zprime] = [', ddaspkz[0],
                    ddaspkzprime[0], ']')

        i=1
        error = False
        for time in problem.stop_t[1:]:
            flag, tout = ig.step(time, ddaspkz[i],  ddaspkzprime[i])
            i += 1

            if flag < 1:
                error = True
                break
        dnr = i
        ddaspkx1t = asarray([ddaspkz[i][0] for i in range(dnr)])
        ddaspky1t = asarray([ddaspkz[i][1] for i in range(dnr)])
        ddaspkx2t = asarray([ddaspkz[i][2] for i in range(dnr)])
        ddaspky2t = asarray([ddaspkz[i][3] for i in range(dnr)])
        ddaspkxp1t = asarray([ddaspkzprime[i][0] for i in range(dnr)])
        ddaspkyp1t = asarray([ddaspkzprime[i][1] for i in range(dnr)])
        ddaspkxp2t = asarray([ddaspkzprime[i][2] for i in range(dnr)])
        ddaspkyp2t = asarray([ddaspkzprime[i][3] for i in range(dnr)])
        ddaspkenergy = problem.m1*problem.g*ddaspky1t + \
                    problem.m2*problem.g*ddaspky2t + \
                    .5 *(problem.m1 * (ddaspkxp1t**2 + ddaspkyp1t**2)
                         + problem.m2 * (ddaspkxp2t**2 + ddaspkyp2t**2) )
        ddaspkrealtime = problem.stop_t[:dnr]
    pylab.ion()
    pylab.figure(1)
    pylab.subplot(211)
    pylab.title('IDA solution option %s' % uinput)
    pylab.scatter(x1t, y1t)
    pylab.scatter(x2t, y2t)
    pylab.xlim(-10, 10)
    pylab.ylim(-8, 2)
    pylab.axis('equal')
    pylab.subplot(212)
    pylab.plot(realtime, energy, 'b')
    pylab.title('Energy Invariant Violation for a Double Pendulum')
    pylab.xlabel('Time (s)')
    pylab.ylabel('Total Energy')
    pylab.axis()
    pylab.show()
    if alsoddaspk:
        pylab.ion()
        pylab.figure(2)
        pylab.subplot(211)
        pylab.title('DDASPK solution option %s' % uinput)
        pylab.scatter(ddaspkx1t, ddaspky1t)
        pylab.scatter(ddaspkx2t, ddaspky2t)
        pylab.xlim(-10, 10)
        pylab.ylim(-8, 2)
        pylab.axis('equal')
        pylab.subplot(212)
        pylab.plot(ddaspkrealtime, ddaspkenergy, 'b')
        pylab.title('Energy Invariant Violation for a Double Pendulum')
        pylab.xlabel('Time (s)')
        pylab.ylabel('Total Energy DDASPK solution')
        pylab.axis()
        pylab.show()

    def circle(ax, x, y, r, color='r'):
        count = 20
        ax.fill([x + r * cos(2.* i * pi/count) for i in range(count+1)],
                [y + r * sin(2.* i * pi/count) for i in range(count+1)],
                color)

    def line(ax, x1, y1, x2, y2, color='black'):
        norm = sqrt((y2-y1)**2 + (x2-x1)**2)
        normal = [(y2-y1)/norm, -(x2-x1)/norm]
        ax.fill(
        [x1-0.01*normal[0],x1+0.01*normal[0],x2+0.01*normal[0],x2-0.01*normal[0]],
        [y1-0.01*normal[1],y1+0.01*normal[1],y2+0.01*normal[1],y2-0.01*normal[1]],
                color)

    def draw(ax, nr):
        sol = z[nr]
        line(ax, 0., 0., sol[0], sol[1])
        line(ax, sol[0], sol[1], sol[2], sol[3])
        circle(ax, sol[0], sol[1], 0.5)
        circle(ax, sol[2], sol[3], 0.5)

    def drawonesol(nr, sizex, sizey, ext=None):
        pylab.clf()
        a = pylab.axes()
        draw(a, nr)
        pylab.axis('scaled')
        pylab.xlim(-sizex, sizex)
        pylab.ylim(-sizey, sizey)
        if ext is None:
            ext = nr
        pylab.savefig('figsdoublependulum' + os.sep + 'outsol%08i.png' % ext)

    def open_file_with_default_application( file_path ):
        """
        Launch a program to open an arbitrary file. The file will be opened using
        whatever program is configured on the host as the default program for that
        type of file.
        """

        norm_path = os.path.normpath( file_path )

        if not os.path.exists(norm_path):
            print("%s does not exist" % file_path)
            return

        if os.sys.platform == 'win32':
            try:
                os.startfile(norm_path)
            except WindowsError as msg:
                print("Error Opening File. " + str(msg))
        else:
            search = os.environ['PATH'].split(':')
            for path in search:
                prog = os.path.join(path, 'xdg-open')
                if os.path.isfile(prog):
                    os.spawnvpe(os.P_NOWAIT, prog, [prog, norm_path], os.environ)
                    return

    def create_animation(sizex, sizey, ext):
        """
        The calculation step is 1e-2, so output every 5 solutions or 0.05, means
        a frame rate of 20 frames per second
        """
        import shutil

        fps = 20
        if os.path.isdir('figsdoublependulum'):
            shutil.rmtree('figsdoublependulum')
        os.mkdir('figsdoublependulum')
        if not os.path.isdir('anidoublependulum'):
            os.mkdir('anidoublependulum')

        pylab.figure(2)
        secs = 0
        frame = 0
        print('Generating output ...\n')
        for solnr in range(0,nr,5):
            drawonesol(solnr, sizex, sizey, frame)
            frame += 1
            if solnr // 500 != secs :
                secs = solnr // 500
                print('     ... at %i seconds ' % (secs * 5 ))

        print('Creating movie using ffmpeg with output ... \n')
        import subprocess
        subprocess.call(['ffmpeg', '-r', '20', '-i', 'figsdoublependulum' + os.sep +
                        'outsol%8d.png',  '-f',  'avi', '-vcodec', 'mpeg2video', '-y',
                        'anidoublependulum' + os.sep +
                                            'doublependulum'+ext+'.mpg'])
        #remove unused pictures
        shutil.rmtree('figsdoublependulum')
        #opening movie with default player
        print('Opening user with default application ... \n')
        open_file_with_default_application('anidoublependulum' + os.sep +
                    'doublependulum'+ext+'.mpg')

    uinput2 = input('Create animation of the solution? (y/n): ')
    print('\n')
    if (uinput2 == 'y' or uinput2 == 'yes'):
        extend = problem.radius1 + problem.radius2 + 1
        create_animation(extend, extend, uinput)