scheduler.c 61.9 KB
Newer Older
1
2
/*******************************************************************************
 * This file is part of SWIFT.
3
 * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
4
 *                    Matthieu Schaller (matthieu.schaller@durham.ac.uk)
5
 *               2016 Peter W. Draper (p.w.draper@durham.ac.uk)
6
 *
7
8
9
10
 * 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.
11
 *
12
13
14
15
 * 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.
16
 *
17
18
 * 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
21
22
23
24
25
 ******************************************************************************/

/* Config parameters. */
#include "../config.h"

/* Some standard headers. */
26
27
28
#include <limits.h>
#include <math.h>
#include <pthread.h>
29
30
31
32
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

33
34
/* MPI headers. */
#ifdef WITH_MPI
35
#include <mpi.h>
36
37
#endif

38
39
40
/* This object's header. */
#include "scheduler.h"

41
42
/* Local headers. */
#include "atomic.h"
43
#include "cycle.h"
44
#include "engine.h"
45
#include "error.h"
46
#include "intrinsics.h"
47
#include "kernel_hydro.h"
48
#include "queue.h"
49
#include "sort_part.h"
50
#include "space.h"
51
#include "space_getsid.h"
52
#include "task.h"
53
#include "timers.h"
54
#include "version.h"
55

56
57
58
59
60
/**
 * @brief Re-set the list of active tasks.
 */
void scheduler_clear_active(struct scheduler *s) { s->active_count = 0; }

61
62
63
64
65
66
67
/**
 * @brief Add an unlock_task to the given task.
 *
 * @param s The #scheduler.
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 */
68
69
void scheduler_addunlock(struct scheduler *s, struct task *ta,
                         struct task *tb) {
70
71
72
73
74
#ifdef SWIFT_DEBUG_CHECKS
  if (ta == NULL) error("Unlocking task is NULL.");
  if (tb == NULL) error("Unlocked task is NULL.");
#endif

75
76
77
78
79
  /* Get an index at which to store this unlock. */
  const int ind = atomic_inc(&s->nr_unlocks);

  /* Does the buffer need to be grown? */
  if (ind == s->size_unlocks) {
80
    /* Allocate the new buffer. */
81
82
83
    struct task **unlocks_new;
    int *unlock_ind_new;
    const int size_unlocks_new = s->size_unlocks * 2;
84
85
    if ((unlocks_new = (struct task **)malloc(sizeof(struct task *) *
                                              size_unlocks_new)) == NULL ||
86
87
        (unlock_ind_new = (int *)malloc(sizeof(int) * size_unlocks_new)) ==
            NULL)
88
      error("Failed to re-allocate unlocks.");
89

90
    /* Wait for all writes to the old buffer to complete. */
91
92
93
    while (s->completed_unlock_writes < ind)
      ;

94
    /* Copy the buffers. */
95
96
97
98
99
100
    memcpy(unlocks_new, s->unlocks, sizeof(struct task *) * ind);
    memcpy(unlock_ind_new, s->unlock_ind, sizeof(int) * ind);
    free(s->unlocks);
    free(s->unlock_ind);
    s->unlocks = unlocks_new;
    s->unlock_ind = unlock_ind_new;
101

102
    /* Publish the new buffer size. */
103
104
    s->size_unlocks = size_unlocks_new;
  }
105

106
  /* Wait for there to actually be space at my index. */
107
108
  while (ind > s->size_unlocks)
    ;
109
110
111
112

  /* Write the unlock to the scheduler. */
  s->unlocks[ind] = tb;
  s->unlock_ind[ind] = ta - s->tasks;
113
  atomic_inc(&s->completed_unlock_writes);
114
115
}

116
117
118
/**
 * @brief Write a dot file with the task dependencies.
 *
Matthieu Schaller's avatar
Matthieu Schaller committed
119
120
121
 * Run plot_task_dependencies.sh for an example of how to use it
 * to generate the figure.
 *
122
 * @param s The #scheduler we are working in.
Matthieu Schaller's avatar
Matthieu Schaller committed
123
 * @param verbose Are we verbose about this?
124
 */
