Exemple #1
0
def add_one_object_hrzn(sim: rebound.Simulation, object_name: str, epoch: datetime, hrzn: Dict):
    """Add one object to a simulation with data fromm horizons (cache or API)."""
    # Identifiers for this object
    object_id = name_to_id[object_name]
    key = (epoch, object_id)

    try:
        # Try to look up the object on the horizons cache
        p: horizon_entry = hrzn[key]
        sim.add(m=p.m, x=p.x, y=p.y, z=p.z, vx=p.vx, vy=p.vy, vz=p.vz, hash=rebound.hash(object_name))
    except KeyError:
        # Search string for the horizon API
        horizon_name = object_to_horizon_name[object_name]
        # Convert epoch to a horizon date string
        horizon_date: str = datetime_to_horizons(epoch)
        print(f'Searching Horizons as of {horizon_date}')
        # Add the particle
        sim.add(horizon_name, date=horizon_date)
        # Set the mass and hash of this particle
        p: rebound.Particle = sim.particles[-1]
        # p.m = mass_tbl[object_name]
        p.m = mass_tbl.get(object_name, 0.0)
        p.hash = rebound.hash(object_name)
        # Create an entry for this particle on the cache
        entry: horizon_entry = horizon_entry(m=p.m, x=p.x, y=p.y, z=p.z, vx=p.vx, vy=p.vy, vz=p.vz, 
                                             object_name=object_name, object_id=object_id, horizon_name=horizon_name)
        hrzn[key] = entry
        
        # Save the revised cache
        save_horizons_cache(hrzn)
Exemple #2
0
 def test_removing_particles(self):
     self.sim.add(a=30.)
     self.sim.remove(index=0)
     self.sim.remove(index=0)
     self.sim.remove(hash=rebound.hash("earth"), keepSorted=0)
     self.assertEqual(self.sim.get_particle_by_hash("jupiter").hash, rebound.hash("jupiter"))
     self.assertEqual(self.sim.N, 2)
     with self.assertRaises(rebound.ParticleNotFound):
         self.sim.get_particle_by_hash("earth")
     self.sim.remove(hash="jupiter")
     with self.assertRaises(rebound.ParticleNotFound):
         self.sim.get_particle_by_hash("jupiter")
Exemple #3
0
 def test_removing_particles(self):
     self.sim.add(a=30.)
     self.sim.remove(0)
     self.sim.remove(0)
     self.sim.remove(hash=rebound.hash("earth"), keepSorted=0)
     self.assertEqual(self.sim.particles["jupiter"].hash.value, rebound.hash("jupiter").value)
     self.assertEqual(self.sim.N, 2)
     with self.assertRaises(rebound.ParticleNotFound):
         self.sim.particles["earth"]
     self.sim.remove(hash="jupiter")
     with self.assertRaises(rebound.ParticleNotFound):
         self.sim.particles["jupiter"]
Exemple #4
0
 def test_removing_particles(self):
     self.sim.add(a=30.)
     self.sim.remove(0)
     self.sim.remove(0)
     self.sim.remove(hash=rebound.hash("earth"), keepSorted=0)
     self.assertEqual(self.sim.particles["jupiter"].hash.value,
                      rebound.hash("jupiter").value)
     self.assertEqual(self.sim.N, 2)
     with self.assertRaises(rebound.ParticleNotFound):
         self.sim.particles["earth"]
     self.sim.remove(hash="jupiter")
     with self.assertRaises(rebound.ParticleNotFound):
         self.sim.particles["jupiter"]
Exemple #5
0
 def test_removing_particles(self):
     self.sim.add(a=30.)
     self.sim.remove(index=0)
     self.sim.remove(index=0)
     self.sim.remove(hash=rebound.hash("earth"), keepSorted=0)
     self.assertEqual(
         self.sim.get_particle_by_hash("jupiter").hash,
         rebound.hash("jupiter"))
     self.assertEqual(self.sim.N, 2)
     with self.assertRaises(rebound.ParticleNotFound):
         self.sim.get_particle_by_hash("earth")
     self.sim.remove(hash="jupiter")
     with self.assertRaises(rebound.ParticleNotFound):
         self.sim.get_particle_by_hash("jupiter")
