def check_margins(trojan1: CelestialBody, trojan2: CelestialBody,\ central: CelestialBody, margin: float) -> bool: """ Checks to see if two planets in a Trojan pair are within a given percent margin of a 1:1 period resonance. Parameters ---------- - trojan1 (CelestialBody): One member of the co-orbital pair. - trojan2 (CelestialBody): The other member of the co-orbital pair. - central (CelestialBody): The central body in the system. - margin (float): The allowed percent deviation from a 1:1 period resonance. Returns ------- - in_margin (bool): True if within the margin, false if not. """ # Get the orbital periods of each planet. P1 = trojan1.period(central) P2 = trojan2.period(central) # Compute the percent difference between the periods. diff = abs(P1 - P2) avg = np.average([P1, P2]) p_diff = (diff / avg) * 100 # Will return true if the percent difference exceeds the margin. return not (p_diff > margin)
def test_ShouldMoveThreeBodiesOfEqualMassTowardsCenterOfMass(self): body1 = CelestialBody("N",6e24,Vector(0,10e10,0),self.zero,self.zero) body2 = CelestialBody("M",6e24,Vector(-6e10,-8e10,0),self.zero,self.zero) body3 = CelestialBody("L",6e24,Vector(6e10,-8e10,0),self.zero,self.zero) system = System("Tri-body", [body1,body2,body3]) system.update(1) self.assertTrue(Vector.sumOfVectors([body1.velocity, body2.velocity,body3.velocity]) == Vector(0,0,0)) self.assertTrue(Vector.absolute(body1.position) == Vector.absolute(body2.position)) self.assertTrue(Vector.absolute(body1.position) == Vector.absolute(body3.position))
def test_ShouldAccelerateASmallBodyWithSmallStartingVelocityTowardsABigOne(self): body1 = CelestialBody("N",6e24,Vector(0,0,0),self.zero,self.zero) body2 = CelestialBody("M",1e3,Vector(1e7,0,0),Vector(0,1000,0),self.zero) system = System("Dual Body", [body1,body2]) distance = 1e7 for _ in range(1,101): system.update(1) new_distance = CelestialBody.calcDistance(body1,body2) self.assertTrue(new_distance < distance) distance = new_distance
def test_ShouldAllowEscapeOfSmallBodyWithHighVelocity(self): body1 = CelestialBody("N",6e24,Vector(0,0,0),self.zero,self.zero) body2 = CelestialBody("M",1e3,Vector(1e7,0,0),Vector(0,3e8,0),self.zero) system = System("Dual Body", [body1,body2]) distance = 1e7 for _ in range(1,101): system.update(1) new_distance = CelestialBody.calcDistance(body1,body2) self.assertTrue(new_distance > distance) distance = new_distance
def test_ShouldGiveSameOutputNoMatterTheTickFrequency(self): body = CelestialBody("Sun", 1E26, self.nonZero, self.nonZero2, self.nonZero3) for _ in range(1, 11): body.update(0.1) print(body.position) print(body.velocity) self.assertAlmostEqual(body.position, Vector(14.5, 9.5, 8.5)) self.assertAlmostEqual(body.velocity, Vector(15, 10, 5))
def test_ShouldMoveTwoStationaryBodiesDirectlyTowardsEachOther(self): body1 = CelestialBody("N",1e25,Vector(-100,0,0),self.zero,self.zero) body2 = CelestialBody("M",1e25,Vector(100,0,0),self.zero,self.zero) system = System("Dual Body", [body1,body2]) system.update(10) self.assertTrue(body1.velocity == Vector.mult(-1,body2.velocity)) self.assertTrue(body1.velocity != body2.velocity) self.assertTrue(Vector.add(body1.velocity,body2.velocity) == self.zero) self.assertTrue(Vector.add(body1.position,body2.position) == self.zero) self.assertTrue(body1.position.y == body2.position.y) self.assertTrue(body1.position.z == body2.position.z) self.assertTrue(body1.position.y == 0) self.assertTrue(body1.position.z == 0)
def test_ShouldConserveMomentum(self): body1 = CelestialBody("N", 6e24, Vector(0, 10e10, 0), Vector(3,6,9), self.zero) body2 = CelestialBody("M", 6e24, Vector(-6e10, -8e10, 0), Vector(5,12,3), self.zero) body3 = CelestialBody("L", 6e24, Vector(6e10, -8e10, 0), Vector(9,2,19), self.zero) bodies = [body1,body2,body3] system = System("Tri-body", bodies) totalMomentumBefore = Vector(0,0,0) for body in bodies: totalMomentumBefore = Vector.add(totalMomentumBefore, body.calcMomentum()) system.update(600) totalMomentumAfter = Vector(0,0,0) for body in bodies: totalMomentumAfter = Vector.add(totalMomentumAfter, body.calcMomentum()) self.assertTrue(totalMomentumBefore == totalMomentumAfter)
def test_ShouldMoveAtConstantVelocitySingleMovingBody(self): body = CelestialBody("N", 1e25, self.zero, Vector(10, 15, 50), self.zero) system = System("Single Body", [body]) system.update(10) self.assertTrue(body.velocity == Vector(10, 15, 50)) self.assertTrue(body.position == Vector(100, 150, 500))
def __init__(self, dat_name, time_step=20000, satelite=False): self.t = time_step self.time = 0 self.energies = ([], []) with open(dat_name + '.json') as json_dat: dat = json.load(json_dat) self.bodies = [CelestialBody(*[body] + dat[body]) for body in dat] self.sat_target = self.bodies[4] self.sat_reached = 0 self.sat_time = 0 for body in self.bodies: body.update_acc(self.bodies, first=True)
def test_ShouldAccelerateASmallBodyTowardsABigOne(self): body1 = CelestialBody("N",1e30,Vector(-100,0,0),self.zero,self.zero) body2 = CelestialBody("M",1e23,Vector(100,0,0),self.zero,self.zero) system = System("Dual Body", [body1,body2]) system.update(10) self.assertTrue(body1.calcSpeed() - body2.calcSpeed() < 0) self.assertTrue(body1.position.x + body2.position.x < 0) self.assertTrue(body1.position.y == body2.position.y) self.assertTrue(body1.position.z == body2.position.z) self.assertTrue(body1.position.y == 0) self.assertTrue(body1.position.z == 0)
def parse_line(line: str) -> CelestialBody: """ Parses a single line of text to produce a CelestialBody object. Parameter --------- - line (string): A line of text containing the information necessary to construct a CelestialBody object. Returns ------- - body (CelestialBody): The CelestialBody object constructed from the parameters given by the input line. """ params: List[str] = line.split(" ") # Variables used to construct the CelestialBody object. body_type: CelestialType = -1 body_is_trojan: bool = False body_name: str = "" body_mass: float = 0.0 body_radius: float = 0.0 body_position: np.array = np.zeros(3) body_velocity: np.array = np.zeros(3) # The parsing function cannot detect missing parameters. for i, param in enumerate(params): if i == 0: # Each line should start by specifying the body type. if params[0] == "STAR": body_type = CelestialType.STAR elif params[0] == "GIANT": body_type = CelestialType.GIANT elif params[0] == "TERRESTRIAL": body_type = CelestialType.TERRESTRIAL else: raise Exception("Each line must start with a valid object type"\ + " specification.") else: tokens = param.split("=") if tokens[0] == "trojan": body_is_trojan = tokens[1] == "True" elif tokens[0] == "name": body_name = tokens[1] elif tokens[0] == "mass": body_mass = float(tokens[1]) elif tokens[0] == "radius": body_radius = float(tokens[1]) elif tokens[0] == "position": vals = tokens[1].split(",") if len(vals) != 3: raise Exception("Position must be specified by three"\ + " comma-separated floats") body_position = np.array([float(vals[0]), float(vals[1]),\ float(vals[2])]) elif tokens[0] == "velocity": vals = tokens[1].split(",") if len(vals) != 3: raise Exception("Velocity must be specified by three"\ + " comma-separated floats") body_velocity = np.array([float(vals[0]), float(vals[1]),\ float(vals[2])]) else: raise Exception("Invalid token detected while parsing input"\ + " file.") body = CelestialBody(type=body_type, trojan=body_is_trojan, name=body_name,\ mass=body_mass, radius=body_radius, position=body_position,\ velocity=body_velocity) return body
def test_ShouldNeverMoveSingleStationaryBody(self): body = CelestialBody("N",1e25,Vector(4,7,9),self.zero,self.zero) system = System("Single Body", [body]) system.update(10000) self.assertTrue(body.position == Vector(4,7,9))
def test_ShouldReturnKineticEnergyWhenGivenMassAndVelocity(self): body = CelestialBody("Sun", 1E26, self.nonZero, Vector(4e4, 0, 0), self.nonZero3) print(body.calcKineticEnergy()) self.assertTrue( System.nearly_equal(body.calcKineticEnergy(), 8e34, 1e-4))
def test_ShouldNotMoveAtZeroVelocityAndAcceleration(self): body = CelestialBody("Sun", 1E26, self.zero, self.zero, self.zero) body.update(10000) self.assertTrue(body.position == self.zero)
def test_ShouldMoveAtIncreasingRateOfChangeOfPositionWithConstantAcceleration( self): body = CelestialBody("Sun", 1E26, self.nonZero, self.nonZero2, self.nonZero3) body.update(1) self.assertTrue(body.position == Vector(14.5, 9.5, 8.5))
def test_ShouldMoveAtIncreasingVelocityWithConstantAcceleration(self): body = CelestialBody("Sun", 1E26, self.nonZero, self.nonZero2, self.nonZero3) body.update(1) self.assertTrue(body.velocity == Vector(15, 10, 5))
def test_ShouldMoveInSmallTimeIntervalAtZeroAcceleration(self): body = CelestialBody("Sun", 1E26, self.nonZero, self.nonZero2, self.zero) body.update(0.25) self.assertTrue(body.position == Vector(5, 4.25, 5.5))
def test_ShouldReturnMomentumWhenGivenMassAndVelocity(self): body = CelestialBody("Sun", 1E26, self.nonZero, Vector(4e4, 0, 0), self.nonZero3) self.assertTrue(body.calcMomentum() == Vector(4e30, 0, 0))
pygame.display.set_caption("Orbital Simulator") # Set up the drawing window WIDTH = 1000 HEIGHT = 1000 screen = pygame.display.set_mode((WIDTH, HEIGHT)) alpha_surf = pygame.Surface(screen.get_size(), pygame.SRCALPHA) # alpha surface for trails FramePerSec = pygame.time.Clock() font = pygame.font.SysFont('Arial', 20) # Adding Planets # earth planetsList.append( CelestialBody("Earth", Vector2(500, 500 + normalize_distance(147100000)), 5.97219e24, 0, (0, 0, 255), normalize_distance(30.29), 0, 5)) # moon # mercury planetsList.append( CelestialBody("Mercury", Vector2(500, 500 + normalize_distance(46000000)), 3.285e23, 1, (200, 100, 30), normalize_distance(58.98), 0, 3)) # venus planetsList.append( CelestialBody("Venus", Vector2(500, 500 + normalize_distance(107476000)), 4.867e24, 2, (234, 213, 191), normalize_distance(35.26), 0, 4)) # mars planetsList.append( CelestialBody("Mars", Vector2(500, 500 + normalize_distance(206600000)), 6.39e23, 3, (200, 20, 20), normalize_distance(26.50), 0, 4))