/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2023 Matthieu Schaller (schaller@strw.leidenuniv.nl) * 2025 Thomas Sandnes (thomas.d.sandnes@durham.ac.uk) * 2026 Filip Husko (husko@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_FORCING_IDEALIZED_AGN_JET_H #define SWIFT_FORCING_IDEALIZED_AGN_JET_H /* Config parameters. */ #include /* Standard includes. */ #include /* Local includes. */ #include "engine.h" #include "error.h" #include "hydro.h" #include "parser.h" #include "part.h" #include "physical_constants.h" #include "space.h" #include "timestep_sync_part.h" #include "units.h" /** * @brief Forcing Term Properties */ struct forcing_terms { /*! Particles with ID <= boundary_particle_max_id are treated as boundary * particles. */ int boundary_particle_max_id; /*! Whether or not boundary particles are fixed in place (0 (false, default) * or 1 (true)) */ int enable_fixed_position; /*! Whether or not boundary particles have hydrodynamic accelerations enabled * (0 (false, default) or 1 (true)) */ int enable_hydro_acceleration; /*! Whether or not boundary particles have gravitational accelerations enabled * (0 (false, default) or 1 (true)) */ int enable_grav_acceleration; /* The jet power */ float jet_power; /* The jet kick velocity */ float jet_velocity; /* How long the jet should be on */ float jet_duration; }; /** * @brief Computes the hydrodynamic forcing terms. * * Resets the hydrodynamic accelerations of boundary particles to zero. * If using fixed boundary particles, their velocities are also set to zero. * * @param time The current time. * @param terms The properties of the forcing terms. * @param s The #space we act on. * @param phys_const The physical constants in internal units. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. */ __attribute__((always_inline)) INLINE static void forcing_hydro_terms_apply( const double time, const struct forcing_terms *terms, const struct space *s, const struct phys_const *phys_const, struct part *p, struct xpart *xp) { if (terms->enable_hydro_acceleration) { /* Skip if not resetting hydro accelerations. */ return; } /* Only kick particles if they haven't yet been kicked, and if it is time to kick them; define max_id of particle that should be kicked up to now */ const float max_id = (terms->jet_power * time) / (0.5 * p->mass * terms->jet_velocity * terms->jet_velocity); if ((p->id <= terms->boundary_particle_max_id) && (p->id > max_id)) { /* Reset the hydro accelerations of boundary particles. */ p->a_hydro[0] = 0.0f; p->a_hydro[1] = 0.0f; p->a_hydro[2] = 0.0f; #if defined(GIZMO_MFV_SPH) || defined(GIZMO_MFM_SPH) /* Some values need to be reset in the Gizmo case. */ hydro_prepare_force(p, &c->hydro.xparts[k], cosmo, e->hydro_properties, e->pressure_floor_props, /*dt_alpha=*/0, /*dt_therm=*/0); rt_prepare_force(p); #endif if (terms->enable_fixed_position) { /* Set velocity of fixed boundary particle to zero. */ xp->v_full[0] = 0.f; xp->v_full[1] = 0.f; xp->v_full[2] = 0.f; } } else if (p->id <= terms->boundary_particle_max_id) { /* Launch particles into jets */ /* Particle position relative to the box centre */ const double delta_x = (p->x[0] - s->dim[0] / 2.0); const double delta_y = (p->x[1] - s->dim[1] / 2.0); const double delta_z = (p->x[2] - s->dim[2] / 2.0); const double R = sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z); /* Assign velocity to be given. We do a kick radially from the origin */ const double vel_kick_vec[3] = {terms->jet_velocity * delta_x / R, terms->jet_velocity * delta_y / R, terms->jet_velocity * delta_z / R}; p->v[0] = vel_kick_vec[0]; p->v[1] = vel_kick_vec[1]; p->v[2] = vel_kick_vec[2]; xp->v_full[0] = vel_kick_vec[0]; xp->v_full[1] = vel_kick_vec[1]; xp->v_full[2] = vel_kick_vec[2]; /* Reset some hydro quantities */ hydro_diffusive_feedback_reset(p); /* Recompute the signal velocity of the particle */ hydro_set_v_sig_based_on_velocity_kick(p, s->e->cosmology, terms->jet_velocity); /* Synchronize the particle on the time-line */ timestep_sync_part(p); /* Increase the particle's id so it's no longer ever kicked */ p->id += terms->boundary_particle_max_id; } } /** * @brief Computes the gravitational forcing terms. * * Resets the gravitational accelerations of boundary particles to zero. * If using fixed boundary particles, their velocities are also set to zero. * * @param id The particle ID. * @param terms The properties of the forcing terms. * @param gp Pointer to the particle data. */ __attribute__((always_inline)) INLINE static void forcing_grav_terms_apply( const long long id, const struct forcing_terms *terms, struct gpart *gp) { /* Nothing to do here */ } /** * @brief Sets the forcing of gparts prior to drift. * * Resets the velocities of fixed boundary particles to zero. * * @param id The particle ID. * @param terms The properties of the forcing terms. * @param gp Pointer to the particle data. */ __attribute__((always_inline)) INLINE static void forcing_gpart_drift_apply( const long long id, const struct forcing_terms *terms, struct gpart *gp) { /* Nothing to do here */ } /** * @brief Sets the forcing of parts prior to drift. * * Resets the velocities of fixed boundary particles to zero. * * @param id The particle ID. * @param terms The properties of the forcing terms. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. */ __attribute__((always_inline)) INLINE static void forcing_part_drift_apply( const long long id, const struct forcing_terms *terms, struct part *p, struct xpart *xp) { if (id <= terms->boundary_particle_max_id && terms->enable_fixed_position) { /* Set velocity of fixed boundary particle to zero. */ xp->v_full[0] = 0.f; xp->v_full[1] = 0.f; xp->v_full[2] = 0.f; } } /** * @brief Sets the forcing of sparts prior to drift. * * Resets the velocities of fixed boundary particles to zero. * * @param id The particle ID. * @param terms The properties of the forcing terms. * @param sp Pointer to the particle data. */ __attribute__((always_inline)) INLINE static void forcing_spart_drift_apply( const long long id, const struct forcing_terms *terms, struct spart *sp) { /* Nothing to do here */ } /** * @brief Sets the forcing of bparts prior to drift. * * Resets the velocities of fixed boundary particles to zero. * * @param id The particle ID. * @param terms The properties of the forcing terms. * @param bp Pointer to the particle data. */ __attribute__((always_inline)) INLINE static void forcing_bpart_drift_apply( const long long id, const struct forcing_terms *terms, struct bpart *bp) { /* Nothing to do here */ } /** * @brief Computes the time-step condition due to the forcing terms. * * Nothing to do here. --> Return FLT_MAX. * * @param time The current time. * @param terms The properties of the forcing terms. * @param phys_const The physical constants in internal units. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. */ __attribute__((always_inline)) INLINE static float forcing_terms_timestep( double time, const struct forcing_terms *terms, const struct phys_const *phys_const, const struct part *p, const struct xpart *xp) { return FLT_MAX; } /** * @brief Prints the properties of the forcing terms to stdout. * * @param terms The #forcing_terms properties of the run. */ static INLINE void forcing_terms_print(const struct forcing_terms *terms) { message("Forcing terms is 'Idealized AGN jet'. Max boundary particle ID: %i.", terms->boundary_particle_max_id); message( "Run with options: Enable fixed position: %i, Enable hydro acceleration: " "%i, Enable grav acceleration: %i", terms->enable_fixed_position, terms->enable_hydro_acceleration, terms->enable_grav_acceleration); } /** * @brief Initialises the forcing term properties * * @param parameter_file The parsed parameter file * @param phys_const Physical constants in internal units * @param us The current internal system of units * @param s The #space object. * @param terms The forcing term properties to initialize */ static INLINE void forcing_terms_init(struct swift_params *parameter_file, const struct phys_const *phys_const, const struct unit_system *us, const struct space *s, struct forcing_terms *terms) { terms->boundary_particle_max_id = parser_get_param_int( parameter_file, "BoundaryParticles:boundary_particle_max_id"); terms->enable_fixed_position = parser_get_opt_param_int( parameter_file, "BoundaryParticles:enable_fixed_position", 0); terms->enable_hydro_acceleration = parser_get_opt_param_int( parameter_file, "BoundaryParticles:enable_hydro_acceleration", 0); terms->enable_grav_acceleration = parser_get_opt_param_int( parameter_file, "BoundaryParticles:enable_grav_acceleration", 0); if ((terms->enable_fixed_position != 0) && (terms->enable_fixed_position != 1)) { error( "BoundaryParticles:enable_fixed_position must be either 0 (false) or 1 " "(true)."); } if (terms->enable_fixed_position) { /* If using fixed boundary particles, both hydro and grav accelerations must * be reset to 0. */ if (terms->enable_hydro_acceleration) { error( "BoundaryParticles:enable_hydro_acceleration must be 0 (false) when " "using fixed boundary particles."); } if (terms->enable_grav_acceleration) { error( "BoundaryParticles:enable_grav_acceleration must be 0 (false) when " "using fixed boundary particles."); } } else { /* If not using fixed boundary particles, hydro and grav accelerations can * be enabled independently. */ if ((terms->enable_hydro_acceleration != 0) && (terms->enable_hydro_acceleration != 1)) { error( "BoundaryParticles:enable_hydro_acceleration must be either 0 " "(false) or 1 (true)."); } if ((terms->enable_grav_acceleration != 0) && (terms->enable_grav_acceleration != 1)) { error( "BoundaryParticles:enable_grav_acceleration must be either 0 (false) " "or 1 (true)."); } } terms->jet_power = parser_get_param_float(parameter_file, "BoundaryParticles:jet_power"); terms->jet_velocity = parser_get_param_float(parameter_file, "BoundaryParticles:jet_velocity"); terms->jet_duration = parser_get_param_float(parameter_file, "BoundaryParticles:jet_duration"); } #endif /* SWIFT_FORCING_IDEALIZED_AGN_JET_H */