Peano
Loading...
Searching...
No Matches
HydroForce.cpph
Go to the documentation of this file.
1#include "equation_of_state.h"
2#include "hydro_dimensions.h"
3#include "kernel_hydro.h"
4
5
6template <typename Particle>
8 const peano4::datamanagement::CellMarker& marker, const bool& localParticleIsContainedInCell, const Particle& localParticle
9) {
10 return ::swift2::kernels::localParticleCanBeUpdatedInCellKernel(marker, localParticleIsContainedInCell, localParticle);
11}
12
13
14template <typename Particle>
16 const peano4::datamanagement::CellMarker& marker, const Particle& localParticle, const Particle& activeParticle
17) {
18 assertion3(marker.isContained(
19 localParticle.getX(),
21 ),
22 marker.toString(), localParticle.toString(), activeParticle.toString()
23 );
24 return &localParticle != &activeParticle;
25}
26
27
28template <typename Particle>
31 Particle& localParticle,
32 const Particle& activeParticle
33) {
36 marker,
37 localParticle,
38 activeParticle
39 ), localParticle.toString(), activeParticle.toString()
40 );
41 force_kernel(&localParticle, &activeParticle);
42}
43
44
45template <typename Particle>
46void swift2::kernels::legacy::hydro_prepare_force(Particle* localParticle) {
47
48 static tarch::logging::Log _log("swift2::kernels::legacy");
49
50 // Grab static parameters
51 const int hydroDimensions = localParticle->getHydroDimensions();
52 const double alphaAV = localParticle->getAlphaAV();
53 double hydro_h_max = std::min(
54 localParticle->getSmlMax(),
55 localParticle->getSearchRadius() / kernel_gamma
56 );
57
58 // Retrieve basic properties of local and active particles
59 const double rho_i = localParticle->getDensity();
60 const double m_i = localParticle->getMass();
61 const double h_i = localParticle->getSmoothingLength();
62 const double u_i = localParticle->getU();
63
64 const double h_inv = 1.0 / h_i;
65
66 // This is needed for cosmological integration.
67 const double fac_balsara_eps = 1.;
68
69 // Compute the norm of the curl
70#if Dimensions < 3
71 const double curl_v = std::sqrt(
72 localParticle->getRot_v() * localParticle->getRot_v()
73 );
74#else
75 const double curl_v = tarch::la::norm2(localParticle->getRot_v());
76#endif
77
78 /* Compute the norm of div v */
79 const double abs_div_v = tarch::la::abs(localParticle->getDiv_v());
80
81 /* Compute the pressure */
82 const double P_i = eos::gas_pressure_from_internal_energy(rho_i, u_i);
83 assertion1(std::isfinite(P_i), localParticle->toString());
84 assertion1(P_i > 0., localParticle->toString());
85
86 /* Compute the sound speed */
87 const double soundspeed = legacy::eos::gas_soundspeed_from_pressure(
88 rho_i,
89 P_i
90 );
91 assertion1(std::isfinite(soundspeed), localParticle->toString());
92
93 /* Compute the "grad h" term - Note here that we have \tilde{x}
94 * as 1 as we use the local number density to find neighbours. This
95 * introduces a j-component that is considered in the force loop,
96 * meaning that this cached grad_h_term gives:
97 *
98 * f_ij = 1.f - grad_h_term_i / m_j */
99 const double common_factor = h_i / hydroDimensions
100 / localParticle->getWcount();
101
102 float grad_h_term;
103 // Ignore changing-kernel effects when h ~= h_max
104 if (h_i > 0.9999 * hydro_h_max) {
105 grad_h_term = 0.;
107 "hydro_prepare_force",
108 "h ~ h_max for particle x=" << localParticle->getX() <<
109#if PeanoDebug > 0
110 ", partID=" << localParticle->getPartid() <<
111#endif
112 ", h = " << h_i << ", h_max = " << hydro_h_max
113 );
114 } else {
115 const double grad_W_term = common_factor * localParticle->getWcount_dh();
116 if (grad_W_term < -0.9999) {
117 /* if we get here, we either had very small neighbour contributions
118 (which should be treated as a no neighbour case in the ghost) or
119 a very weird particle distribution (e.g. particles sitting on
120 top of each other). Either way, we cannot use the normal
121 expression, since that would lead to overflow or excessive round
122 off and cause excessively high accelerations in the force loop */
123 grad_h_term = 0.;
125 "hydro_prepare_force",
126 "grad_W_term very small for particle x="
127 << localParticle->getX() <<
128#if PeanoDebug > 0
129 ", partID=" << localParticle->getPartid() <<
130#endif
131 ", h:" << h_i << ", wcount:" << localParticle->getWcount()
132 << ", wcount_dh:" << localParticle->getWcount_dh() << ", grad_W_term:"
133 << grad_W_term << ", common_factor:" << common_factor
134 );
135 } else {
136 grad_h_term = common_factor * localParticle->getRho_dh()
137 / (1. + grad_W_term);
138 }
139 }
140
141
142 /* Compute the Balsara Switch */
143 const double balsara
144 = alphaAV * abs_div_v
145 / (abs_div_v + curl_v + 0.0001 * fac_balsara_eps * soundspeed * h_inv);
146
148 std::isfinite(balsara),
149 localParticle->toString(),
150 balsara,
151 abs_div_v,
152 curl_v,
154 alphaAV
155 );
156
157 /* Update variables */
158 localParticle->setF(grad_h_term);
159 localParticle->setPressure(P_i);
160 localParticle->setSoundSpeed(soundspeed);
161 localParticle->setBalsara(balsara);
162
163#if PeanoDebug > 0
164 localParticle->setForceNeighbourCount(0);
165#endif
166}
167
168
169template <typename Particle>
171) {
172
173 /* Reset the acceleration*/
174 localParticle->setA(0.0);
175
176 /* Reset the time derivatives */
177 localParticle->setUDot(0.0);
178 localParticle->setHDot(0.0);
179 localParticle->setV_sig_AV(2.0 * localParticle->getSoundSpeed());
180}
181
182
183template <typename Particle>
184void swift2::kernels::legacy::hydro_end_force(Particle* localParticle) {
185
186 static tarch::logging::Log _log("swift2::kernels::legacy");
187
188 const int hydroDimensions = localParticle->getHydroDimensions();
189 const double hydroDimensionsInv = 1. / (double)hydroDimensions;
190
191 localParticle->setHDot(
192 localParticle->getHDot() * localParticle->getSmoothingLength()
193 * hydroDimensionsInv
194 );
196 std::isfinite(localParticle->getHDot()),
197 localParticle->toString(),
198 localParticle->getSmoothingLength()
199 );
200
201#if PeanoDebug > 0
202 // During the smoothing length computation, we complete a neighbour loop
203 // while assuming we have the correct sml. In the final step, we compute
204 // the new sml and compare it to the one we used. If the difference is
205 // small enough, as set by the convergence criterion, we consider the
206 // sml converged. However, it is imporant to note that we use "small
207 // enough", not "zero". So the sml may be slightly different after the
208 // sml computation iteration completes.
209 // Down the line, this can lead to scenarios where we interacted with
210 // more particles during the density loop than the force loop. Provided
211 // the convergence criterion has been set adequately small, the difference
212 // in results should be negligible. However, since for a fixed smoothing
213 // length one expects equal or more neighbour interactions during a force
214 // loop since we take into account either a particle's own radius or the
215 // radius of the interacting neighbour, as opposed to only the particle's
216 // own radius during the density loop, this expectation is no longer strictly
217 // satisfied.
218 // Previously, I used to have an assertion here to make sure the interaction
219 // counts satisfy that expectation. For the reason explained above, that
220 // doesn't work. So instead, we just check for it and raise a warning, since
221 // it *could* be an indication of something going wrong. Typically, one can
222 // expect a 1-2 particle difference. If it's larger than that, there is
223 // most likely an issue present.
224 if (localParticle->getDensityNeighbourCount() > localParticle->getForceNeighbourCount()) {
226 "hydro_end_force()",
227 "Particle interacted with fewer particles in Force than in Density loop"
228 << localParticle->toString()
229 )
230 }
231#endif
232}
233
234
235template <typename Particle>
237 Particle* localParticle,
238 const Particle* activeParticle
239) {
240
241 // macro expansions from swift2/legacy/kernels are cumbersome otherwise.
242 using namespace kernelHydro;
243
244 // Grab static parameters
245 const int hydroDimensions = localParticle->getHydroDimensions();
246 const double alphaAV = localParticle->getAlphaAV();
247 const double betaAV = localParticle->getBetaAV();
248
249 // No cosmology yet: a^{(3 gamma - 5 )/ 2} = 1.
250 const double fac_mu = 1.;
251 const double a2_Hubble = 0.; // a**2 * H, where H = da/dt / a. = 0 without
252 // cosmo
253
254 // Distance between the two particles
256 dx = localParticle->getX() - activeParticle->getX();
257
258 const double r = tarch::la::norm2(dx);
259 const double r_inv = r ? 1.0 / r : 0.0;
260
261 // Get actual interaction radius
262 const double h_i = localParticle->getSmoothingLength();
263 const double iactRi = kernel_gamma * h_i;
264 const double h_j = activeParticle->getSmoothingLength();
265 const double iactRj = kernel_gamma * h_j;
266
267 if ((tarch::la::smaller(r, iactRi) or (tarch::la::smaller(r, iactRj))) and tarch::la::greater(r, 0.0)) {
268
269#if PeanoDebug > 0
270 localParticle->setForceNeighbourCount(
271 localParticle->getForceNeighbourCount() + 1
272 );
273#endif
274
275 // Retrieve basic properties of local and active particles
276 const double m_i = localParticle->getMass();
277 const double m_j = activeParticle->getMass();
278
279 const double rho_i = localParticle->getDensity();
280 const double rho_j = activeParticle->getDensity();
281
282 const double P_i = localParticle->getPressure();
283 const double P_j = activeParticle->getPressure();
284
285 // Get kernel for hi
286 const double h_i_inv = 1. / h_i;
287 const double h_i_inv_dp1 = swift2::kernels::legacy::hydroDimensions::
288 pow_dimension_plus_one(h_i_inv); // 1/h^{dim + 1}
289 const double qi = r * h_i_inv;
290 double wi, dwi_dqi;
291 // Evaluate kernel and its derivative for particle a
292 kernel_deval(qi, wi, dwi_dqi);
293 const double dwi_dr = dwi_dqi * h_i_inv_dp1;
294
295 // Get kernel for hj
296 const double h_j_inv = 1. / h_j;
297 const double h_j_inv_dp1 = swift2::kernels::legacy::hydroDimensions::
298 pow_dimension_plus_one(h_j_inv); // 1/h^{dim + 1}
299 const double qj = r * h_j_inv;
300 double wj, dwj_dqj;
301 // Evaluate kernel and its derivative for particle b
302 kernel_deval(qj, wj, dwj_dqj);
303 const double dwj_dr = dwj_dqj * h_j_inv_dp1;
304
305 // Variable smoothing length term
306
307 // SWIFT "f"
308 const double f_ij = 1.0 - localParticle->getF() / m_j;
309 const double f_ji = 1.0 - activeParticle->getF() / m_i;
310
311 // Compute gradient terms
312 const double P_over_rho2_i = P_i / (rho_i * rho_i) * f_ij;
313 const double P_over_rho2_j = P_j / (rho_j * rho_j) * f_ji;
314
315 // Compute dv dot r.
316 double dvdr = tarch::la::dot(
317 (localParticle->getV() - activeParticle->getV()),
318 dx
319 );
320
321 // Add Hubble flow: Skipped for now
322 const double dvdr_Hubble = dvdr + a2_Hubble * r * r;
323
324 /* Are the particles moving towards each others ? */
325 const double omega_ij = std::min(dvdr_Hubble, 0.);
326 const double mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */
327
328 /* Compute sound speeds and signal velocity */
329 const double v_sig = localParticle->getSoundSpeed()
330 + activeParticle->getSoundSpeed() - betaAV * mu_ij;
331
332 /* Balsara term */
333 const double balsara_i = localParticle->getBalsara();
334 const double balsara_j = activeParticle->getBalsara();
335
336 /* Construct the full viscosity term */
337 const double rho_ij = 0.5 * (rho_i + rho_j);
338 const double visc = -0.25 * v_sig * mu_ij * (balsara_i + balsara_j) / rho_ij;
339
340 /* Convolve with the kernel */
341 const double visc_acc_term = 0.5 * visc * (dwi_dr * f_ij + dwj_dr * f_ji)
342 * r_inv;
343
344 /* SPH acceleration term */
345 const double sph_acc_term = (P_over_rho2_i * dwi_dr + P_over_rho2_j * dwj_dr)
346 * r_inv;
347
348 // Assemble the acceleration
349 const double acc = sph_acc_term + visc_acc_term;
350
352 std::isfinite(visc_acc_term),
353 visc_acc_term,
354 localParticle->toString(),
355 activeParticle->toString(),
356 dwi_dr,
357 f_ij,
358 dwj_dr,
359 f_ji,
360 r_inv,
361 visc
362 );
364 std::isfinite(sph_acc_term),
365 sph_acc_term,
366 localParticle->toString(),
367 activeParticle->toString()
368 );
369
370 // Use the force
371 // NOTE: This is a_hydro in SWIFT
372 localParticle->setA(localParticle->getA() - m_j * acc * dx);
373
374 /* Get the time derivative for u. */
375 const double sph_du_term_i = P_over_rho2_i * dvdr * r_inv * dwi_dr;
376
377 /* Viscosity term */
378 const double visc_du_term = 0.5 * visc_acc_term * dvdr_Hubble;
379
380 // Assemble the energy equation term
381 const double du_dt_i = sph_du_term_i + visc_du_term;
382
383 // Internal energy time derivative
384 localParticle->setUDot(localParticle->getUDot() + m_j * du_dt_i);
385
386 /* Get the time derivative for h. */
387 localParticle->setHDot(
388 localParticle->getHDot() - m_j * dvdr * r_inv / rho_j * dwi_dr * f_ij
389 );
390
391 // Update the signal velocity
392 localParticle->setV_sig_AV(std::max(localParticle->getV_sig_AV(), v_sig));
393
395 not std::isnan(localParticle->getHDot()),
396 localParticle->toString(),
397 dvdr,
398 r_inv,
399 dwi_dr,
400 f_ij,
401 f_ji
402 );
404 not tarch::la::isEntryNan(localParticle->getA()),
405 localParticle->toString(),
406 sph_acc_term,
407 visc_acc_term,
408 f_ij,
409 f_ji,
410 activeParticle->toString()
411 );
412 }
413}
#define assertion2(expr, param0, param1)
#define assertion3(expr, param0, param1, param2)
#define assertion1(expr, param)
#define assertion9(expr, param0, param1, param2, param3, param4, param5, param6, param7, param8)
#define assertion6(expr, param0, param1, param2, param3, param4, param5)
#define logWarning(methodName, logMacroMessageStream)
Wrapper macro around tarch::tarch::logging::Log to improve logging.
Definition Log.h:440
Log Device.
Definition Log.h:516
tarch::logging::Log _log("exahype2::fv")
const float soundspeed
Definition hydro.h:373
p force v_sig
Definition hydro.h:379
File containing macro-riddled functions related to dimensions.
const float dx[3]
Definition hydro_iact.h:54
const float r_inv
Definition hydro_iact.h:69
kernel_deval(ui, &wi, &wi_dx)
const float r
Definition hydro_iact.h:68
const float dvdr
Definition hydro_iact.h:106
const float h_inv
Definition hydro_iact.h:158
InlineMethod T pow_dimension_plus_one(T x)
returns x^{ndim+1}
void hydro_reset_acceleration(Particle *localParticle)
Reset acceleration fields of a particle.
void force_kernel(Particle *localParticle, const Particle *activeParticle)
The actual force kernel, which interacts a local particle and an active particle, and updates the loc...
bool forceKernelUpdateParticlePredicate(const peano4::datamanagement::CellMarker &marker, const bool &localParticleIsContainedInCell, const Particle &localParticle)
void hydro_end_force(Particle *localParticle)
Finishes the force calculation.
bool forceKernelEvaluatePairInteractionPredicate(const peano4::datamanagement::CellMarker &marker, const Particle &localParticle, const Particle &activeParticle)
void hydro_prepare_force(Particle *localParticle)
Prepare a particle for the force calculation.
void forceKernel(const peano4::datamanagement::CellMarker &marker, Particle &localParticle, const Particle &activeParticle)
Generic force kernel implementation.
bool localParticleCanBeUpdatedInCellKernelFromAnyOtherParticle(const peano4::datamanagement::CellMarker &marker, const Particle &localParticle, const Particle &activeParticle)
Can we do work on this particle during a cell kernel sweep stage?
Scalar dot(const Vector< Size, Scalar > &lhs, const Vector< Size, Scalar > &rhs)
Performs the dot (=inner) product of two vectors.
static InlineMethod bool smaller(double lhs, double rhs, double tolerance=NUMERICAL_ZERO_DIFFERENCE)
Smaller operator for floating point values.
bool greater(double lhs, double rhs, double tolerance=NUMERICAL_ZERO_DIFFERENCE)
constexpr double NUMERICAL_ZERO_DIFFERENCE
Definition Scalar.h:17
double abs(double value)
Returns the absolute value of a type by redirecting to std::abs.
int isEntryNan(const Vector< Size, Scalar > &vector)
Scalar norm2(const Vector< Size, Scalar > &vector)
Computes the 2-norm of the vector, i.e.
double relativeGrabOwnershipSpatialSortingTolerance(const ::peano4::datamanagement::VertexMarker &marker)
Definition internal.cpp:23
const struct part *restrict const struct part *restrict const float mu_ij
contains functions and definitions related to the equation of state of ideal gases.
Kernel functions for SPH.
Simple vector class.
Definition Vector.h:150