/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2018 Folkert Nobels (nobels@strw.leidenuniv.nl) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * ******************************************************************************/ #ifndef SWIFT_SNIA_DTD_H #define SWIFT_SNIA_DTD_H /** * @file src/snia_dtd.h * @brief Branches between the different SNIa delay time distributions recipies. */ /* Config parameters. */ #include /* Local includes */ #include "SNIa_DTD_struct.h" #include "feedback_properties.h" #include "parser.h" #include "physical_constants.h" #include "units.h" /* Import the right DTD definition */ #if defined(SNIA_DTD_EXP) /** * @brief Computes the number of supernovae of type Ia exploding for a given * star particle between time t and t+dt * * We follow Foerster et al. 2006, MNRAS, 368 * * @param sp The #spart. * @param t0 The initial time (in Gyr). * @param t1 The final time (in Gyr). * @param props The properties of the stellar model. */ static inline double dtd_number_of_SNIa(const struct spart* sp, const double t0, const double t1, const struct feedback_props* fp) { /* Return zero if below delay time */ if (t1 < fp->dtd_data.delay_time_Gyr) return 0; /* Start from the correct time */ const double tmin = max(t0, fp->dtd_data.delay_time_Gyr); /* The calculation is written as the integral between t0 and t1 of * eq. 3 of Schaye 2015 paper. */ const double tau_inv = fp->dtd_data.SNIa_timescale_Gyr_inv; const double nu = fp->dtd_data.SNIa_efficiency; const double num_SNIa_per_Msun = nu * (exp(-tmin * tau_inv) - exp(-t1 * tau_inv)); return num_SNIa_per_Msun * sp->mass_init * fp->mass_to_solar_mass; } /** * @brief initialize the DTD * * @param fp the properties of the stellar model. * @param phys_const the constant * @param us the unit system * @param params the input parameters */ static inline void dtd_init(struct feedback_props* fp, const struct phys_const* phys_const, const struct unit_system* us, struct swift_params* params) { /* Get the SNIa efficiency */ fp->dtd_data.SNIa_efficiency = parser_get_param_float(params, "SNIaDTD:SNIa_efficiency_p_Msun"); /* Get the exponential delay time for the DTD */ fp->dtd_data.SNIa_timescale_Gyr = parser_get_param_float(params, "SNIaDTD:SNIa_timescale_Gyr"); /* Calculate the inverse of the exponential delay time */ fp->dtd_data.SNIa_timescale_Gyr_inv = 1.f / fp->dtd_data.SNIa_timescale_Gyr; /* Set the delay time of the DTD */ fp->dtd_data.delay_time_Gyr = parser_get_param_double(params, "SNIaDTD:SNIa_delay_time_Gyr"); /* Properly normalize the exponential DTD */ fp->dtd_data.SNIa_efficiency *= exp(-fp->dtd_data.delay_time_Gyr * fp->dtd_data.SNIa_timescale_Gyr_inv); } #elif defined(SNIA_DTD_POWER) /** * @brief Computes the number of supernovae of type Ia exploding for a given * star particle between time t and t+dt * * This model assumes that the SNIa DTD is given by a power law, this is * a common DTD model, Moaz & Mannucci (2012), PASA, 29, 447 gives an * overview of the different variables found in the literature * * @param sp The #spart. * @param t0 The initial time (in Gyr). * @param t1 The final time (in Gyr). * @param props The properties of the stellar model. */ static inline double dtd_number_of_SNIa(const struct spart* sp, const double t0, const double t1, const struct feedback_props* fp) { /* Return zero if below delay time */ if (t1 < fp->dtd_data.delay_time_Gyr) return 0; /* Start from the correct time */ const double tmin = max(t0, fp->dtd_data.delay_time_Gyr); /* The calculation is written as the integral between t0 and t1 of * a constant DTD given by \nu / \tau */ const double norm = fp->dtd_data.norm; const double power = fp->dtd_data.power; /* We do not need to multiply by 1/(1-beta) because we already cancelled * this in the normalisation */ const double num_SNIa_per_Msun = norm * (pow(t1, 1. - power) - pow(tmin, 1. - power)); return num_SNIa_per_Msun * sp->mass_init * fp->mass_to_solar_mass; } /** * @brief initialize the DTD * * @param fp the properties of the stellar model. * @param phys_const the constant * @param us the unit system * @param params the input parameters */ static inline void dtd_init(struct feedback_props* fp, const struct phys_const* phys_const, const struct unit_system* us, struct swift_params* params) { /* Get the SNIa efficiency */ fp->dtd_data.SNIa_efficiency = parser_get_param_float(params, "SNIaDTD:SNIa_efficiency_p_Msun"); /* Get the power of the power law */ fp->dtd_data.power = parser_get_param_double(params, "SNIaDTD:power_law_slope"); /* Get the normalization time over which the DTD is normalized */ fp->dtd_data.normalization_timescale_Gyr = parser_get_param_double(params, "SNIaDTD:normalization_timescale_Gyr"); /* Get the delay time */ fp->dtd_data.delay_time_Gyr = parser_get_param_double(params, "SNIaDTD:SNIa_delay_time_Gyr"); /* Calculate the normalization of the power-law DTD */ const double below_frac = pow(fp->dtd_data.normalization_timescale_Gyr, 1 - fp->dtd_data.power) - pow(fp->dtd_data.delay_time_Gyr, 1 - fp->dtd_data.power); /* Note that we do not multiply by (1-beta) because it will cancell out later */ fp->dtd_data.norm = fp->dtd_data.SNIa_efficiency / below_frac; } #elif defined(SNIA_DTD_POWER_BETA1) /** * @brief Computes the number of supernovae of type Ia exploding for a given * star particle between time t and t+dt * * This model assumes that the SNIa DTD is a power law with \beta = 1, * this model is a special case of the power law model because the * integrals have a different functional form than the general power * law. A lot of observations seem to be close to a power law like this, * see Moaz & Mannucci (2012), PASA, 29, 447 for a review * * @param sp The #spart. * @param t0 The initial time (in Gyr). * @param t1 The final time (in Gyr). * @param props The properties of the stellar model. */ static inline double dtd_number_of_SNIa(const struct spart* sp, const double t0, const double t1, const struct feedback_props* fp) { /* Return zero if below delay time */ if (t1 < fp->dtd_data.delay_time_Gyr) return 0; /* Start from the correct time */ const double tmin = max(t0, fp->dtd_data.delay_time_Gyr); /* The calculation is written as the integral between t0 and t1 of * a power law DTD given by ~\nu /t */ const double norm = fp->dtd_data.norm; const double num_SNIa_per_Msun = norm * log(t1 / tmin); return num_SNIa_per_Msun * sp->mass_init * fp->mass_to_solar_mass; } /** * @brief initialize the DTD * * @param fp the properties of the stellar model. * @param phys_const the constant * @param us the unit system * @param params the input parameters */ static inline void dtd_init(struct feedback_props* fp, const struct phys_const* phys_const, const struct unit_system* us, struct swift_params* params) { /* Get the SNIa efficiency */ fp->dtd_data.SNIa_efficiency = parser_get_param_float(params, "SNIaDTD:SNIa_efficiency_p_Msun"); /* Get the SNIa normalization timescale */ fp->dtd_data.normalization_timescale_Gyr = parser_get_param_double(params, "SNIaDTD:normalization_timescale_Gyr"); /* Get the delay time of the DTD */ fp->dtd_data.delay_time_Gyr = parser_get_param_double(params, "SNIaDTD:SNIa_delay_time_Gyr"); /* If the delay time is zero, exit with an error */ if (fp->dtd_data.delay_time_Gyr == 0.) error("Delay time cannot be zero"); /* Calculate the normalization of the power law DTD with beta=1 */ const double below_frac = log(fp->dtd_data.normalization_timescale_Gyr / fp->dtd_data.delay_time_Gyr); fp->dtd_data.norm = fp->dtd_data.SNIa_efficiency / below_frac; } #elif defined(SNIA_DTD_GAUSSIAN) #include /** * @brief Computes the number of supernovae of type Ia exploding for a given * star particle between time t and t+dt * * This model assumes that the SNIa DTD is a Gaussian following for * example Dahlen et al. 2004, ApJ, 613, 189. * There is the option of using a constant besided the Gaussian this is * following the approach adopted by the Fire 2 simulations (Hopkins et al. * 2018, 480, 800) * * @param sp The #spart. * @param t0 The initial time (in Gyr). * @param t1 The final time (in Gyr). * @param props The properties of the stellar model. */ static inline double dtd_number_of_SNIa(const struct spart* sp, const double t0, const double t1, const struct feedback_props* fp) { /* Return zero if below delay time */ if (t1 < fp->dtd_data.delay_time_Gyr) return 0; /* Start from the correct time */ const double tmin = max(t0, fp->dtd_data.delay_time_Gyr); /* The calculation is written as the integral between t0 and t1 of * a constant DTD given by \nu / \tau */ /* First calculate the number of SNIa for the constant part of the DTD: */ const double norm = fp->dtd_data.norm_const; const double num_SNIa_per_Msun_const = norm * (t1 - tmin); /* Calculate the number of SNIa for the gaussian part of the DTD: */ const double nu_gauss = fp->dtd_data.SNIa_efficiency_gauss; /* get one over the standard deviation time */ const double inv_std = fp->dtd_data.std_characteristic_time_Gyr_inv; /* Get the difference with the characteristic time of the Gaussian * for both the minimum and maximum time on this interval: */ const double tdif0 = tmin - fp->dtd_data.characteristic_time_Gyr; const double tdif1 = t1 - fp->dtd_data.characteristic_time_Gyr; /* calculate the upper term of the integral (not factor 2) */ const double gauss_up = erf(tdif1 * inv_std); /* The lower part */ const double gauss_low = erf(tdif0 * inv_std); /* Finish the integral */ const double integral = .5 * (gauss_up - gauss_low); /* The number of SNIa from the Gaussian part */ const double num_SNIa_per_Msun_gauss = nu_gauss * integral; /* calculate the total Gaussian + constant */ const double num_SNIa_per_Msun = num_SNIa_per_Msun_gauss + num_SNIa_per_Msun_const; return num_SNIa_per_Msun * sp->mass_init * fp->mass_to_solar_mass; } /** * @brief initialize the DTD * * @param fp the properties of the stellar model. * @param phys_const the constant * @param us the unit system * @param params the input parameters */ static inline void dtd_init(struct feedback_props* fp, const struct phys_const* phys_const, const struct unit_system* us, struct swift_params* params) { /* Set the SNIa efficiency for the constant part of the DTD */ fp->dtd_data.SNIa_efficiency_const = parser_get_param_float(params, "SNIaDTD:SNIa_efficiency_const_p_Msun"); /* Set the SNIa efficiency for the Gaussian part of the DTD */ fp->dtd_data.SNIa_efficiency_gauss = parser_get_param_float(params, "SNIaDTD:SNIa_efficiency_gauss_p_Msun"); /* Set the normalization time for the constant part of the DTD */ fp->dtd_data.normalization_timescale_Gyr = parser_get_param_double(params, "SNIaDTD:normalization_timescale_Gyr"); /* Set the delay time of the DTD */ fp->dtd_data.delay_time_Gyr = parser_get_param_double(params, "SNIaDTD:SNIa_delay_time_Gyr"); /* Set the characteristic time of the Gaussian part of the DTD */ fp->dtd_data.characteristic_time_Gyr = parser_get_param_double(params, "SNIaDTD:characteristic_time_Gyr"); /* Set the standard deviation of the Gaussian part of the DTD */ fp->dtd_data.std_characteristic_time_Gyr = parser_get_param_double(params, "SNIaDTD:STD_characteristic_time_Gyr"); /* Calculate the inverse of the standard deviation of the Gaussian part * divided by sqrt 2 */ fp->dtd_data.std_characteristic_time_Gyr_inv = 1. / fp->dtd_data.std_characteristic_time_Gyr / sqrt(2); /* Calculate the norm of the constant part of the DTD */ fp->dtd_data.norm_const = fp->dtd_data.SNIa_efficiency_const / fp->dtd_data.normalization_timescale_Gyr; } #elif defined(SNIA_DTD_CONST) /** * @brief Computes the number of supernovae of type Ia exploding for a given * star particle between time t and t+dt * * This model assumes that the SNIa DTD is constant. * * @param sp The #spart. * @param t0 The initial time (in Gyr). * @param t1 The final time (in Gyr). * @param props The properties of the stellar model. */ static inline double dtd_number_of_SNIa(const struct spart* sp, const double t0, const double t1, const struct feedback_props* fp) { /* Return zero if below delay time */ if (t1 < fp->dtd_data.delay_time_Gyr) return 0; /* Start from the correct time */ const double tmin = max(t0, fp->dtd_data.delay_time_Gyr); /* The calculation is written as the integral between t0 and t1 of * a constant DTD given by \nu / \tau */ const double norm = fp->dtd_data.norm; const double num_SNIa_per_Msun = norm * (t1 - tmin); return num_SNIa_per_Msun * sp->mass_init * fp->mass_to_solar_mass; } /** * @brief initialize the DTD * * @param fp the properties of the stellar model. * @param phys_const the constant * @param us the unit system * @param params the input parameters */ static inline void dtd_init(struct feedback_props* fp, const struct phys_const* phys_const, const struct unit_system* us, struct swift_params* params) { fp->dtd_data.SNIa_efficiency = parser_get_param_float(params, "SNIaDTD:SNIa_efficiency_p_Msun"); fp->dtd_data.normalization_timescale_Gyr = parser_get_param_float(params, "SNIaDTD:normalization_timescale_Gyr"); fp->dtd_data.norm = fp->dtd_data.SNIa_efficiency / fp->dtd_data.normalization_timescale_Gyr; /* Set the delay time of the DTD */ fp->dtd_data.delay_time_Gyr = parser_get_param_double(params, "SNIaDTD:SNIa_delay_time_Gyr"); } #elif defined(SNIA_DTD_BROKEN_POWER_LAW) /** * @brief Computes the number of supernovae of type Ia exploding for a given * star particle between time t and t+dt * * This model assumes that the SNIa DTD is a broken power law. This shape * is common in theoretical models of the DTD in the double degenerate (DD) * scenario, in which the SNIa DTD has a shallow slope below a break time * and a deeper slope after a break time. For a review see Moaz & Mannucci * (2012), PASA, 29, 447 * * @param sp The #spart. * @param t0 The initial time (in Gyr). * @param t1 The final time (in Gyr). * @param props The properties of the stellar model. */ static inline double dtd_number_of_SNIa(const struct spart* sp, const double t0, const double t1, const struct feedback_props* fp) { /* Return zero if below delay time */ if (t1 < fp->dtd_data.delay_time_Gyr) return 0; /* Start from the correct time */ const double tmin = max(t0, fp->dtd_data.delay_time_Gyr); /* The calculation is written as the integral between t0 and t1 of * a constant DTD given by \nu / \tau */ const double tb = fp->dtd_data.break_time_Gyr; /* Check if we are in the long time regime */ if (t0 > tb) { const double norm = fp->dtd_data.norm_long; const double power = fp->dtd_data.power_long_time; const double num_SNIa_per_Msun = norm * (pow(t1, 1. - power) - pow(t0, 1. - power)); return num_SNIa_per_Msun * sp->mass_init * fp->mass_to_solar_mass; } /* Check if we are in the short time regime */ if (t1 < tb) { const double norm = fp->dtd_data.norm_short; const double power = fp->dtd_data.power_short_time; const double num_SNIa_per_Msun = norm * (pow(t1, 1. - power) - pow(tmin, 1. - power)); return num_SNIa_per_Msun * sp->mass_init * fp->mass_to_solar_mass; } /* Now we are in the intermediate regime that requires more calculations */ const double power_short = fp->dtd_data.power_short_time; const double power_long = fp->dtd_data.power_long_time; const double norm_short = fp->dtd_data.norm_short; const double norm_long = fp->dtd_data.norm_long; const double num_SNIa_per_Msun = norm_short * (pow(tb, 1. - power_short) - pow(tmin, 1. - power_short)) + norm_long * (pow(tb, 1. - power_long) - pow(t1, 1. - power_long)); return num_SNIa_per_Msun * sp->mass_init * fp->mass_to_solar_mass; } /** * @brief initialize the DTD * * @param fp the properties of the stellar model. * @param phys_const the constant * @param us the unit system * @param params the input parameters */ static inline void dtd_init(struct feedback_props* fp, const struct phys_const* phys_const, const struct unit_system* us, struct swift_params* params) { /* Get the SNIa efficiency */ fp->dtd_data.SNIa_efficiency = parser_get_param_float(params, "SNIaDTD:SNIa_efficiency_p_Msun"); /* Get the short time power law slope */ fp->dtd_data.power_short_time = parser_get_param_double(params, "SNIaDTD:power_law_slope_short_time"); /* Get the long time power law slope */ fp->dtd_data.power_long_time = parser_get_param_double(params, "SNIaDTD:power_law_slope_long_time"); /* Get the normalization time over which the DTD is normalized */ fp->dtd_data.normalization_timescale_Gyr = parser_get_param_double(params, "SNIaDTD:normalization_timescale_Gyr"); /* Get the delay time */ fp->dtd_data.delay_time_Gyr = parser_get_param_double(params, "SNIaDTD:SNIa_delay_time_Gyr"); /* Get the break time */ fp->dtd_data.break_time_Gyr = parser_get_param_double(params, "SNIaDTD:break_time_Gyr"); /* Calculate the normalization of the power-law DTD */ /* Calculate 1 minus the short time power */ const double one_minus_power_short = 1. - fp->dtd_data.power_short_time; /* Calculate one over this number */ const double one_minus_power_short_inv = 1. / one_minus_power_short; /* Get the delay time*/ const double t_delay = fp->dtd_data.delay_time_Gyr; /* Get the break time */ const double t_break = fp->dtd_data.break_time_Gyr; /* Calculate the first norm */ const double norm1_inv = one_minus_power_short_inv * (1. - pow(t_delay / t_break, one_minus_power_short)); /* Calculate 1 minus the long time power */ const double one_minus_power_long = 1. - fp->dtd_data.power_short_time; /* Calculate one over this number */ const double one_minus_power_long_inv = 1. / one_minus_power_short; const double t_norm = fp->dtd_data.normalization_timescale_Gyr; /* Calculate the second norm */ const double norm2_inv = one_minus_power_long_inv * (pow(t_norm / t_break, one_minus_power_long) - 1.); /* Store the normalization */ fp->dtd_data.norm_short = fp->dtd_data.SNIa_efficiency / (norm1_inv + norm2_inv) * one_minus_power_short_inv; fp->dtd_data.norm_long = fp->dtd_data.SNIa_efficiency / (norm1_inv + norm2_inv) * one_minus_power_long_inv; } #else #error "Invalid choice of the SNIa delay time distribution (DTD)" #endif #endif /* SWIFT_SNIA_DTD_H */