Peano
Loading...
Searching...
No Matches
runner_do_ghost.h
Go to the documentation of this file.
1#pragma once
2
3void runner_do_ghost(Tree *leaf, const hydro_props *hydro_properties, HYDRO_STATS_T *hydro_stats);
4
5void do_density(Tree *leaf) {
6 float r2, hi, hj, hig2, hjg2, dx[3] = {0};
7 struct part *pi, *pj;
8
9 const float a = 1.0f; // SWIFT parameter, ignored by the Minimal SPH scheme
10 const float H = 1.0f; // SWIFT parameter, ignored by the Minimal SPH scheme
11
12 if (leaf->items.empty()) [[unlikely]] return;
13
14 auto activeRegion = Tree::Geo::Region(leaf->range.low - 0.001, leaf->range.high + 0.001);
15 auto *activeRegionParent = leaf->getRegionParent(activeRegion, true);
16 auto activeRegionIter = Tree::InsideRegionLeafsIterator(activeRegionParent, activeRegion);
17
18 auto *activeCell = (Tree *) nullptr;
19 while ((activeCell = activeRegionIter.next().value_or(nullptr))) {
20 for (auto localIdx = 0; localIdx < leaf->items.size(); localIdx++) {
21 pi = &leaf->items[localIdx];
22 hi = pi->h;
23 auto hig = hi * kernel_gamma;
24 hig2 = hig * hig;
25
26 if (!activeCell->range.overlaps({pi->_x - hig, pi->_x + hig})) continue;
27
28 for (auto activeIdx = 0; activeIdx < activeCell->items.size(); activeIdx++) {
29 pj = &activeCell->items[activeIdx];
30 r2 = 0.0f;
31
32 for (int k = 0; k < Geo::D::N; k++) {
33 dx[k] = pi->_x[k] - pj->_x[k];
34 r2 += dx[k] * dx[k];
35 }
36
37 auto hjg = pj->h * kernel_gamma;
38 hjg2 = hjg * hjg;
39
40 /* Hit or miss? */
41 if ((r2 > 0) & (r2 < hig2 | r2 < hjg2)) {
42 /* Interact */
43 runner_iact_nonsym_density(r2, dx, hi, pj->h, pi, pj, a, H);
44 }
45 }
46 }
47 }
48}
49
50void do_density(Tree *leaf, int *pids, int pidCount) {
51 float r2, hi, hj, hig2, hjg2, dx[3] = {0};
52 struct part *pi, *pj;
53
54 const float a = 1.0f; // SWIFT parameter, ignored by the Minimal SPH scheme
55 const float H = 1.0f; // SWIFT parameter, ignored by the Minimal SPH scheme
56
57 if (leaf->items.empty()) [[unlikely]] return;
58
59 auto activeRegion = Tree::Geo::Region(leaf->range.low - 0.001, leaf->range.high + 0.001);
60 auto *activeRegionParent = leaf->getRegionParent(activeRegion, true);
61 auto activeRegionIter = Tree::InsideRegionLeafsIterator(activeRegionParent, activeRegion);
62
63 auto *activeCell = (Tree *) nullptr;
64 while ((activeCell = activeRegionIter.next().value_or(nullptr))) {
65 for (auto pidIdx = 0; pidIdx < pidCount; pidIdx++) {
66 pi = &leaf->items[pids[pidIdx]];
67 hi = pi->h;
68 auto hig = hi * kernel_gamma;
69 hig2 = hig * hig;
70
71 if (!activeCell->range.overlaps({pi->_x - hig, pi->_x + hig})) continue;
72
73 for (auto activeIdx = 0; activeIdx < activeCell->items.size(); activeIdx++) {
74 pj = &activeCell->items[activeIdx];
75 r2 = 0.0f;
76
77 for (int k = 0; k < Geo::D::N; k++) {
78 dx[k] = pi->_x[k] - pj->_x[k];
79 r2 += dx[k] * dx[k];
80 }
81
82 auto hjg = pj->h * kernel_gamma;
83 hjg2 = hjg * hjg;
84
85 /* Hit or miss? */
86 if ((r2 > 0) & (r2 < hig2 | r2 < hjg2)) {
87 /* Interact */
88 runner_iact_nonsym_density(r2, dx, hi, pj->h, pi, pj, a, H);
89 }
90 }
91 }
92 }
93}
94
95void runner_do_ghost(Tree *leaf, const hydro_props *hydro_properties, HYDRO_STATS_T *hydro_stats) {
96 const float hydro_h_max = hydro_properties->h_max;
97 const float hydro_h_min = hydro_properties->h_min;
98 const float eps = hydro_properties->h_tolerance;
99 const float hydro_eta_dim =
100 pow_dimension(hydro_properties->eta_neighbours);
101 const int use_mass_weighted_num_ngb =
102 hydro_properties->use_mass_weighted_num_ngb;
103 const int max_smoothing_iter = hydro_properties->max_smoothing_iterations;
104 int redo = 0, count = 0;
105
106 /* Running value of the maximal smoothing length */
107 float h_max = hydro_stats->h_max;
108 float h_max_active = hydro_stats->h_max_active;
109
110 /* Recurse? */
111 if (false) {} else {
112
113 /* Init the list of active particles that have to be updated and their
114 * current smoothing lengths. */
115 int *pid = NULL;
116 float *h_0 = NULL;
117 float *left = NULL;
118 float *right = NULL;
119 if ((pid = (int *)malloc(sizeof(int) * leaf->items.size())) == NULL)
120 printf("Can't allocate memory for pid.");
121 if ((h_0 = (float *)malloc(sizeof(float) * leaf->items.size())) == NULL)
122 printf("Can't allocate memory for h_0.");
123 if ((left = (float *)malloc(sizeof(float) * leaf->items.size())) == NULL)
124 printf("Can't allocate memory for left.");
125 if ((right = (float *)malloc(sizeof(float) * leaf->items.size())) == NULL)
126 printf("Can't allocate memory for right.");
127 for (int k = 0; k < leaf->items.size(); k++) {
128 pid[count] = k;
129 h_0[count] = leaf->items[k].h;
130 left[count] = 0.f;
131 right[count] = hydro_h_max;
132 ++count;
133 }
134
135 /* While there are particles that need to be updated... */
136 for (int num_reruns = 0; count > 0 && num_reruns < max_smoothing_iter;
137 num_reruns++) {
138
139 /* Reset the redo-count. */
140 redo = 0;
141
142 /* Loop over the remaining active parts in this cell. */
143 for (int i = 0; i < count; i++) {
144
145 /* Get a direct pointer on the part. */
146 struct part *p = &leaf->items[pid[i]];
147 struct xpart *xp = &leaf->items[pid[i]].xpart;
148
149#ifdef SWIFT_DEBUG_CHECKS
150 /* Is this part within the timestep? */
151 if (!part_is_active(p, e)) error("Ghost applied to inactive particle");
152#endif
153
154 /* Get some useful values */
155 const float h_init = h_0[i];
156 const float h_old = p->h;
157 const float h_old_dim = pow_dimension(h_old);
158 const float h_old_dim_minus_one = pow_dimension_minus_one(h_old);
159
160 float h_new;
161 int has_no_neighbours = 0;
162
163 if (p->density.wcount < 1.e-5 * kernel_root) { /* No neighbours case */
164
165 /* Flag that there were no neighbours */
166 has_no_neighbours = 1;
167
168 /* Double h and try again */
169 h_new = 2.f * h_old;
170
171 } else {
172
173 /* Finish the density calculation */
174 hydro_end_density(p, &COSMO);
175
176 /* Are we using the alternative definition of the
177 number of neighbours? */
178 if (use_mass_weighted_num_ngb) {
179#if defined(GIZMO_MFV_SPH) || defined(GIZMO_MFM_SPH) || defined(SHADOWFAX_SPH)
180 error(
181 "Can't use alternative neighbour definition with this scheme!");
182#else
183 const float inv_mass = 1.f / hydro_get_mass(p);
184 p->density.wcount = p->rho * inv_mass;
185 p->density.wcount_dh = p->density.rho_dh * inv_mass;
186#endif
187 }
188
189 /* Compute one step of the Newton-Raphson scheme */
190 const float n_sum = p->density.wcount * h_old_dim;
191 const float n_target = hydro_eta_dim;
192 const float f = n_sum - n_target;
193 const float f_prime =
194 p->density.wcount_dh * h_old_dim +
195 hydro_dimension * p->density.wcount * h_old_dim_minus_one;
196
197 /* Improve the bisection bounds */
198 if (n_sum < n_target)
199 left[i] = MAX(left[i], h_old);
200 else if (n_sum > n_target)
201 right[i] = MAX(right[i], h_old);
202
203#ifdef SWIFT_DEBUG_CHECKS
204 /* Check the validity of the left and right bounds */
205 if (left[i] > right[i])
206 error("Invalid left (%e) and right (%e)", left[i], right[i]);
207#endif
208
209 /* Skip if h is already h_max and we don't have enough neighbours */
210 /* Same if we are below h_min */
211 if (((p->h >= hydro_h_max) && (f < 0.f)) ||
212 ((p->h <= hydro_h_min) && (f > 0.f))) {
213
214 /* We have a particle whose smoothing length is already set (wants
215 * to be larger but has already hit the maximum OR wants to be
216 * smaller but has already reached the minimum). So, just tidy up
217 * as if the smoothing length had converged correctly */
218
219#ifdef EXTRA_HYDRO_LOOP
220
221 /* As of here, particle gradient variables will be set. */
222 /* The force variables are set in the extra ghost. */
223
224 /* Compute variables required for the gradient loop */
225 hydro_prepare_gradient(p, xp, cosmo, hydro_props, pressure_floor);
226 mhd_prepare_gradient(p, xp, cosmo, hydro_props);
227
228 /* The particle gradient values are now set. Do _NOT_
229 try to read any particle density variables! */
230
231 /* Prepare the particle for the gradient loop over neighbours
232 */
233 hydro_reset_gradient(p);
234 mhd_reset_gradient(p);
235
236#else
237
238 /* As of here, particle force variables will be set. */
239
240 /* Compute variables required for the force loop */
241 hydro_prepare_force(p, xp, &COSMO, &HYDRO_PROPS, nullptr,
242 0.0, 0.0);
243
244 /* The particle force values are now set. Do _NOT_
245 try to read any particle density variables! */
246
247 /* Prepare the particle for the force loop over neighbours */
248 hydro_reset_acceleration(p);
249
250#endif /* EXTRA_HYDRO_LOOP */
251
252 /* Ok, we are done with this particle */
253 continue;
254 }
255
256 /* Normal case: Use Newton-Raphson to get a better value of h */
257
258 /* Avoid floating point exception from f_prime = 0 */
259 h_new = h_old - f / (f_prime + std::numeric_limits<float>::min());
260
261 /* Be verbose about the particles that struggle to converge */
262 if (num_reruns > max_smoothing_iter - 10) {
263
264 printf(
265 "Smoothing length convergence problem: iter=%d p->id=%lld "
266 "h_init=%12.8e h_old=%12.8e h_new=%12.8e f=%f f_prime=%f "
267 "n_sum=%12.8e n_target=%12.8e left=%12.8e right=%12.8e\n",
268 num_reruns, p->id, h_init, h_old, h_new, f, f_prime, n_sum,
269 n_target, left[i], right[i]);
270 }
271
272#ifdef SWIFT_DEBUG_CHECKS
273 if (((f > 0.f && h_new > h_old) || (f < 0.f && h_new < h_old)) &&
274 (h_old < 0.999f * hydro_props->h_max))
275 error(
276 "Smoothing length correction not going in the right direction");
277#endif
278
279 /* Safety check: truncate to the range [ h_old/2 , 2h_old ]. */
280 h_new = MIN(h_new, 2.f * h_old);
281 h_new = MAX(h_new, 0.5f * h_old);
282
283 /* Verify that we are actually progrssing towards the answer */
284 h_new = MAX(h_new, left[i]);
285 h_new = MIN(h_new, right[i]);
286 }
287
288 /* Check whether the particle has an inappropriate smoothing length
289 */
290 if (fabsf(h_new - h_old) > eps * h_old) {
291
292 /* Ok, correct then */
293
294 /* Case where we have been oscillating around the solution */
295 if ((h_new == left[i] && h_old == right[i]) ||
296 (h_old == left[i] && h_new == right[i])) {
297
298 /* Bisect the remaining interval */
299 p->h = pow_inv_dimension(
300 0.5f * (pow_dimension(left[i]) + pow_dimension(right[i])));
301
302 } else {
303
304 /* Normal case */
305 p->h = h_new;
306 }
307
308 /* If within the allowed range, try again */
309 if (p->h < hydro_h_max && p->h > hydro_h_min) {
310
311 /* Flag for another round of fun */
312 pid[redo] = pid[i];
313 h_0[redo] = h_0[i];
314 left[redo] = left[i];
315 right[redo] = right[i];
316 redo += 1;
317
318 /* Re-initialise everything */
319 hydro_init_part(p, nullptr);
320
321 /* Off we go ! */
322 continue;
323
324 } else if (p->h <= hydro_h_min) {
325
326 /* Ok, this particle is a lost cause... */
327 p->h = hydro_h_min;
328
329 } else if (p->h >= hydro_h_max) {
330
331 /* Ok, this particle is a lost cause... */
332 p->h = hydro_h_max;
333
334 /* Do some damage control if no neighbours at all were found */
335 if (has_no_neighbours) {
336 assert(false)
337 hydro_part_has_no_neighbours(p, xp, &COSMO);
338 }
339
340 } else {
341 printf(
342 "Fundamental problem with the smoothing length iteration "
343 "logic.");
344 }
345 }
346
347 /* We now have a particle whose smoothing length has converged */
348
349 /* Check if h_max has increased */
350 h_max = MAX(h_max, p->h);
351 h_max_active = MAX(h_max_active, p->h);
352
353
354
355 /* As of here, particle force variables will be set. */
356
357 /* Compute variables required for the force loop */
358 hydro_prepare_force(p, xp, &COSMO, &HYDRO_PROPS, nullptr, 0.0,
359 0.0);
360
361 /* The particle force values are now set. Do _NOT_
362 try to read any particle density variables! */
363
364 /* Prepare the particle for the force loop over neighbours */
365 hydro_reset_acceleration(p);
366
367 }
368
369 /* We now need to treat the particles whose smoothing length had not
370 * converged again */
371
372 /* Re-set the counter for the next loop (potentially). */
373 count = redo;
374 if (count > 0) {
375 do_density(leaf, pid, count);
376 }
377 }
378
379 if (count) {
380 printf(
381 "Smoothing length failed to converge for the following gas "
382 "particles:\n");
383 for (int i = 0; i < count; i++) {
384 struct part *p = &leaf->items[pid[i]];
385 printf("ID: %lld, h: %g, wcount: %g\n", p->id, p->h, p->density.wcount);
386 }
387
388 printf("Smoothing length failed to converge on %i particles.\n", count);
389 }
390
391 /* Be clean */
392 free(left);
393 free(right);
394 free(pid);
395 free(h_0);
396 }
397
398 /* Update h_max */
399 hydro_stats->h_max = h_max;
400 hydro_stats->h_max_active = h_max_active;
401
402#ifdef SWIFT_DEBUG_CHECKS
403 for (int i = 0; i < c->hydro.count; ++i) {
404 const struct part *p = &c->hydro.parts[i];
405 const float h = c->hydro.parts[i].h;
406 if (part_is_inhibited(p, e)) continue;
407
408 if (h > c->hydro.h_max)
409 error("Particle has h larger than h_max (id=%lld)", p->id);
410 if (part_is_active(p, e) && h > c->hydro.h_max_active)
411 error("Active particle has h larger than h_max_active (id=%lld)", p->id);
412 }
413#endif
414
415
416}
double f(double p4, double p1, double p5, double rho1, double rho5, double gamma)
#define assert(...)
Definition LinuxAMD.h:28
const auto COSMO
Definition main.cpp:42
const auto HYDRO_PROPS
Definition main.cpp:29
Geo::Region range
Definition linked_grid.h:51
const struct xpart *restrict const struct cosmology * cosmo
Definition hydro.h:74
const struct cosmology const struct pressure_floor_props * pressure_floor
Definition hydro.h:365
const struct xpart *restrict xp
Definition hydro.h:58
const float const float const float hj
Definition hydro_iact.h:54
const float dx[3]
Definition hydro_iact.h:54
const float const float hi
Definition hydro_iact.h:54
const float const float const float struct part *restrict struct part *restrict pj
Definition hydro_iact.h:55
const float const float const float struct part *restrict struct part *restrict const float const float H
Definition hydro_iact.h:56
const float const float const float struct part *restrict struct part *restrict const float a
Definition hydro_iact.h:55
#define MIN(a, b)
Minimum of two numbers.
Definition minmax.h:27
#define MAX(a, b)
Maximum of two numbers.
Definition minmax.h:39
void do_density(Tree *leaf)
void runner_do_ghost(Tree *leaf, const hydro_props *hydro_properties, HYDRO_STATS_T *hydro_stats)
#define kernel_root
float h_max_active
Definition main.cpp:26
float h_max
Definition main.cpp:25
Vector< Item > items
Definition spacetree.h:74
Spacetree * getRegionParent(const Geo::Region &range, bool refined=false)
Definition spacetree.h:180
InsideRegionLeafsIterator< Spacetree, IterOrder > InsideRegionLeafsIterator
Definition spacetree.h:65
Contains all the constants and parameters of the hydro scheme.
int use_mass_weighted_num_ngb
int max_smoothing_iterations
Particle fields for the SPH particles.
Definition hydro_part.h:99
float h
Definition hydro_part.h:120
Geo::Point _x
Definition hydro_part.h:108
Particle fields not needed during the SPH loops over neighbours.
Definition hydro_part.h:55
constexpr double pi
Definition Poisson.cpp:2