Matthieu Schaller's avatar
Matthieu Schaller committed
125
void scheduler_write_dependencies(struct scheduler *s, int verbose) {
Matthieu Schaller's avatar
Matthieu Schaller committed
126

Matthieu Schaller's avatar
Matthieu Schaller committed
127
  const ticks tic = getticks();
128

Matthieu Schaller's avatar
Matthieu Schaller committed
129
130
  /* Conservative number of dependencies per task type */
  const int max_nber_dep = 128;
lhausamm's avatar
lhausamm committed
131

Peter W. Draper's avatar
Peter W. Draper committed
132
  /* Number of possible relations between tasks */
Matthieu Schaller's avatar
Matthieu Schaller committed
133
134
  const int nber_relation =
      2 * task_type_count * task_subtype_count * max_nber_dep;
135

Matthieu Schaller's avatar
Matthieu Schaller committed
136
137
138
139
  /* To get the table of max_nber_dep for a task:
   * ind = (ta * task_subtype_count + sa) * max_nber_dep * 2
   * where ta is the value of task_type and sa is the value of
   * task_subtype  */
140
  int *table = (int *)malloc(nber_relation * sizeof(int));
Matthieu Schaller's avatar
Matthieu Schaller committed
141
142
  if (table == NULL)
    error("Error allocating memory for task-dependency graph.");
lhausamm's avatar
lhausamm committed
143

Matthieu Schaller's avatar
Matthieu Schaller committed
144
145
  /* Reset everything */
  for (int i = 0; i < nber_relation; i++) table[i] = -1;
lhausamm's avatar
lhausamm committed
146

Matthieu Schaller's avatar
Matthieu Schaller committed
147
  /* Create file */
148
  char filename[200] = "dependency_graph.dot";
Matthieu Schaller's avatar
Matthieu Schaller committed
149
  FILE *f = fopen(filename, "w");
Peter W. Draper's avatar
Peter W. Draper committed
150
  if (f == NULL) error("Error opening dependency graph file.");
151

Matthieu Schaller's avatar
Matthieu Schaller committed
152
  /* Write header */
153
  fprintf(f, "digraph task_dep {\n");
154
  fprintf(f, "label=\"Task dependencies for SWIFT %s\";\n", git_revision());
155
156
157
158
159
  fprintf(f, "\t compound=true;\n");
  fprintf(f, "\t ratio=0.66;\n");
  fprintf(f, "\t node[nodesep=0.15];\n");

  /* loop over all tasks */
Matthieu Schaller's avatar
Matthieu Schaller committed
160
161
  for (int i = 0; i < s->nr_tasks; i++) {
    const struct task *ta = &s->tasks[i];
lhausamm's avatar
lhausamm committed
162

Peter W. Draper's avatar
Peter W. Draper committed
163
    /* and their dependencies */
Matthieu Schaller's avatar
Matthieu Schaller committed
164
165
    for (int j = 0; j < ta->nr_unlock_tasks; j++) {
      const struct task *tb = ta->unlock_tasks[j];
lhausamm's avatar
lhausamm committed
166
167

      /* check if dependency already written */
168
      int written = 0;
lhausamm's avatar
lhausamm committed
169

170
      /* Current index */
171
172
      int ind = ta->type * task_subtype_count + ta->subtype;
      ind *= 2 * max_nber_dep;
lhausamm's avatar
lhausamm committed
173

174
175
      int k = 0;
      int *cur = &table[ind];
lhausamm's avatar
lhausamm committed
176
      while (k < max_nber_dep) {
Matthieu Schaller's avatar
Matthieu Schaller committed
177

lhausamm's avatar
lhausamm committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
        /* not written yet */
        if (cur[0] == -1) {
          cur[0] = tb->type;
          cur[1] = tb->subtype;
          break;
        }

        /* already written */
        if (cur[0] == tb->type && cur[1] == tb->subtype) {
          written = 1;
          break;
        }

        k += 1;
        cur = &cur[3];
      }
194
195
196

      /* max_nber_dep is too small */
      if (k == max_nber_dep)
lhausamm's avatar
lhausamm committed
197
198
        error("Not enough memory, please increase max_nber_dep");

lhausamm's avatar
lhausamm committed
199
      /* Not written yet => write it */
200
      if (!written) {
Matthieu Schaller's avatar
Matthieu Schaller committed
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220

        /* text to write */
        char ta_name[200];
        char tb_name[200];

        /* construct line */
        if (ta->subtype == task_subtype_none)
          sprintf(ta_name, "%s", taskID_names[ta->type]);
        else
          sprintf(ta_name, "\"%s %s\"", taskID_names[ta->type],
                  subtaskID_names[ta->subtype]);

        if (tb->subtype == task_subtype_none)
          sprintf(tb_name, "%s", taskID_names[tb->type]);
        else
          sprintf(tb_name, "\"%s %s\"", taskID_names[tb->type],
                  subtaskID_names[tb->subtype]);

        /* Write to the ffile */
        fprintf(f, "\t %s->%s;\n", ta_name, tb_name);
221

Matthieu Schaller's avatar
Matthieu Schaller committed
222
223
        /* Change colour of implicit tasks */
        if (ta->implicit)
224
          fprintf(f, "\t %s [style = filled];\n\t %s [color = lightgrey];\n",
Matthieu Schaller's avatar
Matthieu Schaller committed
225
226
                  ta_name, ta_name);
        if (tb->implicit)
227
          fprintf(f, "\t %s [style = filled];\n\t %s [color = lightgrey];\n",
Matthieu Schaller's avatar
Matthieu Schaller committed
228
                  tb_name, tb_name);
229
230
231
232
233
234
235
236

        /* Change shape of MPI communications */
        if (ta->type == task_type_send || ta->type == task_type_recv)
          fprintf(f, "\t \"%s %s\" [shape = diamond];\n",
                  taskID_names[ta->type], subtaskID_names[ta->subtype]);
        if (tb->type == task_type_send || tb->type == task_type_recv)
          fprintf(f, "\t \"%s %s\" [shape = diamond];\n",
                  taskID_names[tb->type], subtaskID_names[tb->subtype]);
lhausamm's avatar
lhausamm committed
237
      }
238
    }
lhausamm's avatar
lhausamm committed
239
  }
lhausamm's avatar
lhausamm committed
240

241
  int density_cluster[4] = {0};
242
  int gradient_cluster[4] = {0};
243
244
245
  int force_cluster[4] = {0};
  int gravity_cluster[4] = {0};

246
  /* Check whether we need to construct a group of tasks */
247
248
249
250
251
252
253
254
255
256
257
258
  for (int type = 0; type < task_type_count; ++type) {

    for (int subtype = 0; subtype < task_subtype_count; ++subtype) {

      const int ind = 2 * (type * task_subtype_count + subtype) * max_nber_dep;

      /* Does this task/sub-task exist? */
      if (table[ind] != -1) {

        for (int k = 0; k < 4; ++k) {
          if (type == task_type_self + k && subtype == task_subtype_density)
            density_cluster[k] = 1;
259
260
          if (type == task_type_self + k && subtype == task_subtype_gradient)
            gradient_cluster[k] = 1;
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
          if (type == task_type_self + k && subtype == task_subtype_force)
            force_cluster[k] = 1;
          if (type == task_type_self + k && subtype == task_subtype_grav)
            gravity_cluster[k] = 1;
        }
        if (type == task_type_grav_top_level) gravity_cluster[2] = 1;
        if (type == task_type_grav_long_range) gravity_cluster[3] = 1;
      }
    }
  }

  /* Make a cluster for the density tasks */
  fprintf(f, "\t subgraph cluster0{\n");
  fprintf(f, "\t\t label=\"\";\n");
  for (int k = 0; k < 4; ++k)
    if (density_cluster[k])
      fprintf(f, "\t\t \"%s %s\";\n", taskID_names[task_type_self + k],
              subtaskID_names[task_subtype_density]);
  fprintf(f, "\t};\n");

  /* Make a cluster for the force tasks */
  fprintf(f, "\t subgraph cluster1{\n");
  fprintf(f, "\t\t label=\"\";\n");
  for (int k = 0; k < 4; ++k)
    if (force_cluster[k])
      fprintf(f, "\t\t \"%s %s\";\n", taskID_names[task_type_self + k],
              subtaskID_names[task_subtype_force]);
  fprintf(f, "\t};\n");

290
  /* Make a cluster for the gradient tasks */
291
292
  fprintf(f, "\t subgraph cluster2{\n");
  fprintf(f, "\t\t label=\"\";\n");
293
294
295
296
297
298
299
300
301
  for (int k = 0; k < 4; ++k)
    if (gradient_cluster[k])
      fprintf(f, "\t\t \"%s %s\";\n", taskID_names[task_type_self + k],
              subtaskID_names[task_subtype_gradient]);
  fprintf(f, "\t};\n");

  /* Make a cluster for the gravity tasks */
  fprintf(f, "\t subgraph cluster3{\n");
  fprintf(f, "\t\t label=\"\";\n");
302
303
304
305
306
307
308
309
310
311
  for (int k = 0; k < 2; ++k)
    if (gravity_cluster[k])
      fprintf(f, "\t\t \"%s %s\";\n", taskID_names[task_type_self + k],
              subtaskID_names[task_subtype_grav]);
  if (gravity_cluster[2])
    fprintf(f, "\t\t %s;\n", taskID_names[task_type_grav_top_level]);
  if (gravity_cluster[3])
    fprintf(f, "\t\t %s;\n", taskID_names[task_type_grav_long_range]);
  fprintf(f, "\t};\n");

Matthieu Schaller's avatar
Matthieu Schaller committed
312
  /* Be clean */
313
314
  fprintf(f, "}");
  fclose(f);
315
  free(table);
Matthieu Schaller's avatar
Matthieu Schaller committed
316

Matthieu Schaller's avatar
Matthieu Schaller committed
317
  if (verbose)
Matthieu Schaller's avatar
Matthieu Schaller committed
318
    message("Printing task graph took %.3f %s.",
Matthieu Schaller's avatar
Matthieu Schaller committed
319
            clocks_from_ticks(getticks() - tic), clocks_getunit());
320
321
}