Exemple #6
0
def make_sim(sim_name: str, object_names: List[str], epoch: datetime,
             integrator: str, steps_per_day: int,
             save_file: bool) -> rebound.Simulation:
    """Create or load simulation with the specified objects at the specified time"""
    # Filename for archive
    file_date: str = epoch.strftime('%Y-%m-%d_%H-%M')
    fname_archive: str = f'../data/planets/{sim_name}_{file_date}.bin'

    # If this file already exists, load it and check for both extra and missing bodies
    sim: rebound.Simulation
    try:
        # Attempt to load the named file
        sim = rebound.Simulation(fname_archive)
        # print(f'Loaded {fname_archive}')

        # Generate list of missing object names
        objects_missing: List[str] = [
            nm for nm in object_names if nm not in sim.particles
        ]

        # Extend the simulation and save it with the augmented bodies
        if objects_missing:
            print(f'Found missing objects in {fname_archive}:')
            print(objects_missing)
            extend_sim_horizons(sim, object_names=objects_missing, epoch=epoch)

        # Sets of named and input object hashes
        hashes_sim: Set[int] = set(p.hash.value for p in sim.particles)
        hashes_input: Set[str] = set(
            rebound.hash(nm).value for nm in object_names)

        # Filter the simulation so only the named objects are included
        hashes_remove: List[str] = [
            h for h in hashes_sim if h not in hashes_input
        ]
        for h in hashes_remove:
            sim.remove(hash=h)

    except:
        # Initialize simulation
        sim = make_sim_horizons(object_names=object_names, epoch=epoch)

    # Move to center of momentum
    sim.move_to_com()

    # Set integrator and time step
    sim.integrator = integrator
    dt: float = 1.0 / steps_per_day if steps_per_day > 0 else 0
    sim.dt = dt
    if integrator == 'ias15':
        ias15 = sim.ri_ias15
        ias15.min_dt = dt

    # Save a snapshot to the archive file if requested
    if save_file:
        sim.simulationarchive_snapshot(filename=fname_archive, deletefile=True)

    # Return the simulation
    return sim
Exemple #7
0
def extend_sim_horizons(sim: rebound.Simulation, object_names: List[str], epoch: datetime) -> None:
    """Extend a rebound simulation with initial data from the NASA Horizons system"""
    # Generate list of missing object names
    hashes_present: Set[int] = set(p.hash.value for p in sim.particles)
    objects_missing: List[str] = [nm for nm in object_names if rebound.hash(nm).value not in hashes_present]
    
    # Add missing objects one at a time if not already present
    for object_name in objects_missing:
        add_one_object_hrzn(sim=sim, object_name=object_name, epoch=epoch, hrzn=hrzn)        
    
    # Move to center of mass
    sim.move_to_com()
Exemple #8
0
 def hash(self, value):
     PY3 = sys.version_info[0] == 3
     if PY3:
         string_types = str,
         int_types = int,
     else:
         string_types = basestring,
         int_types = int, long,
     if isinstance(value, int_types):
         self._hash = value
     elif isinstance(value, string_types):
         self._hash = rebound.hash(value)
     else:
         raise AttributeError("Expecting integer or string as argument")
Exemple #9
0
def extend_sim(sim: rebound.Simulation, object_names_new: List[str],
               epoch: datetime):
    """Extend an existing simulation"""
    # Generate list of missing object names
    hashes_present: Set[int] = set(p.hash.value for p in sim.particles)
    objects_missing: List[str] = [
        nm for nm in object_names_new
        if rebound.hash(nm).value not in hashes_present
    ]

    # Extend the simulation and save it with the augmented bodies
    if objects_missing:
        extend_sim_horizons(sim, object_names=objects_missing, epoch=epoch)

    return sim
