def cycper(self): """Return the cyclotron period value at the final position.""" t, r, mom = self.trajectory[-1, 0], self.trajectory[ -1, 1:4], self.trajectory[-1, 4:] gm = np.sqrt(self.mass**2 + np.dot(mom, mom) / c**2) # gamma * mass v = mom / gm return ru.cyclotron_period(t, r, v, self.field, self.mass, self.charge)
def cycper(self): """Return the cyclotron period value at the final position.""" t, r, mom = self.trajectory[-1, 0], self.trajectory[-1, 1:4], self.trajectory[-1, 4:] gm = np.sqrt(self.mass**2 + np.dot(mom,mom)/c**2) # gamma * mass v = mom/gm return ru.cyclotron_period(t, r, v, self.field, self.mass, self.charge)
def advance(self, delta): """ Advance the particle position and momentum for a given duration. The trajectory is initialized at the latest state of the particle and integrated for an additional `delta` seconds. Uses the `scipy.integrate.ode` class with `"dop853"` solver. This method can be called many times. Parameters ---------- delta : float The number of seconds to advance the trajectory. Raises ------- Adiabatic Only if the `check_adiabaticity` attribute is set to True. Notes ----- The particle is subject to the Newton-Lorentz equation of motion. .. math:: \\frac{\mathrm{d}\\vec{x}}{\mathrm{d}t} = \\frac{\\vec{p}}{\gamma m} \\\\ \\frac{\mathrm{d}\\vec{p}}{\mathrm{d}t} = q\\vec{E} + q\\vec{v}\\times\\vec{B} where :math:`\gamma = \sqrt{1 + (|\\vec{p}|/mc)^2}` is the relativistic factor. The explicit runge-kutta method of order 8(5,3) due to Dormand & Prince with stepsize control is used to solve for the motion. The relative tolerance `rtol` and the absolute tolerance `atol` of the solver can be set with: `rapt.params["solvertolerances"] = (rtol, atol)` The `beta` parameter to the `scipy.integrate.ode.setintegrator` method serves to stabilize the solution in gridded fields. """ rtol, atol = params["solvertolerances"] t0 = self.trajectory[-1,0] pos = self.trajectory[-1,1:4] mom = self.trajectory[-1,4:] gm = np.sqrt(self.mass**2 + np.dot(mom,mom)/c**2) # gamma * mass vel = mom/gm # set resolution of cyclotron motion if params["Ptimestep"] != 0: dt = params["Ptimestep"] else: dt = self.cycper()/params["cyclotronresolution"] dt = ru.cyclotron_period(t0, pos, vel, self.field, self.mass, self.charge) / params['cyclotronresolution'] def eom(t, Y): # The Newton-Lorenz equation of motion # Y = x,y,z,px,py,pz nonlocal gm tpos = np.concatenate(([t],Y[:3])) mom = Y[3:] out = np.zeros(6) if not self.field.static: # don't reevaluate gamma every time, if it is not supposed to change. gm = np.sqrt(self.mass**2 + np.dot(mom,mom)/c**2) # gamma * mass # d(pos)/dt = vel = mom / (gamma*m) : out[0:3] = Y[3:]/gm # dp/dt = q(E(t, pos) + (p/gamma*m) x B(t, pos)) : out[3:] = self.charge * (self.field.E(tpos) + np.cross(Y[3:], self.field.B(tpos))/gm) if params["enforce equatorial"]: out[2] = out[5] = 0 return out r = ode(eom).set_integrator("dop853",beta=0.1, rtol=rtol, atol=atol) # Setting beta is necessary to reduce the error. r.set_initial_value(self.trajectory[-1,1:], self.trajectory[-1,0]) while r.successful() and r.t < t0+delta: next = np.hstack(([r.t+dt],r.integrate(r.t+dt))) self.tcur = r.t+dt self.trajectory = np.vstack((self.trajectory,next)) if self.check_adiabaticity and self.isadiabatic(): raise Adiabatic
def advance(self, delta): """ Advance the particle position and momentum for a given duration. The trajectory is initialized at the latest state of the particle and integrated for an additional `delta` seconds. Uses the `scipy.integrate.ode` class with `"dop853"` solver. This method can be called many times. Parameters ---------- delta : float The number of seconds to advance the trajectory. Raises ------- Adiabatic Only if the `check_adiabaticity` attribute is set to True. Notes ----- The particle is subject to the Newton-Lorentz equation of motion. .. math:: \\frac{\mathrm{d}\\vec{x}}{\mathrm{d}t} = \\frac{\\vec{p}}{\gamma m} \\\\ \\frac{\mathrm{d}\\vec{p}}{\mathrm{d}t} = q\\vec{E} + q\\vec{v}\\times\\vec{B} where :math:`\gamma = \sqrt{1 + (|\\vec{p}|/mc)^2}` is the relativistic factor. The explicit runge-kutta method of order 8(5,3) due to Dormand & Prince with stepsize control is used to solve for the motion. The relative tolerance `rtol` and the absolute tolerance `atol` of the solver can be set with: `rapt.params["solvertolerances"] = (rtol, atol)` The `beta` parameter to the `scipy.integrate.ode.setintegrator` method serves to stabilize the solution in gridded fields. """ rtol, atol = params["solvertolerances"] t0 = self.trajectory[-1, 0] pos = self.trajectory[-1, 1:4] mom = self.trajectory[-1, 4:] gm = np.sqrt(self.mass**2 + np.dot(mom, mom) / c**2) # gamma * mass vel = mom / gm # set resolution of cyclotron motion if params["Ptimestep"] != 0: dt = params["Ptimestep"] else: dt = self.cycper() / params["cyclotronresolution"] dt = ru.cyclotron_period(t0, pos, vel, self.field, self.mass, self.charge) / params['cyclotronresolution'] def eom(t, Y): # The Newton-Lorenz equation of motion # Y = x,y,z,px,py,pz nonlocal gm tpos = np.concatenate(([t], Y[:3])) mom = Y[3:] out = np.zeros(6) if not self.field.static: # don't reevaluate gamma every time, if it is not supposed to change. gm = np.sqrt(self.mass**2 + np.dot(mom, mom) / c**2) # gamma * mass # d(pos)/dt = vel = mom / (gamma*m) : out[0:3] = Y[3:] / gm # dp/dt = q(E(t, pos) + (p/gamma*m) x B(t, pos)) : out[3:] = self.charge * (self.field.E(tpos) + np.cross(Y[3:], self.field.B(tpos)) / gm) if params["enforce equatorial"]: out[2] = out[5] = 0 return out r = ode(eom).set_integrator("dop853", beta=0.1, rtol=rtol, atol=atol) # Setting beta is necessary to reduce the error. r.set_initial_value(self.trajectory[-1, 1:], self.trajectory[-1, 0]) while r.successful() and r.t < t0 + delta: next = np.hstack(([r.t + dt], r.integrate(r.t + dt))) self.tcur = r.t + dt self.trajectory = np.vstack((self.trajectory, next)) if self.check_adiabaticity and self.isadiabatic(): raise Adiabatic