/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2019 Matthieu Schaller (schaller@strw.leidenunuiv.nl)
* 2020 Camila Correa (c.a.correa@uva.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_COLIBRE_CHEMISTRY_IACT_H
#define SWIFT_COLIBRE_CHEMISTRY_IACT_H
/**
* @file COLIBRE/chemistry_iact.h
* @brief Smooth metal interaction functions following the COLIBRE model.
*/
/**
* @brief do chemistry computation after the runner_iact_density (symmetric
* version)
*
* @param r2 Comoving square distance between the two particles.
* @param dx Comoving vector separating both particles (pi - pj).
* @param hi Comoving smoothing-length of particle i.
* @param hj Comoving smoothing-length of particle j.
* @param pi First particle.
* @param pj Second particle.
* @param a Current scale factor.
* @param H Current Hubble parameter.
*
* @brief after chemistry computation comes shear tensor computation
*
*/
__attribute__((always_inline)) INLINE static void runner_iact_chemistry(
float r2, const float dx[3], const float hi, const float hj,
struct part *restrict pi, struct part *restrict pj, const float a,
const float H) {
struct chemistry_part_data *di = &pi->chemistry_data;
struct chemistry_part_data *dj = &pj->chemistry_data;
float dwi_dx, dwj_dx;
/* Get the masses */
const float mj = hydro_get_mass(pj);
const float mi = hydro_get_mass(pi);
/* Get r */
const float r = sqrtf(r2);
/* be careful with r==0! */
const float r_inv = r ? 1.f / r : 0.0f;
#ifdef SWIFT_DEBUG_CHECKS
if (r == 0.0f) {
error("Zero particle distance!");
}
if (hi == 0.0f || hj == 0.0f) {
error("Zero smoothing length!");
}
#endif
/* Compute the kernel function for pi */
const float ui = r / hi;
kernel_eval_dWdx(ui, &dwi_dx);
/* Compute the kernel function for pj */
const float uj = r / hj;
kernel_eval_dWdx(uj, &dwj_dx);
const float dwj_r = dwj_dx * r_inv;
const float mi_dwj_r = mi * dwj_r;
const float dwi_r = dwi_dx * r_inv;
const float mj_dwi_r = mj * dwi_r;
/* Compute velocity shear tensor */
for (int k = 0; k < 3; k++) {
di->shear_tensor[k][0] += (pj->v[0] - pi->v[0]) * dx[k] * mj_dwi_r;
di->shear_tensor[k][1] += (pj->v[1] - pi->v[1]) * dx[k] * mj_dwi_r;
di->shear_tensor[k][2] += (pj->v[2] - pi->v[2]) * dx[k] * mj_dwi_r;
dj->shear_tensor[k][0] -= (pi->v[0] - pj->v[0]) * dx[k] * mi_dwj_r;
dj->shear_tensor[k][1] -= (pi->v[1] - pj->v[1]) * dx[k] * mi_dwj_r;
dj->shear_tensor[k][2] -= (pi->v[2] - pj->v[2]) * dx[k] * mi_dwj_r;
}
}
/**
* @brief do chemistry computation after the runner_iact_density (non symmetric
* version)
*
* @param r2 Comoving square distance between the two particles.
* @param dx Comoving vector separating both particles (pi - pj).
* @param hi Comoving smoothing-length of particle i.
* @param hj Comoving smoothing-length of particle j.
* @param pi First particle.
* @param pj Second particle (not updated).
* @param a Current scale factor.
* @param H Current Hubble parameter.
*
* @brief after chemistry computation comes shear tensor computation
*
*/
__attribute__((always_inline)) INLINE static void runner_iact_nonsym_chemistry(
float r2, const float dx[3], const float hi, const float hj,
struct part *restrict pi, const struct part *restrict pj, const float a,
const float H) {
struct chemistry_part_data *di = &pi->chemistry_data;
/* Get the masses. */
const float mj = hydro_get_mass(pj);
float dwi_dx;
/* Get r */
const float r = sqrtf(r2);
const float r_inv = r ? 1.f / r : 0.0f;
#ifdef SWIFT_DEBUG_CHECKS
if (r == 0.0f) {
error("Zero particle distance!");
}
if (hi == 0.0f) {
error("Zero smoothing length!");
}
#endif
/* Compute the kernel function for pi */
const float ui = r / hi;
kernel_eval_dWdx(ui, &dwi_dx);
const float dwi_r = dwi_dx * r_inv;
const float mj_dwi_r = mj * dwi_r;
/* Compute velocity shear tensor */
for (int k = 0; k < 3; k++) {
di->shear_tensor[k][0] += (pj->v[0] - pi->v[0]) * dx[k] * mj_dwi_r;
di->shear_tensor[k][1] += (pj->v[1] - pi->v[1]) * dx[k] * mj_dwi_r;
di->shear_tensor[k][2] += (pj->v[2] - pi->v[2]) * dx[k] * mj_dwi_r;
}
}
/**
* @brief do metal diffusion computation in the
* (symmetric version)
*
* @param r2 Comoving square distance between the two particles.
* @param hi Comoving smoothing-length of particle i.
* @param hj Comoving smoothing-length of particle j.
* @param pi First particle.
* @param pj Second particle.
* @param a Current scale factor.
* @param H Current Hubble parameter.
*
*/
__attribute__((always_inline)) INLINE static void runner_iact_diffusion(
float r2, const float dx[3], const float hi, const float hj,
struct part *restrict pi, struct part *restrict pj, const float a,
const float H, const float time_base, const integertime_t t_current,
const struct cosmology *cosmo, const int with_cosmology) {
struct chemistry_part_data *chi = &pi->chemistry_data;
struct chemistry_part_data *chj = &pj->chemistry_data;
struct dust_part_data *dui = &pi->dust_data;
struct dust_part_data *duj = &pj->dust_data;
if (chj->diffusion_coefficient > 0 || chi->diffusion_coefficient > 0) {
/* Get mass */
const float mj = hydro_get_mass(pj);
const float mi = hydro_get_mass(pi);
const float rhoj = hydro_get_comoving_density(pj);
const float rhoi = hydro_get_comoving_density(pi);
float wi, wj, dwi_dx, dwj_dx;
/* Get r */
const float r = sqrtf(r2);
/* be careful with r==0! */
const float r_inv = r ? 1.f / r : 0.0f;
#ifdef SWIFT_DEBUG_CHECKS
if (r == 0.0f) {
error("Zero particle distance!");
}
if (hi == 0.0f || hj == 0.0f) {
error("Zero smoothing length!");
}
if (rhoi == 0.0f || rhoj == 0.0f) {
error("Zero density!");
}
if (mi == 0.0f || mj == 0.0f) {
error("Zero mass!");
}
#endif
/* part j */
/* Get the kernel for hj */
const float hj_inv = 1.0f / hj;
const float hj_inv_dim = pow_dimension(hj_inv); /* 1/h^d */
const float hj_inv_dim_plus_one = hj_inv_dim * hj_inv; /* 1/h^(d+1) */
const float rho_j_inv = 1.0f / rhoj;
/* Compute the kernel function for pj */
const float xj = r * hj_inv;
kernel_deval(xj, &wj, &dwj_dx);
/* part i */
/* Get the kernel for hi */
const float hi_inv = 1.0f / hi;
const float hi_inv_dim = pow_dimension(hi_inv); /* 1/h^d */
const float hi_inv_dim_plus_one = hi_inv_dim * hi_inv; /* 1/h^(d+1) */
const float rho_i_inv = 1.0f / rhoi;
/* Compute the kernel function for pi */
const float xi = r * hi_inv;
kernel_deval(xi, &wi, &dwi_dx);
float dw_r = 0.5f *
(dwi_dx * hi_inv_dim_plus_one + dwj_dx * hj_inv_dim_plus_one) *
r_inv;
const float mj_dw_r = mj * dw_r;
const float mi_dw_r = mi * dw_r;
/* Compute K_ij coefficient (see Correa et al., in prep.) */
/* K_ij in physical coordinates */
float K;
K = 4.0f * chj->diffusion_coefficient * chi->diffusion_coefficient;
K /= (chj->diffusion_coefficient + chi->diffusion_coefficient);
K *= rho_i_inv * rho_j_inv;
K *= a;
const float K_ij = K * mj_dw_r;
const float K_ji = K * mi_dw_r;
/* Manage time interval of particles i & j to be the smallest */
double dt;
if (with_cosmology) {
const integertime_t ti_step = get_integer_timestep(pi->time_bin);
const integertime_t ti_begin =
get_integer_time_begin(t_current - 1, pi->time_bin);
dt = cosmology_get_delta_time(cosmo, ti_begin, ti_begin + ti_step);
} else {
dt = get_timestep(pi->time_bin, time_base);
}
/* Same for particle j */
double dt_j;
if (with_cosmology) {
const integertime_t tj_step = get_integer_timestep(pj->time_bin);
const integertime_t tj_begin =
get_integer_time_begin(t_current - 1, pj->time_bin);
dt_j = cosmology_get_delta_time(cosmo, tj_begin, tj_begin + tj_step);
} else {
dt_j = get_timestep(pj->time_bin, time_base);
}
if (dt_j < dt) dt = dt_j;
dust_iact_diffusion(dui, duj, K_ij, K_ji, dt);
/* Compute contribution to the metal abundance */
for (int i = 0; i < chemistry_element_count; i++) {
chi->dmetal_mass_fraction[i] +=
K_ij * (chi->metal_mass_fraction[i] - chj->metal_mass_fraction[i]) *
dt;
chj->dmetal_mass_fraction[i] +=
K_ji * (chj->metal_mass_fraction[i] - chi->metal_mass_fraction[i]) *
dt;
chi->diffusion_rate[i] +=
K_ij * (chi->metal_mass_fraction[i] - chj->metal_mass_fraction[i]);
chj->diffusion_rate[i] +=
K_ji * (chj->metal_mass_fraction[i] - chi->metal_mass_fraction[i]);
}
/* Diffusing the total metal mass */
chi->dmetal_mass_fraction_total +=
K_ij *
(chi->metal_mass_fraction_total - chj->metal_mass_fraction_total) * dt;
chj->dmetal_mass_fraction_total +=
K_ji *
(chj->metal_mass_fraction_total - chi->metal_mass_fraction_total) * dt;
/* And diffuse the individual feedback tracers */
chi->dmetal_mass_fraction_from_SNIa +=
K_ij *
(chi->metal_mass_fraction_from_SNIa -
chj->metal_mass_fraction_from_SNIa) *
dt;
chj->dmetal_mass_fraction_from_SNIa +=
K_ji *
(chj->metal_mass_fraction_from_SNIa -
chi->metal_mass_fraction_from_SNIa) *
dt;
chi->dmetal_mass_fraction_from_AGB += K_ij *
(chi->metal_mass_fraction_from_AGB -
chj->metal_mass_fraction_from_AGB) *
dt;
chj->dmetal_mass_fraction_from_AGB += K_ji *
(chj->metal_mass_fraction_from_AGB -
chi->metal_mass_fraction_from_AGB) *
dt;
chi->dmetal_mass_fraction_from_SNII +=
K_ij *
(chi->metal_mass_fraction_from_SNII -
chj->metal_mass_fraction_from_SNII) *
dt;
chj->dmetal_mass_fraction_from_SNII +=
K_ji *
(chj->metal_mass_fraction_from_SNII -
chi->metal_mass_fraction_from_SNII) *
dt;
chi->diron_mass_fraction_from_SNIa += K_ij *
(chi->iron_mass_fraction_from_SNIa -
chj->iron_mass_fraction_from_SNIa) *
dt;
chj->diron_mass_fraction_from_SNIa += K_ji *
(chj->iron_mass_fraction_from_SNIa -
chi->iron_mass_fraction_from_SNIa) *
dt;
chi->dmass_fraction_from_NSM +=
K_ij * (chi->mass_fraction_from_NSM - chj->mass_fraction_from_NSM) * dt;
chj->dmass_fraction_from_NSM +=
K_ji * (chj->mass_fraction_from_NSM - chi->mass_fraction_from_NSM) * dt;
chi->dmass_fraction_from_CEJSN +=
K_ij * (chi->mass_fraction_from_CEJSN - chj->mass_fraction_from_CEJSN) *
dt;
chj->dmass_fraction_from_CEJSN +=
K_ji * (chj->mass_fraction_from_CEJSN - chi->mass_fraction_from_CEJSN) *
dt;
chi->dmass_fraction_from_collapsar += K_ij *
(chi->mass_fraction_from_collapsar -
chj->mass_fraction_from_collapsar) *
dt;
chj->dmass_fraction_from_collapsar += K_ji *
(chj->mass_fraction_from_collapsar -
chi->mass_fraction_from_collapsar) *
dt;
chi->dmass_fraction_from_SNIa +=
K_ij * (chi->mass_fraction_from_SNIa - chj->mass_fraction_from_SNIa) *
dt;
chj->dmass_fraction_from_SNIa +=
K_ji * (chj->mass_fraction_from_SNIa - chi->mass_fraction_from_SNIa) *
dt;
chi->dmass_fraction_from_AGB +=
K_ij * (chi->mass_fraction_from_AGB - chj->mass_fraction_from_AGB) * dt;
chj->dmass_fraction_from_AGB +=
K_ji * (chj->mass_fraction_from_AGB - chi->mass_fraction_from_AGB) * dt;
chi->dmass_fraction_from_SNII +=
K_ij * (chi->mass_fraction_from_SNII - chj->mass_fraction_from_SNII) *
dt;
chj->dmass_fraction_from_SNII +=
K_ji * (chj->mass_fraction_from_SNII - chi->mass_fraction_from_SNII) *
dt;
}
}
/**
* @brief do metal diffusion computation in the
* (nonsymmetric version)
*
* @param r2 Comoving square distance between the two particles.
* @param hi Comoving smoothing-length of particle i.
* @param hj Comoving smoothing-length of particle j.
* @param pi First particle.
* @param pj Second particle.
* @param a Current scale factor.
* @param H Current Hubble parameter.
*
*/
__attribute__((always_inline)) INLINE static void runner_iact_nonsym_diffusion(
float r2, const float dx[3], const float hi, const float hj,
struct part *restrict pi, const struct part *restrict pj, const float a,
const float H, const float time_base, const integertime_t t_current,
const struct cosmology *cosmo, const int with_cosmology) {
struct chemistry_part_data *chi = &pi->chemistry_data;
const struct chemistry_part_data *chj = &pj->chemistry_data;
struct dust_part_data *dui = &pi->dust_data;
const struct dust_part_data *duj = &pj->dust_data;
if (chj->diffusion_coefficient > 0 || chi->diffusion_coefficient > 0) {
/* Get mass */
const float mj = hydro_get_mass(pj);
const float rhoj = hydro_get_comoving_density(pj);
const float rhoi = hydro_get_comoving_density(pi);
float wi, wj, dwi_dx, dwj_dx;
/* Get r */
const float r = sqrtf(r2);
/* be careful with r==0! */
const float r_inv = r ? 1.f / r : 0.0f;
#ifdef SWIFT_DEBUG_CHECKS
if (r == 0.0f) {
error("Zero particle distance!");
}
if (hi == 0.0f || hj == 0.0f) {
error("Zero smoothing length!");
}
if (rhoi == 0.0f || rhoj == 0.0f) {
error("Zero density!");
}
if (mj == 0.0f) {
error("Zero mass!");
}
#endif
/* part j */
/* Get the kernel for hj */
const float hj_inv = 1.0f / hj;
const float hj_inv_dim = pow_dimension(hj_inv); /* 1/h^d */
const float hj_inv_dim_plus_one = hj_inv_dim * hj_inv; /* 1/h^(d+1) */
const float rho_j_inv = 1.0f / rhoj;
/* Compute the kernel function for pj */
const float xj = r * hj_inv;
kernel_deval(xj, &wj, &dwj_dx);
/* part i */
/* Get the kernel for hi */
float hi_inv = 1.0f / hi;
const float hi_inv_dim = pow_dimension(hi_inv); /* 1/h^d */
const float hi_inv_dim_plus_one = hi_inv_dim * hi_inv; /* 1/h^(d+1) */
const float rho_i_inv = 1.0f / rhoi;
/* Compute the kernel function for pi */
const float xi = r * hi_inv;
kernel_deval(xi, &wi, &dwi_dx);
float dw_r = 0.5f *
(dwi_dx * hi_inv_dim_plus_one + dwj_dx * hj_inv_dim_plus_one) *
r_inv;
const float mj_dw_r = mj * dw_r;
/* Compute K_ij coefficient (see Correa et al., in prep.) */
float K;
K = 4.0f * chj->diffusion_coefficient * chi->diffusion_coefficient;
K /= (chj->diffusion_coefficient + chi->diffusion_coefficient);
K *= rho_i_inv * rho_j_inv;
K *= a;
const float K_ij = K * mj_dw_r;
/* Manage time interval of particles i & j to be the smallest */
double dt;
if (with_cosmology) {
const integertime_t ti_step = get_integer_timestep(pi->time_bin);
const integertime_t ti_begin =
get_integer_time_begin(t_current - 1, pi->time_bin);
dt = cosmology_get_delta_time(cosmo, ti_begin, ti_begin + ti_step);
} else {
dt = get_timestep(pi->time_bin, time_base);
}
/* Same for particle j */
double dt_j;
if (with_cosmology) {
const integertime_t tj_step = get_integer_timestep(pj->time_bin);
const integertime_t tj_begin =
get_integer_time_begin(t_current - 1, pj->time_bin);
dt_j = cosmology_get_delta_time(cosmo, tj_begin, tj_begin + tj_step);
} else {
dt_j = get_timestep(pj->time_bin, time_base);
}
if (dt_j < dt) dt = dt_j;
/* Compute contribution to the metal abundance */
for (int i = 0; i < chemistry_element_count; i++) {
chi->dmetal_mass_fraction[i] +=
K_ij * (chi->metal_mass_fraction[i] - chj->metal_mass_fraction[i]) *
dt;
chi->diffusion_rate[i] +=
K_ij * (chi->metal_mass_fraction[i] - chj->metal_mass_fraction[i]);
}
dust_iact_nonsym_diffusion(dui, duj, K_ij, dt);
/* Diffusing the total metal mass */
chi->dmetal_mass_fraction_total +=
K_ij *
(chi->metal_mass_fraction_total - chj->metal_mass_fraction_total) * dt;
/* And diffuse the individual feedback tracers */
chi->dmetal_mass_fraction_from_SNIa +=
K_ij *
(chi->metal_mass_fraction_from_SNIa -
chj->metal_mass_fraction_from_SNIa) *
dt;
chi->dmetal_mass_fraction_from_AGB += K_ij *
(chi->metal_mass_fraction_from_AGB -
chj->metal_mass_fraction_from_AGB) *
dt;
chi->dmetal_mass_fraction_from_SNII +=
K_ij *
(chi->metal_mass_fraction_from_SNII -
chj->metal_mass_fraction_from_SNII) *
dt;
chi->diron_mass_fraction_from_SNIa += K_ij *
(chi->iron_mass_fraction_from_SNIa -
chj->iron_mass_fraction_from_SNIa) *
dt;
chi->dmass_fraction_from_NSM +=
K_ij * (chi->mass_fraction_from_NSM - chj->mass_fraction_from_NSM) * dt;
chi->dmass_fraction_from_CEJSN +=
K_ij * (chi->mass_fraction_from_CEJSN - chj->mass_fraction_from_CEJSN) *
dt;
chi->dmass_fraction_from_collapsar += K_ij *
(chi->mass_fraction_from_collapsar -
chj->mass_fraction_from_collapsar) *
dt;
chi->dmass_fraction_from_SNIa +=
K_ij * (chi->mass_fraction_from_SNIa - chj->mass_fraction_from_SNIa) *
dt;
chi->dmass_fraction_from_AGB +=
K_ij * (chi->mass_fraction_from_AGB - chj->mass_fraction_from_AGB) * dt;
chi->dmass_fraction_from_SNII +=
K_ij * (chi->mass_fraction_from_SNII - chj->mass_fraction_from_SNII) *
dt;
}
}
#endif /* SWIFT_COLIBRE_CHEMISTRY_IACT_H */