Exemple #10
0
 def hash(self, value):
     PY3 = sys.version_info[0] == 3
     hash_types = c_uint32, c_uint, c_ulong
     if PY3:
         string_types = str,
         int_types = int,
     else:
         string_types = basestring,
         int_types = int, long,
     if isinstance(value, hash_types):
         self._hash = value.value
     elif isinstance(value, string_types):
         self._hash = rebound.hash(value).value
     elif isinstance(value, int_types):
         self._hash = value
     else:
         raise AttributeError("Hash must be set to an integer, a ctypes.c_uint32 or a string. See UniquelyIdentifyingParticles.ipynb ipython_example.")
Exemple #11
0
 def hash(self, value):
     PY3 = sys.version_info[0] == 3
     hash_types = c_uint32, c_uint, c_ulong
     if PY3:
         string_types = str,
         int_types = int,
     else:
         string_types = basestring,
         int_types = int, long,
     if isinstance(value, hash_types):
         self._hash = value.value
     elif isinstance(value, string_types):
         self._hash = rebound.hash(value).value
     elif isinstance(value, int_types):
         self._hash = value
     else:
         raise AttributeError("Hash must be set to an integer, a ctypes.c_uint32 or a string. See UniquelyIdentifyingParticles.ipynb ipython_example.")
Exemple #12
0
 def test_hash(self):
     self.case(hashes=[0,1,2,3])
     self.case(hashes=[0,None,2,3])
     self.case(hashes=[2,3,1,4])
     self.case(hashes=[2,4,None,3])
     self.case(hashes=[2,0,4,3])
     self.case(hashes=[2,0,4,None])
     self.case(hashes=[2,3,4,0])
     self.case(hashes=[None,4,3,0])
     e = rebound.hash("earth").value
     self.case(hashes=[0,1,2,e])
     self.case(hashes=[0,None,e,3])
     self.case(hashes=[2,3,e,4])
     self.case(hashes=[2,e,None,3])
     self.case(hashes=[2,0,e,3])
     self.case(hashes=[e,0,4,None])
     self.case(hashes=[2,e,4,0])
     self.case(hashes=[None,4,e,0])
Exemple #13
0
 def test_hash(self):
     self.case(hashes=[0, 1, 2, 3])
     self.case(hashes=[0, None, 2, 3])
     self.case(hashes=[2, 3, 1, 4])
     self.case(hashes=[2, 4, None, 3])
     self.case(hashes=[2, 0, 4, 3])
     self.case(hashes=[2, 0, 4, None])
     self.case(hashes=[2, 3, 4, 0])
     self.case(hashes=[None, 4, 3, 0])
     e = rebound.hash("earth").value
     self.case(hashes=[0, 1, 2, e])
     self.case(hashes=[0, None, e, 3])
     self.case(hashes=[2, 3, e, 4])
     self.case(hashes=[2, e, None, 3])
     self.case(hashes=[2, 0, e, 3])
     self.case(hashes=[e, 0, 4, None])
     self.case(hashes=[2, e, 4, 0])
     self.case(hashes=[None, 4, e, 0])
def make_sim_asteroids(sim_base: rebound.Simulation, 
                       ast_elt: pd.DataFrame, 
                       n0: int, n1: int,
                       progbar: bool = False) -> Tuple[rebound.Simulation, List[str]]:
    """
    Create a simulation with the selected asteroids by their ID numbers.
    INPUTS:
    sim_base: the base simulation, with e.g. the sun, planets, and selected moons
    ast_elt: the DataFrame with asteroid orbital elements at the specified epoch
    n0: the first asteroid number to add, inclusive
    n1: the last asteroid number to add, exclusive
    """
    # Start with a copy of the base simulation
    sim = sim_base.copy()
    # Set the number of active particles to the base simulation
    # https://rebound.readthedocs.io/en/latest/ipython/Testparticles.html
    sim.N_active = sim_base.N

    # Add the specified asteroids one at a time
    mask = (n0 <= ast_elt.Num) & (ast_elt.Num < n1)
    nums = ast_elt.index[mask]
    iters = tqdm_console(nums) if progbar else nums
    for num in iters:
        # Unpack the orbital elements
        a = ast_elt.a[num]
        e = ast_elt.e[num]
        inc = ast_elt.inc[num]
        Omega = ast_elt.Omega[num]
        omega = ast_elt.omega[num]
        M = ast_elt.M[num]
        name = ast_elt.Name[num]
        # Set the primary to the sun (NOT the solar system barycenter!)
        primary = sim.particles['Sun']
        # Add the new asteroid
        sim.add(m=0.0, a=a, e=e, inc=inc, Omega=Omega, omega=omega, M=M, primary=primary)
        # Set the hash to the asteroid's name
        sim.particles[-1].hash = rebound.hash(name)

    # The corresponding list of asteroid names
    asteroid_names = [name for name in ast_elt.Name[nums]]

    # Return the new simulation including the asteroids
    return sim, asteroid_names
