hydro.h 13.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*******************************************************************************
 * This file is part of SWIFT.
 * Coypright (c) 2015 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/>.
 *
 ******************************************************************************/
19
20
#ifndef SWIFT_DEFAULT_HYDRO_H
#define SWIFT_DEFAULT_HYDRO_H
21

22
#include "adiabatic_index.h"
23
#include "approx_math.h"
24
#include "equation_of_state.h"
25
#include "hydro_space.h"
26
#include "minmax.h"
27

28
29
#include <float.h>

30
31
32
33
34
35
36
/**
 * @brief Returns the internal energy of a particle
 *
 * @param p The particle of interest
 * @param dt Time since the last kick
 */
__attribute__((always_inline)) INLINE static float hydro_get_internal_energy(
37
    const struct part *restrict p) {
38
39
40
41
42
43
44
45
46
47
48

  return p->u;
}

/**
 * @brief Returns the pressure of a particle
 *
 * @param p The particle of interest
 * @param dt Time since the last kick
 */
__attribute__((always_inline)) INLINE static float hydro_get_pressure(
49
    const struct part *restrict p) {
50
51
52
53
54
55
56
57
58
59
60

  return gas_pressure_from_internal_energy(p->rho, p->u);
}

/**
 * @brief Returns the entropy of a particle
 *
 * @param p The particle of interest
 * @param dt Time since the last kick
 */
__attribute__((always_inline)) INLINE static float hydro_get_entropy(
61
    const struct part *restrict p) {
62
63
64
65
66
67
68
69
70
71
72

  return gas_entropy_from_internal_energy(p->rho, p->u);
}

/**
 * @brief Returns the sound speed of a particle
 *
 * @param p The particle of interest
 * @param dt Time since the last kick
 */
__attribute__((always_inline)) INLINE static float hydro_get_soundspeed(
73
    const struct part *restrict p) {
74
75
76
77

  return p->force.soundspeed;
}

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
 * @brief Returns the density of a particle
 *
 * @param p The particle of interest
 */
__attribute__((always_inline)) INLINE static float hydro_get_density(
    const struct part *restrict p) {

  return p->rho;
}

/**
 * @brief Returns the mass of a particle
 *
 * @param p The particle of interest
 */
__attribute__((always_inline)) INLINE static float hydro_get_mass(
    const struct part *restrict p) {

  return p->mass;
}

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**
 * @brief Returns the velocities drifted to the current time of a particle.
 *
 * @param p The particle of interest
 * @param xp The extended data of the particle.
 * @param dt The time since the last kick.
 * @param v (return) The velocities at the current time.
 */
__attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities(
    const struct part *restrict p, const struct xpart *xp, float dt,
    float v[3]) {

  v[0] = xp->v_full[0] + p->a_hydro[0] * dt;
  v[1] = xp->v_full[1] + p->a_hydro[1] * dt;
  v[2] = xp->v_full[2] + p->a_hydro[2] * dt;
}

117
/**
118
 * @brief Returns the time derivative of internal energy of a particle
119
 *
120
 * We assume a constant density.
121
 *
122
 * @param p The particle of interest
123
 */
124
125
__attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt(
    const struct part *restrict p) {
126

127
  return p->force.u_dt;
128
129
130
}

/**
131
 * @brief Returns the time derivative of internal energy of a particle
132
 *
133
 * We assume a constant density.
134
 *
135
136
 * @param p The particle of interest.
 * @param du_dt The new time derivative of the internal energy.
137
 */
138
139
__attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt(
    struct part *restrict p, float du_dt) {
140

141
  p->force.u_dt = du_dt;
142
143
}

144
145
146
147
148
149
150
151
/**
 * @brief Computes the hydro time-step of a given particle
 *
 * @param p Pointer to the particle data
 * @param xp Pointer to the extended particle data
 *
 */
