PropagationCK::Y PropagationCK::dYdt(const Y &y, ParticleState &p, double z) const { // normalize direction vector to prevent numerical losses Vector3d velocity = y.u.getUnitVector() * c_light; Vector3d B(0, 0, 0); try { B = field->getField(y.x, z); } catch (std::exception &e) { std::cerr << "PropagationCK: Exception in getField." << std::endl; std::cerr << e.what() << std::endl; } // Lorentz force: du/dt = q*c/E * (v x B) Vector3d dudt = p.getCharge() * c_light / p.getEnergy() * velocity.cross(B); return Y(velocity, dudt); }
const double rms_beam_emittance(ParticleState const &ps, unsigned axis, unsigned beam_axis) { if (ps.particle_count == 0) return 0; double mean_x = 0; double mean_xp = 0; double mean_x_squared = 0; double mean_xp_squared = 0; double mean_xxp = 0; // see doc/notes.tm for (particle_number pn = 0; pn < ps.particle_count; pn++) { const double x = ps.positions[pn*ps.xdim() + axis]; mean_x += x; mean_x_squared += square(x); const double px = ps.momenta[pn*ps.vdim() + axis]; const double pz = ps.momenta[pn*ps.vdim() + beam_axis]; const double xprime = pz ? px/pz : 0; mean_xp += xprime; mean_xp_squared += square(xprime); mean_xxp += x*xprime; } mean_x /= ps.particle_count; mean_xp /= ps.particle_count; mean_x_squared /= ps.particle_count; mean_xp_squared /= ps.particle_count; mean_xxp /= ps.particle_count; return sqrt( mean_x_squared*mean_xp_squared - square(mean_x)*mean_xp_squared - mean_x_squared*square(mean_xp) - ( square(mean_xxp) -2*mean_xxp*mean_x*mean_xp ) ); }
TEST(testPropagationCK, neutron) { PropagationCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); propa.setMinimumStep(1 * kpc); propa.setMaximumStep(42 * Mpc); ParticleState p; p.setId(nucleusId(1, 0)); p.setEnergy(100 * EeV); p.setPosition(Vector3d(0, 0, 0)); p.setDirection(Vector3d(0, 1, 0)); Candidate c(p); propa.process(&c); EXPECT_DOUBLE_EQ(1 * kpc, c.getCurrentStep()); EXPECT_DOUBLE_EQ(42 * Mpc, c.getNextStep()); EXPECT_EQ(Vector3d(0, 1 * kpc, 0), c.current.getPosition()); EXPECT_EQ(Vector3d(0, 1, 0), c.current.getDirection()); }
TEST(testPropagationCK, proton) { PropagationCK propa(new UniformMagneticField(Vector3d(0, 0, 1 * nG))); double minStep = 0.1 * kpc; propa.setMinimumStep(minStep); ParticleState p; p.setId(nucleusId(1, 1)); p.setEnergy(100 * EeV); p.setPosition(Vector3d(0, 0, 0)); p.setDirection(Vector3d(0, 1, 0)); Candidate c(p); c.setNextStep(0); propa.process(&c); EXPECT_DOUBLE_EQ(minStep, c.getCurrentStep()); // perform minimum step EXPECT_DOUBLE_EQ(5 * minStep, c.getNextStep()); // acceleration by factor 5 }
const double rms_beam_size(ParticleState const &ps, unsigned axis) { if (ps.particle_count == 0) return 0; double result = 0; for (particle_number pn = 0; pn < ps.particle_count; pn++) result += square(ps.positions[pn*ps.xdim() + axis]); return sqrt(result/ps.particle_count); }
const py_vector particle_momentum(ParticleState const &ps) { const unsigned vdim = ps.vdim(); py_vector result(vdim); result.clear(); for (particle_number pn = 0; pn < ps.particle_count; pn++) result += subrange(ps.momenta, vdim*pn, vdim*(pn+1)); return result; }
const py_vector particle_current(ParticleState const &ps, py_vector const &velocities, double length) { const unsigned vdim = ps.vdim(); py_vector result(vdim); result.clear(); for (particle_number pn = 0; pn < ps.particle_count; pn++) result += ps.charges[pn] * subrange(velocities, vdim*pn, vdim*(pn+1)); return result / length; }
TEST(testSimplePropagation, step) { double minStep = 20; double maxStep = 100; SimplePropagation propa(minStep, maxStep); ParticleState p; p.setPosition(Vector3d(0, 0, 0)); p.setDirection(Vector3d(0, 1, 0)); Candidate c(p); c.setNextStep(10); propa.process(&c); EXPECT_EQ(minStep, c.getCurrentStep()); EXPECT_EQ(maxStep, c.getNextStep()); EXPECT_EQ(Vector3d(0, 0, 0), c.created.getPosition()); EXPECT_EQ(Vector3d(0, 1, 0), c.created.getDirection()); EXPECT_EQ(Vector3d(0, 0, 0), c.previous.getPosition()); EXPECT_EQ(Vector3d(0, 1, 0), c.previous.getDirection()); EXPECT_EQ(Vector3d(0, 20, 0), c.current.getPosition()); EXPECT_EQ(Vector3d(0, 1, 0), c.current.getDirection()); }
const py_vector kinetic_energies(ParticleState const &ps, double vacuum_c) { const unsigned vdim = ps.vdim(); py_vector result(ps.particle_count); const double c_squared = vacuum_c*vacuum_c; for (particle_number pn = 0; pn < ps.particle_count; pn++) { const unsigned vpstart = vdim*pn; const unsigned vpend = vdim*(pn+1); const double m = ps.masses[pn]; double p = norm_2(subrange(ps.momenta, vpstart, vpend)); double v = vacuum_c*p/sqrt(m*m*c_squared + p*p); result[pn] = (p/v-m)*c_squared; } return result; }
bool EmissionMap::checkDirection(const ParticleState& state) const { return checkDirection(state.getId(), state.getEnergy(), state.getDirection()); }
bool EmissionMap::drawDirection(const ParticleState& state, Vector3d& direction) const { return drawDirection(state.getId(), state.getEnergy(), direction); }
void EmissionMap::fillMap(const ParticleState& state, double weight) { fillMap(state.getId(), state.getEnergy(), state.getDirection(), weight); }