322
/**
323
 * @brief Split a hydrodynamic task if too large.
324
 *
325
326
 * @param t The #task
 * @param s The #scheduler we are working in.
327
 */
328
static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) {
329

330
331
332
  /* Iterate on this task until we're done with it. */
  int redo = 1;
  while (redo) {
333

334
335
    /* Reset the redo flag. */
    redo = 0;
336

337
    /* Non-splittable task? */
338
339
    if ((t->ci == NULL) || (t->type == task_type_pair && t->cj == NULL) ||
        t->ci->count == 0 || (t->cj != NULL && t->cj->count == 0)) {
340
      t->type = task_type_none;
341
342
      t->subtype = task_subtype_none;
      t->cj = NULL;
343
344
345
      t->skip = 1;
      break;
    }
346

347
348
    /* Self-interaction? */
    if (t->type == task_type_self) {
349

350
351
352
353
354
      /* Get a handle on the cell involved. */
      struct cell *ci = t->ci;

      /* Foreign task? */
      if (ci->nodeID != s->nodeID) {
355
        t->skip = 1;
356
        break;
357
358
      }

359
      /* Is this cell even split and the task does not violate h ? */
360
      if (cell_can_split_self_task(ci)) {
361

362
        /* Make a sub? */
363
        if (scheduler_dosub && ci->count < space_subsize_self_hydro) {
364

365
366
367
368
369
          /* convert to a self-subtask. */
          t->type = task_type_sub_self;

          /* Otherwise, make tasks explicitly. */
        } else {
370

371
372
373
374
375
376
377
378
          /* Take a step back (we're going to recycle the current task)... */
          redo = 1;

          /* Add the self tasks. */
          int first_child = 0;
          while (ci->progeny[first_child] == NULL) first_child++;
          t->ci = ci->progeny[first_child];
          for (int k = first_child + 1; k < 8; k++)
379
            if (ci->progeny[k] != NULL && ci->progeny[k]->count)
380
              scheduler_splittask_hydro(
381
                  scheduler_addtask(s, task_type_self, t->subtype, 0, 0,
382
                                    ci->progeny[k], NULL),
383
384
                  s);

385
386
          /* Make a task for each pair of progeny */
          for (int j = 0; j < 8; j++)
387
            if (ci->progeny[j] != NULL && ci->progeny[j]->count)
388
              for (int k = j + 1; k < 8; k++)
389
                if (ci->progeny[k] != NULL && ci->progeny[k]->count)
390
391
                  scheduler_splittask_hydro(
                      scheduler_addtask(s, task_type_pair, t->subtype,
392
                                        sub_sid_flag[j][k], 0, ci->progeny[j],
393
394
                                        ci->progeny[k]),
                      s);
395
        }
396
      } /* Cell is split */
397

398
    } /* Self interaction */
399

400
401
    /* Pair interaction? */
    else if (t->type == task_type_pair) {
402

403
404
405
      /* Get a handle on the cells involved. */
      struct cell *ci = t->ci;
      struct cell *cj = t->cj;
406

407
408
409
410
411
      /* Foreign task? */
      if (ci->nodeID != s->nodeID && cj->nodeID != s->nodeID) {
        t->skip = 1;
        break;
      }
412

413
414
415
      /* Get the sort ID, use space_getsid and not t->flags
         to make sure we get ci and cj swapped if needed. */
      double shift[3];
Matthieu Schaller's avatar
Matthieu Schaller committed
416
      const int sid = space_getsid(s->space, &ci, &cj, shift);
417

418
      /* Should this task be split-up? */
419
      if (cell_can_split_pair_task(ci) && cell_can_split_pair_task(cj)) {
420
421

        /* Replace by a single sub-task? */
422
        if (scheduler_dosub && /* Use division to avoid integer overflow. */
423
            ci->count * sid_scale[sid] < space_subsize_pair_hydro / cj->count &&
424
            !sort_is_corner(sid)) {
425
426
427
428
429

          /* Make this task a sub task. */
          t->type = task_type_sub_pair;

          /* Otherwise, split it. */
430
431
        } else {

432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
          /* Take a step back (we're going to recycle the current task)... */
          redo = 1;

          /* For each different sorting type... */
          switch (sid) {

            case 0: /* (  1 ,  1 ,  1 ) */
              t->ci = ci->progeny[7];
              t->cj = cj->progeny[0];
              t->flags = 0;
              break;

            case 1: /* (  1 ,  1 ,  0 ) */
              t->ci = ci->progeny[6];
              t->cj = cj->progeny[0];
              t->flags = 1;
448
              scheduler_splittask_hydro(
449
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
450
                                    ci->progeny[7], cj->progeny[1]),
451
                  s);
452
              scheduler_splittask_hydro(
453
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
454
                                    ci->progeny[6], cj->progeny[1]),
455
                  s);
456
              scheduler_splittask_hydro(
457
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
458
                                    ci->progeny[7], cj->progeny[0]),
459
460
461
462
463
464
465
466
467
468
469
470
471
                  s);
              break;

            case 2: /* (  1 ,  1 , -1 ) */
              t->ci = ci->progeny[6];
              t->cj = cj->progeny[1];
              t->flags = 2;
              break;

            case 3: /* (  1 ,  0 ,  1 ) */
              t->ci = ci->progeny[5];
              t->cj = cj->progeny[0];
              t->flags = 3;
472
              scheduler_splittask_hydro(
473
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
474
                                    ci->progeny[7], cj->progeny[2]),
475
                  s);
476
              scheduler_splittask_hydro(
477
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
478
                                    ci->progeny[5], cj->progeny[2]),
479
                  s);
480
              scheduler_splittask_hydro(
481
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
482
                                    ci->progeny[7], cj->progeny[0]),
483
484
485
486
487
488
489
                  s);
              break;

            case 4: /* (  1 ,  0 ,  0 ) */
              t->ci = ci->progeny[4];
              t->cj = cj->progeny[0];
              t->flags = 4;