__attribute__((always_inline)) INLINE static float hydro_compute_timestep(
152
153
    const struct part *restrict p, const struct xpart *restrict xp,
    const struct hydro_props *restrict hydro_properties) {
154
155

  const float CFL_condition = hydro_properties->CFL_condition;
156
157

  /* CFL condition */
158
159
  const float dt_cfl =
      2.f * kernel_gamma * CFL_condition * p->h / p->force.v_sig;
160
161

  /* Limit change in u */
Matthieu Schaller's avatar
Matthieu Schaller committed
162
163
164
  const float dt_u_change =
      (p->force.u_dt != 0.0f) ? fabsf(const_max_u_change * p->u / p->force.u_dt)
                              : FLT_MAX;
165

166
  return min(dt_cfl, dt_u_change);
167
168
}

169
170
171
172
173
174
175
176
177
178
/**
 * @brief Does some extra hydro operations once the actual physical time step
 * for the particle is known.
 *
 * @param p The particle to act upon.
 * @param dt Physical time step of the particle during the next step.
 */
__attribute__((always_inline)) INLINE static void hydro_timestep_extra(
    struct part *p, float dt) {}

179
180
181
/**
 * @brief Prepares a particle for the density calculation.
 *
182
 * Zeroes all the relevant arrays in preparation for the sums taking place in
183
184
185
 * the variaous density tasks
 *
 * @param p The particle to act upon
186
 * @param hs #hydro_space containing hydro specific space information.
187
 */
188
__attribute__((always_inline)) INLINE static void hydro_init_part(
189
    struct part *restrict p, const struct hydro_space *hs) {
190
191
192
193
194
  p->density.wcount = 0.f;
  p->density.wcount_dh = 0.f;
  p->rho = 0.f;
  p->rho_dh = 0.f;
  p->density.div_v = 0.f;
195
196
197
  p->density.rot_v[0] = 0.f;
  p->density.rot_v[1] = 0.f;
  p->density.rot_v[2] = 0.f;
198
199
200
}

/**
201
 * @brief Finishes the density calculation.
202
 *
203
 * Multiplies the density and number of neighbours by the appropiate constants
204
205
206
207
 * and add the self-contribution term.
 *
 * @param p The particle to act upon
 */
208
__attribute__((always_inline)) INLINE static void hydro_end_density(
209
    struct part *restrict p) {
210
211
212

  /* Some smoothing length multiples. */
  const float h = p->h;
213
214
215
  const float h_inv = 1.0f / h;                       /* 1/h */
  const float h_inv_dim = pow_dimension(h_inv);       /* 1/h^d */
  const float h_inv_dim_plus_one = h_inv_dim * h_inv; /* 1/h^(d+1) */
216

217
218
  /* Final operation on the density (add self-contribution). */
  p->rho += p->mass * kernel_root;
219
  p->rho_dh -= hydro_dimension * p->mass * kernel_root;
220
221
222
  p->density.wcount += kernel_root;

  /* Finish the calculation by inserting the missing h-factors */
223
224
  p->rho *= h_inv_dim;
  p->rho_dh *= h_inv_dim_plus_one;
225
  p->density.wcount *= kernel_norm;
226
  p->density.wcount_dh *= h_inv * kernel_gamma * kernel_norm;
227
228
229

  const float irho = 1.f / p->rho;

230
  /* Finish calculation of the velocity curl components */
231
232
233
  p->density.rot_v[0] *= h_inv_dim_plus_one * irho;
  p->density.rot_v[1] *= h_inv_dim_plus_one * irho;
  p->density.rot_v[2] *= h_inv_dim_plus_one * irho;
234
235

  /* Finish calculation of the velocity divergence */
236
  p->density.div_v *= h_inv_dim_plus_one * irho;
237
238
}

239
240
241
242
243
244
245
246
247
/**
 * @brief Sets all particle fields to sensible values when the #part has 0 ngbs.
 *
 * @param p The particle to act upon
 * @param xp The extended particle data to act upon
 */
__attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
    struct part *restrict p, struct xpart *restrict xp) {

248
249
250
251
252
  /* Some smoothing length multiples. */
  const float h = p->h;
  const float h_inv = 1.0f / h;                 /* 1/h */
  const float h_inv_dim = pow_dimension(h_inv); /* 1/h^d */

253
  /* Re-set problematic values */
254
255
  p->rho = p->mass * kernel_root * h_inv_dim;
  p->density.wcount = kernel_root * kernel_norm * h_inv_dim;
256
257
258
259
260
261
262
263
  p->rho_dh = 0.f;
  p->density.wcount_dh = 0.f;
  p->density.div_v = 0.f;
  p->density.rot_v[0] = 0.f;
  p->density.rot_v[1] = 0.f;
  p->density.rot_v[2] = 0.f;
}

264
265
266
267
268
269
270
/**
 * @brief Prepare a particle for the force calculation.
 *
 * Computes viscosity term, conduction term and smoothing length gradient terms.
 *
 * @param p The particle to act upon
 * @param xp The extended particle data to act upon
271
 * @param time The current time
272
 */
Matthieu Schaller's avatar
Matthieu Schaller committed
273
__attribute__((always_inline)) INLINE static void hydro_prepare_force(
274
    struct part *restrict p, struct xpart *restrict xp) {
275
276
277

  /* Some smoothing length multiples. */
  const float h = p->h;
278
  const float h_inv = 1.0f / h;
279
280

  /* Pre-compute some stuff for the balsara switch. */
281
  const float normDiv_v = fabs(p->density.div_v);
282
  const float normRot_v = sqrtf(p->density.rot_v[0] * p->density.rot_v[0] +
Matthieu Schaller's avatar
Matthieu Schaller committed
283
                                p->density.rot_v[1] * p->density.rot_v[1] +
284
                                p->density.rot_v[2] * p->density.rot_v[2]);
285
286
287

  /* Compute this particle's sound speed. */
  const float u = p->u;
Matthieu Schaller's avatar
Matthieu Schaller committed
288
289
  const float fc = p->force.soundspeed =
      sqrtf(hydro_gamma * hydro_gamma_minus_one * u);
290

291
292
293
  /* Compute the derivative term */
  p->rho_dh = 1.f / (1.f + hydro_dimension_inv * p->h * p->rho_dh / p->rho);

294
  /* Compute the P/Omega/rho2. */
295
  xp->omega = 1.0f + hydro_dimension_inv * h * p->rho_dh / p->rho;
296
  p->force.P_over_rho2 = u * hydro_gamma_minus_one / (p->rho * xp->omega);
297
298

  /* Balsara switch */
299
  p->force.balsara = normDiv_v / (normDiv_v + normRot_v + 0.0001f * fc * h_inv);
300
301

  /* Viscosity parameter decay time */
302
303
  /* const float tau = h / (2.f * const_viscosity_length * p->force.soundspeed);
   */
304
305

  /* Viscosity source term */
306
  /* const float S = max(-normDiv_v, 0.f); */
307
308

  /* Compute the particle's viscosity parameter time derivative */
309
310
  /* const float alpha_dot = (const_viscosity_alpha_min - p->alpha) / tau + */
  /*                         (const_viscosity_alpha_max - p->alpha) * S; */
311
312

  /* Update particle's viscosity paramter */
313
  /* p->alpha += alpha_dot * (p->ti_end - p->ti_begin) * timeBase; */  // MATTHIEU
314
315
316
317
318
319
320
321
322
323
}

/**
 * @brief Reset acceleration fields of a particle
 *
 * Resets all hydro acceleration and time derivative fields in preparation
 * for the sums taking place in the variaous force tasks
 *
 * @param p The particle to act upon
 */
