コード例 #1
0
    def test_entity_view(self):
        """Test that setting and getting _EntityView attrs propagate."""
        ps = PhysicsState(None, self.proto_state)
        self.assertEqual(ps[0].name, 'First')
        entity = ps[0]
        self.assertTrue(isinstance(entity, _EntityView))

        self.assertEqual(entity.x, 10)
        self.assertEqual(entity.y, 20)
        self.assertEqual(entity.vx, 30)
        self.assertEqual(entity.vy, 40)
        self.assertEqual(entity.spin, 50)
        self.assertEqual(entity.fuel, 60)
        self.assertEqual(entity.landed_on, '')
        self.assertEqual(entity.throttle, 70)

        ps.y0()
        self.assertEqual(entity.heading, 7 % (2 * np.pi))

        ps[0].landed_on = 'Second'
        self.assertEqual(entity.landed_on, 'Second')
        entity.x = 500
        self.assertEqual(ps[0].x, 500)
        entity.pos = np.array([55, 66])
        self.assertEqual(ps['First'].x, 55)
        self.assertEqual(ps['First'].y, 66)
コード例 #2
0
    def test_y_vector_init(self):
        """Test that initializing with a y-vector uses y-vector values."""
        y0 = np.concatenate((
            np.array([
                10,
                20,  # x
                30,
                40,  # y
                50,
                60,  # vx
                0,
                0,  # vy
                0,
                0,  # heading
                70,
                80,  # spin
                90,
                100,  # fuel
                0,
                0,  # throttle
                1,
                -1,  # only First is landed on Second
                0,
                1,  # Second is broken
                common.SRB_EMPTY,
                1  # time_acc
            ]),
            np.zeros(EngineeringState.N_ENGINEERING_FIELDS)))

        ps = PhysicsState(y0, self.proto_state)
        self.assertTrue(np.array_equal(ps.y0(), y0.astype(ps.y0().dtype)))
        self.assertEqual(ps['First'].landed_on, 'Second')

        proto_state = ps.as_proto()
        proto_state.timestamp = 50
        self.assertEqual(proto_state.timestamp, 50)
        self.assertEqual(proto_state.entities[0].fuel, 90)
        self.assertTrue(proto_state.entities[1].broken)
コード例 #3
0
ファイル: engine.py プロジェクト: Arcayik/orbitx
    def _run_simulation(self, t: float, y: PhysicsState) -> None:
        # An overview of how time is managed:
        #
        # self._last_simtime is the main thread's latest idea of
        # what the current time is in the simulation. Every call to
        # get_state(), self._timetime_of_last_request is incremented by the
        # amount of time that passed since the last call to get_state(),
        # factoring in time_acc
        #
        # self._solutions is a fixed-size queue of ODE solutions.
        # Each element has an attribute, t_max, which describes the largest
        # time that the solution can be evaluated at and still be accurate.
        # The highest such t_max should always be larger than the current
        # simulation time, i.e. self._last_simtime
        proto_state = y._proto_state

        while not self._stopping_simthread:
            derive_func = functools.partial(
                self._derive, pass_through_state=proto_state)

            events: List[Event] = [
                CollisionEvent(y, self.R), HabFuelEvent(y), LiftoffEvent(y),
                SrbFuelEvent(), HabReactorTempEvent(), AyseReactorTempEvent()
            ]
            if y.craft is not None:
                events.append(HighAccEvent(
                    derive_func,
                    self._artificials,
                    TIME_ACC_TO_BOUND[round(y.time_acc)],
                    y.time_acc,
                    len(y)))

            ivp_out = scipy.integrate.solve_ivp(
                fun=derive_func,
                t_span=[t, t + min(y.time_acc, 10 * self.MAX_STEP_SIZE)],
                # solve_ivp requires a 1D y0 array
                y0=y.y0(),
                events=events,
                dense_output=True,
                max_step=self.MAX_STEP_SIZE
            )

            if not ivp_out.success:
                # Integration error
                raise Exception(ivp_out.message)

            # When we create a new solution, let other people know.
            with self._solutions_cond:
                # If adding another solution to our max-sized deque would drop
                # our oldest solution, and the main thread is still asking for
                # state in the t interval of our oldest solution, take a break
                # until the main thread has caught up.
                self._solutions_cond.wait_for(
                    lambda:
                    len(self._solutions) < SOLUTION_CACHE_SIZE or
                    self._last_simtime > self._solutions[0].t_max or
                    self._stopping_simthread
                )
                if self._stopping_simthread:
                    break

                # self._solutions contains ODE solutions for the interval
                # [self._solutions[0].t_min, self._solutions[-1].t_max].
                self._solutions.append(ivp_out.sol)
                self._solutions_cond.notify_all()

            y = PhysicsState(ivp_out.y[:, -1], proto_state)
            t = ivp_out.t[-1]

            if ivp_out.status > 0:
                log.info(f'Got event: {ivp_out.t_events} at t={t}.')
                for index, event_t in enumerate(ivp_out.t_events):
                    if len(event_t) == 0:
                        # If this event didn't occur, then event_t == []
                        continue
                    event = events[index]
                    if isinstance(event, CollisionEvent):
                        # Collision, simulation ended. Handled it and continue.
                        assert len(ivp_out.t_events[0]) == 1
                        assert len(ivp_out.t) >= 2
                        y = _collision_decision(t, y, events[0])
                        y = _reconcile_entity_dynamics(y)
                    if isinstance(event, HabFuelEvent):
                        # Something ran out of fuel.
                        for artificial_index in self._artificials:
                            artificial = y[artificial_index]
                            if round(artificial.fuel) != 0:
                                continue
                            log.info(f'{artificial.name} ran out of fuel.')
                            # This craft is out of fuel, the next iteration
                            # won't consume any fuel. Set throttle to zero.
                            artificial.throttle = 0
                            # Set fuel to a negative value, so it doesn't
                            # trigger the event function.
                            artificial.fuel = 0
                    if isinstance(event, LiftoffEvent):
                        # A craft has a TWR > 1
                        craft = y.craft_entity()
                        log.info(
                            'We have liftoff of the '
                            f'{craft.name} from {craft.landed_on} at {t}.')
                        craft.landed_on = ''
                    if isinstance(event, SrbFuelEvent):
                        # SRB fuel exhaustion.
                        log.info('SRB exhausted.')
                        y.srb_time = common.SRB_EMPTY
                    if isinstance(event, HighAccEvent):
                        # The acceleration acting on the craft is high, might
                        # result in inaccurate results. SLOOWWWW DOWWWWNNNN.
                        slower_time_acc_index = list(
                            TIME_ACC_TO_BOUND.keys()
                        ).index(round(y.time_acc)) - 1
                        assert slower_time_acc_index >= 0
                        slower_time_acc = \
                            common.TIME_ACCS[slower_time_acc_index]
                        assert slower_time_acc.value > 0
                        log.info(
                            f'{y.time_acc} is too fast, '
                            f'slowing down to {slower_time_acc.value}')
                        # We should lower the time acc.
                        y.time_acc = slower_time_acc.value
                        raise PhysicsEngine.RestartSimulationException(t, y)
                    if isinstance(event, HabReactorTempEvent):
                        y.engineering.hab_reactor_alarm = not y.engineering.hab_reactor_alarm
                    if isinstance(event, AyseReactorTempEvent):
                        y.engineering.ayse_reactor_alarm = not y.engineering.ayse_reactor_alarm