#ifndef SWIFT_COLIBRE_TABLES_RESTRICT_H #define SWIFT_COLIBRE_TABLES_RESTRICT_H /** * @file src/cooling/CHIMES/colibre_tables_restrict.h * @brief COLIBRE cooling tables - restricted. */ /* Config parameters */ #include /* Local includes. */ #include "chemistry_struct.h" #include "cooling_properties.h" #include "error.h" #include "exp10.h" /** * @brief Compute ratio of mass fraction to solar mass fraction * for each element carried by a given particle. * * The solar abundances are taken from the tables themselves. * * The COLIBRE chemistry model does not track S and Ca. We assume * that their abundance with respect to solar is the same as * the ratio for Si. * * The other un-tracked elements are scaled with the total metallicity. * * We optionally apply a correction if the user asked for a different * ratio. * * We also re-order the elements such that they match the order of the * tables. This is [H, He, C, N, O, Ne, Mg, Si, S, Ca, Fe, OA]. * * The solar abundances table (from the cooling struct) is arranged as * [H, He, C, N, O, Ne, Mg, Si, S, Ca, Fe]. * * @param p Pointer to #part struct. * @param table Colibre cooling table structure. * @param ratio_solar (return) Array of ratios to solar abundances. */ __attribute__((always_inline)) INLINE static float abundance_ratio_to_solar( const struct part *p, const struct colibre_cooling_tables *table, float ratio_solar[colibre_cooling_N_elementtypes]) { /* Get the particle's metal mass fractions (M_x / M) */ // const float *Z_mass_frac = // chemistry_get_metal_mass_fraction_for_cooling(p); static float // *Z_mass_frac = chemistry_get_metal_mass_fraction_for_cooling(p); float const *Z_mass_frac = chemistry_get_metal_mass_fraction_for_cooling(p); /* Convert mass fractions to abundances (nx/nH) and compute metal mass */ float totmass = 0., metalmass = 0.; for (enum colibre_cooling_element elem = element_H; elem < element_OA; elem++) { /* Normal elements: Get the abundance from the particle carried arrays */ if ((elem != element_S) && (elem != element_Ca)) { const int indx1d = cooling_row_major_index_2d( table->indxZsol, elem, colibre_cooling_N_metallicity, colibre_cooling_N_elementtypes); const float Mfrac = Z_mass_frac[element_from_table_to_code(elem)]; /* ratio_X = ((M_x/M) / (M_H/M)) * (m_H / m_X) * (1 / Z_sun_X) */ ratio_solar[elem] = (Mfrac / Z_mass_frac[element_from_table_to_code(element_H)]) * table->atomicmass[element_H] * table->atomicmass_inv[elem] * table->Abundances_inv[indx1d]; totmass += Mfrac; if (elem > element_He) metalmass += Mfrac; /* Special case: S scales with Si */ } else if (elem == element_S) { ratio_solar[element_S] = ratio_solar[element_Si] * table->S_over_Si_ratio_in_solar; const int indx1d = cooling_row_major_index_2d( table->indxZsol, element_Si, colibre_cooling_N_metallicity, colibre_cooling_N_elementtypes); /* mass fraction S */ const int indxS = cooling_row_major_index_2d( table->indxZsol, element_S, colibre_cooling_N_metallicity, colibre_cooling_N_elementtypes); /* ratio_S = ((M_S/M) / (M_H/M)) * (m_H / m_S) * (1 / Z_sun_S) */ const float Mfrac = table->S_over_Si_ratio_in_solar * table->atomicmass[element_S] * table->atomicmass_inv[element_Si] * table->Abundances[indxS] * table->Abundances_inv[indx1d] * Z_mass_frac[element_from_table_to_code(element_Si)]; totmass += Mfrac; metalmass += Mfrac; /* Special case: Ca scales with Si */ } else if (elem == element_Ca) { ratio_solar[element_Ca] = ratio_solar[element_Si] * table->Ca_over_Si_ratio_in_solar; const int indx1d = cooling_row_major_index_2d( table->indxZsol, element_Si, colibre_cooling_N_metallicity, colibre_cooling_N_elementtypes); /* mass fraction Ca */ const int indxCa = cooling_row_major_index_2d( table->indxZsol, element_Ca, colibre_cooling_N_metallicity, colibre_cooling_N_elementtypes); /* ratio_Ca = ((M_Ca/M) / (M_H/M)) * (m_H / m_Ca) * (1 / Z_sun_Ca) */ const float Mfrac = table->Ca_over_Si_ratio_in_solar * table->atomicmass[element_Ca] * table->atomicmass_inv[element_Si] * table->Abundances[indxCa] * table->Abundances_inv[indx1d] * Z_mass_frac[element_from_table_to_code(element_Si)]; totmass += Mfrac; metalmass += Mfrac; } else { #ifdef SWIFT_DEBUG_CHECKS error("Invalid element!"); #endif } } /* Get total metallicity [Z/Z_sun] from the particle data */ const float Z_total = (float)chemistry_get_total_metal_mass_fraction_for_cooling(p); float ZZsol = Z_total * table->Zsol_inv[0]; if (ZZsol <= 0.0f) ZZsol = FLT_MIN; const float logZZsol = log10f(ZZsol); /* All other elements (element_OA): scale with metallicity */ ratio_solar[element_OA] = ZZsol; /* Get index and offset from the metallicity table corresponding to this * metallicity */ int met_index; float d_met; cooling_get_index_1d(table->Metallicity, colibre_cooling_N_metallicity, logZZsol, &met_index, &d_met); /* At this point ratio_solar is (nx/nH) / (nx/nH)_sol. * To multiply with the tables, we want the individual abundance ratio * relative to what is used in the tables for each metallicity */ /* For example: for a metallicity of 1 per cent solar, the metallicity bin * for logZZsol = -2 has already the reduced cooling rates for each element; * it should therefore NOT be multiplied by 0.01 again. * * BUT: if e.g. Carbon is twice as abundant as the solar abundance ratio, * i.e. nC / nH = 0.02 * (nC/nH)_sol for the overall metallicity of 0.01, * the Carbon cooling rate is multiplied by 2 * * We only do this if we are not in the primodial metallicity bin in which * case the ratio to solar should be 0. */ for (int i = 0; i < colibre_cooling_N_elementtypes; i++) { /* Are we considering a metal and are *not* in the primodial metallicity * bin? Or are we looking at H or He? */ if ((met_index > 0) || (i == element_H) || (i == element_He)) { /* Get min/max abundances */ const float log_nx_nH_min = table->LogAbundances[cooling_row_major_index_2d( met_index, i, colibre_cooling_N_metallicity, colibre_cooling_N_elementtypes)]; const float log_nx_nH_max = table->LogAbundances[cooling_row_major_index_2d( met_index + 1, i, colibre_cooling_N_metallicity, colibre_cooling_N_elementtypes)]; /* Get solar abundances */ const float log_nx_nH_sol = table->LogAbundances[cooling_row_major_index_2d( table->indxZsol, i, colibre_cooling_N_metallicity, colibre_cooling_N_elementtypes)]; /* Interpolate ! (linearly in log-space) */ const float log_nx_nH = (log_nx_nH_min * (1.f - d_met) + log_nx_nH_max * d_met) - log_nx_nH_sol; ratio_solar[i] *= exp10f(-log_nx_nH); } else { /* Primordial bin --> Z/Z_sun is 0 for that element */ ratio_solar[i] = 0.0; } } /* at this point ratio_solar is (nx/nH) / (nx/nH)_table [Z], * the metallicity dependent abundance ratio for solar abundances. * We also return the total metallicity */ return logZZsol; } #endif // SWIFT_COLIBRE_TABLES_RESTRICT_H