324
__attribute__((always_inline)) INLINE static void hydro_reset_acceleration(
325
    struct part *restrict p) {
326
327

  /* Reset the acceleration. */
Matthieu Schaller's avatar
Matthieu Schaller committed
328
329
330
  p->a_hydro[0] = 0.0f;
  p->a_hydro[1] = 0.0f;
  p->a_hydro[2] = 0.0f;
331

332
333
  /* Reset the time derivatives. */
  p->force.u_dt = 0.0f;
334
  p->force.h_dt = 0.0f;
335
336
337
  p->force.v_sig = 0.0f;
}

338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
/**
 * @brief Sets the values to be predicted in the drifts to their values at a
 * kick time
 *
 * @param p The particle.
 * @param xp The extended data of this particle.
 */
__attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
    struct part *restrict p, const struct xpart *restrict xp) {

  /* Re-set the predicted velocities */
  p->v[0] = xp->v_full[0];
  p->v[1] = xp->v_full[1];
  p->v[2] = xp->v_full[2];
}

354
355
356
357
358
/**
 * @brief Predict additional particle fields forward in time when drifting
 *
 * @param p The particle
 * @param xp The extended data of the particle
359
 * @param dt The drift time-step.
Matthieu Schaller's avatar
Matthieu Schaller committed
360
361
 * @param t0 The time at the start of the drift
 * @param t1 The time at the end of the drift
362
 * @param timeBase The minimal time-step size
363
 */
364
__attribute__((always_inline)) INLINE static void hydro_predict_extra(
365
    struct part *restrict p, struct xpart *restrict xp, float dt) {
366
367
  float u, w;

368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  const float h_inv = 1.f / p->h;

  /* Predict smoothing length */
  const float w1 = p->force.h_dt * h_inv * dt;
  if (fabsf(w1) < 0.2f)
    p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */
  else
    p->h *= expf(w1);

  /* Predict density */
  const float w2 = -hydro_dimension * w1;
  if (fabsf(w2) < 0.2f)
    p->rho *= approx_expf(w2); /* 4th order expansion of exp(w) */
  else
    p->rho *= expf(w2);
Matthieu Schaller's avatar
Matthieu Schaller committed
383

384
385
  /* Predict internal energy */
  w = p->force.u_dt / p->u * dt;
386
387
  if (fabsf(w) < 0.2f)
    u = p->u *= approx_expf(w);
388
389
  else
    u = p->u *= expf(w);
390

391
  /* Predict gradient term */
392
  p->force.P_over_rho2 = u * hydro_gamma_minus_one / (p->rho * xp->omega);
393
394
395
}

/**
396
 * @brief Finishes the force calculation.
397
 *
398
 * Multiplies the forces and accelerationsby the appropiate constants
399
400
401
 *
 * @param p The particle to act upon
 */
402
__attribute__((always_inline)) INLINE static void hydro_end_force(
403
    struct part *restrict p) {
404
  p->force.h_dt *= p->h * hydro_dimension_inv;
405
}
406
407
408
409
410

/**
 * @brief Kick the additional variables
 *
 * @param p The particle to act upon
411
412
413
 * @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
414
 */
415
__attribute__((always_inline)) INLINE static void hydro_kick_extra(
416
    struct part *restrict p, struct xpart *restrict xp, float dt) {}
417
418

/**
419
 *  @brief Converts hydro quantity of a particle at the start of a run
420
421
422
423
424
 *
 * Requires the density to be known
 *
 * @param p The particle to act upon
 */
425
__attribute__((always_inline)) INLINE static void hydro_convert_quantities(
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
    struct part *restrict p, struct xpart *restrict xp) {}

/**
 * @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 *restrict p, struct xpart *restrict xp) {

  p->time_bin = 0;
  xp->v_full[0] = p->v[0];
  xp->v_full[1] = p->v[1];
  xp->v_full[2] = p->v[2];
  xp->u_full = p->u;

  hydro_reset_acceleration(p);
447
  hydro_init_part(p, NULL);
448
}
449
450

#endif /* SWIFT_DEFAULT_HYDRO_H */