/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2016 Matthieu Schaller (schaller@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_EAGLE_STARS_H #define SWIFT_EAGLE_STARS_H #include "exp10.h" #include /** * @brief Computes the time-step length of a given star particle from stars * physics * * @param sp Pointer to the s-particle data. * @param stars_properties Properties of the stars model. * @param with_cosmology Are we running with cosmological time integration. * @param cosmo The current cosmological model (used if running with * cosmology). * @param time The current time (used if running without cosmology). */ __attribute__((always_inline)) INLINE static float stars_compute_timestep( const struct spart* const sp, const struct stars_props* stars_properties, const int with_cosmology, const struct cosmology* cosmo, const double time) { /* Background star particles have no time-step limits */ if (sp->birth_time == -1.) { return FLT_MAX; } /* Star age (in internal units) */ double star_age; if (with_cosmology) { /* Deal with rounding issues */ if (sp->birth_scale_factor >= cosmo->a) { star_age = 0.; } else { star_age = cosmology_get_delta_time_from_scale_factors( cosmo, sp->birth_scale_factor, cosmo->a); } } else { star_age = time - sp->birth_time; } /* What age category are we in? */ if (star_age > stars_properties->age_threshold_unlimited) { return FLT_MAX; } else if (star_age > stars_properties->age_threshold) { return stars_properties->max_time_step_old; } else { return stars_properties->max_time_step_young; } } /** * @brief Returns the age of a star in internal units * * @param sp The star particle. * @param cosmo The cosmological model. * @param time The current time (in internal units). * @param with_cosmology Are we running with cosmological integration? */ __attribute__((always_inline)) INLINE static double stars_compute_age( const struct spart* sp, const struct cosmology* cosmo, double time, const int with_cosmology) { if (with_cosmology) { return cosmology_get_delta_time_from_scale_factors( cosmo, (double)sp->birth_scale_factor, cosmo->a); } else { return time - (double)sp->birth_time; } } /** * @brief Prepares a s-particle for its interactions * * @param sp The particle to act upon */ __attribute__((always_inline)) INLINE static void stars_init_spart( struct spart* sp) { #ifdef DEBUG_INTERACTIONS_STARS for (int i = 0; i < MAX_NUM_OF_NEIGHBOURS_STARS; ++i) sp->ids_ngbs_density[i] = -1; sp->num_ngb_density = 0; #endif sp->density.wcount = 0.f; sp->density.wcount_dh = 0.f; #ifdef SWIFT_STARS_DENSITY_CHECKS sp->N_density = 0; sp->N_density_exact = 0; sp->rho = 0.f; sp->rho_exact = 0.f; sp->n = 0.f; sp->n_exact = 0.f; sp->inhibited_exact = 0; #endif } /** * @brief Initialises the s-particles for the first time * * This function is called only once just after the ICs have been * read in to do some conversions. * * @param sp The particle to act upon. * @param stars_properties Properties of the stars model. * @param with_cosmology Are we running with cosmological time integration. * @param scale_factor The current scale-factor (used if running with * cosmology). * @param time The current time (used if running without cosmology). */ __attribute__((always_inline)) INLINE static void stars_first_init_spart( struct spart* sp, const struct stars_props* stars_properties, const int with_cosmology, const double scale_factor, const double time) { sp->time_bin = 0; sp->f_E = -1.f; sp->count_since_last_enrichment = -1; sp->number_of_heating_events = 0.; sp->number_of_SNII_events = 0; if (stars_properties->overwrite_birth_time) sp->birth_time = stars_properties->spart_first_init_birth_time; if (stars_properties->overwrite_birth_density) sp->birth_density = stars_properties->spart_first_init_birth_density; if (stars_properties->overwrite_birth_temperature) sp->birth_temperature = stars_properties->spart_first_init_birth_temperature; if (with_cosmology) sp->last_enrichment_time = scale_factor; else sp->last_enrichment_time = time; stars_init_spart(sp); } /** * @brief Predict additional particle fields forward in time when drifting * * @param sp The particle * @param dt_drift The drift time-step for positions. */ __attribute__((always_inline)) INLINE static void stars_predict_extra( struct spart* restrict sp, float dt_drift) {} /** * @brief Sets the values to be predicted in the drifts to their values at a * kick time * * @param sp The particle. */ __attribute__((always_inline)) INLINE static void stars_reset_predicted_values( struct spart* restrict sp) {} /** * @brief Finishes the calculation of (non-gravity) forces acting on stars * * Multiplies the forces and accelerations by the appropiate constants * * @param sp The particle to act upon */ __attribute__((always_inline)) INLINE static void stars_end_feedback( struct spart* sp) {} /** * @brief Kick the additional variables * * @param sp The particle to act upon * @param dt The time-step for this kick */ __attribute__((always_inline)) INLINE static void stars_kick_extra( struct spart* sp, float dt) {} /** * @brief Finishes the calculation of density on stars * * @param sp The particle to act upon * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void stars_end_density( struct spart* sp, const struct cosmology* cosmo) { /* Some smoothing length multiples. */ const float h = sp->h; const float h_inv = 1.0f / h; /* 1/h */ const float h_inv_dim = pow_dimension(h_inv); /* 1/h^d */ const float h_inv_dim_plus_one = h_inv_dim * h_inv; /* 1/h^(d+1) */ /* Finish the calculation by inserting the missing h-factors */ sp->density.wcount *= h_inv_dim; sp->density.wcount_dh *= h_inv_dim_plus_one; #ifdef SWIFT_STARS_DENSITY_CHECKS sp->rho *= h_inv_dim; sp->n *= h_inv_dim; #endif } /** * @brief Sets all particle fields to sensible values when the #spart has 0 * ngbs. * * @param sp The particle to act upon * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void stars_spart_has_no_neighbours( struct spart* restrict sp, const struct cosmology* cosmo) { warning( "Star particle with ID %lld treated as having no neighbours (h: %g, " "wcount: %g).", sp->id, sp->h, sp->density.wcount); /* Re-set problematic values */ sp->density.wcount = 0.f; sp->density.wcount_dh = 0.f; } /** * @brief Reset acceleration fields of a particle * * This is the equivalent of hydro_reset_acceleration. * We do not compute the acceleration on star, therefore no need to use it. * * @param p The particle to act upon */ __attribute__((always_inline)) INLINE static void stars_reset_acceleration( struct spart* restrict p) { #ifdef DEBUG_INTERACTIONS_STARS p->num_ngb_feedback = 0; #endif } /** * @brief Reset acceleration fields of a particle * * This is the equivalent of hydro_reset_acceleration. * We do not compute the acceleration on star, therefore no need to use it. * * @param p The particle to act upon */ __attribute__((always_inline)) INLINE static void stars_reset_feedback( struct spart* restrict p) { #ifdef DEBUG_INTERACTIONS_STARS for (int i = 0; i < MAX_NUM_OF_NEIGHBOURS_STARS; ++i) p->ids_ngbs_feedback[i] = -1; p->num_ngb_feedback = 0; #endif } /** * @brief Compute the luminosities of a particles in different bands. * * @param sp The particle. * @param with_cosmology Are we running a cosmological simulation? * @param cosmo The #cosmology object. * @param time The current physical time (internal units). * @param phys_const The physical constants in internal units. * @param props The #stars_props of that run. * @param luminosities (return) The luminosity in each band. */ INLINE static void stars_get_luminosities( const struct spart* sp, const int with_cosmology, const struct cosmology* cosmo, const double time, const struct phys_const* phys_const, const struct stars_props* props, float luminosities[luminosity_bands_count]) { const int count_Z = eagle_stars_lum_tables_N_Z; const int count_ages = eagle_stars_lum_tables_N_ages; /* Get star properties (all in internal units */ const float Z = chemistry_get_star_total_metal_mass_fraction_for_luminosity(sp); const float mass = sp->mass_init; float age; if (with_cosmology) age = cosmology_get_delta_time_from_scale_factors( cosmo, sp->birth_scale_factor, cosmo->a); else age = time - sp->birth_time; /* Convert to the units of the tables */ const float mass_Msun = mass / phys_const->const_solar_mass; const float age_Gyr = age / phys_const->const_year / 1e9; for (int i = 0; i < (int)luminosity_bands_count; ++i) { /* Log things */ float log10_Z = log10(Z + FLT_MIN); float log10_age_Gyr = log10(age_Gyr + FLT_MIN); /* Clip the input */ log10_Z = max(log10_Z, props->lum_tables_Z[i][0]); log10_Z = min(log10_Z, props->lum_tables_Z[i][count_Z - 1]); log10_age_Gyr = max(log10_age_Gyr, props->lum_tables_ages[i][0]); log10_age_Gyr = min(log10_age_Gyr, props->lum_tables_ages[i][count_ages - 1]); /* Get index along the interpolation axis */ int Z_index = 0, age_index = 0; for (int j = 0; j < count_Z - 1; ++j) { if (log10_Z >= props->lum_tables_Z[i][j]) ++Z_index; } for (int j = 0; j < count_ages - 1; ++j) { if (log10_age_Gyr >= props->lum_tables_ages[i][j]) ++age_index; } #ifdef SWIFT_DEBUG_CHECKS if (age_index == 0) error("Invalid age index!"); if (Z_index == 0) error("Invalid Z index!"); #endif const float* array = props->lum_tables_luminosities[i]; /* 2D interpolation */ const float f_11 = array[(Z_index - 1) * count_ages + (age_index - 1)]; const float f_12 = array[(Z_index - 0) * count_ages + (age_index - 1)]; const float f_21 = array[(Z_index - 1) * count_ages + (age_index - 0)]; const float f_22 = array[(Z_index - 0) * count_ages + (age_index - 0)]; const float x_diff1 = props->lum_tables_ages[i][age_index] - log10_age_Gyr; const float x_diff2 = log10_age_Gyr - props->lum_tables_ages[i][age_index - 1]; const float x_diff3 = props->lum_tables_ages[i][age_index] - props->lum_tables_ages[i][age_index - 1]; const float y_diff1 = props->lum_tables_Z[i][Z_index] - log10_Z; const float y_diff2 = log10_Z - props->lum_tables_Z[i][Z_index - 1]; const float y_diff3 = props->lum_tables_Z[i][Z_index] - props->lum_tables_Z[i][Z_index - 1]; const float f_1 = (f_11 * x_diff1 + f_21 * x_diff2) / x_diff3; const float f_2 = (f_12 * x_diff1 + f_22 * x_diff2) / x_diff3; const float log10_f = (y_diff1 * f_1 + y_diff2 * f_2) / y_diff3; /* Final conversion */ luminosities[i] = exp10f(log10_f) * mass_Msun * props->lum_tables_factor; } } #endif /* SWIFT_EAGLE_STARS_H */