/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
* 2021 Edo Altamura (edoardo.altamura@manchester.ac.uk)
*
* 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_TRACERS_EAGLE_IO_H
#define SWIFT_TRACERS_EAGLE_IO_H
/* Config parameters. */
#include
/* Local includes */
#include "black_holes_properties.h"
#include "io_properties.h"
#include "tracers.h"
#ifdef HAVE_HDF5
/**
* @brief Writes the current model of tracers to the file.
*
* @param h_grp The HDF5 group in which to write
*/
__attribute__((always_inline)) INLINE static void tracers_write_flavour(
hid_t h_grp) {
io_write_attribute_s(h_grp, "Tracers", "EAGLE");
}
#endif
INLINE static void convert_part_averaged_SFR(const struct engine* e,
const struct part* p,
const struct xpart* xp,
float* ret) {
for (int i = 0; i < num_snapshot_triggers_part; ++i) {
if (e->snapshot_recording_triggers_started_part[i])
ret[i] = xp->tracers_data.averaged_SFR[i] /
e->snapshot_recording_triggers_part[i];
else
ret[i] = 0.f;
}
}
INLINE static void convert_spart_averaged_SFR(const struct engine* e,
const struct spart* sp,
float* ret) {
/* Note: We use the 'part' trigger here as the SF would have started when the
* particle was still in gas form */
for (int i = 0; i < num_snapshot_triggers_part; ++i) {
if (e->snapshot_recording_triggers_started_part[i])
ret[i] = sp->tracers_data.averaged_SFR[i] /
e->snapshot_recording_triggers_part[i];
else
ret[i] = 0.f;
}
}
INLINE static void convert_bpart_averaged_accretion_rate(const struct engine* e,
const struct bpart* bp,
float* ret) {
for (int i = 0; i < num_snapshot_triggers_bpart; ++i) {
if (e->snapshot_recording_triggers_started_bpart[i])
ret[i] = bp->tracers_data.averaged_accretion_rate[i] /
e->snapshot_recording_triggers_bpart[i];
else
ret[i] = 0.f;
}
}
/**
* @brief Specifies which particle fields to write to a dataset
*
* @param parts The particle array.
* @param xparts The extended data particle array.
* @param list The list of i/o properties to write.
* @param with_cosmology Are we running with cosmology switched on?
*
* @return Returns the number of fields to write.
*/
__attribute__((always_inline)) INLINE static int tracers_write_particles(
const struct part* parts, const struct xpart* xparts, struct io_props* list,
const int with_cosmology) {
list[0] = io_make_output_field(
"MaximalTemperatures", FLOAT, 1, UNIT_CONV_TEMPERATURE, 0.f, xparts,
tracers_data.maximum_temperature,
"Maximal temperatures ever reached by the particles");
if (with_cosmology) {
list[1] = io_make_physical_output_field(
"MaximalTemperatureScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f,
xparts, tracers_data.maximum_temperature_scale_factor,
/*can convert to comoving=*/0,
"Scale-factors at which the maximal temperature was reached");
} else {
list[1] = io_make_output_field(
"MaximalTemperatureTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts,
tracers_data.maximum_temperature_time,
"Times at which the maximal temperature was reached");
}
list[2] =
io_make_output_field("HeatedBySNIIFeedback", CHAR, 1, UNIT_CONV_NO_UNITS,
0.f, xparts, tracers_data.hit_by_SNII_feedback,
"Flags the particles that have been directly hit by "
"a SNII feedback event at some point in the past. "
"If > 0, contains the number of individual events.");
list[3] =
io_make_output_field("HeatedByAGNFeedback", CHAR, 1, UNIT_CONV_NO_UNITS,
0.f, xparts, tracers_data.hit_by_AGN_feedback,
"Flags the particles that have been directly hit by "
"an AGN feedback event at some point in the past. "
"If > 0, contains the number of individual events.");
list[4] = io_make_output_field("EnergiesReceivedFromAGNFeedback", FLOAT, 1,
UNIT_CONV_ENERGY, 0.f, xparts,
tracers_data.AGN_feedback_energy,
"Total amount of thermal energy from AGN "
"feedback events received by the particles.");
list[5] = io_make_physical_output_field(
"DensitiesBeforeLastAGNEvent", FLOAT, 1, UNIT_CONV_DENSITY, 0.f, xparts,
tracers_data.density_before_last_AGN_feedback_event,
/*can convert to comoving=*/0,
"Physical density (not subgrid) of the gas fetched before the last AGN "
"feedback event that hit the particles. -1 if the particles have never "
"been heated.");
list[6] = io_make_physical_output_field(
"EntropiesBeforeLastAGNEvent", FLOAT, 1, UNIT_CONV_ENTROPY_PER_UNIT_MASS,
0.f, xparts, tracers_data.entropy_before_last_AGN_feedback_event,
/*can convert to comoving=*/0,
"Physical entropy (not subgrid) per unit mass of the gas fetched before "
"the last AGN feedback event that hit the particles. -1 if the particles "
"have never been heated.");
list[7] = io_make_physical_output_field(
"DensitiesAtLastAGNEvent", FLOAT, 1, UNIT_CONV_DENSITY, 0.f, xparts,
tracers_data.density_at_last_AGN_feedback_event,
/*can convert to comoving=*/0,
"Physical density (not subgrid) of the gas at the last AGN feedback "
"event that hit the particles. -1 if the particles have never been "
"heated.");
list[8] = io_make_physical_output_field(
"EntropiesAtLastAGNEvent", FLOAT, 1, UNIT_CONV_ENTROPY_PER_UNIT_MASS, 0.f,
xparts, tracers_data.entropy_at_last_AGN_feedback_event,
/*can convert to comoving=*/0,
"Physical entropy (not subgrid) per unit mass of the gas at the last AGN "
"feedback event that hit the particles. -1 if the particles have never "
"been heated.");
if (with_cosmology) {
list[9] = io_make_physical_output_field(
"LastAGNFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f,
xparts, tracers_data.last_AGN_injection_scale_factor,
/*can convert to comoving=*/0,
"Scale-factors at which the particles were last hit by AGN feedback. "
"-1 if a particle has never been hit by feedback");
} else {
list[9] = io_make_output_field(
"LastAGNFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts,
tracers_data.last_AGN_injection_time,
"Times at which the particles were last hit by AGN feedback. -1 if a "
"particle has never been hit by feedback");
}
list[10] = io_make_output_field_convert_part(
"AveragedStarFormationRates", FLOAT, 2, UNIT_CONV_SFR, 0.f, parts, xparts,
convert_part_averaged_SFR,
"Star formation rates of the particles averaged over the period set by "
"the first two snapshot triggers");
if (with_jets) {
list[11] = io_make_output_field(
"KickedByJetFeedback", CHAR, 1, UNIT_CONV_NO_UNITS, 0.f, xparts,
tracers_data.hit_by_jet_feedback,
"Flags the particles that have been directly kicked by"
"an AGN jet feedback event at some point in the past. "
"If > 0, contains the number of individual events.");
list[12] = io_make_physical_output_field(
"EnergiesReceivedFromJetFeedback", FLOAT, 1, UNIT_CONV_ENERGY, 0.f,
xparts, tracers_data.jet_feedback_energy, /*can convert to comoving=*/0,
"Total amount of kinetic energy from AGN "
"jet feedback events received by the "
"particles while they were still gas "
"particles.");
if (with_cosmology) {
list[13] = io_make_physical_output_field(
"LastAGNJetFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f,
xparts, tracers_data.last_AGN_jet_feedback_scale_factor,
/*can convert to comoving=*/0,
"Scale-factors at which the particles were last hit by jet "
"feedback while they were still gas particles. "
"-1 if a particle has never been hit by feedback");
} else {
list[13] = io_make_output_field(
"LastAGNJetFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts,
tracers_data.last_AGN_jet_feedback_time,
"Times at which the particles were last hit by jet"
"feedback while they were still gas particles. "
"-1 if a particle has never been hit by feedback");
}
list[14] = io_make_output_field("LastAGNJetKickVelocities", FLOAT, 1,
UNIT_CONV_VELOCITY, 0.f, xparts,
tracers_data.last_jet_kick_velocity,
"Kick velocity at last AGN jet event.");
list[15] = io_make_output_field("LastAGNJetKickMode", CHAR, 1,
UNIT_CONV_NO_UNITS, 0.f, xparts,
tracers_data.last_jet_kick_accretion_mode,
"The accretion/feedback mode the BH was "
"in when it kicked this particle. 0 "
"corresponds to the thick disc, 1 to the "
"thin disc and 2 to the slim disc.");
list[16] = io_make_output_field("LastAGNJetKickBHId", ULONGLONG, 1,
UNIT_CONV_NO_UNITS, 0.f, xparts,
tracers_data.last_jet_kick_BH_id,
"The id of the BH that last kicked this "
"particle.");
return 17;
} else {
return 11;
}
}
__attribute__((always_inline)) INLINE static int tracers_write_sparticles(
const struct spart* sparts, struct io_props* list,
const int with_cosmology) {
list[0] = io_make_output_field(
"MaximalTemperatures", FLOAT, 1, UNIT_CONV_TEMPERATURE, 0.f, sparts,
tracers_data.maximum_temperature,
"Maximal temperatures ever reached by the particles before they got "
"converted to stars");
if (with_cosmology) {
list[1] = io_make_physical_output_field(
"MaximalTemperatureScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f,
sparts, tracers_data.maximum_temperature_scale_factor,
/*can convert to comoving=*/0,
"Scale-factors at which the maximal temperature was reached");
} else {
list[1] = io_make_output_field(
"MaximalTemperatureTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, sparts,
tracers_data.maximum_temperature_time,
"Times at which the maximal temperature was reached");
}
list[2] =
io_make_output_field("HeatedBySNIIFeedback", CHAR, 1, UNIT_CONV_NO_UNITS,
0.f, sparts, tracers_data.hit_by_SNII_feedback,
"Flags the particles that have been directly hit by "
"a SNII feedback event at some point in the past "
"when the particle was still a gas particle.");
list[3] =
io_make_output_field("HeatedByAGNFeedback", CHAR, 1, UNIT_CONV_NO_UNITS,
0.f, sparts, tracers_data.hit_by_AGN_feedback,
"Flags the particles that have been directly hit by "
"an AGN feedback event at some point in the past "
"when the particle was still a gas particle.");
list[4] = io_make_physical_output_field(
"EnergiesReceivedFromAGNFeedback", FLOAT, 1, UNIT_CONV_ENERGY, 0.f,
sparts, tracers_data.AGN_feedback_energy, /*can convert to comoving=*/0,
"Total amount of thermal energy from AGN feedback events received by the "
"particles when the particle was still a gas particle.");
list[5] = io_make_physical_output_field(
"DensitiesBeforeLastAGNEvent", FLOAT, 1, UNIT_CONV_DENSITY, 0.f, sparts,
tracers_data.density_before_last_AGN_feedback_event,
/*can convert to comoving=*/0,
"Physical density (not subgrid) of the gas fetched before the last AGN "
"feedback "
"event that hit the particles when they were still gas particles. -1 if "
"the particles have never been heated.");
list[6] = io_make_physical_output_field(
"EntropiesBeforeLastAGNEvent", FLOAT, 1, UNIT_CONV_ENTROPY_PER_UNIT_MASS,
0.f, sparts, tracers_data.entropy_before_last_AGN_feedback_event,
/*can convert to comoving=*/0,
"Physical entropy (not subgrid) per unit mass of the gas fetched before "
"the last AGN "
"feedback event that hit the particles when they were still gas "
"particles."
" -1 if the particles have never been heated.");
list[7] = io_make_physical_output_field(
"DensitiesAtLastAGNEvent", FLOAT, 1, UNIT_CONV_DENSITY, 0.f, sparts,
tracers_data.density_at_last_AGN_feedback_event,
/*can convert to comoving=*/0,
"Physical density (not subgrid) of the gas at the last AGN feedback "
"event that hit the particles when they were still gas particles. -1 if "
"the particles have never been heated.");
list[8] = io_make_physical_output_field(
"EntropiesAtLastAGNEvent", FLOAT, 1, UNIT_CONV_ENTROPY_PER_UNIT_MASS, 0.f,
sparts, tracers_data.entropy_at_last_AGN_feedback_event,
/*can convert to comoving=*/0,
"Physical entropy (not subgrid) per unit mass of the gas at the last AGN "
"feedback event that hit the particles when they were still gas "
"particles."
" -1 if the particles have never been heated.");
if (with_cosmology) {
list[9] = io_make_physical_output_field(
"LastAGNFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f,
sparts, tracers_data.last_AGN_injection_scale_factor,
/*can convert to comoving=*/0,
"Scale-factors at which the particles were last hit by AGN feedback "
"when they were still gas particles. -1 if a particle has never been "
"hit by feedback");
} else {
list[9] =
io_make_output_field("LastAGNFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME,
0.f, sparts, tracers_data.last_AGN_injection_time,
"Times at which the particles were last hit by "
"AGN feedback when they were still gas particles. "
"-1 if a particle has never been hit by feedback");
}
list[10] = io_make_output_field_convert_spart(
"AveragedStarFormationRates", FLOAT, num_snapshot_triggers_part,
UNIT_CONV_SFR, 0.f, sparts, convert_spart_averaged_SFR,
"Star formation rates of the particles averaged over the period set by "
"the first two snapshot triggers when the particle was still a gas "
"particle.");
if (with_jets) {
list[11] = io_make_output_field(
"KickedByJetFeedback", CHAR, 1, UNIT_CONV_NO_UNITS, 0.f, sparts,
tracers_data.hit_by_jet_feedback,
"Flags the particles that have been directly kicked by"
"an AGN jet feedback event at some point in the past. "
"If > 0, contains the number of individual events.");
list[12] = io_make_output_field("EnergiesReceivedFromJetFeedback", FLOAT, 1,
UNIT_CONV_ENERGY, 0.f, sparts,
tracers_data.jet_feedback_energy,
"Total amount of kinetic energy from AGN "
"jet feedback events received by the "
"particles while they were still gas "
"particles.");
if (with_cosmology) {
list[13] = io_make_physical_output_field(
"LastAGNJetFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f,
sparts, tracers_data.last_AGN_jet_feedback_scale_factor,
/*can convert to comoving=*/0,
"Scale-factors at which the particles were last hit by jet "
"feedback while they were still gas particles. "
"-1 if a particle has never been hit by feedback");
} else {
list[13] = io_make_output_field(
"LastAGNJetFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, sparts,
tracers_data.last_AGN_jet_feedback_time,
"Times at which the particles were last hit by jet"
"feedback while they were still gas particles. "
"-1 if a particle has never been hit by feedback");
}
list[14] = io_make_output_field("LastAGNJetKickVelocities", FLOAT, 1,
UNIT_CONV_VELOCITY, 0.f, sparts,
tracers_data.last_jet_kick_velocity,
"Kick velocity at last AGN jet event.");
list[15] = io_make_output_field("LastAGNJetKickMode", CHAR, 1,
UNIT_CONV_NO_UNITS, 0.f, sparts,
tracers_data.last_jet_kick_accretion_mode,
"The accretion/feedback mode the BH was "
"in when it kicked this particle. 0 "
"corresponds to the thick disc, 1 to the "
"thin disc and 2 to the slim disc.");
list[16] = io_make_output_field("LastAGNJetKickBHId", ULONGLONG, 1,
UNIT_CONV_NO_UNITS, 0.f, sparts,
tracers_data.last_jet_kick_BH_id,
"The id of the BH that last kicked this "
"particle.");
return 17;
} else {
return 11;
}
}
__attribute__((always_inline)) INLINE static int tracers_write_bparticles(
const struct bpart* bparts, struct io_props* list,
const int with_cosmology) {
list[0] = io_make_output_field_convert_bpart(
"AveragedAccretionRates", FLOAT, num_snapshot_triggers_bpart,
UNIT_CONV_MASS_PER_UNIT_TIME, 0.f, bparts,
convert_bpart_averaged_accretion_rate,
"Accretion rates of the black holes averaged over the period set by the "
"first two snapshot triggers");
return 1;
}
#endif /* SWIFT_TRACERS_EAGLE_IO_H */