/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk)
* 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_DISC_PATCH_H
#define SWIFT_DISC_PATCH_H
/* Config parameters. */
#include
/* Some standard headers. */
#include
#include
/* Local includes. */
#include "error.h"
#include "gravity.h"
#include "minmax.h"
#include "parser.h"
#include "part.h"
#include "physical_constants.h"
#include "space.h"
#include "units.h"
/**
* @brief External Potential Properties - Disc patch case
*
* See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948.
*
* We truncate the accelerations beyond z_trunc using a 1-cos(z) function
* that smoothly brings the accelerations to 0 at z_max.
*/
struct external_potential {
/*! Surface density of the disc (sigma) */
float surface_density;
/*! Disc scale-height (b) */
float scale_height;
/*! Inverse of disc scale-height (1/b) */
float scale_height_inv;
/*! Position of the disc along the x-axis */
float x_disc;
/*! Position above which the accelerations get truncated */
float x_trunc;
/*! Position above which the accelerations are zero */
float x_max;
/*! The truncated transition regime */
float x_trans;
/*! Inverse of the truncated transition regime */
float x_trans_inv;
/*! Dynamical time of the system */
float dynamical_time;
/*! Time over which to grow the disk */
float growth_time;
/*! Inverse of the growth time */
float growth_time_inv;
/*! Time-step condition pre-factor */
float timestep_mult;
/*! Constant pre-factor (2 pi G sigma) */
float norm;
/*! Constant pre-factor (2 pi sigma)*/
float norm_over_G;
};
/**
* @brief Computes the time-step from the acceleration due to a hydrostatic
* disc.
*
* See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948,
* equations 17 and 20.
* We do not use the truncated potential here.
*
* @param time The current time.
* @param potential The properties of the potential.
* @param phys_const The physical constants in internal units.
* @param g Pointer to the g-particle data.
*/
__attribute__((always_inline)) INLINE static float external_gravity_timestep(
double time, const struct external_potential* restrict potential,
const struct phys_const* restrict phys_const,
const struct gpart* restrict g) {
/* initilize time step to disc dynamical time */
const float dt_dyn = potential->dynamical_time;
const float b = potential->scale_height;
const float b_inv = potential->scale_height_inv;
const float norm = potential->norm;
/* absolute value of height above disc */
const float dx = fabs(g->x[0] - potential->x_disc);
/* vertical acceleration */
const float x_accel = norm * tanhf(dx * b_inv);
float dt = dt_dyn;
/* demand that dt * velocity < fraction of scale height of disc */
if (g->v_full[0] != 0.f) {
const float dt1 = b / fabsf(g->v_full[0]);
dt = min(dt1, dt);
}
/* demand that dt^2 * acceleration < fraction of scale height of disc */
if (x_accel != 0.f) {
const float dt2 = b / fabsf(x_accel);
if (dt2 < dt * dt) dt = sqrtf(dt2);
}
/* demand that dt^3 * jerk < fraction of scale height of disc */
if (g->v_full[0] != 0.f) {
const float cosh_dx_inv = 1.f / coshf(dx * b_inv);
const float cosh_dx_inv2 = cosh_dx_inv * cosh_dx_inv;
const float dx_accel_over_dt =
norm * cosh_dx_inv2 * b_inv * fabsf(g->v_full[0]);
const float dt3 = b / fabsf(dx_accel_over_dt);
if (dt3 < dt * dt * dt) dt = cbrtf(dt3);
}
return potential->timestep_mult * dt;
}
/**
* @brief Computes the gravitational acceleration along x due to a hydrostatic
* disc
*
* See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948,
* equation 17.
* We truncate the accelerations beyond x_trunc using a 1-cos(x) function
* that smoothly brings the accelerations to 0 at x_max.
*
* @param time The current time in internal units.
* @param potential The properties of the potential.
* @param phys_const The physical constants in internal units.
* @param g Pointer to the g-particle data.
*/
__attribute__((always_inline)) INLINE static void external_gravity_acceleration(
double time, const struct external_potential* restrict potential,
const struct phys_const* restrict phys_const, struct gpart* restrict g) {
const float dx = g->x[0] - potential->x_disc;
const float abs_dx = fabsf(dx);
const float t_growth = potential->growth_time;
const float t_growth_inv = potential->growth_time_inv;
const float b = potential->scale_height;
const float b_inv = potential->scale_height_inv;
const float x_trunc = potential->x_trunc;
const float x_max = potential->x_max;
const float x_trans_inv = potential->x_trans_inv;
const float norm_over_G = potential->norm_over_G;
/* Are we still growing the disc ? */
const float reduction_factor = time < t_growth ? time * t_growth_inv : 1.f;
/* Truncated or not ? */
float a_x;
float pot;
if (abs_dx < x_trunc) {
/* Acc. 2 pi sigma tanh(x/b) */
a_x = reduction_factor * norm_over_G * tanhf(abs_dx * b_inv);
pot = -reduction_factor * norm_over_G * logf(coshf(abs_dx * b_inv)) * b;
} else if (abs_dx < x_max) {
/* Acc. 2 pi sigma tanh(x/b) [1/2 + 1/2cos((x-xmax)/(pi x_trans))] */
a_x =
reduction_factor * norm_over_G * tanhf(abs_dx * b_inv) *
(0.5f + 0.5f * cosf((float)(M_PI) * (abs_dx - x_trunc) * x_trans_inv));
pot = 0.f;
} else {
/* Acc. 0 */
a_x = 0.f;
pot = 0.f;
}
/* Get the correct sign. Recall G is multipiled in later on */
if (dx > 0) g->a_grav[0] -= a_x;
if (dx < 0) g->a_grav[0] += a_x;
gravity_add_comoving_potential(g, pot);
}
/**
* @brief Computes the gravitational potential energy of a particle in the
* disc patch potential.
*
* See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948,
* equation 22.
* We truncate the accelerations beyond x_trunc using a 1-cos(x) function
* that smoothly brings the accelerations to 0 at x_max.
*
* @param time The current time.
* @param potential The #external_potential used in the run.
* @param phys_const Physical constants in internal units.
* @param gp Pointer to the particle data.
*/
__attribute__((always_inline)) INLINE static float
external_gravity_get_potential_energy(
double time, const struct external_potential* potential,
const struct phys_const* const phys_const, const struct gpart* gp) {
const float dx = gp->x[0] - potential->x_disc;
const float abs_dx = fabsf(dx);
const float t_growth = potential->growth_time;
const float t_growth_inv = potential->growth_time_inv;
const float b = potential->scale_height;
const float b_inv = potential->scale_height_inv;
const float norm = potential->norm;
const float x_trunc = potential->x_trunc;
const float x_max = potential->x_max;
/* Are we still growing the disc ? */
const float reduction_factor = time < t_growth ? time * t_growth_inv : 1.f;
/* Truncated or not ? */
float pot;
if (abs_dx < x_trunc) {
/* Potential (2 pi G sigma b ln(cosh(x/b)) */
pot = b * logf(coshf(dx * b_inv));
} else if (abs_dx < x_max) {
/* Potential. At x>>b, phi(x) = norm * x / b */
pot = 0.f;
} else {
pot = 0.f;
}
return pot * reduction_factor * norm;
}
/**
* @brief Initialises the external potential properties in the internal system
* of units.
*
* See Creasey, Theuns & Bower, 2013, MNRAS, Volume 429, Issue 3, p.1922-1948,
* equation 22.
*
* @param parameter_file The parsed parameter file
* @param phys_const Physical constants in internal units
* @param us The current internal system of units
* @param potential The external potential properties to initialize
*/
static INLINE void potential_init_backend(
struct swift_params* parameter_file, const struct phys_const* phys_const,
const struct unit_system* us, const struct space* s,
struct external_potential* potential) {
potential->surface_density = parser_get_param_double(
parameter_file, "DiscPatchPotential:surface_density");
potential->scale_height = parser_get_param_double(
parameter_file, "DiscPatchPotential:scale_height");
potential->x_disc =
parser_get_param_double(parameter_file, "DiscPatchPotential:x_disc");
potential->x_trunc = parser_get_opt_param_double(
parameter_file, "DiscPatchPotential:x_trunc", FLT_MAX);
potential->x_max = parser_get_opt_param_double(
parameter_file, "DiscPatchPotential:x_max", FLT_MAX);
potential->timestep_mult = parser_get_param_double(
parameter_file, "DiscPatchPotential:timestep_mult");
potential->growth_time = parser_get_opt_param_double(
parameter_file, "DiscPatchPotential:growth_time", 0.);
/* Compute the dynamical time */
potential->dynamical_time =
sqrt(potential->scale_height /
(phys_const->const_newton_G * potential->surface_density));
/* Convert the growth time multiplier to physical time */
potential->growth_time *= potential->dynamical_time;
/* Some cross-checks */
if (potential->x_trunc > potential->x_max)
error("Potential truncation x larger than maximal z");
if (potential->x_trunc < potential->scale_height)
error("Potential truncation x smaller than scale height");
/* Compute derived quantities */
potential->scale_height_inv = 1. / potential->scale_height;
potential->norm =
2. * M_PI * phys_const->const_newton_G * potential->surface_density;
potential->norm_over_G = 2 * M_PI * potential->surface_density;
potential->x_trans = potential->x_max - potential->x_trunc;
if (potential->x_trans != 0.f)
potential->x_trans_inv = 1. / potential->x_trans;
else
potential->x_trans_inv = FLT_MAX;
if (potential->growth_time != 0.)
potential->growth_time_inv = 1. / potential->growth_time;
else
potential->growth_time_inv = FLT_MAX;
}
/**
* @brief Prints the properties of the external potential to stdout.
*
* @param potential The external potential properties.
*/
static INLINE void potential_print_backend(
const struct external_potential* potential) {
message(
"External potential is 'Disk-patch' with Sigma=%f, x_disc=%f, b=%f and "
"dt_mult=%f.",
potential->surface_density, potential->x_disc, potential->scale_height,
potential->timestep_mult);
if (potential->x_max < FLT_MAX)
message("Potential will be truncated at x_trunc=%f and zeroed at x_max=%f",
potential->x_trunc, potential->x_max);
if (potential->growth_time > 0.)
message("Disc will grow for %f [time_units]. (%f dynamical time)",
potential->growth_time,
potential->growth_time / potential->dynamical_time);
}
#endif /* SWIFT_DISC_PATCH_H */