Exemple #15
0
def make_sim_horizons(object_names: List[str], horizon_date: str):
    """Create a new rebound simulation with initial data from the NASA Horizons system"""
    # Create a simulation
    sim = rebound.Simulation()
    
    # Set units
    sim.units = ('yr', 'AU', 'Msun')
    
    # Add these objects from Horizons
    sim.add(object_names, date=horizon_date)
          
    # Add hashes for the object names
    for i, particle in enumerate(sim.particles):
        particle.hash = rebound.hash(object_names[i])
        
    # Move to center of mass
    sim.move_to_com()
    
    return sim
def make_sim_from_elts(elts: Dict[str, np.array], epoch: float):
    """
    Create a simulation for planets and asteroids parameterized by their orbital elements
    INPUTS:
        elts: dictionary with keys 'a', 'e', etc. for 6 orbital elements.  values arrays of shape (N,)
        epoch: MJD as of which these orbital elements apply    
    """
    # Convert epoch to a datetime
    epoch_dt = mjd_to_datetime(epoch)
    # Base Rebound simulation of the planets and moons on this date
    sim = make_sim_planets(epoch=epoch_dt)
    # Set the number of active particles to the base simulation
    sim.N_active = sim.N

    # Unpack the orbital elements
    a = elts['a']
    e = elts['e']
    inc = elts['inc']
    Omega = elts['Omega']
    omega = elts['omega']
    f = elts['f']
    
    # Get the number of asteroids in the data set
    n: int = a.shape[0]
    
    # Add the specified asteroids one at a time
    for i in range(n):
        # Set the primary to the sun (NOT the solar system barycenter!)
        # Put this inside the loop b/c not guaranteed to remain constant as particles are added
        primary = sim.particles['Sun']
        # Add the new asteroid
        sim.add(m=0.0, a=a[i], e=e[i], inc=inc[i], Omega=Omega[i], omega=omega[i], f=f[i], primary=primary)
        # Set the hash to the asteroid's number in this batch
        sim.particles[-1].hash = rebound.hash(f'{i}')
        
    # Return the new simulation including the asteroids
    return sim
def get_wd_hash():
    wd_hash = rebound.hash('wd').value
    return wd_hash
Exemple #18
0
 def test_add(self):
     self.sim.add(a=7., hash = "planet 9")
     self.assertEqual(rebound.hash("planet 9"), self.sim.get_particle_by_hash("planet 9").hash)
Exemple #19
0
 def test_rebound_hash(self):
     self.assertNotEqual(rebound.hash("foo"), rebound.hash("bar"))
     self.assertEqual(rebound.hash("earth"), 1424801690)
Exemple #20
0
 def test_add(self):
     self.sim.add(a=7., hash="planet 9")
     self.assertEqual(
         rebound.hash("planet 9").value,
         self.sim.particles["planet 9"].hash.value)
