void NuclearDecay::nucleonEmission(Candidate *candidate, int dA, int dZ) const {
	Random &random = Random::instance();
	int id = candidate->current.getId();
	int A = massNumber(id);
	int Z = chargeNumber(id);
	double EpA = candidate->current.getEnergy() / double(A);

	try
	{
		candidate->current.setId(nucleusId(A - dA, Z - dZ));
	}
	catch (std::runtime_error &e)
	{
		KISS_LOG_ERROR<< "Something went wrong in the NuclearDecay\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64();
		throw;
	}

	candidate->current.setEnergy(EpA * (A - dA));
	Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(),candidate->current.getPosition());

	try
	{
		candidate->addSecondary(nucleusId(dA, dZ), EpA * dA, pos);
	}
	catch (std::runtime_error &e)
	{
		KISS_LOG_ERROR<< "Something went wrong in the NuclearDecay\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64();
		throw;
	}

}
void NuclearDecay::gammaEmission(Candidate *candidate, int channel) const {
	int id = candidate->current.getId();
	int Z = chargeNumber(id);
	int N = massNumber(id) - Z;

	// get photon energies and emission probabilities for decay channel
	const std::vector<DecayMode> &decays = decayTable[Z * 31 + N];
	size_t idecay = decays.size();
	while (idecay-- != 0) {
		if (decays[idecay].channel == channel)
			break;
	}

	const std::vector<double> &energy = decays[idecay].energy;
	const std::vector<double> &intensity = decays[idecay].intensity;

	// check if photon emission available
	if (energy.size() == 0)
		return;

	Random &random = Random::instance();
	Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition());

	for (int i = 0; i < energy.size(); ++i) {
		// check if photon of specific energy is emitted
		if (random.rand() > intensity[i])
			continue;
		// create secondary photon; boost to lab frame
		double cosTheta = 2 * random.rand() - 1;
		double E = energy[i] * candidate->current.getLorentzFactor() * (1. - cosTheta);
		candidate->addSecondary(22, E, pos);
	}
}
Exemple #3
0
void ParticleState::setId(int newId) {
	id = newId;
	if (isNucleus(id)) {
		pmass = nuclearMass(id);
		charge = chargeNumber(id) * eplus;
		if (id < 0)
			charge *= -1; // anti-nucleus
	} else {
		// pmass missing for non-nuclei
		charge = HepPID::charge(id) * eplus;
	}
}
Exemple #4
0
void ParticleState::setId(int newId) {
	id = newId;
	if (isNucleus(id)) {
		pmass = nuclearMass(id);
		charge = chargeNumber(id) * eplus;
		if (id < 0)
			charge *= -1; // anti-nucleus
	} else {
		if (abs(id) == 11)
			pmass = mass_electron;
		charge = HepPID::charge(id) * eplus;
	}
}
void NuclearDecay::process(Candidate *candidate) const {
	// the loop should be processed at least once for limiting the next step
	double step = candidate->getCurrentStep();
	double z = candidate->getRedshift();
	do {
		// check if nucleus
		int id = candidate->current.getId();
		if (not (isNucleus(id)))
			return;

		int A = massNumber(id);
		int Z = chargeNumber(id);
		int N = A - Z;

		// check if particle can decay
		const std::vector<DecayMode> &decays = decayTable[Z * 31 + N];
		if (decays.size() == 0)
			return;

		// find interaction mode with minimum random decay distance
		Random &random = Random::instance();
		double randDistance = std::numeric_limits<double>::max();
		int channel;
		double totalRate = 0;

		for (size_t i = 0; i < decays.size(); i++) {
			double rate = decays[i].rate;
			rate /= candidate->current.getLorentzFactor();  // relativistic time dilation
			rate /= (1 + z);  // rate per light travel distance -> rate per comoving distance
			totalRate += rate;
			double d = -log(random.rand()) / rate;
			if (d > randDistance)
				continue;
			randDistance = d;
			channel = decays[i].channel;
		}

		// check if interaction doesn't happen
		if (step < randDistance) {
			// limit next step to a fraction of the mean free path
			candidate->limitNextStep(limit / totalRate);
			return;
		}

		// interact and repeat with remaining step
		performInteraction(candidate, channel);
		step -= randDistance;
	} while (step > 0);
}
double NuclearDecay::meanFreePath(int id, double gamma) {
	if (not (isNucleus(id)))
		return std::numeric_limits<double>::max();

	int A = massNumber(id);
	int Z = chargeNumber(id);
	int N = A - Z;

	// check if particle can decay
	const std::vector<DecayMode> &decays = decayTable[Z * 31 + N];
	if (decays.size() == 0)
		return std::numeric_limits<double>::max();

	double totalRate = 0;

	for (size_t i = 0; i < decays.size(); i++) {
		double rate = decays[i].rate;
		rate /= gamma;
		totalRate += rate;
	}

	return 1. / totalRate;
}
void NuclearDecay::betaDecay(Candidate *candidate, bool isBetaPlus) const {
	double gamma = candidate->current.getLorentzFactor();
	int id = candidate->current.getId();
	int A = massNumber(id);
	int Z = chargeNumber(id);

	// beta- decay
	int electronId = 11; // electron
	int neutrinoId = -12; // anti-electron neutrino
	int dZ = 1;
	// beta+ decay
	if (isBetaPlus) {
		electronId = -11; // positron
		neutrinoId = 12; // electron neutrino
		dZ = -1;
	}

	// update candidate, nuclear recoil negligible
	try
	{
		candidate->current.setId(nucleusId(A, Z + dZ));
	}
	catch (std::runtime_error &e)
	{
		KISS_LOG_ERROR<< "Something went wrong in the NuclearDecay\n" << "Please report this error on https://github.com/CRPropa/CRPropa3/issues including your simulation setup and the following random seed:\n" << Random::instance().getSeed_base64();
		throw;
	}

	candidate->current.setLorentzFactor(gamma);

	if (not (haveElectrons or haveNeutrinos))
		return;

	// Q-value of the decay, subtract total energy of emitted photons
	double m1 = nuclearMass(A, Z);
	double m2 = nuclearMass(A, Z+dZ);
	double Q = (m1 - m2 - mass_electron) * c_squared;

	// generate cdf of electron energy, neglecting Coulomb correction
	// see Basdevant, Fundamentals in Nuclear Physics, eq. (4.92)
	std::vector<double> energies;
	std::vector<double> densities; // cdf(E), unnormalized

	energies.reserve(51);
	densities.reserve(51);

	double me = mass_electron * c_squared;
	double cdf = 0;
	for (int i = 0; i <= 50; i++) {
		double E = me + i / 50. * Q;
		cdf += E * sqrt(E * E - me * me) * pow(Q + me - E, 2);
		energies.push_back(E);
		densities.push_back(cdf);
	}

	// draw random electron energy and angle
	Random &random = Random::instance();
	double E = interpolate(random.rand() * cdf, densities, energies);
	double p = sqrt(E * E - me * me);  // p*c
	double cosTheta = 2 * random.rand() - 1;

	// boost to lab frame
	double Ee = gamma * (E - p * cosTheta);
	double Enu = gamma * (Q + me - E) * (1 + cosTheta);  // pnu*c ~ Enu

	Vector3d pos = random.randomInterpolatedPosition(candidate->previous.getPosition(), candidate->current.getPosition());
	if (haveElectrons)
		candidate->addSecondary(electronId, Ee, pos);
	if (haveNeutrinos)
		candidate->addSecondary(neutrinoId, Enu, pos);
}
void MinimumRigidity::process(Candidate *c) const {
	double rigidity = fabs(c->current.getEnergy() / chargeNumber(c->current.getId()));
	if (rigidity < minRigidity)
		reject(c);
}