/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2018 Matthieu Schaller (matthieu.schaller@durham.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_COLIBRE_IO_H #define SWIFT_TRACERS_COLIBRE_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", "COLIBRE"); } #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_physical_output_field( "StellarWindMomentaReceived", FLOAT, 1, UNIT_CONV_MOMENTUM, 0.f, xparts, tracers_data.stellar_wind_momentum_received, /*can convert to comoving=*/0, "Momentum received from stellar winds in physical coordinates"); list[3] = io_make_output_field("HIIregionsEndTime", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts, tracers_data.HIIregion_timer_gas, "Time until particle is in HII region"); list[4] = io_make_physical_output_field( "HIIregionsStarIDs", LONGLONG, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, tracers_data.HIIregion_starid, /*can convert to comoving=*/0, "ID of star particle responsible for this HII region"); if (with_cosmology) { list[5] = io_make_physical_output_field( "LastSNIIThermalFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, tracers_data.last_SNII_thermal_injection_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particles were last hit by SNII thermal " "feedback. -1 if a particle has never been hit by feedback"); } else { list[5] = io_make_output_field( "LastSNIIThermalFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts, tracers_data.last_SNII_thermal_injection_time, "Times at which the particles were last hit by SNII thermal feedback. " "-1 if a particle has never been hit by feedback"); } if (with_cosmology) { list[6] = io_make_physical_output_field( "LastSNIaThermalFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, tracers_data.last_SNIa_thermal_injection_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particles were last hit by SNIa thermal " "feedback. -1 if a particle has never been hit by feedback"); } else { list[6] = io_make_output_field( "LastSNIaThermalFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts, tracers_data.last_SNIa_thermal_injection_time, "Times at which the particles were last hit by SNIa thermal feedback. " "-1 if a particle has never been hit by feedback"); } if (with_cosmology) { list[7] = io_make_physical_output_field( "LastKineticEarlyFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, tracers_data.last_stellar_wind_kick_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particles were last hit by kinetic early " "feedback. -1 if a particle has never been hit by feedback"); } else { list[7] = io_make_output_field( "LastKineticEarlyFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts, tracers_data.last_stellar_wind_kick_time, "Times at which the particles were last hit by kinetic early feedback. " "-1 if a particle has never been hit by feedback"); } if (with_cosmology) { list[8] = 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[8] = 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[9] = io_make_physical_output_field( "DensitiesAtLastSupernovaEvent", FLOAT, 1, UNIT_CONV_DENSITY, 0.f, xparts, tracers_data.density_at_last_SN_thermal_feedback_event, /*can convert to comoving=*/0, "Physical density (not subgrid) of the gas at the last SN (type-II or " "type-Ia) thermal feedback event that hit the particles. -1 if the " "particles have never been heated."); list[10] = io_make_physical_output_field( "TemperatureIncreasesAtLastSupernovaEvent", FLOAT, 1, UNIT_CONV_TEMPERATURE, 0.f, xparts, tracers_data.delta_T_at_last_SN_thermal_feedback_event, /*can convert to comoving=*/0, "The increase in temperature of the gas at the last SN (type-II or " "type-Ia) thermal feedback event that hit the particles. -1 if the " "particles have never been heated."); list[11] = io_make_physical_output_field( "EnergiesReceivedFromAGNFeedback", FLOAT, 1, UNIT_CONV_ENERGY, 0.f, xparts, tracers_data.AGN_feedback_energy, /*can convert to comoving=*/0, "Total amount of thermal energy from AGN " "feedback events received by the particles."); list[12] = io_make_physical_output_field( "LastEnergiesReceivedFromAGNFeedback", FLOAT, 1, UNIT_CONV_ENERGY, 0.f, xparts, tracers_data.last_AGN_feedback_energy, /*can convert to comoving=*/0, "The energy the particles received the " "last time they were heated by AGN " "feedback."); if (with_cosmology) { list[13] = io_make_physical_output_field( "LastSNIIKineticFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, tracers_data.last_SNII_kick_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particles were last hit by SNII kinetic " "feedback. -1 if a particle has never been hit by feedback"); } else { list[13] = io_make_output_field( "LastSNIIKineticFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts, tracers_data.last_SNII_kick_time, "Times at which the particles were last hit by SNII kinetic feedback. " "-1 if a particle has never been hit by feedback"); } list[14] = io_make_physical_output_field( "LastSNIIKineticFeedbackvkick", FLOAT, 1, UNIT_CONV_VELOCITY, 0.f, xparts, tracers_data.last_SNII_kick_velocity, /*can convert to comoving=*/0, "Physical kick velocity the particles were kicked with at last SNII " "kinetic feedback event. -1 if a particle has never been hit by " "feedback"); list[15] = io_make_physical_output_field( "MaximalSNIIKineticFeedbackvkick", FLOAT, 1, UNIT_CONV_VELOCITY, 0.f, xparts, tracers_data.max_SNII_kick_velocity, /*can convert to comoving=*/0, "Maximal physical kick velocity the particles were kicked with in SNII " "kinetic feedback. -1 if a particle has never been hit by feedback"); list[16] = 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[17] = io_make_physical_output_field( "TemperatureIncreasesAtLastAGNEvent", FLOAT, 1, UNIT_CONV_TEMPERATURE, 0.f, xparts, tracers_data.delta_T_at_last_AGN_feedback_event, /*can convert to comoving=*/0, "The increase in temperature 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[18] = io_make_physical_output_field( "LastISMScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, tracers_data.last_ISM_scale_factor, /*can convert to comoving=*/0, "Scale-factor at which the particle was part of the ISM for the last " "time, i.e. its density was larger than 100 times the mean density and " "(its neutral fraction larger than 50% OR be an HII region). " "-1 if the particle was never part of the ISM."); } else { list[18] = io_make_physical_output_field( "LastISMTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts, tracers_data.last_ISM_time, /*can convert to comoving=*/0, "Time at which the particle was part of the ISM for the last time, " "i.e. its density was larger than 100 times the mean density and " "(its neutral fraction larger than 50% OR be an HII region). " "-1 if the particle was never part of the ISM."); } list[19] = 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"); list[20] = io_make_output_field( "MinimalSmoothingLengths", FLOAT, 1, UNIT_CONV_LENGTH, 1.f, xparts, tracers_data.min_h, "Maximal temperatures ever reached by the particles"); if (with_cosmology) { list[21] = io_make_physical_output_field( "MinimalSmoothingLengthScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, tracers_data.min_h_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the minimal smoothing length was reached"); } else { list[21] = io_make_output_field( "MinimalSmoothingLengthTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts, tracers_data.min_h_time, "Times at which the minimal smoothing length was reached"); } list[22] = io_make_output_field( "LastFOFHaloMasses", FLOAT, 1, UNIT_CONV_MASS, 0.f, xparts, tracers_data.last_halo_mass, "Masses of the last FOF haloes the particles where part of. -1 if the " "particle has never been in a FOF group"); if (with_cosmology) { list[23] = io_make_physical_output_field( "LastFOFHaloMassesScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, tracers_data.last_in_halo_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particle was last in a FOF group"); } else { list[23] = io_make_output_field( "LastFOFHaloMassesTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, xparts, tracers_data.last_in_halo_time, "Times at which the particles were last in a FOF group"); } if (with_jets) { list[24] = 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[25] = 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."); if (with_cosmology) { list[26] = 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. -1 if a particle has never been hit by feedback"); } else { list[26] = 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. " "-1 if a particle has never been hit by feedback"); } list[27] = io_make_physical_output_field( "LastAGNJetKickVelocities", FLOAT, 1, UNIT_CONV_VELOCITY, 0.f, xparts, tracers_data.last_jet_kick_velocity, /*can convert to comoving=*/0, "Kick velocity at last AGN jet event."); list[28] = 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[29] = io_make_physical_output_field( "LastAGNJetKickBHId", ULONGLONG, 1, UNIT_CONV_NO_UNITS, 0.f, xparts, tracers_data.last_jet_kick_BH_id, /*can convert to comoving=*/0, "The id of the BH that last kicked this " "particle."); list[30] = io_make_physical_output_field( "LastAGNJetFeedbackInitialVolumes", FLOAT, 1, UNIT_CONV_VOLUME, 0.f, xparts, tracers_data.jet_radio_emission.last_jet_kick_initial_volume, /*can convert to comoving=*/0, "The physical volumes the particles had the last time they were heated " "by AGN."); list[31] = io_make_physical_output_field( "JetRadioEmissionShockingIntegrals", FLOAT, 3, UNIT_CONV_ENERGY, 0.f, xparts, tracers_data.jet_radio_emission.shocking_integrals, /*can convert to comoving=*/0, "The integrals over the shocking rates, used for radio emission " "modeling, in physical frame. The first integral corresponds to the " "electron integral, the second to the magnetic field integral, and " "the last to the 'minimum' auxilliary integral (see documentation)."); list[32] = io_make_physical_output_field( "JetRadioEmissionGammaIntegrals", FLOAT, 2, UNIT_CONV_ENERGY_DENSITY_TIME, 0.f, xparts, tracers_data.jet_radio_emission.gamma_integrals, /*can convert to comoving=*/0, "Integrals over the synchrotron photon and CMB photon energy " "densities, respectively, in physical frame. These are used for radio " "emission modeling (see documentation)."); list[33] = io_make_physical_output_field( "JetRadioEmissionGammaEffectiveIntegrals", FLOAT, 2, UNIT_CONV_ENERGY_SQUARED_TIME_PER_UNIT_VOLUME, 0.f, xparts, tracers_data.jet_radio_emission.gamma_effective_integrals, /*can convert to comoving=*/0, "Integrals over the gamma integrals, which are used to compute values " "weighted by the shock injection rates as a function of time. These " "are in physical frame."); list[34] = io_make_physical_output_field( "WeightedJetInjectionScaleFactors", FLOAT, 1, UNIT_CONV_ENERGY, 0.f, xparts, tracers_data.jet_radio_emission.weighted_injection_scale_factor, /*can convert to comoving=*/0, "The integral of the scale factor times shocking rate (injection rate " "of relativistic electrons), in physical frame. Once divided by a " "similar integral over the shocking rate, we get a weighted scale " "factor of when most of the injection occurred."); return 35; } else { return 24; } } __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_physical_output_field( "StellarWindMomentaReceived", FLOAT, 1, UNIT_CONV_MOMENTUM, 0.f, sparts, tracers_data.stellar_wind_momentum_received, /*can convert to comoving=*/0, "Momentum received by the gas particles from stellar winds before it was " "converted to a star in physical coordinates"); if (with_cosmology) { list[3] = io_make_physical_output_field( "LastSNIIThermalFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, tracers_data.last_SNII_thermal_injection_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particles were last hit by SNII thermal " "feedback when they were still gas particles. -1 if a particle has " "never been hit by feedback"); } else { list[3] = io_make_output_field( "LastSNIIThermalFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, sparts, tracers_data.last_SNII_thermal_injection_time, "Times at which the particles were last hit by SNII thermal feedback " "when they were still gas particles. -1 if a particle has never been " "hit by feedback"); } if (with_cosmology) { list[4] = io_make_physical_output_field( "LastSNIaThermalFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, tracers_data.last_SNIa_thermal_injection_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particles were last hit by SNIa thermal " "feedback when they were still gas particles. -1 if a particle has " "never been hit by feedback"); } else { list[4] = io_make_output_field( "LastSNIaThermalFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, sparts, tracers_data.last_SNIa_thermal_injection_time, "Times at which the particles were last hit by SNIa thermal feedback " "when they were still gas particles. -1 if a particle has never been " "hit by feedback"); } if (with_cosmology) { list[5] = io_make_physical_output_field( "LastKineticEarlyFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, tracers_data.last_stellar_wind_kick_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particles were last hit by kinetic early " "feedback when they were still gas particles. -1 if a particle has " "never been hit by feedback"); } else { list[5] = io_make_output_field( "LastKineticEarlyFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, sparts, tracers_data.last_stellar_wind_kick_time, "Times at which the particles were last hit by kinetic early feedback " "when they were still gas particles. -1 if a particle has never been " "hit by feedback"); } if (with_cosmology) { list[6] = 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[6] = 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[7] = io_make_physical_output_field( "DensitiesAtLastSupernovaEvent", FLOAT, 1, UNIT_CONV_DENSITY, 0.f, sparts, tracers_data.density_at_last_SN_thermal_feedback_event, /*can convert to comoving=*/0, "Physical density (not subgrid) of the gas at the last SN (type-II or " "type-Ia) thermal 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( "TemperatureIncreasesAtLastSupernovaEvent", FLOAT, 1, UNIT_CONV_TEMPERATURE, 0.f, sparts, tracers_data.delta_T_at_last_SN_thermal_feedback_event, /*can convert to comoving=*/0, "The increase in temperature of the gas at the last SN (type-II or " "type-Ia) thermal feedback event that hit the particles when they were " "still gas particles. -1 if the particles have never been heated."); list[9] = 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 particles were still gas particles."); list[10] = io_make_physical_output_field( "LastEnergiesReceivedFromAGNFeedback", FLOAT, 1, UNIT_CONV_ENERGY, 0.f, sparts, tracers_data.last_AGN_feedback_energy, /*can convert to comoving=*/0, "The energy the particles received the last time they were heated by AGN " "feedback while they were still gas particles."); if (with_cosmology) { list[11] = io_make_physical_output_field( "LastSNIIKineticFeedbackScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, tracers_data.last_SNII_kick_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particles were last hit by SNII kinetic " "feedback when they were still gas particles. -1 if a particle has " "never been hit by feedback"); } else { list[11] = io_make_output_field( "LastSNIIKineticFeedbackTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, sparts, tracers_data.last_SNII_kick_time, "Times at which the particles were last hit by SNII kinetic feedback " "when they were still gas particles. -1 if a particle has never been " "hit by feedback"); } list[12] = io_make_physical_output_field( "LastSNIIKineticFeedbackvkick", FLOAT, 1, UNIT_CONV_VELOCITY, 0.f, sparts, tracers_data.last_SNII_kick_velocity, /*can convert to comoving=*/0, "Physical kick velocity at last SNII kinetic feedback event when the " "stellar particles were kicked with when they were still gas particles. " "-1 if a particle has never been hit by feedback"); list[13] = io_make_physical_output_field( "MaximalSNIIKineticFeedbackvkick", FLOAT, 1, UNIT_CONV_VELOCITY, 0.f, sparts, tracers_data.max_SNII_kick_velocity, /*can convert to comoving=*/0, "Maximal physical kick velocity in SNII kinetic feedback when the stellar" " particles were kicked with when they were still gas particles. -1 if a" " particle has never been hit by feedback"); list[14] = 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[15] = io_make_physical_output_field( "TemperatureIncreasesAtLastAGNEvent", FLOAT, 1, UNIT_CONV_TEMPERATURE, 0.f, sparts, tracers_data.delta_T_at_last_AGN_feedback_event, /*can convert to comoving=*/0, "The increase in temperature 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[16] = 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."); list[17] = io_make_output_field("LastFOFHaloMasses", FLOAT, 1, UNIT_CONV_MASS, 0.f, sparts, tracers_data.last_halo_mass, "Masses of the last FOF haloes the particles where " "part of when they were still a gas particle. -1 if " "the particle has never been in a FOF group"); if (with_cosmology) { list[18] = io_make_physical_output_field( "LastFOFHaloMassesScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, tracers_data.last_in_halo_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the particle was last in a FOF group when they " "were still a gas particle"); } else { list[18] = io_make_output_field("LastFOFHaloMassesTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, sparts, tracers_data.last_in_halo_time, "Times at which the particles were last in a FOF " "group when they were still a gas particle"); } if (with_jets) { list[19] = 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[20] = io_make_physical_output_field( "EnergiesReceivedFromJetFeedback", FLOAT, 1, UNIT_CONV_ENERGY, 0.f, sparts, 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[21] = 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[21] = 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[22] = io_make_physical_output_field( "LastAGNJetKickVelocities", FLOAT, 1, UNIT_CONV_VELOCITY, 0.f, sparts, tracers_data.last_jet_kick_velocity, /*can convert to comoving=*/0, "Kick velocity at last AGN jet event."); list[23] = 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[24] = io_make_physical_output_field( "LastAGNJetKickBHId", ULONGLONG, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, tracers_data.last_jet_kick_BH_id, /*can convert to comoving=*/0, "The id of the BH that last kicked this particle."); return 25; } else { return 19; } } __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"); list[1] = io_make_output_field("MinimalTimeBins", CHAR, 1, UNIT_CONV_NO_UNITS, 0.f, bparts, tracers_data.min_time_bin, "Minimal Time Bins reached by the black holes"); if (with_cosmology) { list[2] = io_make_physical_output_field( "MinimalTimeBinScaleFactors", FLOAT, 1, UNIT_CONV_NO_UNITS, 0.f, bparts, tracers_data.min_time_bin_scale_factor, /*can convert to comoving=*/0, "Scale-factors at which the minimal time-bin was reached"); } else { list[2] = io_make_output_field("MinimalTimeBinTimes", FLOAT, 1, UNIT_CONV_TIME, 0.f, bparts, tracers_data.min_time_bin_time, "Times at which the minimal time-bin was reached"); } return 3; } #endif /* SWIFT_TRACERS_COLIBRE_IO_H */