Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
Setting this flag to 1 (default 0) triggers the WHFast integrator
to recalculate Jacobi coordinates. This is needed if the user changes
the particle position, velocity or mass inbetween timesteps.
After every timestep the flag is set back to 0, so if you continuously
update the particles manually, you need to set this flag to 1 after every timestep.
:ivar int safe_mode:
If safe_mode is 1 (default) particles can be modified between
timesteps and particle velocities and positions are always synchronised.
If you set safe_mode to 0, the speed and accuracy of WHFast improves.
However, make sure you are aware of the consequences. Read the iPython tutorial
on advanced WHFast usage to learn more.
"""
_fields_ = [("corrector", c_uint),
("recalculate_jacobi_this_timestep", c_uint),
("safe_mode", c_uint),
("p_j", POINTER(Particle)),
("eta", POINTER(c_double)),
("Mtotal", c_double),
("is_synchronized", c_uint),
("allocatedN", c_uint),
("timestep_warning", c_uint),
("recalculate_jacobi_but_not_synchronized_warning", c_uint)]
class Orbit(Structure):
"""
A class containing orbital parameters for a particle.
This is an abstraction of the reb_orbit data structure in C.
When using the various REBOUND functions using Orbits, all angles are in radians.
The following image illustrated the most important angles used.
In REBOUND the reference direction is the positive x direction, the reference plane
is the xy plane.
ax.add_collection(l)
else:
ax.add_collection(lc)
alpha = 0.2 if orbit_type=="trail" else 1.
pts = np.array(p.sample_orbit(Npts=Narc+1, primary=prim, trailing=False, useTrueAnomaly=False))
proj['x'],proj['y'],proj['z'] = [pts[:,i] for i in range(3)]
lc = fading_line(proj[axes[0]], proj[axes[1]], colori, alpha_initial=alpha, alpha_final=alpha, lw=lw, glow=fancy)
if type(lc) is list:
for l in lc:
ax.add_collection(l)
else:
ax.add_collection(lc)
if periastron:
newp = Particle(a=o.a, f=0., inc=o.inc, omega=o.omega, Omega=o.Omega, e=o.e, m=p.m, primary=prim, simulation=sim)
ax.plot([getattr(prim,axes[0]), getattr(newp,axes[0])], [getattr(prim,axes[1]), getattr(newp,axes[1])], linestyle="dotted", c=colori, zorder=1, lw=lw)
ax.scatter([getattr(newp,axes[0])],[getattr(newp,axes[1])], marker="o", s=5.*lw, facecolor="none", edgecolor=colori, zorder=1)
clibrebound.reb_add(byref(self), particle)
else: # use particle as primary
self.add(Particle(simulation=self, primary=particle, **kwargs))
elif isinstance(particle, list):
for p in particle:
self.add(p)
elif isinstance(particle,str):
if None in self.units.values():
self.units = ('AU', 'yr2pi', 'Msun')
self.add(horizons.getParticle(particle,**kwargs))
units_convert_particle(self.particles[-1], 'km', 's', 'kg', self._units['length'], self._units['time'], self._units['mass'])
else:
raise ValueError("Argument passed to add() not supported.")
else:
self.add(Particle(simulation=self, **kwargs))
1) A single Particle structure.
2) The particle's mass and a set of cartesian coordinates: m,x,y,z,vx,vy,vz.
3) The primary as a Particle structure, the particle's mass and a set of orbital elements primary,a,anom,e,omega,inv,Omega,MEAN (see kepler_particle() for the definition of orbital elements).
4) A name of an object (uses NASA Horizons to look up coordinates)
5) A list of particles or names.
"""
if particle is not None:
if isinstance(particle, Particle):
if kwargs == {}: # copy particle
if (self.gravity == "tree" or self.collision == "tree") and self.root_size <=0.:
raise ValueError("The tree code for gravity and/or collision detection has been selected. However, the simulation box has not been configured yet. You cannot add particles until the the simulation box has a finite size.")
clibrebound.reb_add(byref(self), particle)
else: # use particle as primary
self.add(Particle(simulation=self, primary=particle, **kwargs))
elif isinstance(particle, list):
for p in particle:
self.add(p)
elif isinstance(particle,str):
if None in self.units.values():
self.units = ('AU', 'yr2pi', 'Msun')
self.add(horizons.getParticle(particle,**kwargs))
units_convert_particle(self.particles[-1], 'km', 's', 'kg', self._units['length'], self._units['time'], self._units['mass'])
else:
raise ValueError("Argument passed to add() not supported.")
else:
self.add(Particle(simulation=self, **kwargs))
def jacobi_com(self):
clibrebound.reb_get_jacobi_com.restype = Particle
return clibrebound.reb_get_jacobi_com(byref(self))
@property
def copy(self):
"""
Returns a deep copy of the particle. The particle is not added to any simulation by default.
"""
np = Particle()
memmove(byref(np), byref(self), sizeof(self))
return np
This parameter determines which orbital parameter is varied.
variation2: string, optional
This is only used for second order variations which can depend on two varying parameters. If omitted, then it is assumed that the parameter variation is variation2.
primary: Particle, optional
By default variational particles are created in the Heliocentric frame.
Set this parameter to use any other particles as a primary (e.g. the center of mass).
"""
if self.order==2 and variation2 is None:
variation2 = variation
if self._sim is not None:
sim = self._sim.contents
particles = sim.particles
else:
raise RuntimeError("Something went wrong. Cannot seem to find simulation corresponding to variation.")
if self.testparticle >= 0:
particles[self.index] = Particle(simulation=sim,particle=particles[particle_index], variation=variation, variation2=variation2, primary=primary)
else:
particles[self.index + particle_index] = Particle(simulation=sim,particle=particles[particle_index], variation=variation, variation2=variation2, primary=primary)
l = random.vonmisesvariate(0.,0.)
if theta == "uniform":
theta = random.vonmisesvariate(0.,0.)
self.hash = hash # set via the property, which checks for type
if variation:
if primary is None:
primary = simulation.particles[0]
# Find particle to differenciate
lc = locals().copy()
del lc["self"]
del lc["variation"]
del lc["variation2"]
if particle is None:
particle = Particle(**lc)
# First or second order?
if variation and variation2:
variation_order = 2
else:
variation_order = 1
# Shortcuts for variable names
if variation == "l":
variation = "lambda"
if variation2 == "l":
variation2 = "lambda"
if variation == "i":
variation = "inc"
if variation2 == "i":
variation2 = "inc"
variationtypes = ["m","a","e","inc","omega","Omega","f","k","h","lambda","ix","iy"]
The function returns a list of particles which are sorted in the same way as those in
sim.particles
The particles are pointers and thus can be modified.
If there are N real particles, this function will also return a list of N particles (all of which are
variational particles).
"""
sim = self._sim.contents
ps = []
if self.testparticle>=0:
N = 1
else:
N = sim.N-sim.N_var
ParticleList = Particle*N
ps = ParticleList.from_address(ctypes.addressof(sim._particles.contents)+self.index*ctypes.sizeof(Particle))
return ps