490
              scheduler_splittask_hydro(
491
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
492
                                    ci->progeny[5], cj->progeny[0]),
493
                  s);
494
              scheduler_splittask_hydro(
495
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
496
                                    ci->progeny[6], cj->progeny[0]),
497
                  s);
498
              scheduler_splittask_hydro(
499
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
500
                                    ci->progeny[7], cj->progeny[0]),
501
                  s);
502
              scheduler_splittask_hydro(
503
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
504
                                    ci->progeny[4], cj->progeny[1]),
505
                  s);
506
              scheduler_splittask_hydro(
507
                  scheduler_addtask(s, task_type_pair, t->subtype, 4, 0,
508
                                    ci->progeny[5], cj->progeny[1]),
509
                  s);
510
              scheduler_splittask_hydro(
511
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
512
                                    ci->progeny[6], cj->progeny[1]),
513
                  s);
514
              scheduler_splittask_hydro(
515
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
516
                                    ci->progeny[7], cj->progeny[1]),
517
                  s);
518
              scheduler_splittask_hydro(
519
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
520
                                    ci->progeny[4], cj->progeny[2]),
521
                  s);
522
              scheduler_splittask_hydro(
523
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
524
                                    ci->progeny[5], cj->progeny[2]),
525
                  s);
526
              scheduler_splittask_hydro(
527
                  scheduler_addtask(s, task_type_pair, t->subtype, 4, 0,
528
                                    ci->progeny[6], cj->progeny[2]),
529
                  s);