Exemple #21
0
    def propagate(self, epochs, units=Units(), **kwargs):
        '''
        Numerically integrate all bodies to the desired date.
        This routine synchronizes the epochs.
        '''

        if kwargs.get('func') is not None:
            f = True
            func = kwargs.get('func')
        else:
            f = False

        units.timescale = 'tdb'

        epochs = self.detect_timescale(np.atleast_1d(epochs), units.timescale)

        self.move_to_com()

        #for time in track(np.sort(epochs.tdb.jd)):
        #    self.integrate(time, exact_finish_time=1)

        for time in np.sort(epochs.tdb.jd):
            self.integrate(time, exact_finish_time=1)

            if f == True:
                func(self)

            for p in self.particles:
                h = p.hash.value
                arr = [time] + p.xyz + p.vxyz
                self.simdata[h].append(arr)

        pepoch = []
        px = []
        py = []
        pz = []
        pvx = []
        pvy = []
        pvz = []
        pname = []
        for n in self.perturber_names:
            ts, xs, ys, zs, vxs, vys, vzs = np.array(
                self.simdata[rebound.hash(n).value]).T
            pepoch.append(ts.tolist())
            px.append(xs.tolist())
            py.append(ys.tolist())
            pz.append(zs.tolist())
            pvx.append(vxs.tolist())
            pvy.append(vys.tolist())
            pvz.append(vzs.tolist())
            pname.append([n for _ in range(len(ts))])

        pepoch = np.hstack(pepoch)
        px = np.hstack(px)
        py = np.hstack(py)
        pz = np.hstack(pz)
        pvx = np.hstack(pvx)
        pvy = np.hstack(pvy)
        pvz = np.hstack(pvz)
        pname = np.hstack(pname)

        planets = SpaceRock(x=px,
                            y=py,
                            z=pz,
                            vx=pvx,
                            vy=pvy,
                            vz=pvz,
                            name=pname,
                            epoch=pepoch,
                            origin='ssb',
                            units=units)

        if hasattr(self, 'testparticle_names'):
            epoch = []
            x = []
            y = []
            z = []
            vx = []
            vy = []
            vz = []
            name = []
            for n in self.testparticle_names:
                ts, xs, ys, zs, vxs, vys, vzs = np.array(
                    self.simdata[rebound.hash(n).value]).T
                epoch.append(ts.tolist())
                x.append(xs.tolist())
                y.append(ys.tolist())
                z.append(zs.tolist())
                vx.append(vxs.tolist())
                vy.append(vys.tolist())
                vz.append(vzs.tolist())
                name.append([n for _ in range(len(ts))])

            epoch = np.hstack(epoch)
            x = np.hstack(x)
            y = np.hstack(y)
            z = np.hstack(z)
            vx = np.hstack(vx)
            vy = np.hstack(vy)
            vz = np.hstack(vz)
            name = np.hstack(name)

            rocks = SpaceRock(x=x,
                              y=y,
                              z=z,
                              vx=vx,
                              vy=vy,
                              vz=vz,
                              name=name,
                              epoch=epoch,
                              origin='ssb',
                              units=units)

        else:
            rocks = ()

        return rocks, planets, self
Exemple #22
0
    'Varda': ao + 174567,
    '2007 OR10': ao + 225088,
    '229762': ao + 229762,
    # Miscellaneous heavy non-numbered asteroids
    'Vanth': uo + 1,
    'Hiʻiaka': uo + 2,
    '2001 QC298': uo + 3,
}

# *********************************************************************************************************************
# Dictionary mapping from ID to name
id_to_name: Dict[int, str] = {name_to_id[name]: name for name in name_to_id}

# Dictionary mapping from rebound hash to name
hash_to_name: Dict[int, str] = {
    rebound.hash(name_to_id[name]).value: name
    for name in name_to_id
}
name_to_hash: Dict[str, int] = {
    name: rebound.hash(name_to_id[name]).value
    for name in name_to_id
}

