Skip to content

Commit

Permalink
Treat alpha deposition as pure heating instead of non-thermal lepton …
Browse files Browse the repository at this point in the history
…ionisation/excitation/heating (#128)

If alphas contribute significantly to the ionisation then it might worth
making a separate Spencer-Fano calculation. Sending them to k-packet
directly probably makes more sense than treating them as non-thermal
electron deposition with the wrong cross sections. This will only affect
future runs that have both NT_ON and ThermalisationScheme::DETAILED.
  • Loading branch information
lukeshingles committed Sep 17, 2024
1 parent c210f2c commit d6608c2
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 75 deletions.
76 changes: 18 additions & 58 deletions gammapkt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -324,17 +324,11 @@ auto choose_f(const double xx, const double zrand) -> double
auto thomson_angle() -> double {
const double B_coeff = (8. * rng_uniform()) - 4.;

double t_coeff = sqrt((B_coeff * B_coeff) + 4);
t_coeff = t_coeff - B_coeff;
t_coeff = t_coeff / 2;
t_coeff = cbrt(t_coeff);
const double t_coeff = std::cbrt((std::sqrt((B_coeff * B_coeff) + 4) - B_coeff) / 2);

const double mu = (1 / t_coeff) - t_coeff;

if (fabs(mu) > 1) {
printout("Error in Thomson. Abort.\n");
std::abort();
}
assert_always(fabs(mu) <= 1);

return mu;
}
Expand Down Expand Up @@ -396,23 +390,16 @@ void compton_scatter(Packet &pkt) {
// factor by which the energy changes "f" such that
// sigma_partial/sigma_tot = zrand

bool stay_gamma = false;
double f{NAN};
if (xx < THOMSON_LIMIT) {
f = 1.; // no energy loss
stay_gamma = true;
} else {
// initialise with Thomson limit case (no energy loss)
double f = 1.;
bool stay_gamma = true;
if (xx >= THOMSON_LIMIT) {
f = choose_f(xx, rng_uniform());

// Check that f lies between 1.0 and (2xx + 1)

if ((f < 1) || (f > (2 * xx + 1))) {
printout("Compton f out of bounds. Abort.\n");
std::abort();
}
assert_always(f >= 1.);
assert_always(f <= (2 * xx + 1.));

// Prob of keeping gamma ray is...

const double prob_gamma = 1. / f;

stay_gamma = (rng_uniform() < prob_gamma);
Expand All @@ -437,20 +424,8 @@ void compton_scatter(Packet &pkt) {

const auto new_dir = scatter_dir(cmf_dir, cos_theta);

const double test = dot(new_dir, new_dir);
if (fabs(1. - test) > 1.e-8) {
printout("Not a unit vector - Compton. Abort. %g %g %g\n", f, xx, test);
printout("new_dir %g %g %g\n", new_dir[0], new_dir[1], new_dir[2]);
printout("cmf_dir %g %g %g\n", cmf_dir[0], cmf_dir[1], cmf_dir[2]);
printout("cos_theta %g", cos_theta);
std::abort();
}

const double test2 = dot(new_dir, cmf_dir);
if (fabs(test2 - cos_theta) > 1.e-8) {
printout("Problem with angle - Compton. Abort.\n");
std::abort();
}
assert_testmodeonly(fabs(1. - dot(new_dir, new_dir)) < 1e-8);
assert_testmodeonly(fabs(dot(new_dir, cmf_dir) - cos_theta) < 1e-8);

// Now convert back again.

Expand Down Expand Up @@ -571,7 +546,7 @@ auto get_chi_photo_electric_rf(const Packet &pkt) -> double {
}

// calculate the absorption coefficient [cm^-1] for pair production in the observer reference frame
auto sigma_pair_prod_rf(const Packet &pkt) -> double {
auto get_chi_pair_prod_rf(const Packet &pkt) -> double {
const int mgi = grid::get_cell_modelgridindex(pkt.where);
const double rho = grid::get_rho(mgi);

Expand Down Expand Up @@ -662,7 +637,7 @@ void update_gamma_dep(const Packet &pkt, const double dist, const int mgi, const

const double xx = H * pkt.nu_cmf / ME / CLIGHT / CLIGHT;
double heating_cont = ((meanf_sigma(xx) * grid::get_nnetot(mgi)) + get_chi_photo_electric_rf(pkt) +
(sigma_pair_prod_rf(pkt) * (1. - (2.46636e+20 / pkt.nu_cmf))));
(get_chi_pair_prod_rf(pkt) * (1. - (2.46636e+20 / pkt.nu_cmf))));
heating_cont = heating_cont * pkt.e_rf * dist * doppler_sq;

// The terms in the above are for Compton, photoelectric and pair production. The pair production one
Expand All @@ -689,10 +664,7 @@ void update_gamma_dep(const Packet &pkt, const double dist, const int mgi, const
void pair_prod(Packet &pkt) {
const double prob_gamma = 1.022 * MEV / (H * pkt.nu_cmf);

if (prob_gamma < 0) {
printout("prob_gamma < 0. pair_prod. Abort. %g\n", prob_gamma);
std::abort();
}
assert_always(prob_gamma >= 0);

if (rng_uniform() > prob_gamma) {
// Convert it to an e-minus packet - actually it could be positron EK too, but this works
Expand Down Expand Up @@ -746,7 +718,7 @@ void transport_gamma(Packet &pkt, const double t2) {
if (sdist > maxsdist) {
printout("Unreasonably large sdist (gamma). Abort. %g %g %g\n", globals::rmax, pkt.prop_time / globals::tmin,
sdist);
std::abort();
assert_always(false);
}

if (sdist < 0) {
Expand All @@ -757,7 +729,7 @@ void transport_gamma(Packet &pkt, const double t2) {
if (((snext < 0) && (snext != -99)) || (snext >= grid::ngrid)) {
printout("Heading for inappropriate grid cell. Abort.\n");
printout("Current cell %d, target cell %d.\n", pkt.where, snext);
std::abort();
assert_always(false);
}

if (sdist > globals::max_path_step) {
Expand All @@ -775,7 +747,7 @@ void transport_gamma(Packet &pkt, const double t2) {
}

const double chi_photo_electric = get_chi_photo_electric_rf(pkt);
const double chi_pair_prod = sigma_pair_prod_rf(pkt);
const double chi_pair_prod = get_chi_pair_prod_rf(pkt);
const double chi_tot = chi_compton + chi_photo_electric + chi_pair_prod;

assert_testmodeonly(std::isfinite(chi_compton));
Expand Down Expand Up @@ -841,25 +813,13 @@ void transport_gamma(Packet &pkt, const double t2) {
pkt.type = TYPE_NTLEPTON_DEPOSITED;
pkt.absorptiontype = -4;
stats::increment(stats::COUNTER_NT_STAT_FROM_GAMMA);
} else if ((chi_compton + chi_photo_electric + chi_pair_prod) > chi_rnd) {
} else {
// It's a pair production
pair_prod(pkt);
} else {
printout(
"Failed to identify event. Gamma (1). chi_compton %g chi_photo_electric %g chi_tot %g chi_rnd %g Abort.\n",
chi_compton, chi_photo_electric, chi_tot, chi_rnd);
const int cellindex = pkt.where;
printout(
" globals::cell[pkt.where].rho %g pkt.nu_cmf %g pkt.dir[0] %g pkt.dir[1] %g "
"pkt.dir[2] %g pkt.pos[0] %g pkt.pos[1] %g pkt.pos[2] %g \n",
grid::get_rho(grid::get_cell_modelgridindex(cellindex)), pkt.nu_cmf, pkt.dir[0], pkt.dir[0], pkt.dir[1],
pkt.dir[2], pkt.pos[1], pkt.pos[2]);

std::abort();
}
} else {
printout("Failed to identify event. Gamma (2). edist %g, sdist %g, tdist %g Abort.\n", edist, sdist, tdist);
std::abort();
assert_always(false);
}
}

Expand Down
13 changes: 11 additions & 2 deletions nonthermal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2102,8 +2102,7 @@ void calculate_deposition_rate_density(const int modelgridindex, const int times
}

deposition_rate_density_all_cells[modelgridindex] =
(heatingcoolingrates->dep_gamma + heatingcoolingrates->dep_positron + heatingcoolingrates->dep_electron +
heatingcoolingrates->dep_alpha);
(heatingcoolingrates->dep_gamma + heatingcoolingrates->dep_positron + heatingcoolingrates->dep_electron);
}

__host__ __device__ auto get_deposition_rate_density(const int modelgridindex) -> double
Expand Down Expand Up @@ -2294,6 +2293,16 @@ __host__ __device__ auto nt_excitation_ratecoeff(const int modelgridindex, const
return ratecoeffperdeposition * deposition_rate_density;
}

__host__ __device__ void do_ntalpha_deposit(Packet &pkt) {
// if ionisation by alpha particles is found to be important for the ionisation state, we could do a separate
// Spencer-Fano solution. For now, just treat alpha deposition as pure heating (even though the alpha deposition rate
// was calculated from the sum of ionisation and plasma heating)
atomicadd(nt_energy_deposited, pkt.e_cmf);
pkt.last_event = 22;
pkt.type = TYPE_KPKT;
stats::increment(stats::COUNTER_NT_STAT_TO_KPKT);
}

__host__ __device__ void do_ntlepton_deposit(Packet &pkt) {
atomicadd(nt_energy_deposited, pkt.e_cmf);

Expand Down
1 change: 1 addition & 0 deletions nonthermal.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ void calculate_deposition_rate_density(int modelgridindex, int timestep, Heating
[[nodiscard]] auto get_nt_frac_heating(int modelgridindex) -> float;
[[nodiscard]] auto nt_excitation_ratecoeff(int modelgridindex, int element, int ion, int lowerlevel, int uptransindex,
int lineindex) -> double;
void do_ntalpha_deposit(Packet &pkt);
void do_ntlepton_deposit(Packet &pkt);
void write_restart_data(FILE *gridsave_file);
void read_restart_data(FILE *gridsave_file);
Expand Down
1 change: 1 addition & 0 deletions packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum packet_type : int {
TYPE_NONTHERMAL_PREDEPOSIT_BETAMINUS = 21,
TYPE_NONTHERMAL_PREDEPOSIT_BETAPLUS = 22,
TYPE_NONTHERMAL_PREDEPOSIT_ALPHA = 23,
TYPE_NTALPHA_DEPOSITED = 24,
TYPE_PRE_KPKT = 120,
};

Expand Down
12 changes: 8 additions & 4 deletions thermalbalance.cc
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ auto T_e_eqn_heating_minus_cooling(const double T_e, void *paras) -> double {

const int modelgridindex = params->modelgridindex;
const double t_current = params->t_current;
auto *heatingcoolingrates = params->heatingcoolingrates;
auto *const heatingcoolingrates = params->heatingcoolingrates;

// Set new T_e guess for the current cell and update populations
// globals::cell[cellnumber].T_e = T_e;
Expand All @@ -204,9 +204,13 @@ auto T_e_eqn_heating_minus_cooling(const double T_e, void *paras) -> double {
kpkt::calculate_cooling_rates(modelgridindex, heatingcoolingrates);
calculate_heating_rates(modelgridindex, T_e, nne, heatingcoolingrates, *params->bfheatingcoeffs);

heatingcoolingrates->nt_frac_heating = nonthermal::get_nt_frac_heating(modelgridindex);
heatingcoolingrates->heating_dep =
nonthermal::get_deposition_rate_density(modelgridindex) * heatingcoolingrates->nt_frac_heating;
const auto ntlepton_frac_heating = nonthermal::get_nt_frac_heating(modelgridindex);
const auto ntlepton_dep = nonthermal::get_deposition_rate_density(modelgridindex);
const auto ntalpha_frac_heating = 1.;
const auto ntalpha_dep = heatingcoolingrates->dep_alpha;
heatingcoolingrates->heating_dep = ntlepton_dep * ntlepton_frac_heating + ntalpha_dep * ntalpha_frac_heating;
heatingcoolingrates->dep_frac_heating =
(ntalpha_dep > 0) ? heatingcoolingrates->heating_dep / (ntlepton_dep + ntalpha_dep) : ntlepton_frac_heating;

// Adiabatic cooling term
const double nntot = get_nnion_tot(modelgridindex) + nne;
Expand Down
2 changes: 1 addition & 1 deletion thermalbalance.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct HeatingCoolingRates {
double heating_bf{0};
double heating_ff{0};
double heating_dep{0};
double nt_frac_heating{0};
double dep_frac_heating{0};
double dep_gamma{0};
double dep_positron{0};
double dep_electron{0};
Expand Down
2 changes: 1 addition & 1 deletion update_grid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ void write_to_estimators_file(FILE *estimators_file, const int mgi, const int ti
heatingcoolingrates->dep_alpha);
fprintf(estimators_file, "heating: ff %11.5e bf %11.5e coll %11.5e dep %11.5e heating_dep/total_dep %.3f\n",
heatingcoolingrates->heating_ff, heatingcoolingrates->heating_bf, heatingcoolingrates->heating_collisional,
heatingcoolingrates->heating_dep, heatingcoolingrates->nt_frac_heating);
heatingcoolingrates->heating_dep, heatingcoolingrates->dep_frac_heating);
fprintf(estimators_file, "cooling: ff %11.5e fb %11.5e coll %11.5e adiabatic %11.5e\n",
heatingcoolingrates->cooling_ff, heatingcoolingrates->cooling_fb, heatingcoolingrates->cooling_collisional,
heatingcoolingrates->cooling_adiabatic);
Expand Down
27 changes: 18 additions & 9 deletions update_packets.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,38 +33,40 @@ void do_nonthermal_predeposit(Packet &pkt, const int nts, const double t2) {
const auto nonemptymgi = grid::get_modelcell_nonemptymgi(mgi);
const auto priortype = pkt.type;
const double ts = pkt.prop_time;
const auto deposit_type =
(pkt.type == TYPE_NONTHERMAL_PREDEPOSIT_ALPHA) ? TYPE_NTALPHA_DEPOSITED : TYPE_NTLEPTON_DEPOSITED;

if constexpr (PARTICLE_THERMALISATION_SCHEME == ThermalisationScheme::INSTANT) {
// absorption happens
pkt.type = TYPE_NTLEPTON_DEPOSITED;
pkt.type = deposit_type;
} else if constexpr (PARTICLE_THERMALISATION_SCHEME == ThermalisationScheme::BARNES) {
const double E_kin = grid::get_ejecta_kinetic_energy();
const double v_ej = std::sqrt(E_kin * 2 / grid::mtot_input);

const double prefactor = (pkt.pellet_decaytype == decay::DECAYTYPE_ALPHA) ? 7.74 : 7.4;
const double prefactor = (pkt.type == TYPE_NONTHERMAL_PREDEPOSIT_ALPHA) ? 7.74 : 7.4;
const double tau_ineff = prefactor * 86400 * std::sqrt(grid::mtot_input / (5.e-3 * 1.989 * 1.e33)) *
std::pow((0.2 * 29979200000) / v_ej, 3. / 2.);
const double f_p = std::log1p(2. * ts * ts / tau_ineff / tau_ineff) / (2. * ts * ts / tau_ineff / tau_ineff);
assert_always(f_p >= 0.);
assert_always(f_p <= 1.);
if (rng_uniform() < f_p) {
pkt.type = TYPE_NTLEPTON_DEPOSITED;
pkt.type = deposit_type;
} else {
en_deposited = 0.;
pkt.type = TYPE_ESCAPE;
grid::change_cell(pkt, -99);
}
} else if constexpr (PARTICLE_THERMALISATION_SCHEME == ThermalisationScheme::WOLLAEGER) {
// particle thermalisation from Wollaeger+2018, similar to Barnes but using a slightly different expression
const double A = (pkt.pellet_decaytype == decay::DECAYTYPE_ALPHA) ? 1.2 * 1.e-11 : 1.3 * 1.e-11;
const double A = (pkt.type == TYPE_NONTHERMAL_PREDEPOSIT_ALPHA) ? 1.2 * 1.e-11 : 1.3 * 1.e-11;
const double aux_term = 2 * A / (ts * grid::get_rho(mgi));
// In Bulla 2023 (arXiv:2211.14348), the following line contains (<-> eq. 7) contains a typo. The way implemented
// here is the original from Wollaeger paper without the typo
const double f_p = std::log1p(aux_term) / aux_term;
assert_always(f_p >= 0.);
assert_always(f_p <= 1.);
if (rng_uniform() < f_p) {
pkt.type = TYPE_NTLEPTON_DEPOSITED;
pkt.type = deposit_type;
} else {
en_deposited = 0.;
pkt.type = TYPE_ESCAPE;
Expand Down Expand Up @@ -100,7 +102,7 @@ void do_nonthermal_predeposit(Packet &pkt, const int nts, const double t2) {
const auto t_new = std::min(t_absorb, t2);

if (t_absorb <= t2) {
pkt.type = TYPE_NTLEPTON_DEPOSITED;
pkt.type = deposit_type;
} else {
pkt.nu_cmf = (particle_en - endot * (t_new - ts)) / H;
}
Expand All @@ -109,19 +111,21 @@ void do_nonthermal_predeposit(Packet &pkt, const int nts, const double t2) {
pkt.prop_time = t_new;
}

// contribute to the trajectory integrated deposition estimator
// and if a deposition event occurred, also the discrete Monte Carlo count deposition rate
if (priortype == TYPE_NONTHERMAL_PREDEPOSIT_BETAMINUS) {
atomicadd(globals::dep_estimator_electron[nonemptymgi], en_deposited);
if (pkt.type == TYPE_NTLEPTON_DEPOSITED) {
if (pkt.type == deposit_type) {
atomicadd(globals::timesteps[nts].electron_dep_discrete, pkt.e_cmf);
}
} else if (priortype == TYPE_NONTHERMAL_PREDEPOSIT_BETAPLUS) {
atomicadd(globals::dep_estimator_positron[nonemptymgi], en_deposited);
if (pkt.type == TYPE_NTLEPTON_DEPOSITED) {
if (pkt.type == deposit_type) {
atomicadd(globals::timesteps[nts].positron_dep_discrete, pkt.e_cmf);
}
} else if (priortype == TYPE_NONTHERMAL_PREDEPOSIT_ALPHA) {
atomicadd(globals::dep_estimator_alpha[nonemptymgi], en_deposited);
if (pkt.type == TYPE_NTLEPTON_DEPOSITED) {
if (pkt.type == deposit_type) {
atomicadd(globals::timesteps[nts].alpha_dep_discrete, pkt.e_cmf);
}
}
Expand Down Expand Up @@ -231,6 +235,11 @@ void do_packet(Packet &pkt, const double t2, const int nts)
break;
}

case TYPE_NTALPHA_DEPOSITED: {
nonthermal::do_ntalpha_deposit(pkt);
break;
}

case TYPE_PRE_KPKT: {
kpkt::do_kpkt_blackbody(pkt);
break;
Expand Down

0 comments on commit d6608c2

Please sign in to comment.