530
              scheduler_splittask_hydro(
531
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
532
                                    ci->progeny[7], cj->progeny[2]),
533
                  s);
534
              scheduler_splittask_hydro(
535
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
536
                                    ci->progeny[4], cj->progeny[3]),
537
                  s);
538
              scheduler_splittask_hydro(
539
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
540
                                    ci->progeny[5], cj->progeny[3]),
541
                  s);
542
              scheduler_splittask_hydro(
543
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
544
                                    ci->progeny[6], cj->progeny[3]),
545
                  s);
546
              scheduler_splittask_hydro(
547
                  scheduler_addtask(s, task_type_pair, t->subtype, 4, 0,
548
                                    ci->progeny[7], cj->progeny[3]),
549
550
551
552
553
554
555
                  s);
              break;

            case 5: /* (  1 ,  0 , -1 ) */
              t->ci = ci->progeny[4];
              t->cj = cj->progeny[1];
              t->flags = 5;
556
              scheduler_splittask_hydro(
557
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
558
                                    ci->progeny[6], cj->progeny[3]),
559
                  s);
560
              scheduler_splittask_hydro(
561
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
562
                                    ci->progeny[4], cj->progeny[3]),
563
                  s);
564
              scheduler_splittask_hydro(
565
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
566
                                    ci->progeny[6], cj->progeny[1]),
