コード例 #1
0
ファイル: integrator_leap_frog.py プロジェクト: PennyQ/ABIE
    def integrate(self, to_time=None):
        if self.__initialized is False:
            self.initialize()
            self.__initialized = True
        print(to_time, self.t_end)
        # Allocate dense output
        npts = int(np.floor((self.t_end - self.t_start) / self.h) + 1)

        # Initial state
        x = np.concatenate((self.particles.positions, self.particles.velocities))
        # Vector of times
        sol_time = np.linspace(self.t_start, self.t_start + self.h * (npts - 1), npts)
        energy_init = self.calculate_energy()
        # Compute second step
        dxdt0 = ODE.ode_n_body_first_order(x, self.CONST_G, self.particles.masses)
        x = x + dxdt0 * self.h

        # Launch integration
        count = 2
        for t in sol_time[count:]:
            dxdt = ODE.ode_n_body_first_order(x, self.CONST_G, self.particles.masses)
            # Advance step
            x += 0.5 * self.h * (3 * dxdt - dxdt0)

            # Update
            dxdt0 = dxdt
            self.particles.positions = x[0:self.particles.N * 3]
            self.particles.velocities = x[self.particles.N * 3:]
            self._t = t
            self.store_state()
            energy = self.calculate_energy()
            print(('t = %f, E/E0 = %g' % (self.t, np.abs(energy - energy_init) / energy_init)))
            count += 1
        self.buf.close()
        return 0
コード例 #2
0
    def __initial_time_step(y0, dy0, G, masses, nbodies):

        p = 15
        ###########   ESTIMATE INITIAL STEP SIZE
        # Compute scaling
        # sc =  abs(y0)*epsb
        # Evaluate function
        f0 = ODE.ode_n_body_second_order(y0, G, masses)
        d0 = max(abs(y0))
        d1 = max(abs(f0))

        if (d0 < 1e-5) or (d1 < 1e-5):
            dt0 = 1e-6
        else:
            dt0 = 0.01 * (d0 / d1)

        # Perform one Euler step
        y1 = y0 + dt0 * dy0
        dy1 = dy0 + dt0 * f0
        # Call function
        f1 = ODE.ode_n_body_second_order(y1, G, masses)
        d2 = max(abs((f1 - f0))) / dt0

        if max(d1, d2) <= 1e-15:
            dt1 = max([1e-6, dt0 * 1e-3])
        else:
            dt1 = (0.01 / max([d1, d2]))**(1.0 / (p + 1))

        dt = min([100 * dt0, dt1])
        return dt
コード例 #3
0
ファイル: integrator_runge_kutta.py プロジェクト: PennyQ/ABIE
    def integrate_numpy(self, to_time=None):
        if to_time is not None:
            self.t_end = to_time
        # Allocate dense output
        npts = int(np.floor((self.t_end - self.t_start) / self.h) + 1)

        # Initial state
        x = np.concatenate(
            (self._particles.positions, self._particles.velocities))
        # Vector of times
        sol_time = np.linspace(self.t_start,
                               self.t_start + self.h * (npts - 1), npts)
        energy_init = self.calculate_energy()
        # Launch integration
        count = 1
        for t in sol_time[count:]:
            # Evaluate coefficients
            k1 = ODE.ode_n_body_first_order(x, self.CONST_G,
                                            self._particles.masses)
            k2 = ODE.ode_n_body_first_order(x + 0.5 * self.h * k1,
                                            self.CONST_G,
                                            self._particles.masses)
            k3 = ODE.ode_n_body_first_order(x + 0.5 * self.h * k2,
                                            self.CONST_G,
                                            self._particles.masses)
            k4 = ODE.ode_n_body_first_order(x + self.h * k3, self.CONST_G,
                                            self._particles.masses)

            # Advance the state
            x += (self.h * (k1 + 2 * k2 + 2 * k3 + k4) / 6.0)

            # Store step
            self.particles.positions = x[0:self._particles.N * 3]
            self.particles.velocities = x[self._particles.N * 3:]
            self._t = t
            self.store_state()
            energy = self.calculate_energy()
            print(('t = %f, E/E0 = %g' %
                   (self.t, np.abs(energy - energy_init) / energy_init)))
            count += 1
        self.buf.close()
        return 0
