about summary refs log tree commit diff
path: root/src/simulation.py
blob: 9f6c38978182d01861146e726076bb5cc2977b38 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import math
from dataclasses import dataclass

from universe import Universe
from body import Body
from rocket import Rocket

@dataclass
class Simulation_Snapshot:
    universe: type[Universe]
    body: type[Body]
    rocket: type[Rocket]

class Simulation():
    def __init__(self, universe: type[Universe], body: type[Body], rocket: type[Rocket]):
        self.ticks = 0
        self.time = 0
        self.universe = universe
        self.body = body
        self.rocket = rocket
        self.x = 0#TODO
        self.y = self.body.radius #TODO: we need to make it so there is height() to calc height based on x and y
        self.speed_x = 0
        self.speed_y = 0
        self.acceleration_x = 0
        self.acceleration_y = 0

        self.heading = 0

    #simulation logic
    def tick(self, delta: int) -> None:
        current_stage = self.rocket.current_stage()
        #calculate upwards force by fuel       
        fuel_used = current_stage.total_fuel_used(delta)
        if current_stage.fuel_mass < fuel_used:
            fuel_used = current_stage.fuel_mass
        current_stage.fuel_mass -= fuel_used
        print("Fuel remaining: " + str(current_stage.fuel_mass))

        g = self.body.g(G=self.universe.G, height=self.rocket_altitude())
        print("g: " + str(g))
                
        force_x = 0
        force_y = 0
        if fuel_used > 0:
            total_thrust = current_stage.current_thrust(g, self.heading)
            force_x = total_thrust[0]
            force_y = total_thrust[1]
        
        print("Thrust X: " + str(force_x))
        print("Thrust Y: " + str(force_y))

        print("BODY MASS: " + str(self.body.mass()))
        print("ROCKET TOTAL MASS: " + str(self.rocket.total_mass()))

        #calculate downwards force by drag and gravity
        gravitational_force_y = g * self.rocket.total_mass()
        print("Gravity Y: " + str(gravitational_force_y))

        #Remove gravity from force
        force_y -= gravitational_force_y

        curr_atmospheric_density = self.body.atmosphere.density_at_height(self.rocket_altitude(), g)
        print("Atmosphere density: " + str(curr_atmospheric_density))

        #TODO: cross sectional area and drag coef for x should b different
        drag_force_x = (1/2) * curr_atmospheric_density * (self.speed_x ** 2) * self.rocket.rocket_x_drag_coefficient() * self.rocket.rocket_x_cross_sectional_area()
        #drag goes against speed
        if force_x < 0:
            drag_force_x *= -1
        print("Drag X: " + str(drag_force_x))

        #https://www.grc.nasa.gov/www/k-12/airplane/drageq.html
        drag_force_y = (1/2) * curr_atmospheric_density * (self.speed_y ** 2) * self.rocket.rocket_y_drag_coefficient() * self.rocket.rocket_y_cross_sectional_area()
        #drag goes against speed
        if force_y < 0:
            drag_force_y *= -1
        print("Drag Y: " + str(drag_force_y))

        #remove drag
        force_x -= drag_force_x
        force_y -= drag_force_y

        print("Total Force X: " + str(force_x))
        print("Total Force Y: " + str(force_y))

        self.acceleration_x = force_x / self.rocket.total_mass()
        self.acceleration_y = force_y / self.rocket.total_mass()
        print("Acceleration x: " + str(self.acceleration_x))
        print("Acceleration y: " + str(self.acceleration_y))
        
        self.speed_x = self.speed_x + (self.acceleration_x * delta)
        self.speed_y = self.speed_y + (self.acceleration_y * delta)
        
        #update position based on velocity and delta
        self.x += self.speed_x * delta
        self.y += self.speed_y * delta
        if self.rocket_altitude() < 0:
            #undo positional changes
            self.x -= self.speed_x * delta
            self.y -= self.speed_y * delta
            self.speed_x = 0
            self.speed_y = 0

        print("Speed x: " + str(self.speed_x))
        print("Speed y: " + str(self.speed_y))
            
        print("X: " + str(self.x))
        print("Y: " + str(self.y))

        ref_vec = (0, 1)
        acc_vec = (self.speed_x, self.speed_y)
        dot = (acc_vec[0] * ref_vec[0]) + (acc_vec[1] * ref_vec[1])
        det = (acc_vec[0] * ref_vec[1]) - (acc_vec[1] * ref_vec[0])
        self.heading = math.degrees(math.atan2(det, dot))
        print("Heading: " + str(self.heading))

        print("Total Simulation Time: " + str(self.time))
        print("")

        self.ticks += 1
        self.time += delta

    def rocket_altitude(self):
        #take into account body and allow for 360 height
        altitude = math.sqrt(self.x**2 + self.y**2)
        altitude -= self.body.radius
        return altitude 

    def snapshot(self) -> Simulation_Snapshot:
        return Simulation_Snapshot(self.universe, self.body, self.rocket)

    def str_snapshot(self) -> str:
        return str(self.universe) + "\n" + \
               str(self.body) + "\n" + \
               str(self.rocket)