567
568
569
570
571
572
573
574
575
576
577
578
579
                  s);
              break;

            case 6: /* (  1 , -1 ,  1 ) */
              t->ci = ci->progeny[5];
              t->cj = cj->progeny[2];
              t->flags = 6;
              break;

            case 7: /* (  1 , -1 ,  0 ) */
              t->ci = ci->progeny[4];
              t->cj = cj->progeny[3];
              t->flags = 6;
580
              scheduler_splittask_hydro(
581
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
582
                                    ci->progeny[5], cj->progeny[2]),
583
                  s);
584
              scheduler_splittask_hydro(
585
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
586
                                    ci->progeny[4], cj->progeny[2]),
587
                  s);
588
              scheduler_splittask_hydro(
589
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
590
                                    ci->progeny[5], cj->progeny[3]),
591
592
593
594
595
596
597
598
599
600
601
602
603
                  s);
              break;

            case 8: /* (  1 , -1 , -1 ) */
              t->ci = ci->progeny[4];
              t->cj = cj->progeny[3];
              t->flags = 8;
              break;

            case 9: /* (  0 ,  1 ,  1 ) */
              t->ci = ci->progeny[3];
              t->cj = cj->progeny[0];
              t->flags = 9;
604
              scheduler_splittask_hydro(
605
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
606
                                    ci->progeny[7], cj->progeny[4]),
607
                  s);
608
              scheduler_splittask_hydro(
609
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
610
                                    ci->progeny[3], cj->progeny[4]),
611
                  s);
612
              scheduler_splittask_hydro(
613
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
614
                                    ci->progeny[7], cj->progeny[0]),
615
616
617
618
619
620
621
                  s);
              break;

            case 10: /* (  0 ,  1 ,  0 ) */
              t->ci = ci->progeny[2];
              t->cj = cj->progeny[0];
              t->flags = 10;
622
              scheduler_splittask_hydro(
623
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
624
                                    ci->progeny[3], cj->progeny[0]),
625
                  s);
626
              scheduler_splittask_hydro(
627
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
628
                                    ci->progeny[6], cj->progeny[0]),
629
                  s);
630
              scheduler_splittask_hydro(
631
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
632
                                    ci->progeny[7], cj->progeny[0]),
633
                  s);
634
              scheduler_splittask_hydro(
635
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
636
                                    ci->progeny[2], cj->progeny[1]),
637
                  s);
638
              scheduler_splittask_hydro(
639
                  scheduler_addtask(s, task_type_pair, t->subtype, 10, 0,
640
                                    ci->progeny[3], cj->progeny[1]),
641
                  s);
642
              scheduler_splittask_hydro(
643
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
644
                                    ci->progeny[6], cj->progeny[1]),
645
                  s);