コード例 #4
0
    def integrate_numpy(self, to_time):
        # Some parameters
        epsb = self.tol  # recommended 1e-9
        fac = 0.25

        # For fixed step integration, choose exponent = 0
        # exponent = 0;
        exponent = 1. / 7

        y0 = self.particles.positions
        dy0 = self.particles.velocities
        # Dimension of the system
        dim = len(y0)

        # Tolerance Predictor-Corrector
        tolpc = 1e-18

        # Return Radau spacing
        [hs, nh] = self.__radau_spacing()

        ddy0 = ODE.ode_n_body_second_order(y0, self.CONST_G,
                                           self._particles.masses)

        # Initial time step
        self.h = self.__initial_time_step(y0, dy0, self.CONST_G,
                                          self._particles.masses,
                                          self.particles.N)

        # Initialize
        bs0 = np.zeros((nh - 1, dim))
        bs = np.zeros((nh - 1, dim))
        g = np.zeros((nh - 1, dim))
        self._t = self.t_start
        E = np.zeros((nh - 1, dim))
        ddys = np.zeros((nh, dim))

        r = self.__compute_rs()
        c = self.__compute_cs()

        integrate = True
        if to_time is not None:
            self.t_end = to_time
        imode = 0
        energy_init = self.calculate_energy()
        while integrate:
            # if self.t + self.h > self.t_end:
            #     self.h = self.t_end - self.t
            #     integrate = False

            # Advance one step and return:
            y, dy, ddy, self._t, dt, g, bs, E, bs0, istat, imode = self.gaus_radau15_step(
                y0, dy0, ddy0, ddys, self.h, self.t, self.t_end, nh, hs, bs0,
                bs, E, g, r, c, self.tol, exponent, fac, imode, self.CONST_G,
                self._particles.masses, self.particles.N)

            # Detect end of integration:
            if istat == 2:
                integrate = False

            # Update step
            y0 = y
            dy0 = dy
            ddy0 = ddy

            self.particles.positions = y
            self.particles.velocities = dy
            self.store_state()
            energy = self.calculate_energy()
            # print('t = %f, E/E0 = %g' % (self.t, np.abs(energy-energy_init)/energy_init))
        self.buf.close()
        return 0
コード例 #5
0
    def gaus_radau15_step(self, y0, dy0, ddy0, ddys, dt, t, tf, nh, hs, bs0,
                          bs, E, g, r, c, tol, exponent, fac, imode, G, masses,
                          nbodies):

        istat = 0
        while (True):
            # Variable number of iterations in PC
            for ipc in range(0, 12):
                ddys = ddys * 0
                # Advance along the Radau sequence
                for ih in range(0, nh):
                    # Estimate position and velocity with bs0 and current h
                    y = self.__approx_pos(y0, dy0, ddy0, hs[ih], bs, dt)
                    dy = self.__approx_vel(dy0, ddy0, hs[ih], bs, dt)
                    # Evaluate force function and store
                    ddys[ih, :] = ODE.ode_n_body_second_order(
                        y, self.CONST_G, self._particles.masses)
                    g = self.__compute_gs(g, r, ddys, ih)
                    bs = self.__compute_bs_from_gs(bs, g, ih, c)
                # Estimate convergence of PC
                db6 = bs[-1, :] - bs0[-1, :]
                if (max(abs(db6)) / max(abs(ddys[-1, :])) < 1e-16):
                    break
                bs0 = bs

            # Advance the solution:
            y = self.__approx_pos(y0, dy0, ddy0, 1., bs, dt)
            dy = self.__approx_vel(dy0, ddy0, 1., bs, dt)
            ddy = ODE.ode_n_body_second_order(y, self.CONST_G,
                                              self.particles.masses)

            # Estimate relative error
            estim_b6 = max(abs(bs[-1, :])) / max(abs(ddy))
            err = (estim_b6 / tol)**(exponent)

            # Step-size required for next step:
            dtreq = dt / err

            # Accept the step
            if (err <= 1):

                # Report accepted step:
                istat = 1

                # Advance time:
                t = t + dt

                # Update b coefficients:
                bs0 = bs

                # Refine predictor-corrector coefficients for next pass:
                [bs, E] = self.__refine_bs(bs, dtreq / dt, E, imode)

                # Normal refine mode:
                imode = 1

                # Check if tf was reached:
                if (t >= tf):
                    istat = 2

            # Step size for next iteration:
            if (dtreq / dt > 1.0 / fac):
                dt = dt / fac
            elif (dtreq < 1e-12):
                dt = dt * fac
            else:
                dt = dtreq

            # Correct overshooting:
            if (t + dt > tf):
                dt = tf - t
            # Return if the step was accepted:
            if (istat > 0):
                break

        return y, dy, ddy, t, dt, g, bs, E, bs0, istat, imode