diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 7f8af2fc2679e8bab96f8dd1796794d8dbf6b5fd..8f61a060b37b0e62189160d0a8c61e713cfd3b8f 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -759,7 +759,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = @top_srcdir@ @top_srcdir@/src @top_srcdir@/src/hydro/Default @top_srcdir@/src/gravity/Default +INPUT = @top_srcdir@ @top_srcdir@/src @top_srcdir@/src/hydro/Minimal @top_srcdir@/src/gravity/Default # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/src/Makefile.am b/src/Makefile.am index a20416c617527b5dfbc2dc324539561d78388f4e..573e51ddc00394a27f5b34bb29252e02a25a9401 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,11 +44,13 @@ AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \ kernel.c tools.c part.c # Include files for distribution, not installation. -noinst_HEADERS = atomic.h cycle.h error.h inline.h kernel.h vector.h \ +noinst_HEADERS = approx_math.h atomic.h cycle.h error.h inline.h kernel.h vector.h \ runner_doiact.h runner_doiact_grav.h units.h intrinsics.h \ hydro.h hydro_io.h gravity.h \ gravity/Default/gravity.h gravity/Default/runner_iact_grav.h \ gravity/Default/gravity_part.h + hydro/Minimal/hydro.h hydro/Minimal/hydro_iact.h hydro/Minimal/hydro_io.h \ + hydro/Minimal/hydro_debug.h hydro/Minimal/hydro_part.h hydro/Default/hydro.h hydro/Default/hydro_iact.h hydro/Default/hydro_io.h \ hydro/Default/hydro_debug.h hydro/Default/hydro_part.h \ hydro/Gadget2/hydro.h hydro/Gadget2/hydro_iact.h hydro/Gadget2/hydro_io.h \ diff --git a/src/approx_math.h b/src/approx_math.h new file mode 100644 index 0000000000000000000000000000000000000000..ef93ea63c383c74caa3eaff65446962872389a35 --- /dev/null +++ b/src/approx_math.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 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 <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_APPROX_MATH_H +#define SWIFT_APPROX_MATH_H + +/** + * @brief Approximate version of expf(x) using a 4th order Taylor expansion + * + * The absolute error is of order 10^-6 for -0.2 < x < 0.2. + * + * @param x The number to take the exponential of. + */ +__attribute__((always_inline)) INLINE static float approx_expf(float x) { + return 1.f + x * (1.f + x * (0.5f + x * (1.f / 6.0f + 1.f / 24.0f * x))); +} + +#endif /* SWIFT_APPROX_MATH_H */ diff --git a/src/cell.c b/src/cell.c index f7fe61ba30c7d04362003c495702c9f23a6efbd3..6d84dafdaa4038f6cf30b9198381fab67a8b6b27 100644 --- a/src/cell.c +++ b/src/cell.c @@ -564,6 +564,7 @@ void cell_init_parts(struct cell *c, void *data) { xp[i].v_full[0] = p[i].v[0]; xp[i].v_full[1] = p[i].v[1]; xp[i].v_full[2] = p[i].v[2]; + hydro_first_init_part(&p[i], &xp[i]); hydro_init_part(&p[i]); hydro_reset_acceleration(&p[i]); } diff --git a/src/cell.h b/src/cell.h index e821d0438f96a7dbc20db6da78d00cf48c4c85cc..0ba63d1f037167e49130af64acc05ea1c879b95d 100644 --- a/src/cell.h +++ b/src/cell.h @@ -136,8 +136,8 @@ struct cell { /* Momentum of particles in cell. */ float mom[3], ang[3]; - /* Potential and kinetic energy of particles in this cell. */ - double epot, ekin; + /* Mass, potential, internal and kinetic energy of particles in this cell. */ + double mass, e_pot, e_int, e_kin; /* Number of particles updated in this cell. */ int updated; diff --git a/src/common_io.c b/src/common_io.c index b7a9a887e450b3fcc664650688a19910efcfab3d..7059f1e813d6cdaf6afd1e637a826292674a51fe 100644 --- a/src/common_io.c +++ b/src/common_io.c @@ -267,59 +267,6 @@ void writeAttribute_s(hid_t grp, char* name, const char* str) { writeStringAttribute(grp, name, str, strlen(str)); } -/* ------------------------------------------------------------------------------------------------ - * This part writes the XMF file descriptor enabling a visualisation through - * ParaView - * ------------------------------------------------------------------------------------------------ - */ -/** - * @brief Writes the current model of SPH to the file - * @param h_file The (opened) HDF5 file in which to write - */ -void writeSPHflavour(hid_t h_file) { - hid_t h_grpsph = 0; - - h_grpsph = H5Gcreate1(h_file, "/SPH", 0); - if (h_grpsph < 0) error("Error while creating SPH group"); - - writeAttribute_f(h_grpsph, "Kernel eta", const_eta_kernel); - writeAttribute_f(h_grpsph, "Weighted N_ngb", kernel_nwneigh); - writeAttribute_f(h_grpsph, "Delta N_ngb", const_delta_nwneigh); - writeAttribute_f(h_grpsph, "Hydro gamma", const_hydro_gamma); - -#ifdef LEGACY_GADGET2_SPH - writeAttribute_s(h_grpsph, "Thermal Conductivity Model", - "(No treatment) Legacy Gadget-2 as in Springel (2005)"); - writeAttribute_s(h_grpsph, "Viscosity Model", - "Legacy Gadget-2 as in Springel (2005)"); - writeAttribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha); - writeAttribute_f(h_grpsph, "Viscosity beta", 3.f); -#else - writeAttribute_s(h_grpsph, "Thermal Conductivity Model", - "Price (2008) without switch"); - writeAttribute_f(h_grpsph, "Thermal Conductivity alpha", - const_conductivity_alpha); - writeAttribute_s(h_grpsph, "Viscosity Model", - "Morris & Monaghan (1997), Rosswog, Davies, Thielemann & " - "Piran (2000) with additional Balsara (1995) switch"); - writeAttribute_f(h_grpsph, "Viscosity alpha_min", const_viscosity_alpha_min); - writeAttribute_f(h_grpsph, "Viscosity alpha_max", const_viscosity_alpha_max); - writeAttribute_f(h_grpsph, "Viscosity beta", 2.f); - writeAttribute_f(h_grpsph, "Viscosity decay length", const_viscosity_length); -#endif - - writeAttribute_f(h_grpsph, "CFL parameter", const_cfl); - writeAttribute_f(h_grpsph, "Maximal ln(Delta h) change over dt", - const_ln_max_h_change); - writeAttribute_f(h_grpsph, "Maximal Delta h change over dt", - exp(const_ln_max_h_change)); - writeAttribute_f(h_grpsph, "Maximal Delta u change over dt", - const_max_u_change); - writeAttribute_s(h_grpsph, "Kernel", kernel_name); - - H5Gclose(h_grpsph); -} - /** * @brief Writes the current Unit System * @param h_file The (opened) HDF5 file in which to write @@ -372,6 +319,12 @@ void writeCodeDescription(hid_t h_file) { H5Gclose(h_grpcode); } +/* ------------------------------------------------------------------------------------------------ + * This part writes the XMF file descriptor enabling a visualisation through + * ParaView + * ------------------------------------------------------------------------------------------------ + */ + /** * @brief Prepares the XMF file for the new entry * diff --git a/src/const.h b/src/const.h index 01326e3a22b3f608dfa9c0cf25a1dffe41697edc..3bd9edff8227a87d040ec7309998364c946307af 100644 --- a/src/const.h +++ b/src/const.h @@ -38,7 +38,7 @@ 1.f /* Value taken from (Price,2008), not used in legacy gadget mode */ /* Time integration constants. */ -#define const_cfl 0.2f +#define const_cfl 0.1f #define const_ln_max_h_change \ 0.231111721f /* Particle can't change volume by more than a factor of \ 2=1.26^3 over one time step */ @@ -55,7 +55,7 @@ #define const_theta_max \ 0.57735f /* Opening criteria, which is the ratio of the \ cell distance over the cell width. */ -// #define const_G 6.67384e-8f /* Gravitational constant. */ + #define const_G 6.672e-8f /* Gravitational constant. */ #define const_epsilon 0.0014f /* Gravity blending distance. */ #define const_iepsilon 714.285714286f /* Inverse gravity blending distance. */ @@ -66,7 +66,9 @@ #define const_iepsilon6 (const_iepsilon3* const_iepsilon3) /* SPH variant to use */ -#define LEGACY_GADGET2_SPH +//#define MINIMAL_SPH +#define GADGET2_SPH +//#define DEFAULT_SPH /* System of units */ #define const_unit_length_in_cgs 1 /* 3.08567810e16 /\* 1Mpc *\/ */ diff --git a/src/debug.c b/src/debug.c index 3efca024d10030c3bf4a9c0f9861ec0dc2f07310..2be981175eabe41a8a7e57aec4261a9b38def6ac 100644 --- a/src/debug.c +++ b/src/debug.c @@ -28,10 +28,14 @@ #include "debug.h" /* Import the right hydro definition */ -#ifdef LEGACY_GADGET2_SPH +#if defined(MINIMAL_SPH) +#include "./hydro/Minimal/hydro_debug.h" +#elif defined(GADGET2_SPH) #include "./hydro/Gadget2/hydro_debug.h" -#else +#elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_debug.h" +#else +#error "Invalid choice of SPH variant" #endif /** diff --git a/src/engine.c b/src/engine.c index 4fd9fff3ca6eb9346a47f6b4a2b4bc1c5e39b09f..2cca53610c88459e0a076b246645dd4ad998d666 100644 --- a/src/engine.c +++ b/src/engine.c @@ -1616,41 +1616,51 @@ void engine_barrier(struct engine *e, int tid) { void engine_collect_kick(struct cell *c) { - int k, updated = 0; + int updated = 0; float t_end_min = FLT_MAX, t_end_max = 0.0f; - double ekin = 0.0, epot = 0.0; + double e_kin = 0.0, e_int = 0.0, e_pot = 0.0; float mom[3] = {0.0f, 0.0f, 0.0f}, ang[3] = {0.0f, 0.0f, 0.0f}; struct cell *cp; - /* If I am a super-cell, return immediately. */ - if (c->kick != NULL || c->count == 0) return; - - /* If this cell is not split, I'm in trouble. */ - if (!c->split) error("Cell has no super-cell."); - - /* Collect the values from the progeny. */ - for (k = 0; k < 8; k++) - if ((cp = c->progeny[k]) != NULL) { - engine_collect_kick(cp); - t_end_min = fminf(t_end_min, cp->t_end_min); - t_end_max = fmaxf(t_end_max, cp->t_end_max); - updated += cp->updated; - ekin += cp->ekin; - epot += cp->epot; - mom[0] += cp->mom[0]; - mom[1] += cp->mom[1]; - mom[2] += cp->mom[2]; - ang[0] += cp->ang[0]; - ang[1] += cp->ang[1]; - ang[2] += cp->ang[2]; - } + /* Skip super-cells (Their values are already set) */ + if (c->kick != NULL) return; + + /* Only do something is the cell is non-empty */ + if (c->count != 0) { + + /* If this cell is not split, I'm in trouble. */ + if (!c->split) error("Cell has no super-cell."); + + /* Collect the values from the progeny. */ + for (int k = 0; k < 8; k++) + if ((cp = c->progeny[k]) != NULL) { + + /* Recurse */ + engine_collect_kick(cp); + + /* And update */ + t_end_min = fminf(t_end_min, cp->t_end_min); + t_end_max = fmaxf(t_end_max, cp->t_end_max); + updated += cp->updated; + e_kin += cp->e_kin; + e_int += cp->e_int; + e_pot += cp->e_pot; + mom[0] += cp->mom[0]; + mom[1] += cp->mom[1]; + mom[2] += cp->mom[2]; + ang[0] += cp->ang[0]; + ang[1] += cp->ang[1]; + ang[2] += cp->ang[2]; + } + } /* Store the collected values in the cell. */ c->t_end_min = t_end_min; c->t_end_max = t_end_max; c->updated = updated; - c->ekin = ekin; - c->epot = epot; + c->e_kin = e_kin; + c->e_int = e_int; + c->e_pot = e_pot; c->mom[0] = mom[0]; c->mom[1] = mom[1]; c->mom[2] = mom[2]; @@ -1709,12 +1719,12 @@ void engine_init_particles(struct engine *e) { message("Initialising particles"); + engine_prepare(e); + /* Make sure all particles are ready to go */ /* i.e. clean-up any stupid state in the ICs */ space_map_cells_pre(s, 1, cell_init_parts, NULL); - engine_prepare(e); - engine_marktasks(e); // printParticle(e->s->parts, 1000, e->s->nr_parts); @@ -1766,8 +1776,9 @@ void engine_init_particles(struct engine *e) { engine_launch(e, e->nr_threads, mask, submask); TIMER_TOC(timer_runners); - // message("\n0th ENTROPY CONVERSION\n"); +// message("\n0th ENTROPY CONVERSION\n") + /* Apply some conversions (e.g. internal energy -> entropy) */ space_map_cells_pre(s, 1, cell_convert_hydro, NULL); // printParticle(e->s->parts, e->s->xparts,1000, e->s->nr_parts); @@ -1787,7 +1798,7 @@ void engine_step(struct engine *e) { int k; int updates = 0; float t_end_min = FLT_MAX, t_end_max = 0.f; - double epot = 0.0, ekin = 0.0; + double e_pot = 0.0, e_int = 0.0, e_kin = 0.0; float mom[3] = {0.0, 0.0, 0.0}; float ang[3] = {0.0, 0.0, 0.0}; struct cell *c; @@ -1799,11 +1810,16 @@ void engine_step(struct engine *e) { for (k = 0; k < s->nr_cells; k++) if (s->cells[k].nodeID == e->nodeID) { c = &s->cells[k]; + + /* Recurse */ engine_collect_kick(c); + + /* And aggregate */ t_end_min = fminf(t_end_min, c->t_end_min); t_end_max = fmaxf(t_end_max, c->t_end_max); - ekin += c->ekin; - epot += c->epot; + e_kin += c->e_kin; + e_int += c->e_int; + e_pot += c->e_pot; updates += c->updated; mom[0] += c->mom[0]; mom[1] += c->mom[1]; @@ -1815,7 +1831,7 @@ void engine_step(struct engine *e) { /* Aggregate the data from the different nodes. */ #ifdef WITH_MPI - double in[3], out[3]; + double in[4], out[4]; out[0] = t_end_min; if (MPI_Allreduce(out, in, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD) != MPI_SUCCESS) @@ -1827,20 +1843,16 @@ void engine_step(struct engine *e) { error("Failed to aggregate t_end_max."); t_end_max = in[0]; out[0] = updates; - out[1] = ekin; - out[2] = epot; + out[1] = e_kin; + out[2] = e_int; + out[3] = e_pot; if (MPI_Allreduce(out, in, 3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD) != MPI_SUCCESS) error("Failed to aggregate energies."); updates = in[0]; - ekin = in[1]; - epot = in[2]; -/* int nr_parts; -if ( MPI_Allreduce( &s->nr_parts , &nr_parts , 1 , MPI_INT , MPI_SUM , -MPI_COMM_WORLD ) != MPI_SUCCESS ) - error( "Failed to aggregate particle count." ); -if ( e->nodeID == 0 ) - message( "nr_parts=%i." , nr_parts ); */ + e_kin = in[1]; + e_int = in[2]; + e_pot = in[3]; #endif // message("\nDRIFT\n"); @@ -1916,9 +1928,17 @@ if ( e->nodeID == 0 ) TIMER_TOC2(timer_step); if (e->nodeID == 0) { + + /* Print some information to the screen */ printf("%d %f %f %d %.3f\n", e->step, e->time, e->timeStep, updates, ((double)timers[timer_count - 1]) / CPU_TPS * 1000); fflush(stdout); + + /* Write some energy statistics */ + fprintf(e->file_stats, "%d %f %f %f %f %f %f %f %f %f %f %f\n", e->step, + e->time, e_kin, e_int, e_pot, e_kin + e_int + e_pot, mom[0], mom[1], + mom[2], ang[0], ang[1], ang[2]); + fflush(e->file_stats); } // printParticle(e->s->parts, e->s->xparts,1000, e->s->nr_parts); @@ -2211,6 +2231,7 @@ void engine_init(struct engine *e, struct space *s, float dt, int nr_threads, e->timeStep = 0.; e->dt_min = dt_min; e->dt_max = dt_max; + e->file_stats = NULL; engine_rank = nodeID; /* Make the space link back to the engine. */ @@ -2230,6 +2251,14 @@ void engine_init(struct engine *e, struct space *s, float dt, int nr_threads, #endif } + /* Open some files */ + if (e->nodeID == 0) { + e->file_stats = fopen("energy.txt", "w"); + fprintf(e->file_stats, + "# Step Time E_kin E_int E_pot E_tot " + "p_x p_y p_z ang_x ang_y ang_z\n"); + } + /* Print policy */ engine_print_policy(e); diff --git a/src/engine.h b/src/engine.h index 4540a737d39c37133ea515bfbace78143b4ed1d3..46c89a331f1bdf834cf512708503c98fd78b18b9 100644 --- a/src/engine.h +++ b/src/engine.h @@ -29,6 +29,7 @@ /* Some standard headers. */ #include <pthread.h> +#include <stdio.h> /* Includes. */ #include "lock.h" @@ -112,8 +113,8 @@ struct engine { /* Time step */ float timeStep; - /* The system energies from the previous step. */ - double ekin, epot; + /* File for statistics */ + FILE *file_stats; /* The current step number. */ int step, nullstep; diff --git a/src/hydro.h b/src/hydro.h index c57c60d696105c94af70ad1b24fce197163ce698..4b131ea7bb65302aaa69503130f7429710dc221f 100644 --- a/src/hydro.h +++ b/src/hydro.h @@ -22,12 +22,17 @@ #include "./const.h" /* Import the right functions */ -#ifdef LEGACY_GADGET2_SPH -#include "./hydro/Gadget2/hydro.h" +#if defined(MINIMAL_SPH) +#include "./hydro/Minimal/hydro_iact.h" +#include "./hydro/Minimal/hydro.h" +#elif defined(GADGET2_SPH) #include "./hydro/Gadget2/hydro_iact.h" -#else -#include "./hydro/Default/hydro.h" +#include "./hydro/Gadget2/hydro.h" +#elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_iact.h" +#include "./hydro/Default/hydro.h" +#else +#error "Invalid choice of SPH variant" #endif -#endif +#endif /* SWIFT_HYDRO_H */ diff --git a/src/hydro/Default/hydro.h b/src/hydro/Default/hydro.h index 3215390e83db1e5f134768211c52d2dec32cecad..466bc72757be625ab71c90003269823845733291 100644 --- a/src/hydro/Default/hydro.h +++ b/src/hydro/Default/hydro.h @@ -28,19 +28,27 @@ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( struct part* p, struct xpart* xp) { /* CFL condition */ - float dt_cfl = const_cfl * p->h / p->force.v_sig; - - /* Limit change in h */ - float dt_h_change = (p->force.h_dt != 0.0f) - ? fabsf(const_ln_max_h_change * p->h / p->force.h_dt) - : FLT_MAX; + const float dt_cfl = 2.f * const_cfl * kernel_gamma * p->h / p->force.v_sig; /* Limit change in u */ - float dt_u_change = (p->force.u_dt != 0.0f) - ? fabsf(const_max_u_change * p->u / p->force.u_dt) - : FLT_MAX; + const float dt_u_change = + (p->force.u_dt != 0.0f) ? fabsf(const_max_u_change * p->u / p->force.u_dt) + : FLT_MAX; - return fminf(dt_cfl, fminf(dt_h_change, dt_u_change)); + return fminf(dt_cfl, dt_u_change); +} + +/** + * @brief Initialises the particles for the first time + * + * This function is called only once just after the ICs have been + * read in to do some conversions. + * + * @param p The particle to act upon + * @param xp The extended particle data to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_first_init_part(struct part* p, struct xpart* xp) { } /** @@ -97,9 +105,10 @@ __attribute__((always_inline)) * * @param p The particle to act upon * @param xp The extended particle data to act upon + * @param time The current time */ -__attribute__((always_inline)) - INLINE static void hydro_prepare_force(struct part* p, struct xpart* xp) { +__attribute__((always_inline)) INLINE static void hydro_prepare_force( + struct part* p, struct xpart* xp, float time) { /* Some smoothing length multiples. */ const float h = p->h; @@ -152,13 +161,13 @@ __attribute__((always_inline)) INLINE static void hydro_reset_acceleration(struct part* p) { /* Reset the acceleration. */ - p->a[0] = 0.0f; - p->a[1] = 0.0f; - p->a[2] = 0.0f; + p->a_hydro[0] = 0.0f; + p->a_hydro[1] = 0.0f; + p->a_hydro[2] = 0.0f; /* Reset the time derivatives. */ p->force.u_dt = 0.0f; - p->force.h_dt = 0.0f; + p->h_dt = 0.0f; p->force.v_sig = 0.0f; } @@ -196,19 +205,18 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( * @param p The particle to act upon */ __attribute__((always_inline)) - INLINE static void hydro_end_force(struct part* p) { - - p->force.h_dt *= p->h * 0.333333333f; -} + INLINE static void hydro_end_force(struct part* p) {} /** * @brief Kick the additional variables * * @param p The particle to act upon + * @param xp The particle extended data to act upon * @param dt The time-step for this kick + * @param half_dt The half time-step for this kick */ -__attribute__((always_inline)) - INLINE static void hydro_kick_extra(struct part* p, float dt) {} +__attribute__((always_inline)) INLINE static void hydro_kick_extra( + struct part* p, struct xpart* xp, float dt, float half_dt) { } /** * @brief Converts hydro quantity of a particle @@ -219,3 +227,14 @@ __attribute__((always_inline)) */ __attribute__((always_inline)) INLINE static void hydro_convert_quantities(struct part* p) {} + +/** + * @brief Returns the internal energy of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) + INLINE static float hydro_get_internal_energy(struct part* p) { + + return p->u; +} diff --git a/src/hydro/Default/hydro_debug.h b/src/hydro/Default/hydro_debug.h index 36eb75ae60e7a49ae798c232377985dd90cff54a..5b1648e222c36dc142362f26ad5188a2af397192 100644 --- a/src/hydro/Default/hydro_debug.h +++ b/src/hydro/Default/hydro_debug.h @@ -25,6 +25,7 @@ __attribute__((always_inline)) "h=%.3e, " "wcount=%d, m=%.3e, dh_drho=%.3e, rho=%.3e, t_begin=%.3e, t_end=%.3e\n", p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], xp->v_full[0], - xp->v_full[1], xp->v_full[2], p->a[0], p->a[1], p->a[2], 2. * p->h, - (int)p->density.wcount, p->mass, p->rho_dh, p->rho, p->t_begin, p->t_end); + xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], + p->h, (int)p->density.wcount, p->mass, p->rho_dh, p->rho, p->t_begin, + p->t_end); } diff --git a/src/hydro/Default/hydro_iact.h b/src/hydro/Default/hydro_iact.h index 95342cd852ff359f23fdec755df8df65b41a2ce0..b5b631501b2f9c398cf1f7e5ee32fd5c962ba86e 100644 --- a/src/hydro/Default/hydro_iact.h +++ b/src/hydro/Default/hydro_iact.h @@ -432,8 +432,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( /* Use the force, Luke! */ for (k = 0; k < 3; k++) { f = dx[k] * w; - pi->a[k] -= mj * f; - pj->a[k] += mi * f; + pi->a_hydro[k] -= mj * f; + pj->a_hydro[k] += mi * f; } /* Get the time derivative for u. */ @@ -447,8 +447,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( pj->force.u_dt += mi * tc * (pj->u - pi->u); /* Get the time derivative for h. */ - pi->force.h_dt -= mj * dvdr / rhoj * wi_dr; - pj->force.h_dt -= mi * dvdr / rhoi * wj_dr; + pi->h_dt -= mj * dvdr / rhoj * wi_dr; + pj->h_dt -= mi * dvdr / rhoi * wj_dr; /* Update the signal velocity. */ pi->force.v_sig = fmaxf(pi->force.v_sig, v_sig); @@ -656,8 +656,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_vec_force( for (k = 0; k < VEC_SIZE; k++) { pi[k]->force.u_dt += piu_dt.f[k]; pj[k]->force.u_dt += pju_dt.f[k]; - pi[k]->force.h_dt -= pih_dt.f[k]; - pj[k]->force.h_dt -= pjh_dt.f[k]; + pi[k]->h_dt -= pih_dt.f[k]; + pj[k]->h_dt -= pjh_dt.f[k]; pi[k]->force.v_sig = vi_sig.f[k]; pj[k]->force.v_sig = vj_sig.f[k]; for (j = 0; j < 3; j++) { @@ -747,7 +747,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Use the force, Luke! */ for (k = 0; k < 3; k++) { f = dx[k] * w; - pi->a[k] -= mj * f; + pi->a_hydro[k] -= mj * f; } /* Get the time derivative for u. */ @@ -758,7 +758,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->force.u_dt += mj * tc * (pi->u - pj->u); /* Get the time derivative for h. */ - pi->force.h_dt -= mj * dvdr / rhoj * wi_dr; + pi->h_dt -= mj * dvdr / rhoj * wi_dr; /* Update the signal velocity. */ pi->force.v_sig = fmaxf(pi->force.v_sig, v_sig); @@ -957,7 +957,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_vec_force( /* Store the forces back on the particles. */ for (k = 0; k < VEC_SIZE; k++) { pi[k]->force.u_dt += piu_dt.f[k]; - pi[k]->force.h_dt -= pih_dt.f[k]; + pi[k]->h_dt -= pih_dt.f[k]; pi[k]->force.v_sig = vi_sig.f[k]; pj[k]->force.v_sig = vj_sig.f[k]; for (j = 0; j < 3; j++) pi[k]->a[j] -= pia[j].f[k]; diff --git a/src/hydro/Default/hydro_io.h b/src/hydro/Default/hydro_io.h index fa25a600fd9c928eb27ce93d39d54f1af324df9e..958bf5a1869718b57678246ff3b1985e54145824 100644 --- a/src/hydro/Default/hydro_io.h +++ b/src/hydro/Default/hydro_io.h @@ -45,7 +45,7 @@ __attribute__((always_inline)) INLINE static void hydro_read_particles( COMPULSORY); readArray(h_grp, "ParticleIDs", ULONGLONG, N, 1, parts, N_total, offset, id, COMPULSORY); - readArray(h_grp, "Acceleration", FLOAT, N, 3, parts, N_total, offset, a, + readArray(h_grp, "Acceleration", FLOAT, N, 3, parts, N_total, offset, a_hydro, OPTIONAL); readArray(h_grp, "Density", FLOAT, N, 1, parts, N_total, offset, rho, OPTIONAL); @@ -84,7 +84,43 @@ __attribute__((always_inline)) INLINE static void hydro_write_particles( writeArray(h_grp, fileName, xmfFile, "ParticleIDs", ULONGLONG, N, 1, parts, N_total, mpi_rank, offset, id, us, UNIT_CONV_NO_UNITS); writeArray(h_grp, fileName, xmfFile, "Acceleration", FLOAT, N, 3, parts, - N_total, mpi_rank, offset, a, us, UNIT_CONV_ACCELERATION); + N_total, mpi_rank, offset, a_hydro, us, UNIT_CONV_ACCELERATION); writeArray(h_grp, fileName, xmfFile, "Density", FLOAT, N, 1, parts, N_total, mpi_rank, offset, rho, us, UNIT_CONV_DENSITY); } + +/** + * @brief Writes the current model of SPH to the file + * @param h_grpsph The HDF5 group in which to write + */ +void writeSPHflavour(hid_t h_grpsph) { + + /* Kernel function description */ + writeAttribute_s(h_grpsph, "Kernel", kernel_name); + writeAttribute_f(h_grpsph, "Kernel eta", const_eta_kernel); + writeAttribute_f(h_grpsph, "Weighted N_ngb", kernel_nwneigh); + writeAttribute_f(h_grpsph, "Delta N_ngb", const_delta_nwneigh); + writeAttribute_f(h_grpsph, "Hydro gamma", const_hydro_gamma); + + /* Viscosity and thermal conduction */ + writeAttribute_s(h_grpsph, "Thermal Conductivity Model", + "Price (2008) without switch"); + writeAttribute_f(h_grpsph, "Thermal Conductivity alpha", + const_conductivity_alpha); + writeAttribute_s(h_grpsph, "Viscosity Model", + "Morris & Monaghan (1997), Rosswog, Davies, Thielemann & " + "Piran (2000) with additional Balsara (1995) switch"); + writeAttribute_f(h_grpsph, "Viscosity alpha_min", const_viscosity_alpha_min); + writeAttribute_f(h_grpsph, "Viscosity alpha_max", const_viscosity_alpha_max); + writeAttribute_f(h_grpsph, "Viscosity beta", 2.f); + writeAttribute_f(h_grpsph, "Viscosity decay length", const_viscosity_length); + + /* Time integration properties */ + writeAttribute_f(h_grpsph, "CFL parameter", const_cfl); + writeAttribute_f(h_grpsph, "Maximal ln(Delta h) change over dt", + const_ln_max_h_change); + writeAttribute_f(h_grpsph, "Maximal Delta h change over dt", + exp(const_ln_max_h_change)); + writeAttribute_f(h_grpsph, "Maximal Delta u change over dt", + const_max_u_change); +} diff --git a/src/hydro/Default/hydro_part.h b/src/hydro/Default/hydro_part.h index 6bfe81822f1519b1239428234a72a48868cf170e..b84fc2700b353e1aadc597b6fa7fe1e30676a26d 100644 --- a/src/hydro/Default/hydro_part.h +++ b/src/hydro/Default/hydro_part.h @@ -17,10 +17,7 @@ * ******************************************************************************/ -/* Some standard headers. */ -#include <stdlib.h> - -/* Extra particle data not needed during the computation. */ +/* Extra particle data not needed during the SPH loops over neighbours. */ struct xpart { /* Old position, at last tree rebuild. */ @@ -29,9 +26,6 @@ struct xpart { /* Velocity at the last full step. */ float v_full[3]; - /* Entropy at the half-step. */ - float u_hdt; - /* Old density. */ float omega; @@ -47,11 +41,14 @@ struct part { float v[3]; /* Particle acceleration. */ - float a[3]; + float a_hydro[3]; /* Particle cutoff radius. */ float h; + /* Change in smoothing length over time. */ + float h_dt; + /* Particle time of beginning of time-step. */ float t_begin; @@ -101,9 +98,6 @@ struct part { /* Change in particle energy over time. */ float u_dt; - /* Change in smoothing length over time. */ - float h_dt; - /* Signal velocity */ float v_sig; diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h index 7ac07f499e1b1997f07dde6361d9f80c4c42ba1e..5194bccc6c3534c9ac896cf97e4cf503b6718273 100644 --- a/src/hydro/Gadget2/hydro.h +++ b/src/hydro/Gadget2/hydro.h @@ -28,17 +28,32 @@ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( struct part* p, struct xpart* xp) { /* Acceleration */ - float ac = sqrtf(p->a[0] * p->a[0] + p->a[1] * p->a[1] + p->a[2] * p->a[2]); + float ac = + sqrtf(p->a_hydro[0] * p->a_hydro[0] + p->a_hydro[1] * p->a_hydro[1] + + p->a_hydro[2] * p->a_hydro[2]); ac = fmaxf(ac, 1e-30); const float dt_accel = sqrtf(2.f); // MATTHIEU /* CFL condition */ - const float dt_cfl = 2.f * const_cfl * p->h / p->v_sig; + const float dt_cfl = 2.f * const_cfl * kernel_gamma * p->h / p->force.v_sig; return fminf(dt_cfl, dt_accel); } +/** + * @brief Initialises the particles for the first time + * + * This function is called only once just after the ICs have been + * read in to do some conversions. + * + * @param p The particle to act upon + * @param xp The extended particle data to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_first_init_part(struct part* p, struct xpart* xp) { +} + /** * @brief Prepares a particle for the density calculation. * @@ -54,10 +69,9 @@ __attribute__((always_inline)) p->rho = 0.f; p->rho_dh = 0.f; p->div_v = 0.f; - p->curl_v = 0.f; - p->rot_v[0] = 0.f; - p->rot_v[1] = 0.f; - p->rot_v[2] = 0.f; + p->density.rot_v[0] = 0.f; + p->density.rot_v[1] = 0.f; + p->density.rot_v[2] = 0.f; } /** @@ -86,29 +100,21 @@ __attribute__((always_inline)) /* Finish the calculation by inserting the missing h-factors */ p->rho *= ih * ih2; p->rho_dh *= ih4; - p->density.wcount *= (4.0f / 3.0 * M_PI * kernel_gamma3); - p->density.wcount_dh *= ih * (4.0f / 3.0 * M_PI * kernel_gamma3); + p->density.wcount *= (4.0f / 3.0f * M_PI * kernel_gamma3); + p->density.wcount_dh *= ih * (4.0f / 3.0f * M_PI * kernel_gamma3); - /* Compute the derivative term */ - p->rho_dh = 1.f / (1.f + 0.33333333f * p->h * p->rho_dh / p->rho); + const float irho = 1.f / p->rho; - /* Finish calculation of the velocity curl */ - p->rot_v[0] *= ih4; - p->rot_v[1] *= ih4; - p->rot_v[2] *= ih4; + /* Compute the derivative term */ + p->rho_dh = 1.f / (1.f + 0.33333333f * p->h * p->rho_dh * irho); - /* And compute the norm of the curl */ - p->curl_v = sqrtf(p->rot_v[0] * p->rot_v[0] + p->rot_v[1] * p->rot_v[1] + - p->rot_v[2] * p->rot_v[2]) / - p->rho; + /* Finish calculation of the velocity curl components */ + p->density.rot_v[0] *= ih4 * irho; + p->density.rot_v[1] *= ih4 * irho; + p->density.rot_v[2] *= ih4 * irho; /* Finish calculation of the velocity divergence */ - p->div_v *= ih4 / p->rho; - - /* Compute the pressure */ - const float dt = time - 0.5f * (p->t_begin + p->t_end); - p->pressure = - (p->entropy + p->entropy_dt * dt) * powf(p->rho, const_hydro_gamma); + p->div_v *= ih4 * irho; } /** @@ -118,38 +124,23 @@ __attribute__((always_inline)) * * @param p The particle to act upon * @param xp The extended particle data to act upon + * @param time The current time */ -__attribute__((always_inline)) - INLINE static void hydro_prepare_force(struct part* p, struct xpart* xp) { +__attribute__((always_inline)) INLINE static void hydro_prepare_force( + struct part* p, struct xpart* xp, float time) { - /* Some smoothing length multiples. */ - /* const float h = p->h; */ - /* const float ih = 1.0f / h; */ - /* const float ih2 = ih * ih; */ - /* const float ih4 = ih2 * ih2; */ - - /* /\* Pre-compute some stuff for the balsara switch. *\/ */ - /* const float normDiv_v = fabs(p->density.div_v / p->rho * ih4); */ - /* const float normCurl_v = sqrtf(p->density.curl_v[0] * p->density.curl_v[0] - * + */ - /* p->density.curl_v[1] * p->density.curl_v[1] + - */ - /* p->density.curl_v[2] * p->density.curl_v[2]) / - */ - /* p->rho * ih4; */ - - /* /\* Compute this particle's sound speed. *\/ */ - /* const float u = p->u; */ - /* const float fc = p->force.c = */ - /* sqrtf(const_hydro_gamma * (const_hydro_gamma - 1.0f) * u); */ - - /* /\* Compute the P/Omega/rho2. *\/ */ - /* xp->omega = 1.0f + 0.3333333333f * h * p->rho_dh / p->rho; */ - /* p->force.POrho2 = u * (const_hydro_gamma - 1.0f) / (p->rho * xp->omega); */ - - /* /\* Balsara switch *\/ */ - /* p->force.balsara = */ - /* normDiv_v / (normDiv_v + normCurl_v + 0.0001f * fc * ih); */ + /* Compute the norm of the curl */ + p->force.curl_v = sqrtf(p->density.rot_v[0] * p->density.rot_v[0] + + p->density.rot_v[1] * p->density.rot_v[1] + + p->density.rot_v[2] * p->density.rot_v[2]); + + /* Compute the pressure */ + const float dt = time - 0.5f * (p->t_begin + p->t_end); + p->force.pressure = + (p->entropy + p->entropy_dt * dt) * powf(p->rho, const_hydro_gamma); + + /* Compute the sound speed */ + p->force.soundspeed = sqrtf(const_hydro_gamma * p->force.pressure / p->rho); } /** @@ -164,15 +155,17 @@ __attribute__((always_inline)) INLINE static void hydro_reset_acceleration(struct part* p) { /* Reset the acceleration. */ - p->a[0] = 0.0f; - p->a[1] = 0.0f; - p->a[2] = 0.0f; + p->a_hydro[0] = 0.0f; + p->a_hydro[1] = 0.0f; + p->a_hydro[2] = 0.0f; + + p->h_dt = 0.0f; /* Reset the time derivatives. */ p->entropy_dt = 0.0f; /* Reset maximal signal velocity */ - p->v_sig = 0.0f; + p->force.v_sig = 0.0f; } /** @@ -186,14 +179,13 @@ __attribute__((always_inline)) __attribute__((always_inline)) INLINE static void hydro_predict_extra( struct part* p, struct xpart* xp, float t0, float t1) { - const float dt = t1 - t0; - - p->rho *= expf(-p->div_v * dt); - p->h *= expf(0.33333333f * p->div_v * dt); - + /* Drift the pressure */ const float dt_entr = t1 - 0.5f * (p->t_begin + p->t_end); - p->pressure = + p->force.pressure = (p->entropy + p->entropy_dt * dt_entr) * powf(p->rho, const_hydro_gamma); + + /* Compute the new sound speed */ + p->force.soundspeed = sqrtf(const_hydro_gamma * p->force.pressure / p->rho); } /** @@ -214,9 +206,12 @@ __attribute__((always_inline)) * @brief Kick the additional variables * * @param p The particle to act upon + * @param xp The particle extended data to act upon + * @param dt The time-step for this kick + * @param half_dt The half time-step for this kick */ -__attribute__((always_inline)) - INLINE static void hydro_kick_extra(struct part* p, float dt) { +__attribute__((always_inline)) INLINE static void hydro_kick_extra( + struct part* p, struct xpart* xp, float dt, float half_dt) { /* Do not decrease the entropy (temperature) by more than a factor of 2*/ const float entropy_change = p->entropy_dt * dt; @@ -243,3 +238,15 @@ __attribute__((always_inline)) p->entropy = (const_hydro_gamma - 1.f) * p->entropy * powf(p->rho, -(const_hydro_gamma - 1.f)); } + +/** + * @brief Returns the internal energy of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) + INLINE static float hydro_get_internal_energy(struct part* p) { + + return p->entropy * powf(p->rho, const_hydro_gamma - 1.f) * + (1.f / (const_hydro_gamma - 1.f)); +} diff --git a/src/hydro/Gadget2/hydro_debug.h b/src/hydro/Gadget2/hydro_debug.h index 3d17c4f94191cec37521f7f1fd4aa1716c8f5fc2..5ac83e227c3b59595a045ea9fb0474671ee5df92 100644 --- a/src/hydro/Gadget2/hydro_debug.h +++ b/src/hydro/Gadget2/hydro_debug.h @@ -24,12 +24,13 @@ __attribute__((always_inline)) "v=[%.3e,%.3e,%.3e],v_full=[%.3e,%.3e,%.3e] \n a=[%.3e,%.3e,%.3e],\n " "h=%.3e, " "wcount=%d, m=%.3e, dh_drho=%.3e, rho=%.3e, P=%.3e, S=%.3e, " - "dS/dt=%.3e,\n" + "dS/dt=%.3e, c=%.3e\n" "divV=%.3e, curlV=%.3e, rotV=[%.3e,%.3e,%.3e] \n " - "v_sig=%e t_begin=%.3e, t_end=%.3e\n", + "v_sig=%e dh/dt=%.3e t_begin=%.3e, t_end=%.3e\n", p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], xp->v_full[0], - xp->v_full[1], xp->v_full[2], p->a[0], p->a[1], p->a[2], 2. * p->h, - (int)p->density.wcount, p->mass, p->rho_dh, p->rho, p->pressure, - p->entropy, p->entropy_dt, p->div_v, p->curl_v, p->rot_v[0], p->rot_v[1], - p->rot_v[2], p->v_sig, p->t_begin, p->t_end); + xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], + p->h, (int)p->density.wcount, p->mass, p->rho_dh, p->rho, + p->force.pressure, p->entropy, p->entropy_dt, p->force.soundspeed, + p->div_v, p->force.curl_v, p->density.rot_v[0], p->density.rot_v[1], + p->density.rot_v[2], p->force.v_sig, p->h_dt, p->t_begin, p->t_end); } diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h index 31528b63f5b3dc89ce533a3a7acafabee3c91332..f92531bcce30d6c1461bb1366f88bc282a2747e7 100644 --- a/src/hydro/Gadget2/hydro_iact.h +++ b/src/hydro/Gadget2/hydro_iact.h @@ -37,8 +37,6 @@ *errors and interactions * missed by the Gadget-2 tree-code neighbours search. * - * The code uses internal energy instead of entropy as a thermodynamical - *variable. */ /** @@ -103,13 +101,13 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( curlvr[1] = dv[2] * dx[0] - dv[0] * dx[2]; curlvr[2] = dv[0] * dx[1] - dv[1] * dx[0]; - pi->rot_v[0] += faci * curlvr[0]; - pi->rot_v[1] += faci * curlvr[1]; - pi->rot_v[2] += faci * curlvr[2]; + pi->density.rot_v[0] += faci * curlvr[0]; + pi->density.rot_v[1] += faci * curlvr[1]; + pi->density.rot_v[2] += faci * curlvr[2]; - pj->rot_v[0] += facj * curlvr[0]; - pj->rot_v[1] += facj * curlvr[1]; - pj->rot_v[2] += facj * curlvr[2]; + pj->density.rot_v[0] += facj * curlvr[0]; + pj->density.rot_v[1] += facj * curlvr[1]; + pj->density.rot_v[2] += facj * curlvr[2]; } /** @@ -142,9 +140,6 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( pi->density.wcount += wi; pi->density.wcount_dh -= u * wi_dx; - /* const float ih3 = h_inv * h_inv * h_inv; */ - /* const float ih4 = h_inv * h_inv * h_inv * h_inv; */ - const float fac = mj * wi_dx * ri; /* Compute dv dot r */ @@ -154,32 +149,14 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( const float dvdr = dv[0] * dx[0] + dv[1] * dx[1] + dv[2] * dx[2]; pi->div_v -= fac * dvdr; - /* if(pi->id == 515050 && pj->id == 504849) */ - /* message("Interacting with %lld. r=%e hi=%e u=%e W=%e dW/dx=%e dh_drho1=%e - * dh_drho2=%e\n fac=%e dvdr=%e pj->v=[%.3e,%.3e,%.3e]", */ - /* pj->id, */ - /* r, */ - /* hi, */ - /* u, */ - /* wi * ih3, */ - /* wi_dx * ih4, */ - /* -mj * (3.f * kernel_igamma * wi) * ih4, */ - /* -mj * u * wi_dx * kernel_igamma * ih4, */ - /* fac * ih4, */ - /* dvdr, */ - /* pj->v[0], */ - /* pj->v[1], */ - /* pj->v[2] */ - /* ); */ - /* Compute dv cross r */ curlvr[0] = dv[1] * dx[2] - dv[2] * dx[1]; curlvr[1] = dv[2] * dx[0] - dv[0] * dx[2]; curlvr[2] = dv[0] * dx[1] - dv[1] * dx[0]; - pi->rot_v[0] += fac * curlvr[0]; - pi->rot_v[1] += fac * curlvr[1]; - pi->rot_v[2] += fac * curlvr[2]; + pi->density.rot_v[0] += fac * curlvr[0]; + pi->density.rot_v[1] += fac * curlvr[1]; + pi->density.rot_v[2] += fac * curlvr[2]; } /** @@ -197,12 +174,12 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( const float r_inv = 1.0f / r; /* Get some values in local variables. */ - // const float mi = pi->mass; + const float mi = pi->mass; const float mj = pj->mass; const float rhoi = pi->rho; const float rhoj = pj->rho; - const float pressurei = pi->pressure; - const float pressurej = pj->pressure; + const float pressurei = pi->force.pressure; + const float pressurej = pj->force.pressure; /* Get the kernel for hi. */ const float hi_inv = 1.0f / hi; @@ -223,70 +200,61 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( const float P_over_rho_j = pressurej / (rhoj * rhoj) * pj->rho_dh; /* Compute sound speeds */ - const float ci = sqrtf(const_hydro_gamma * pressurei / rhoi); - const float cj = sqrtf(const_hydro_gamma * pressurej / rhoj); - float v_sig = ci + cj; + const float ci = pi->force.soundspeed; + const float cj = pj->force.soundspeed; /* Compute dv dot r. */ const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + (pi->v[2] - pj->v[2]) * dx[2]; - /* Artificial viscosity term */ - float visc = 0.f; - if (dvdr < 0.f) { - const float mu_ij = fac_mu * dvdr * r_inv; - v_sig -= 3.f * mu_ij; - const float rho_ij = 0.5f * (rhoi + rhoj); - const float balsara_i = fabsf(pi->div_v) / (fabsf(pi->div_v) + pi->curl_v + - 0.0001 * ci / fac_mu / hi); - const float balsara_j = fabsf(pj->div_v) / (fabsf(pj->div_v) + pj->curl_v + - 0.0001 * cj / fac_mu / hj); - visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij / rho_ij * - (balsara_i + balsara_j); - } + /* Balsara term */ + const float balsara_i = + fabsf(pi->div_v) / + (fabsf(pi->div_v) + pi->force.curl_v + 0.0001 * ci / fac_mu / hi); + const float balsara_j = + fabsf(pj->div_v) / + (fabsf(pj->div_v) + pj->force.curl_v + 0.0001 * cj / fac_mu / hj); + + /* Are the particles moving towards each others ? */ + const float omega_ij = fminf(dvdr, 0.f); + const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */ + + /* Signal velocity */ + const float v_sig = ci + cj - 3.f * mu_ij; + + /* Now construct the full viscosity term */ + const float rho_ij = 0.5f * (rhoi + rhoj); + const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * + (balsara_i + balsara_j) / rho_ij; /* Now, convolve with the kernel */ - const float visc_term = 0.5f * mj * visc * (wi_dr + wj_dr) * r_inv; - const float sph_term = - mj * (P_over_rho_i * wi_dr + P_over_rho_j * wj_dr) * r_inv; + const float visc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; + const float sph_term = (P_over_rho_i * wi_dr + P_over_rho_j * wj_dr) * r_inv; /* Eventually got the acceleration */ const float acc = visc_term + sph_term; - /* //if(pi->id == 1000 && pj->id == 1100) */ - /* if(pi->id == 515050 && pj->id == 504849) */ - /* message("Interacting with %lld. r=%e hi=%e hj=%e dWi/dx=%e dWj/dx=%3e - * dvdr=%e visc=%e sph=%e", */ - /* pj->id, */ - /* r, */ - /* 2*hi, */ - /* 2*hj, */ - /* wi_dr, */ - /* wj_dr, */ - /* dvdr, */ - /* visc_term, */ - /* sph_term */ - /* ); */ - /* if(pi->id == 1100 && pj->id == 1000) */ - /* message("oO"); */ - /* Use the force Luke ! */ - pi->a[0] -= acc * dx[0]; - pi->a[1] -= acc * dx[1]; - pi->a[2] -= acc * dx[2]; + pi->a_hydro[0] -= mj * acc * dx[0]; + pi->a_hydro[1] -= mj * acc * dx[1]; + pi->a_hydro[2] -= mj * acc * dx[2]; + + pj->a_hydro[0] += mi * acc * dx[0]; + pj->a_hydro[1] += mi * acc * dx[1]; + pj->a_hydro[2] += mi * acc * dx[2]; - pj->a[0] += acc * dx[0]; - pj->a[1] += acc * dx[1]; - pj->a[2] += acc * dx[2]; + /* Get the time derivative for h. */ + pi->h_dt -= mj * dvdr * r_inv / rhoj * wi_dr; + pj->h_dt -= mi * dvdr * r_inv / rhoi * wj_dr; /* Update the signal velocity. */ - pi->v_sig = fmaxf(pi->v_sig, v_sig); - pj->v_sig = fmaxf(pj->v_sig, v_sig); + pi->force.v_sig = fmaxf(pi->force.v_sig, v_sig); + pj->force.v_sig = fmaxf(pj->force.v_sig, v_sig); /* Change in entropy */ - pi->entropy_dt += 0.5f * visc_term * dvdr; - pj->entropy_dt -= 0.5f * visc_term * dvdr; + pi->entropy_dt += 0.5f * mj * visc_term * dvdr; + pj->entropy_dt -= 0.5f * mi * visc_term * dvdr; } /** @@ -308,8 +276,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( const float mj = pj->mass; const float rhoi = pi->rho; const float rhoj = pj->rho; - const float pressurei = pi->pressure; - const float pressurej = pj->pressure; + const float pressurei = pi->force.pressure; + const float pressurej = pj->force.pressure; /* Get the kernel for hi. */ const float hi_inv = 1.0f / hi; @@ -330,47 +298,54 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( const float P_over_rho_j = pressurej / (rhoj * rhoj) * pj->rho_dh; /* Compute sound speeds */ - const float ci = sqrtf(const_hydro_gamma * pressurei / rhoi); - const float cj = sqrtf(const_hydro_gamma * pressurej / rhoj); - float v_sig = ci + cj; + const float ci = pi->force.soundspeed; + const float cj = pj->force.soundspeed; /* Compute dv dot r. */ const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + (pi->v[2] - pj->v[2]) * dx[2]; - /* Artificial viscosity term */ - float visc = 0.f; - if (dvdr < 0.f) { - const float mu_ij = fac_mu * dvdr * r_inv; - v_sig -= 3.f * mu_ij; - const float rho_ij = 0.5f * (rhoi + rhoj); - const float balsara_i = fabsf(pi->div_v) / (fabsf(pi->div_v) + pi->curl_v + - 0.0001 * ci / fac_mu / hi); - const float balsara_j = fabsf(pj->div_v) / (fabsf(pj->div_v) + pj->curl_v + - 0.0001 * cj / fac_mu / hj); - visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij / rho_ij * - (balsara_i + balsara_j); - } + /* Balsara term */ + const float balsara_i = + fabsf(pi->div_v) / + (fabsf(pi->div_v) + pi->force.curl_v + 0.0001 * ci / fac_mu / hi); + const float balsara_j = + fabsf(pj->div_v) / + (fabsf(pj->div_v) + pj->force.curl_v + 0.0001 * cj / fac_mu / hj); + + /* Are the particles moving towards each others ? */ + const float omega_ij = fminf(dvdr, 0.f); + const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */ + + /* Signal velocity */ + const float v_sig = ci + cj - 3.f * mu_ij; + + /* Now construct the full viscosity term */ + const float rho_ij = 0.5f * (rhoi + rhoj); + const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * + (balsara_i + balsara_j) / rho_ij; /* Now, convolve with the kernel */ - const float visc_term = 0.5f * mj * visc * (wi_dr + wj_dr) * r_inv; - const float sph_term = - mj * (P_over_rho_i * wi_dr + P_over_rho_j * wj_dr) * r_inv; + const float visc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; + const float sph_term = (P_over_rho_i * wi_dr + P_over_rho_j * wj_dr) * r_inv; /* Eventually got the acceleration */ const float acc = visc_term + sph_term; /* Use the force Luke ! */ - pi->a[0] -= acc * dx[0]; - pi->a[1] -= acc * dx[1]; - pi->a[2] -= acc * dx[2]; + pi->a_hydro[0] -= mj * acc * dx[0]; + pi->a_hydro[1] -= mj * acc * dx[1]; + pi->a_hydro[2] -= mj * acc * dx[2]; + + /* Get the time derivative for h. */ + pi->h_dt -= mj * dvdr * r_inv / rhoj * wi_dr; /* Update the signal velocity. */ - pi->v_sig = fmaxf(pi->v_sig, v_sig); + pi->force.v_sig = fmaxf(pi->force.v_sig, v_sig); /* Change in entropy */ - pi->entropy_dt += 0.5f * visc_term * dvdr; + pi->entropy_dt += 0.5f * mj * visc_term * dvdr; } #endif /* SWIFT_RUNNER_IACT_LEGACY_H */ diff --git a/src/hydro/Gadget2/hydro_io.h b/src/hydro/Gadget2/hydro_io.h index 5e01d67fddcc81d766e8aa59eee2d6368378170c..17c3d3013644c3572f3c26fc3e270b1c1bc465ed 100644 --- a/src/hydro/Gadget2/hydro_io.h +++ b/src/hydro/Gadget2/hydro_io.h @@ -45,7 +45,7 @@ __attribute__((always_inline)) INLINE static void hydro_read_particles( entropy, COMPULSORY); readArray(h_grp, "ParticleIDs", ULONGLONG, N, 1, parts, N_total, offset, id, COMPULSORY); - readArray(h_grp, "Acceleration", FLOAT, N, 3, parts, N_total, offset, a, + readArray(h_grp, "Acceleration", FLOAT, N, 3, parts, N_total, offset, a_hydro, OPTIONAL); readArray(h_grp, "Density", FLOAT, N, 1, parts, N_total, offset, rho, OPTIONAL); @@ -85,7 +85,36 @@ __attribute__((always_inline)) INLINE static void hydro_write_particles( writeArray(h_grp, fileName, xmfFile, "ParticleIDs", ULONGLONG, N, 1, parts, N_total, mpi_rank, offset, id, us, UNIT_CONV_NO_UNITS); writeArray(h_grp, fileName, xmfFile, "Acceleration", FLOAT, N, 3, parts, - N_total, mpi_rank, offset, a, us, UNIT_CONV_ACCELERATION); + N_total, mpi_rank, offset, a_hydro, us, UNIT_CONV_ACCELERATION); writeArray(h_grp, fileName, xmfFile, "Density", FLOAT, N, 1, parts, N_total, mpi_rank, offset, rho, us, UNIT_CONV_DENSITY); } + +/** + * @brief Writes the current model of SPH to the file + * @param h_grpsph The HDF5 group in which to write + */ +void writeSPHflavour(hid_t h_grpsph) { + + /* Kernel function description */ + writeAttribute_s(h_grpsph, "Kernel", kernel_name); + writeAttribute_f(h_grpsph, "Kernel eta", const_eta_kernel); + writeAttribute_f(h_grpsph, "Weighted N_ngb", kernel_nwneigh); + writeAttribute_f(h_grpsph, "Delta N_ngb", const_delta_nwneigh); + writeAttribute_f(h_grpsph, "Hydro gamma", const_hydro_gamma); + + /* Viscosity and thermal conduction */ + writeAttribute_s(h_grpsph, "Thermal Conductivity Model", + "(No treatment) Legacy Gadget-2 as in Springel (2005)"); + writeAttribute_s(h_grpsph, "Viscosity Model", + "Legacy Gadget-2 as in Springel (2005)"); + writeAttribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha); + writeAttribute_f(h_grpsph, "Viscosity beta", 3.f); + + /* Time integration properties */ + writeAttribute_f(h_grpsph, "CFL parameter", const_cfl); + writeAttribute_f(h_grpsph, "Maximal ln(Delta h) change over dt", + const_ln_max_h_change); + writeAttribute_f(h_grpsph, "Maximal Delta h change over dt", + exp(const_ln_max_h_change)); +} diff --git a/src/hydro/Gadget2/hydro_part.h b/src/hydro/Gadget2/hydro_part.h index 8ad6a6ef24add67f6fcfea0059738b44b3f20175..41898513aadddf7a7f7f5f6acb7516af6ecad1f4 100644 --- a/src/hydro/Gadget2/hydro_part.h +++ b/src/hydro/Gadget2/hydro_part.h @@ -17,10 +17,7 @@ * ******************************************************************************/ -/* Some standard headers. */ -#include <stdlib.h> - -/* Extra particle data not needed during the computation. */ +/* Extra particle data not needed during the SPH loops over neighbours. */ struct xpart { /* Old position, at last tree rebuild. */ @@ -29,12 +26,6 @@ struct xpart { /* Velocity at the last full step. */ float v_full[3]; - /* Entropy at the half-step. */ - float u_hdt; - - /* Old density. */ - float omega; - } __attribute__((aligned(xpart_align))); /* Data of a single particle. */ @@ -47,30 +38,20 @@ struct part { float v[3]; /* Particle acceleration. */ - float a[3]; + float a_hydro[3]; /* Particle cutoff radius. */ float h; + /* Time derivative of the smoothing length */ + float h_dt; + /* Particle time of beginning of time-step. */ float t_begin; /* Particle time of end of time-step. */ float t_end; - struct { - - /* Number of neighbours */ - float wcount; - - /* Number of neighbours spatial derivative */ - float wcount_dh; - - } density; - - /* Particle entropy. */ - float entropy; - /* Particle density. */ float rho; @@ -78,24 +59,49 @@ struct part { */ float rho_dh; + /* Particle entropy. */ + float entropy; + + /* Entropy time derivative */ + float entropy_dt; + /* Particle mass. */ float mass; - /* Particle pressure */ - float pressure; + union { - /* Entropy time derivative */ - float entropy_dt; + struct { - /* Velocity divergence */ - float div_v; + /* Number of neighbours */ + float wcount; + + /* Number of neighbours spatial derivative */ + float wcount_dh; + + /* Velocity curl components */ + float rot_v[3]; + + } density; - /* Velocity curl */ - float curl_v; - float rot_v[3]; + struct { - /* Signal velocity */ - float v_sig; + /* Velocity curl norm*/ + float curl_v; + + /* Signal velocity */ + float v_sig; + + /* Particle pressure */ + float pressure; + + /* Particle sound speed */ + float soundspeed; + + } force; + }; + + /* Velocity divergence */ + float div_v; /* Particle ID. */ unsigned long long id; diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h new file mode 100644 index 0000000000000000000000000000000000000000..3585fc3c295be2d449adee5425d61c6024fa7caf --- /dev/null +++ b/src/hydro/Minimal/hydro.h @@ -0,0 +1,235 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 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 <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +#include "approx_math.h" + +/** + * @brief Computes the hydro time-step of a given particle + * + * This function returns the time-step of a particle given its hydro-dynamical + * state. A typical time-step calculation would be the use of the CFL condition. + * + * @param p Pointer to the particle data + * @param xp Pointer to the extended particle data + * + */ +__attribute__((always_inline)) INLINE static float hydro_compute_timestep( + struct part* p, struct xpart* xp) { + + /* CFL condition */ + const float dt_cfl = 2.f * const_cfl * kernel_gamma * p->h / p->force.v_sig; + + return dt_cfl; +} + +/** + * @brief Initialises the particles for the first time + * + * This function is called only once just after the ICs have been + * read in to do some conversions or assignments between the particle + * and extended particle fields. + * + * @param p The particle to act upon + * @param xp The extended particle data to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_first_init_part(struct part* p, struct xpart* xp) { + + xp->u_full = p->u; +} + +/** + * @brief Prepares a particle for the density calculation. + * + * Zeroes all the relevant arrays in preparation for the sums taking place in + * the various density loop over neighbours. Typically, all fields of the + * density sub-structure of a particle get zeroed in here. + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_init_part(struct part* p) { + p->density.wcount = 0.f; + p->density.wcount_dh = 0.f; + p->rho = 0.f; + p->rho_dh = 0.f; +} + +/** + * @brief Finishes the density calculation. + * + * Multiplies the density and number of neighbours by the appropiate constants + * and add the self-contribution term. + * Additional quantities such as velocity gradients will also get the final + *terms + * added to them here. + * + * @param p The particle to act upon + * @param time The current time + */ +__attribute__((always_inline)) + INLINE static void hydro_end_density(struct part* p, float time) { + + /* Some smoothing length multiples. */ + const float h = p->h; + const float ih = 1.0f / h; + const float ih2 = ih * ih; + const float ih4 = ih2 * ih2; + + /* Final operation on the density (add self-contribution). */ + p->rho += p->mass * kernel_root; + p->rho_dh -= 3.0f * p->mass * kernel_root * kernel_igamma; + p->density.wcount += kernel_root; + + /* Finish the calculation by inserting the missing h-factors */ + p->rho *= ih * ih2; + p->rho_dh *= ih4; + p->density.wcount *= (4.0f / 3.0f * M_PI * kernel_gamma3); + p->density.wcount_dh *= ih * (4.0f / 3.0f * M_PI * kernel_gamma3); +} + +/** + * @brief Prepare a particle for the force calculation. + * + * This function is called in the ghost task to convert some quantities coming + * from the density loop over neighbours into quantities ready to be used in the + * force loop over neighbours. Quantities are typically read from the density + * sub-structure and written to the force sub-structure. + * Examples of calculations done here include the calculation of viscosity term + * constants, thermal conduction terms, hydro conversions, etc. + * + * @param p The particle to act upon + * @param xp The extended particle data to act upon + * @param time The current time + */ +__attribute__((always_inline)) INLINE static void hydro_prepare_force( + struct part* p, struct xpart* xp, float time) { + + p->force.pressure = p->rho * p->u * (const_hydro_gamma - 1.f); +} + +/** + * @brief Reset acceleration fields of a particle + * + * Resets all hydro acceleration and time derivative fields in preparation + * for the sums taking place in the various force tasks. + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_reset_acceleration(struct part* p) { + + /* Reset the acceleration. */ + p->a_hydro[0] = 0.0f; + p->a_hydro[1] = 0.0f; + p->a_hydro[2] = 0.0f; + + /* Reset the time derivatives. */ + p->u_dt = 0.0f; + p->h_dt = 0.0f; + p->force.v_sig = 0.0f; +} + +/** + * @brief Predict additional particle fields forward in time when drifting + * + * Additional hydrodynamic quantites are drifted forward in time here. These + * include thermal quantities (thermal energy or total energy or entropy, ...). + * + * @param p The particle + * @param xp The extended data of the particle + * @param t0 The time at the start of the drift + * @param t1 The time at the end of the drift + */ +__attribute__((always_inline)) INLINE static void hydro_predict_extra( + struct part* p, struct xpart* xp, float t0, float t1) { + + const float dt = t1 - t0; + + /* Predict internal energy */ + const float w = p->u_dt / p->u * dt; + if (fabsf(w) < 0.2f) + p->u *= approx_expf(w); /* 4th order expansion of exp(w) */ + else + p->u *= expf(w); + + /* Need to recompute the pressure as well */ + p->force.pressure = p->rho * p->u * (const_hydro_gamma - 1.f); +} + +/** + * @brief Finishes the force calculation. + * + * Multiplies the force and accelerations by the appropiate constants + * and add the self-contribution term. In most cases, there is nothing + * to do here. + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_end_force(struct part* p) {} + +/** + * @brief Kick the additional variables + * + * Additional hydrodynamic quantites are kicked forward in time here. These + * include thermal quantities (thermal energy or total energy or entropy, ...). + * + * @param p The particle to act upon + * @param xp The particle extended data to act upon + * @param dt The time-step for this kick + * @param half_dt The half time-step for this kick + */ +__attribute__((always_inline)) INLINE static void hydro_kick_extra( + struct part* p, struct xpart* xp, float dt, float half_dt) { + + /* Kick in momentum space */ + xp->u_full += p->u_dt * dt; + + /* Get the predicted internal energy */ + p->u = xp->u_full - half_dt * p->u_dt; +} + +/** + * @brief Converts hydro quantity of a particle at the start of a run + * + * This function is called once at the end of the engine_init_particle() + * routine (at the start of a calculation) after the densities of + * particles have been computed. + * This can be used to convert internal energy into entropy for instance. + * + * @param p The particle to act upon + */ +__attribute__((always_inline)) + INLINE static void hydro_convert_quantities(struct part* p) {} + +/** + * @brief Returns the internal energy of a particle + * + * For implementations where the main thermodynamic variable + * is not internal energy, this function computes the internal + * energy from the thermodynamic variable. + * + * @param p The particle of interest + */ +__attribute__((always_inline)) + INLINE static float hydro_get_internal_energy(struct part* p) { + + return p->u; +} diff --git a/src/hydro/Minimal/hydro_debug.h b/src/hydro/Minimal/hydro_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..b208d5b867779aaaa204d8783b75681156506fe7 --- /dev/null +++ b/src/hydro/Minimal/hydro_debug.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2016 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 <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +__attribute__((always_inline)) + INLINE static void hydro_debug_particle(struct part* p, struct xpart* xp) { + printf( + "x=[%.3e,%.3e,%.3e], " + "v=[%.3e,%.3e,%.3e],v_full=[%.3e,%.3e,%.3e] \n a=[%.3e,%.3e,%.3e], " + "u_full=%.3e, u=%.3e, du/dt=%.3e v_sig=%.3e, P=%.3e\n" + "h=%.3e, dh/dt=%.3e " + "wcount=%d, m=%.3e, dh_drho=%.3e, rho=%.3e, t_begin=%.3e, t_end=%.3e\n", + p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], xp->v_full[0], + xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], + xp->u_full, p->u, p->u_dt, p->force.v_sig, p->force.pressure, p->h, + p->h_dt, (int)p->density.wcount, p->mass, p->rho_dh, p->rho, p->t_begin, + p->t_end); +} diff --git a/src/hydro/Minimal/hydro_iact.h b/src/hydro/Minimal/hydro_iact.h new file mode 100644 index 0000000000000000000000000000000000000000..6afb9d8d38a4fc7f1d38b7286720ddb7f3c51ab4 --- /dev/null +++ b/src/hydro/Minimal/hydro_iact.h @@ -0,0 +1,248 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 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 <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_RUNNER_IACT_H +#define SWIFT_RUNNER_IACT_H + +/* Includes. */ +#include "const.h" +#include "kernel.h" +#include "part.h" +#include "vector.h" + +/** + * @brief Minimal conservative implementation of SPH + * + * The thermal variable is the internal energy (u). No viscosity nor + * thermal conduction terms are implemented. + */ + +/** + * @brief Density loop + */ +__attribute__((always_inline)) INLINE static void runner_iact_density( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + + float r = sqrtf(r2); + float xi, xj; + float h_inv; + float wi, wj, wi_dx, wj_dx; + float mi, mj; + + /* Get the masses. */ + mi = pi->mass; + mj = pj->mass; + + /* Compute density of pi. */ + h_inv = 1.0 / hi; + xi = r * h_inv; + kernel_deval(xi, &wi, &wi_dx); + + pi->rho += mj * wi; + pi->rho_dh -= mj * (3.0 * wi + xi * wi_dx); + pi->density.wcount += wi; + pi->density.wcount_dh -= xi * wi_dx; + + /* Compute density of pj. */ + h_inv = 1.f / hj; + xj = r * h_inv; + kernel_deval(xj, &wj, &wj_dx); + + pj->rho += mi * wj; + pj->rho_dh -= mi * (3.0 * wj + xj * wj_dx); + pj->density.wcount += wj; + pj->density.wcount_dh -= xj * wj_dx; +} + +/** + * @brief Density loop (non-symmetric version) + */ + +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + + float r; + float xi; + float h_inv; + float wi, wi_dx; + float mj; + + /* Get the masses. */ + mj = pj->mass; + + /* Get r and r inverse. */ + r = sqrtf(r2); + + h_inv = 1.f / hi; + xi = r * h_inv; + kernel_deval(xi, &wi, &wi_dx); + + pi->rho += mj * wi; + pi->rho_dh -= mj * (3.0 * wi + xi * wi_dx); + pi->density.wcount += wi; + pi->density.wcount_dh -= xi * wi_dx; +} + +/** + * @brief Force loop + */ + +__attribute__((always_inline)) INLINE static void runner_iact_force( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + + const float r = sqrtf(r2); + const float r_inv = 1.0f / r; + + /* Recover some data */ + const float mi = pi->mass; + const float mj = pj->mass; + const float rhoi = pi->rho; + const float rhoj = pj->rho; + const float pressurei = pi->force.pressure; + const float pressurej = pj->force.pressure; + + /* Get the kernel for hi. */ + const float hi_inv = 1.0f / hi; + const float hi2_inv = hi_inv * hi_inv; + const float xi = r * hi_inv; + float wi, wi_dx; + kernel_deval(xi, &wi, &wi_dx); + const float wi_dr = hi2_inv * hi2_inv * wi_dx; + + /* Get the kernel for hj. */ + const float hj_inv = 1.0f / hj; + const float hj2_inv = hj_inv * hj_inv; + const float xj = r * hj_inv; + float wj, wj_dx; + kernel_deval(xj, &wj, &wj_dx); + const float wj_dr = hj2_inv * hj2_inv * wj_dx; + + /* Compute gradient terms */ + const float P_over_rho_i = pressurei / (rhoi * rhoi) * pi->rho_dh; + const float P_over_rho_j = pressurej / (rhoj * rhoj) * pj->rho_dh; + + /* Compute dv dot r. */ + float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + + (pi->v[2] - pj->v[2]) * dx[2]; + dvdr *= r_inv; + + /* Compute the relative velocity. (This is 0 if the particles move away from + * each other and negative otherwise) */ + const float omega_ij = fminf(dvdr, 0.f); + + /* Compute sound speeds */ + const float ci = sqrtf(const_hydro_gamma * pressurei / rhoi); + const float cj = sqrtf(const_hydro_gamma * pressurej / rhoj); + float v_sig = ci + cj + 3.f * omega_ij; + + /* SPH acceleration term */ + const float sph_term = (P_over_rho_i * wi_dr + P_over_rho_j * wj_dr) * r_inv; + + /* Use the force Luke ! */ + pi->a_hydro[0] -= mj * sph_term * dx[0]; + pi->a_hydro[1] -= mj * sph_term * dx[1]; + pi->a_hydro[2] -= mj * sph_term * dx[2]; + + pj->a_hydro[0] += mi * sph_term * dx[0]; + pj->a_hydro[1] += mi * sph_term * dx[1]; + pj->a_hydro[2] += mi * sph_term * dx[2]; + + /* Get the time derivative for u. */ + pi->u_dt += P_over_rho_i * mj * dvdr * wi_dr; + pj->u_dt += P_over_rho_j * mi * dvdr * wj_dr; + + /* Get the time derivative for h. */ + pi->h_dt -= mj * dvdr * r_inv / rhoj * wi_dr; + pj->h_dt -= mi * dvdr * r_inv / rhoi * wj_dr; + + /* Update the signal velocity. */ + pi->force.v_sig = fmaxf(pi->force.v_sig, v_sig); + pj->force.v_sig = fmaxf(pj->force.v_sig, v_sig); +} + +/** + * @brief Force loop (non-symmetric version) + */ + +__attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( + float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + + const float r = sqrtf(r2); + const float r_inv = 1.0f / r; + + /* Recover some data */ + // const float mi = pi->mass; + const float mj = pj->mass; + const float rhoi = pi->rho; + const float rhoj = pj->rho; + const float pressurei = pi->force.pressure; + const float pressurej = pj->force.pressure; + + /* Get the kernel for hi. */ + const float hi_inv = 1.0f / hi; + const float hi2_inv = hi_inv * hi_inv; + const float xi = r * hi_inv; + float wi, wi_dx; + kernel_deval(xi, &wi, &wi_dx); + const float wi_dr = hi2_inv * hi2_inv * wi_dx; + + /* Get the kernel for hj. */ + const float hj_inv = 1.0f / hj; + const float hj2_inv = hj_inv * hj_inv; + const float xj = r * hj_inv; + float wj, wj_dx; + kernel_deval(xj, &wj, &wj_dx); + const float wj_dr = hj2_inv * hj2_inv * wj_dx; + + /* Compute gradient terms */ + const float P_over_rho_i = pressurei / (rhoi * rhoi) * pi->rho_dh; + const float P_over_rho_j = pressurej / (rhoj * rhoj) * pj->rho_dh; + + /* Compute dv dot r. */ + float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + + (pi->v[2] - pj->v[2]) * dx[2]; + dvdr *= r_inv; + + /* Compute the relative velocity. (This is 0 if the particles move away from + * each other and negative otherwise) */ + const float omega_ij = fminf(dvdr, 0.f); + + /* Compute sound speeds */ + const float ci = sqrtf(const_hydro_gamma * pressurei / rhoi); + const float cj = sqrtf(const_hydro_gamma * pressurej / rhoj); + float v_sig = ci + cj + 3.f * omega_ij; + + /* SPH acceleration term */ + const float sph_term = (P_over_rho_i * wi_dr + P_over_rho_j * wj_dr) * r_inv; + + /* Use the force Luke ! */ + pi->a_hydro[0] -= mj * sph_term * dx[0]; + pi->a_hydro[1] -= mj * sph_term * dx[1]; + pi->a_hydro[2] -= mj * sph_term * dx[2]; + + /* Get the time derivative for u. */ + pi->u_dt += P_over_rho_i * mj * dvdr * wi_dr; + + /* Get the time derivative for h. */ + pi->h_dt -= mj * dvdr * r_inv / rhoj * wi_dr; + + /* Update the signal velocity. */ + pi->force.v_sig = fmaxf(pi->force.v_sig, v_sig); +} + +#endif /* SWIFT_RUNNER_IACT_H */ diff --git a/src/hydro/Minimal/hydro_io.h b/src/hydro/Minimal/hydro_io.h new file mode 100644 index 0000000000000000000000000000000000000000..2c56fb489ab84ca7c30426b54cf95e26e3821084 --- /dev/null +++ b/src/hydro/Minimal/hydro_io.h @@ -0,0 +1,118 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2016 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 <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/** + * @brief Reads the different particles to the HDF5 file + * + * @param h_grp The HDF5 group in which to read the arrays. + * @param N The number of particles on that MPI rank. + * @param N_total The total number of particles (only used in MPI mode) + * @param offset The offset of the particles for this MPI rank (only used in MPI + *mode) + * @param parts The particle array + * + */ +__attribute__((always_inline)) INLINE static void hydro_read_particles( + hid_t h_grp, int N, long long N_total, long long offset, + struct part* parts) { + + /* Read arrays */ + readArray(h_grp, "Coordinates", DOUBLE, N, 3, parts, N_total, offset, x, + COMPULSORY); + readArray(h_grp, "Velocities", FLOAT, N, 3, parts, N_total, offset, v, + COMPULSORY); + readArray(h_grp, "Masses", FLOAT, N, 1, parts, N_total, offset, mass, + COMPULSORY); + readArray(h_grp, "SmoothingLength", FLOAT, N, 1, parts, N_total, offset, h, + COMPULSORY); + readArray(h_grp, "InternalEnergy", FLOAT, N, 1, parts, N_total, offset, u, + COMPULSORY); + readArray(h_grp, "ParticleIDs", ULONGLONG, N, 1, parts, N_total, offset, id, + COMPULSORY); + readArray(h_grp, "Acceleration", FLOAT, N, 3, parts, N_total, offset, a_hydro, + OPTIONAL); + readArray(h_grp, "Density", FLOAT, N, 1, parts, N_total, offset, rho, + OPTIONAL); +} + +/** + * @brief Writes the different particles to the HDF5 file + * + * @param h_grp The HDF5 group in which to write the arrays. + * @param fileName The name of the file (unsued in MPI mode). + * @param xmfFile The XMF file to write to (unused in MPI mode). + * @param N The number of particles on that MPI rank. + * @param N_total The total number of particles (only used in MPI mode) + * @param mpi_rank The MPI rank of this node (only used in MPI mode) + * @param offset The offset of the particles for this MPI rank (only used in MPI + *mode) + * @param parts The particle array + * @param us The unit system to use + * + */ +__attribute__((always_inline)) INLINE static void hydro_write_particles( + hid_t h_grp, char* fileName, FILE* xmfFile, int N, long long N_total, + int mpi_rank, long long offset, struct part* parts, struct UnitSystem* us) { + + /* Write arrays */ + writeArray(h_grp, fileName, xmfFile, "Coordinates", DOUBLE, N, 3, parts, + N_total, mpi_rank, offset, x, us, UNIT_CONV_LENGTH); + writeArray(h_grp, fileName, xmfFile, "Velocities", FLOAT, N, 3, parts, + N_total, mpi_rank, offset, v, us, UNIT_CONV_SPEED); + writeArray(h_grp, fileName, xmfFile, "Masses", FLOAT, N, 1, parts, N_total, + mpi_rank, offset, mass, us, UNIT_CONV_MASS); + writeArray(h_grp, fileName, xmfFile, "SmoothingLength", FLOAT, N, 1, parts, + N_total, mpi_rank, offset, h, us, UNIT_CONV_LENGTH); + writeArray(h_grp, fileName, xmfFile, "InternalEnergy", FLOAT, N, 1, parts, + N_total, mpi_rank, offset, u, us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + writeArray(h_grp, fileName, xmfFile, "ParticleIDs", ULONGLONG, N, 1, parts, + N_total, mpi_rank, offset, id, us, UNIT_CONV_NO_UNITS); + writeArray(h_grp, fileName, xmfFile, "Acceleration", FLOAT, N, 3, parts, + N_total, mpi_rank, offset, a_hydro, us, UNIT_CONV_ACCELERATION); + writeArray(h_grp, fileName, xmfFile, "Density", FLOAT, N, 1, parts, N_total, + mpi_rank, offset, rho, us, UNIT_CONV_DENSITY); +} + +/** + * @brief Writes the current model of SPH to the file + * @param h_grpsph The HDF5 group in which to write + */ +void writeSPHflavour(hid_t h_grpsph) { + + /* Kernel function description */ + writeAttribute_s(h_grpsph, "Kernel", kernel_name); + writeAttribute_f(h_grpsph, "Kernel eta", const_eta_kernel); + writeAttribute_f(h_grpsph, "Weighted N_ngb", kernel_nwneigh); + writeAttribute_f(h_grpsph, "Delta N_ngb", const_delta_nwneigh); + writeAttribute_f(h_grpsph, "Hydro gamma", const_hydro_gamma); + + /* Viscosity and thermal conduction */ + /* Nothing in this minimal model... */ + writeAttribute_s(h_grpsph, "Thermal Conductivity Model", "No model"); + writeAttribute_s(h_grpsph, "Viscosity Model", "No model"); + + /* Time integration properties */ + writeAttribute_f(h_grpsph, "CFL parameter", const_cfl); + writeAttribute_f(h_grpsph, "Maximal ln(Delta h) change over dt", + const_ln_max_h_change); + writeAttribute_f(h_grpsph, "Maximal Delta h change over dt", + exp(const_ln_max_h_change)); + writeAttribute_f(h_grpsph, "Maximal Delta u change over dt", + const_max_u_change); +} diff --git a/src/hydro/Minimal/hydro_part.h b/src/hydro/Minimal/hydro_part.h new file mode 100644 index 0000000000000000000000000000000000000000..b89cc249a42032e05bd35498c5c6435f3ebc4f4b --- /dev/null +++ b/src/hydro/Minimal/hydro_part.h @@ -0,0 +1,108 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 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 <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/** + * @brief Particle fields not needed during the SPH loops over neighbours. + * + * This structure contains the particle fields that are not used in the + * density or force loops. Quantities should be used in the kick, drift and + * potentially ghost tasks only. + */ +struct xpart { + + double x_old[3]; /*!< Old position, at last tree rebuild. */ + + float v_full[3]; /*!< Velocity at the last full step. */ + + float u_full; /*!< Thermal energy at the last full step. */ + +} __attribute__((aligned(xpart_align))); + +/** + * @brief Particle fields for the SPH particles + * + * The density and force substructures are used to contain variables only used + * within the density and force loops over neighbours. All more permanent + * variables should be declared in the main part of the part structure, + */ +struct part { + + double x[3]; /*!< Particle position. */ + + float v[3]; /*!< Particle predicted velocity. */ + + float a_hydro[3]; /*!< Particle acceleration. */ + + float mass; /*!< Particle mass. */ + + float h; /*!< Particle smoothing length. */ + + float h_dt; /*!< Time derivative of smoothing length */ + + float t_begin; /*!< Time at the beginning of time-step. */ + + float t_end; /*!< Time at the end of time-step. */ + + float u; /*!< Particle internal energy. */ + + float u_dt; /*!< Time derivative of the internal energy. */ + + float rho; /*!< Particle density. */ + + float rho_dh; /*!< Derivative of density with respect to h */ + + /* Store density/force specific stuff. */ + union { + + /** + * @brief Structure for the variables only used in the density loop over + * neighbours. + * + * Quantities in this sub-structure should only be accessed in the density + * loop over neighbours and the ghost task. + */ + struct { + + float wcount; /*!< Neighbour number count. */ + + float wcount_dh; /*!< Derivative of the neighbour number with respect to + h. */ + } density; + + /** + * @brief Structure for the variables only used in the force loop over + * neighbours. + * + * Quantities in this sub-structure should only be accessed in the force + * loop over neighbours and the ghost and kick tasks. + */ + struct { + + float pressure; /*!< Particle pressure. */ + + float v_sig; /*!< Particle signal velocity */ + + } force; + }; + + unsigned long long id; /*!< Particle unique ID. */ + + struct gpart* gpart; /*!< Pointer to corresponding gravity part. */ + +} __attribute__((aligned(part_align))); diff --git a/src/hydro_io.h b/src/hydro_io.h index b39661185668f71ae4adfe151de127a2a4766189..30d663f647c9b763e9b19177e9ba8ef374855768 100644 --- a/src/hydro_io.h +++ b/src/hydro_io.h @@ -22,10 +22,14 @@ #include "./const.h" /* Import the right functions */ -#ifdef LEGACY_GADGET2_SPH +#if defined(MINIMAL_SPH) +#include "./hydro/Minimal/hydro_io.h" +#elif defined(GADGET2_SPH) #include "./hydro/Gadget2/hydro_io.h" -#else +#elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_io.h" +#else +#error "Invalid choice of SPH variant" #endif -#endif +#endif /* SWIFT_HYDRO_IO_H */ diff --git a/src/parallel_io.c b/src/parallel_io.c index 1391322af1e1520cabc007eee354b669bc4219c6..5ac0d7122b17c135dca386f3e9c74123d15676cd 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -459,7 +459,7 @@ void write_output_parallel(struct engine* e, struct UnitSystem* us, int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info) { - hid_t h_file = 0, h_grp = 0; + hid_t h_file = 0, h_grp = 0, h_grpsph = 0; int N = e->s->nr_parts; int periodic = e->s->periodic; unsigned int numParticles[6] = {N, 0}; @@ -546,7 +546,10 @@ void write_output_parallel(struct engine* e, struct UnitSystem* us, writeCodeDescription(h_file); /* Print the SPH parameters */ - writeSPHflavour(h_file); + h_grpsph = H5Gcreate1(h_file, "/SPH", 0); + if (h_grpsph < 0) error("Error while creating SPH group"); + writeSPHflavour(h_grpsph); + H5Gclose(h_grpsph); /* Print the system of Units */ writeUnitSystem(h_file, us); diff --git a/src/part.h b/src/part.h index 3aaa28939c240bb24fb7053ad949f8b7ec999a88..168e80b68bb211d1d773f1f80f1fa9cc757edfcb 100644 --- a/src/part.h +++ b/src/part.h @@ -38,10 +38,14 @@ #define xpart_align 32 /* Import the right particle definition */ -#ifdef LEGACY_GADGET2_SPH +#if defined(MINIMAL_SPH) +#include "./hydro/Minimal/hydro_part.h" +#elif defined(GADGET2_SPH) #include "./hydro/Gadget2/hydro_part.h" -#else +#elif defined(DEFAULT_SPH) #include "./hydro/Default/hydro_part.h" +#else +#error "Invalid choice of SPH variant" #endif #include "./gravity/Default/gravity_part.h" diff --git a/src/runner.c b/src/runner.c index bfdaba3c64d0a4589b6477f7c7fd98ebbb2797f2..157616ad29c954bb7ebfd72acfea96454327e4ee 100644 --- a/src/runner.c +++ b/src/runner.c @@ -34,6 +34,7 @@ #include "runner.h" /* Local headers. */ +#include "approx_math.h" #include "atomic.h" #include "const.h" #include "debug.h" @@ -514,9 +515,6 @@ void runner_doinit(struct runner *r, struct cell *c, int timer) { if (p->t_end <= t_end) { - /* if(p->id == 1000) message("init 1000!"); */ - /* if(p->id == 515050) message("init 515050!"); */ - /* Get ready for a density calculation */ hydro_init_part(p); } @@ -579,9 +577,6 @@ void runner_doghost(struct runner *r, struct cell *c) { p = &parts[pid[i]]; xp = &xparts[pid[i]]; - /* if(p->id == 1000) message("ghost 1000"); */ - /* if(p->id == 515050) message("ghost 515050"); */ - /* Is this part within the timestep? */ if (p->t_end <= t_end) { @@ -619,14 +614,14 @@ void runner_doghost(struct runner *r, struct cell *c) { } /* We now have a particle whose smoothing length has converged */ - // if(p->id == 1000) - // printParticle(parts, 1000, count); - /* As of here, particle force variables will be set. Do _NOT_ - try to read any particle density variables! */ + /* As of here, particle force variables will be set. */ /* Compute variables required for the force loop */ - hydro_prepare_force(p, xp); + hydro_prepare_force(p, xp, t_end); + + /* The particle force values are now set. Do _NOT_ + try to read any particle density variables! */ /* Prepare the particle for the force loop over neighbours */ hydro_reset_acceleration(p); @@ -705,6 +700,7 @@ void runner_dodrift(struct runner *r, struct cell *c, int timer) { struct part *restrict p, *restrict parts = c->parts; struct xpart *restrict xp, *restrict xparts = c->xparts; float dx_max = 0.f, h_max = 0.f; + float w; TIMER_TIC @@ -718,52 +714,36 @@ void runner_dodrift(struct runner *r, struct cell *c, int timer) { p = &parts[k]; xp = &xparts[k]; + /* Useful quantity */ + const float h_inv = 1.0f / p->h; + /* Drift... */ p->x[0] += xp->v_full[0] * dt; p->x[1] += xp->v_full[1] * dt; p->x[2] += xp->v_full[2] * dt; - /* Predict velocities */ - p->v[0] += p->a[0] * dt; - p->v[1] += p->a[1] * dt; - p->v[2] += p->a[2] * dt; - - /* /\* Predict smoothing length *\/ */ - /* w = p->force.h_dt * ih * dt; */ - /* if (fabsf(w) < 0.01f) /\* 1st order expansion of exp(w) *\/ */ - /* p->h *= */ - /* 1.0f + */ - /* w * (1.0f + w * (0.5f + w * (1.0f / 6.0f + 1.0f / 24.0f * - * w))); */ - /* else */ - /* p->h *= expf(w); */ - - // MATTHIEU - - /* /\* Predict density *\/ */ - /* w = -3.0f * p->force.h_dt * ih * dt; */ - /* if (fabsf(w) < 0.1f) */ - /* p->rho *= */ - /* 1.0f + */ - /* w * (1.0f + w * (0.5f + w * (1.0f / 6.0f + 1.0f / 24.0f * - * w))); */ - /* else */ - /* p->rho *= expf(w); */ + /* Predict velocities (for hydro terms) */ + p->v[0] += p->a_hydro[0] * dt; + p->v[1] += p->a_hydro[1] * dt; + p->v[2] += p->a_hydro[2] * dt; + + /* Predict smoothing length */ + w = p->h_dt * h_inv * dt; + if (fabsf(w) < 0.2f) + p->h *= approx_expf(w); /* 4th order expansion of exp(w) */ + else + p->h *= expf(w); + + /* Predict density */ + w = -3.0f * p->h_dt * h_inv * dt; + if (fabsf(w) < 0.2f) + p->rho *= approx_expf(w); /* 4th order expansion of exp(w) */ + else + p->rho *= expf(w); /* Predict the values of the extra fields */ hydro_predict_extra(p, xp, r->e->timeOld, r->e->time); - /* if(p->id == 1000 || p->id == 515050 || p->id == 504849) */ - /* message("%lld: current_t=%f t0=%f t1=%f v=[%.3e %.3e %.3e]\n", - */ - /* p->id, */ - /* r->e->time, */ - /* r->e->timeOld, */ - /* r->e->time, */ - /* p->v[0], */ - /* p->v[1], */ - /* p->v[2]); */ - /* Compute motion since last cell construction */ const float dx = sqrtf((p->x[0] - xp->x_old[0]) * (p->x[0] - xp->x_old[0]) + @@ -827,9 +807,10 @@ void runner_dokick(struct runner *r, struct cell *c, int timer) { int updated = 0; float t_end_min = FLT_MAX, t_end_max = 0.f; - double ekin = 0.0, epot = 0.0; - float mom[3] = {0.0f, 0.0f, 0.0f}, ang[3] = {0.0f, 0.0f, 0.0f}; - float m, x[3], v_full[3]; + double e_kin = 0.0, e_int = 0.0, e_pot = 0.0, mass = 0.0; + float mom[3] = {0.0f, 0.0f, 0.0f}; + float ang[3] = {0.0f, 0.0f, 0.0f}; + float x[3], v_full[3]; struct part *restrict p, *restrict parts = c->parts; struct xpart *restrict xp, *restrict xparts = c->xparts; @@ -845,7 +826,7 @@ void runner_dokick(struct runner *r, struct cell *c, int timer) { p = &parts[k]; xp = &xparts[k]; - m = p->mass; + const float m = p->mass; x[0] = p->x[0]; x[1] = p->x[1]; x[2] = p->x[2]; @@ -854,8 +835,13 @@ void runner_dokick(struct runner *r, struct cell *c, int timer) { if (is_fixdt || p->t_end <= t_current) { /* First, finish the force loop */ + p->h_dt *= p->h * 0.333333333f; + + /* And do the same of the extra variable */ hydro_end_force(p); + /* Now we are ready to compute the next time-step size */ + if (is_fixdt) { /* Now we have a time step, proceed with the kick */ @@ -869,6 +855,13 @@ void runner_dokick(struct runner *r, struct cell *c, int timer) { new_dt = fminf(new_dt_hydro, new_dt_grav); + /* Limit change in h */ + const float dt_h_change = + (p->h_dt != 0.0f) ? fabsf(const_ln_max_h_change * p->h / p->h_dt) + : FLT_MAX; + + new_dt = fminf(new_dt, dt_h_change); + /* Recover the current timestep */ const float current_dt = p->t_end - p->t_begin; @@ -898,28 +891,16 @@ void runner_dokick(struct runner *r, struct cell *c, int timer) { p->t_end = p->t_begin + new_dt; /* Kick particles in momentum space */ - xp->v_full[0] += p->a[0] * dt; - xp->v_full[1] += p->a[1] * dt; - xp->v_full[2] += p->a[2] * dt; - - p->v[0] = xp->v_full[0] - half_dt * p->a[0]; - p->v[1] = xp->v_full[1] - half_dt * p->a[1]; - p->v[2] = xp->v_full[2] - half_dt * p->a[2]; - - /* if(p->id == 1000 || p->id == 515050 || p->id == 504849) */ - /* message("%lld: current_t=%f t_beg=%f t_end=%f half_dt=%f v=[%.3e - * %.3e %.3e]\n", */ - /* p->id, */ - /* t_current, */ - /* p->t_begin, */ - /* p->t_end, */ - /* half_dt, */ - /* p->v[0], */ - /* p->v[1], */ - /* p->v[2]); */ + xp->v_full[0] += p->a_hydro[0] * dt; + xp->v_full[1] += p->a_hydro[1] * dt; + xp->v_full[2] += p->a_hydro[2] * dt; + + p->v[0] = xp->v_full[0] - half_dt * p->a_hydro[0]; + p->v[1] = xp->v_full[1] - half_dt * p->a_hydro[1]; + p->v[2] = xp->v_full[2] - half_dt * p->a_hydro[2]; /* Extra kick work */ - hydro_kick_extra(p, dt); + hydro_kick_extra(p, xp, dt, half_dt); } /* Now collect quantities for statistics */ @@ -928,6 +909,9 @@ void runner_dokick(struct runner *r, struct cell *c, int timer) { v_full[1] = xp->v_full[1]; v_full[2] = xp->v_full[2]; + /* Collect mass */ + mass += m; + /* Collect momentum */ mom[0] += m * v_full[0]; mom[1] += m * v_full[1]; @@ -939,9 +923,10 @@ void runner_dokick(struct runner *r, struct cell *c, int timer) { ang[2] += m * (x[0] * v_full[1] - x[1] * v_full[0]); /* Collect total energy. */ - ekin += 0.5 * m * (v_full[0] * v_full[0] + v_full[1] * v_full[1] + - v_full[2] * v_full[2]); - epot += m * xp->u_hdt; + e_kin += 0.5 * m * (v_full[0] * v_full[0] + v_full[1] * v_full[1] + + v_full[2] * v_full[2]); + e_pot += 0.f; /* No gravitational potential thus far */ + e_int += hydro_get_internal_energy(p); /* Minimal time for next end of time-step */ t_end_min = fminf(p->t_end, t_end_min); @@ -960,11 +945,16 @@ void runner_dokick(struct runner *r, struct cell *c, int timer) { for (int k = 0; k < 8; k++) if (c->progeny[k] != NULL) { struct cell *cp = c->progeny[k]; + + /* Recurse */ runner_dokick(r, cp, 0); + /* And aggregate */ updated += cp->updated; - ekin += cp->ekin; - epot += cp->epot; + e_kin += cp->e_kin; + e_int += cp->e_int; + e_pot += cp->e_pot; + mass += cp->mass; mom[0] += cp->mom[0]; mom[1] += cp->mom[1]; mom[2] += cp->mom[2]; @@ -978,8 +968,10 @@ void runner_dokick(struct runner *r, struct cell *c, int timer) { /* Store the values. */ c->updated = updated; - c->ekin = ekin; - c->epot = epot; + c->e_kin = e_kin; + c->e_int = e_int; + c->e_pot = e_pot; + c->mass = mass; c->mom[0] = mom[0]; c->mom[1] = mom[1]; c->mom[2] = mom[2]; diff --git a/src/runner_doiact.h b/src/runner_doiact.h index cddd249acd77f305a456d7b78023d4e4ca613cc7..1b987eb140569629fc4583199c58e3f33446cb78 100644 --- a/src/runner_doiact.h +++ b/src/runner_doiact.h @@ -1398,9 +1398,6 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { /* Get a pointer to the ith particle. */ pi = &parts[pid]; - /* if(pi->id == 1000) message("oO 1000"); */ - /* if(pi->id == 515050) message("oO 515050"); */ - /* Get the particle position and radius. */ for (k = 0; k < 3; k++) pix[k] = pi->x[k]; hi = pi->h; @@ -1624,9 +1621,6 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { /* Get a pointer to the ith particle. */ pi = &parts[pid]; - /* if(pi->id == 1000) message("oO 1000"); */ - /* if(pi->id == 515050) message("oO 515050"); */ - /* Get the particle position and radius. */ for (k = 0; k < 3; k++) pix[k] = pi->x[k]; hi = pi->h; diff --git a/src/serial_io.c b/src/serial_io.c index ebb7eee68882766c5f550cda7feee1d9b68ab5cc..5402afba096bc62530ef04a5c717c2180d7a7c95 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -241,10 +241,10 @@ void prepareArray(hid_t grp, char* fileName, FILE* xmfFile, char* name, * * Calls #error() if an error occurs. */ -void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, - enum DATA_TYPE type, int N, int dim, long long N_total, - int mpi_rank, long long offset, char* part_c, - struct UnitSystem* us, +void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, + enum DATA_TYPE type, int N, int dim, long long N_total, + int mpi_rank, long long offset, char* part_c, + struct UnitSystem* us, enum UnitConversionFactor convFactor) { hid_t h_data = 0, h_err = 0, h_memspace = 0, h_filespace = 0; @@ -259,11 +259,10 @@ void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, /* message("Writing '%s' array...", name); */ /* Prepare the arrays in the file */ - if(mpi_rank == 0) - prepareArray(grp, fileName, xmfFile, name, type, N_total, dim, - us, convFactor); + if (mpi_rank == 0) + prepareArray(grp, fileName, xmfFile, name, type, N_total, dim, us, + convFactor); - /* Allocate temporary buffer */ temp = malloc(N * dim * sizeOfType(type)); if (temp == NULL) error("Unable to allocate memory for temporary buffer"); @@ -359,9 +358,9 @@ void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, */ #define writeArray(grp, fileName, xmfFile, name, type, N, dim, part, N_total, \ mpi_rank, offset, field, us, convFactor) \ - writeArrayBackEnd(grp, fileName, xmfFile, name, type, N, dim, N_total, \ - mpi_rank, offset, (char*)(&(part[0]).field), \ - us, convFactor) + writeArrayBackEnd(grp, fileName, xmfFile, name, type, N, dim, N_total, \ + mpi_rank, offset, (char*)(&(part[0]).field), us, \ + convFactor) /* Import the right hydro definition */ #include "hydro_io.h" @@ -512,7 +511,7 @@ void read_ic_serial(char* fileName, double dim[3], struct part** parts, int* N, */ void write_output_serial(struct engine* e, struct UnitSystem* us, int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info) { - hid_t h_file = 0, h_grp = 0; + hid_t h_file = 0, h_grp = 0, h_grpsph = 0; int N = e->s->nr_parts; int periodic = e->s->periodic; int numParticles[6] = {N, 0}; @@ -602,7 +601,10 @@ void write_output_serial(struct engine* e, struct UnitSystem* us, int mpi_rank, writeCodeDescription(h_file); /* Print the SPH parameters */ - writeSPHflavour(h_file); + h_grpsph = H5Gcreate1(h_file, "/SPH", 0); + if (h_grpsph < 0) error("Error while creating SPH group"); + writeSPHflavour(h_grpsph); + H5Gclose(h_grpsph); /* Print the system of Units */ writeUnitSystem(h_file, us); @@ -639,8 +641,8 @@ void write_output_serial(struct engine* e, struct UnitSystem* us, int mpi_rank, error("Error while opening particle group on rank %d.\n", mpi_rank); /* Write particle fields from the particle structure */ - hydro_write_particles(h_grp, fileName, xmfFile, N, N_total, mpi_rank, offset, - parts, us); + hydro_write_particles(h_grp, fileName, xmfFile, N, N_total, mpi_rank, + offset, parts, us); /* Close particle group */ H5Gclose(h_grp); diff --git a/src/single_io.c b/src/single_io.c index 1a74f690f1a0658f74a58c55d3ab0ffcf2717463..b0e350ffe2e2f7ff077c29dd0b581c9c3c555822 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -383,7 +383,7 @@ void read_ic_single(char* fileName, double dim[3], struct part** parts, int* N, */ void write_output_single(struct engine* e, struct UnitSystem* us) { - hid_t h_file = 0, h_grp = 0; + hid_t h_file = 0, h_grp = 0, h_grpsph = 0; int N = e->s->nr_parts; int periodic = e->s->periodic; int numParticles[6] = {N, 0}; @@ -451,7 +451,10 @@ void write_output_single(struct engine* e, struct UnitSystem* us) { writeCodeDescription(h_file); /* Print the SPH parameters */ - writeSPHflavour(h_file); + h_grpsph = H5Gcreate1(h_file, "/SPH", 0); + if (h_grpsph < 0) error("Error while creating SPH group"); + writeSPHflavour(h_grpsph); + H5Gclose(h_grpsph); /* Print the system of Units */ writeUnitSystem(h_file, us); diff --git a/src/tools.c b/src/tools.c index 34cd4c436a128a3e177a7d4405b313130b143889..5feba7759f730faea1f38ceb9835f2076bc37a56 100644 --- a/src/tools.c +++ b/src/tools.c @@ -420,7 +420,7 @@ void engine_single_force(double *dim, long long int pid, } /* Dump the result. */ - message("part %lli (h=%e) has a=[%.3e,%.3e,%.3e]", p.id, p.h, p.a[0], p.a[1], - p.a[2]); + message("part %lli (h=%e) has a=[%.3e,%.3e,%.3e]", p.id, p.h, p.a_hydro[0], + p.a_hydro[1], p.a_hydro[2]); fflush(stdout); }