# *********************************************************************************************************************
# Mass of all solar system objects available on Wikipedia
# https://en.wikipedia.org/wiki/List_of_Solar_System_objects_by_size
mass_tbl = {
    'Sun': 1.000000000000E+00,
    # Inner planets
    'Mercury': 1.660506399135E-07,
    'Venus': 2.448266324709E-06,
Exemple #23
0
 def test_add(self):
     self.sim.add(a=7., hash="planet 9")
     self.assertEqual(rebound.hash("planet 9"),
                      self.sim.get_particle_by_hash("planet 9").hash)
def calc_ast_pos(elts: Dict[str, np.array], epoch: float, ts: np.array) -> np.array:
    """
    Calculate asteroid positions from the given elements on the fly
    INPUTS:
        elts: dictionary with keys 'a', 'e', etc. for 6 orbital elements.  values arrays of shape (N,)
        epoch: MJD as of which these orbital elements apply
        ts: array of MJDs as of which 
    Outputs:
        q_earth: position of earth at input times; shape (traj_size, 3,)
        q_ast: positions of asteroids at input times; shape (num_ast, traj_size, 3,)
    Note: this function has some overlap with make_archive_impl in rebount_utils.py
    It's different though because it's intended to generate arrays on the fly, not save them to disk.
    """
    # Build the simulation at the epoch
    sim_epoch = make_sim_from_elts(elts, epoch)
    
    # Create copies of the simulation to integrate forward and backward
    sim_fwd: rebound.Simulation = sim_epoch.copy()
    sim_back: rebound.Simulation = sim_epoch.copy()

    # Set the time counter on both simulation copies to the epoch time
    sim_fwd.t = epoch
    sim_back.t = epoch

    # Set the times for snapshots in both directions;
    idx: int = np.searchsorted(ts, epoch, side='left')
    ts_fwd: np.array = ts[idx:]
    ts_back: np.array = ts[:idx][::-1]

    # Number of snapshots
    M_back: int = len(ts_back)
    M_fwd: int = len(ts_fwd)
    M: int = M_back + M_fwd
    # Number of particles
    N = sim_epoch.N
    # Number of asteroids (smaller than total number of particles; not including sun and planets)
    N_ast: int = elts['a'].shape[0]
    # Number of heavy bodies; saved before first asteroid in output array
    N_heavy: int = N - N_ast

    # The sun is the primary and is always in column 0
    sun_idx = 0
    # Column index of Earth by searching for hash of earth in all hashes of the simulation
    hash_earth = rebound.hash('Earth')
    hashes = np.zeros(N, dtype=np.uint32)
    sim_epoch.serialize_particle_data(hash=hashes)
    earth_idx = np.argmax(hashes==hash_earth)
    
    # Initialize array for the positions of all particles in the simulation
    # Match the order required by rebound for efficient serialization!
    # This must be permuted at the end
    q: np.array = np.zeros(shape=(M, N, 3,), dtype=np.float64)
    
    # Subfunction: process one row of the loop    
    def process_row(sim: rebound.Simulation, t: float, row: int):
        # Integrate to the current time step with an exact finish time
        sim.integrate(t, exact_finish_time=1)
        
        # Serialize the positions of earth and all the bodies
        sim.serialize_particle_data(xyz=q[row])
    
    # process times in the forward direction
    for i, t in enumerate(ts_fwd):
        # Row index for position data
        row: int = M_back + i
        # Process this row
        process_row(sim=sim_fwd, t=t, row=row)
    
    # process times in the backward direction
    for i, t in enumerate(ts_back):
        # Row index for position data
        row: int = M_back - (i+1)
        # Process this row
        process_row(sim=sim_back, t=t, row=row)
    
    # Position of sun is the relevant column
    q_sun = q[:, sun_idx, 0:3]
    # Position of earth is the relevant column
    q_earth = q[:, earth_idx, 0:3]
    # The asteroid positions are in the right-hand slice of q_all
    # Transpose so resulting array has size (N_ast, traj_size, 3)
    q_ast = q[:, N_heavy:N, 0:3].transpose((1,0,2))

    return q_ast, q_sun, q_earth
Exemple #25
0
 def test_add(self):
     self.sim.add(a=7., hash = "planet 9")
     self.assertEqual(rebound.hash("planet 9").value, self.sim.particles["planet 9"].hash.value)
Exemple #26
0
 def test_rebound_hash(self):
     self.assertNotEqual(
         rebound.hash("foo").value,
         rebound.hash("bar").value)
     self.assertEqual(rebound.hash("earth").value, 1424801690)