646
              scheduler_splittask_hydro(
647
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
648
                                    ci->progeny[7], cj->progeny[1]),
649
                  s);
650
              scheduler_splittask_hydro(
651
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
652
                                    ci->progeny[2], cj->progeny[4]),
653
                  s);
654
              scheduler_splittask_hydro(
655
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
656
                                    ci->progeny[3], cj->progeny[4]),
657
                  s);
658
              scheduler_splittask_hydro(
659
                  scheduler_addtask(s, task_type_pair, t->subtype, 10, 0,
660
                                    ci->progeny[6], cj->progeny[4]),
661
                  s);
662
              scheduler_splittask_hydro(
663
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
664
                                    ci->progeny[7], cj->progeny[4]),
665
                  s);
666
              scheduler_splittask_hydro(
667
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
668
                                    ci->progeny[2], cj->progeny[5]),
669
                  s);
670
              scheduler_splittask_hydro(
671
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
672
                                    ci->progeny[3], cj->progeny[5]),
673
                  s);
674
              scheduler_splittask_hydro(
675
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
676
                                    ci->progeny[6], cj->progeny[5]),
677
                  s);
678
              scheduler_splittask_hydro(
679
                  scheduler_addtask(s, task_type_pair, t->subtype, 10, 0,
680
                                    ci->progeny[7], cj->progeny[5]),
681
682
683
684
685
686
687
                  s);
              break;

            case 11: /* (  0 ,  1 , -1 ) */
              t->ci = ci->progeny[2];
              t->cj = cj->progeny[1];
              t->flags = 11;
688
              scheduler_splittask_hydro(
689
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
690
                                    ci->progeny[6], cj->progeny[5]),
691
                  s);
692
              scheduler_splittask_hydro(
693
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
694
                                    ci->progeny[2], cj->progeny[5]),
695
                  s);
696
              scheduler_splittask_hydro(
697
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
698
                                    ci->progeny[6], cj->progeny[1]),
699
700
701
702
703
704
705
                  s);
              break;

            case 12: /* (  0 ,  0 ,  1 ) */
              t->ci = ci->progeny[1];
              t->cj = cj->progeny[0];
              t->flags = 12;
706
              scheduler_splittask_hydro(
707
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
708
                                    ci->progeny[3], cj->progeny[0]),
709
                  s);
710
              scheduler_splittask_hydro(
711
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
712
                                    ci->progeny[5], cj->progeny[0]),
713
                  s);
714
              scheduler_splittask_hydro(
715
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
716
                                    ci->progeny[7], cj->progeny[0]),
717
                  s);
718
              scheduler_splittask_hydro(
719
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
720
                                    ci->progeny[1], cj->progeny[2]),
721
                  s);
722
              scheduler_splittask_hydro(
723
                  scheduler_addtask(s, task_type_pair, t->subtype, 12, 0,
724
                                    ci->progeny[3], cj->progeny[2]),
725
                  s);
726
              scheduler_splittask_hydro(
727
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
728
                                    ci->progeny[5], cj->progeny[2]),
729
                  s);
730
              scheduler_splittask_hydro(
731
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
732
                                    ci->progeny[7], cj->progeny[2]),
733
                  s);
734
              scheduler_splittask_hydro(
735
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
736
                                    ci->progeny[1], cj->progeny[4]),
737
                  s);
738
              scheduler_splittask_hydro(
739
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
740
                                    ci->progeny[3], cj->progeny[4]),
741
                  s);
742
              scheduler_splittask_hydro(
743
                  scheduler_addtask(s, task_type_pair, t->subtype, 12, 0,
744
                                    ci->progeny[5], cj->progeny[4]),
745
                  s);
746
              scheduler_splittask_hydro(
747
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
748
                                    ci->progeny[7], cj->progeny[4]),
749
                  s);
750
              scheduler_splittask_hydro(
751
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
752
                                    ci->progeny[1], cj->progeny[6]),
753
                  s);
754
              scheduler_splittask_hydro(
755
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
756
                                    ci->progeny[3], cj->progeny[6]),
757
                  s);
758
              scheduler_splittask_hydro(
759
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
760
                                    ci->progeny[5], cj->progeny[6]),
761
                  s);
762
              scheduler_splittask_hydro(
763
                  scheduler_addtask(s, task_type_pair, t->subtype, 12, 0,
764
                                    ci->progeny[7], cj->progeny[6]),