scheduler.c 92.8 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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
32
#include <sys/stat.h>
33

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

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

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

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

62
63
64
65
66
67
68
/**
 * @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.
 */
69
70
void scheduler_addunlock(struct scheduler *s, struct task *ta,
                         struct task *tb) {
71
72
73
74
75
#ifdef SWIFT_DEBUG_CHECKS
  if (ta == NULL) error("Unlocking task is NULL.");
  if (tb == NULL) error("Unlocked task is NULL.");
#endif

76
77
78
79
80
  /* 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) {
81
    /* Allocate the new buffer. */
82
83
84
    struct task **unlocks_new;
    int *unlock_ind_new;
    const int size_unlocks_new = s->size_unlocks * 2;
85
86
    if ((unlocks_new = (struct task **)malloc(sizeof(struct task *) *
                                              size_unlocks_new)) == NULL ||
87
88
        (unlock_ind_new = (int *)malloc(sizeof(int) * size_unlocks_new)) ==
            NULL)
89
      error("Failed to re-allocate unlocks.");
90

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

95
    /* Copy the buffers. */
96
97
98
99
100
101
    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;
102

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

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

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

117
118
119
120
121
122
123
124
125
126
/**
 * @brief compute the number of same dependencies
 *
 * @param s The #scheduler
 * @param ta The #task
 * @param tb The dependent #task
 *
 * @return Number of dependencies
 */
int scheduler_get_number_relation(const struct scheduler *s,
127
128
                                  const struct task *ta,
                                  const struct task *tb) {
129
130
131
132
133
134
135
136
137
138
139

  int count = 0;

  /* loop over all tasks */
  for (int i = 0; i < s->nr_tasks; i++) {
    const struct task *ta_tmp = &s->tasks[i];

    /* and their dependencies */
    for (int j = 0; j < ta->nr_unlock_tasks; j++) {
      const struct task *tb_tmp = ta->unlock_tasks[j];

140
141
142
      if (ta->type == ta_tmp->type && ta->subtype == ta_tmp->subtype &&
          tb->type == tb_tmp->type && tb->subtype == tb_tmp->subtype) {
        count += 1;
143
144
145
146
147
148
      }
    }
  }
  return count;
}

149
/* Conservative number of dependencies per task type */
150
#define MAX_NUMBER_DEP 128
151
152
153
154
155
156
157
158
159

/**
 * @brief Informations about all the task dependencies of
 *   a single task.
 */
struct task_dependency {
  /* Main task */
  /* ID of the task */
  int type_in;
160

161
162
163
164
165
166
167
168
  /* ID of the subtask */
  int subtype_in;

  /* Is the task implicit */
  int implicit_in;

  /* Dependent task */
  /* ID of the dependent task */
169
  int type_out[MAX_NUMBER_DEP];
170
171

  /* ID of the dependent subtask */
172
173
  int subtype_out[MAX_NUMBER_DEP];

174
  /* Is the dependent task implicit */
175
  int implicit_out[MAX_NUMBER_DEP];
176
177
178

  /* Statistics */
  /* number of link between the two task type */
179
  int number_link[MAX_NUMBER_DEP];
180
181

  /* number of ranks having this relation */
182
  int number_rank[MAX_NUMBER_DEP];
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
};

#ifdef WITH_MPI
/**
 * @brief Define the #task_dependency for MPI
 *
 * @param tstype The #MPI_Datatype to initialize
 */
void task_dependency_define(MPI_Datatype *tstype) {

  /* Define the variables */
  const int count = 8;
  int blocklens[count];
  MPI_Datatype types[count];
  MPI_Aint disps[count];

  /* all the type are int */
200
  for (int i = 0; i < count; i++) {
201
202
203
204
205
206
207
208
209
210
211
212
213
    types[i] = MPI_INT;
  }

  /* Task in */
  disps[0] = offsetof(struct task_dependency, type_in);
  blocklens[0] = 1;
  disps[1] = offsetof(struct task_dependency, subtype_in);
  blocklens[1] = 1;
  disps[2] = offsetof(struct task_dependency, implicit_in);
  blocklens[2] = 1;

  /* Task out */
  disps[3] = offsetof(struct task_dependency, type_out);
214
  blocklens[3] = MAX_NUMBER_DEP;
215
  disps[4] = offsetof(struct task_dependency, subtype_out);
216
  blocklens[4] = MAX_NUMBER_DEP;
217
  disps[5] = offsetof(struct task_dependency, implicit_out);
218
  blocklens[5] = MAX_NUMBER_DEP;
219
220
221

  /* statistics */
  disps[6] = offsetof(struct task_dependency, number_link);
222
  blocklens[6] = MAX_NUMBER_DEP;
223
  disps[7] = offsetof(struct task_dependency, number_rank);
224
  blocklens[7] = MAX_NUMBER_DEP;
225
226
227
228
229
230
231
232
233
234
235
236
237
238

  /* define it for MPI */
  MPI_Type_create_struct(count, blocklens, disps, types, tstype);
  MPI_Type_commit(tstype);
}

/**
 * @brief Sum operator of #task_dependency for MPI
 *
 * @param in_p The #task_dependency to add
 * @param out_p The #task_dependency where in_p is added
 * @param len The length of the arrays
 * @param type The MPI datatype
 */
239
240
void task_dependency_sum(void *in_p, void *out_p, int *len,
                         MPI_Datatype *type) {
241
242
243
244
245
246
247
248
249

  /* change pointer type */
  struct task_dependency *in = in_p;
  struct task_dependency *out = out_p;

  /* Loop over all the current objects */
  for (int i = 0; i < *len; i++) {

    /* loop over all the object set in invals */
250
    for (int j = 0; j < MAX_NUMBER_DEP; j++) {
251
252
253

      /* Have we reached the end of the links? */
      if (in[i].number_link[j] == -1) {
254
        break;
255
256
257
258
259
260
261
262
263
      }

      /* get a few variables */
      int tb_type = in[i].type_out[j];
      int tb_subtype = in[i].subtype_out[j];

#ifdef SWIFT_DEBUG_CHECKS
      /* Check tasks */
      if (tb_type >= task_type_count) {
264
        error("Unknown task type %i", tb_type);
265
266
267
      }

      if (tb_subtype >= task_subtype_count) {
268
        error("Unknown subtask type %i", tb_subtype);
269
270
271
272
273
      }
#endif

      /* find the corresponding id */
      int k = 0;
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
      while (k < MAX_NUMBER_DEP) {
        /* have we reached the end of the links? */
        if (out[i].number_link[k] == -1) {
          /* reset the counter in order to be safe */
          out[i].number_link[k] = 0;
          out[i].number_rank[k] = 0;

          /* set the relation */
          out[i].type_in = in[i].type_in;
          out[i].subtype_in = in[i].subtype_in;
          out[i].implicit_in = in[i].implicit_in;

          out[i].type_out[k] = in[i].type_out[j];
          out[i].subtype_out[k] = in[i].subtype_out[j];
          out[i].implicit_out[k] = in[i].implicit_out[j];
          break;
        }

        /* do we have the same relation? */
        if (out[i].type_out[k] == tb_type &&
            out[i].subtype_out[k] == tb_subtype) {
          break;
        }

        k++;
299
300
301
      }

      /* Check if we are still in the memory */
302
303
      if (k == MAX_NUMBER_DEP) {
        error("Not enough memory, please increase MAX_NUMBER_DEP");
304
305
306
307
308
      }

#ifdef SWIFT_DEBUG_CHECKS
      /* Check if correct relation */
      if (out[i].type_in != in[i].type_in ||
309
310
311
312
313
314
          out[i].subtype_in != in[i].subtype_in ||
          out[i].implicit_in != in[i].implicit_in ||
          out[i].type_out[k] != in[i].type_out[j] ||
          out[i].subtype_out[k] != in[i].subtype_out[j] ||
          out[i].implicit_out[k] != in[i].implicit_out[j]) {
        error("Tasks do not correspond");
315
316
317
318
319
320
321
322
323
324
325
326
      }
#endif

      /* sum the contributions */
      out[i].number_link[k] += in[i].number_link[j];
      out[i].number_rank[k] += in[i].number_rank[j];
    }
  }

  return;
}

327
#endif  // WITH_MPI
328

329
330
331
/**
 * @brief Write a dot file with the task dependencies.
 *
Matthieu Schaller's avatar
Matthieu Schaller committed
332
333
334
 * Run plot_task_dependencies.sh for an example of how to use it
 * to generate the figure.
 *
335
 * @param s The #scheduler we are working in.
Matthieu Schaller's avatar
Matthieu Schaller committed
336
 * @param verbose Are we verbose about this?
337
 */
Matthieu Schaller's avatar
Matthieu Schaller committed
338
void scheduler_write_dependencies(struct scheduler *s, int verbose) {
Matthieu Schaller's avatar
Matthieu Schaller committed
339

Matthieu Schaller's avatar
Matthieu Schaller committed
340
  const ticks tic = getticks();
341

Peter W. Draper's avatar
Peter W. Draper committed
342
  /* Number of possible relations between tasks */
343
  const int nber_tasks = task_type_count * task_subtype_count;
344

345
346
  /* To get the table for a task:
   * ind = (ta * task_subtype_count + sa)
Matthieu Schaller's avatar
Matthieu Schaller committed
347
348
   * where ta is the value of task_type and sa is the value of
   * task_subtype  */
349
  struct task_dependency *task_dep = (struct task_dependency *)malloc(
350
      nber_tasks * sizeof(struct task_dependency));
351

352
353
  if (task_dep == NULL)
    error("Error allocating memory for task-dependency graph (table).");
lhausamm's avatar
lhausamm committed
354

355
356
  /* Reset counter */
  for (int i = 0; i < nber_tasks; i++) {
357
    for (int j = 0; j < MAX_NUMBER_DEP; j++) {
358
359
      /* Use number_link as indicator of the existance of a relation */
      task_dep[i].number_link[j] = -1;
360
361
362
    }
  }

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

367
368
369
370
371
372
373
374
375
376
    /* Current index */
    int ind = ta->type * task_subtype_count + ta->subtype;

    struct task_dependency *cur = &task_dep[ind];

    /* Set ta */
    cur->type_in = ta->type;
    cur->subtype_in = ta->subtype;
    cur->implicit_in = ta->implicit;

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

381
      int k = 0;
382
      while (k < MAX_NUMBER_DEP) {
Matthieu Schaller's avatar
Matthieu Schaller committed
383

lhausamm's avatar
lhausamm committed
384
        /* not written yet */
385
        if (cur->number_link[k] == -1) {
386
          /* set tb */
387
388
          cur->type_out[k] = tb->type;
          cur->subtype_out[k] = tb->subtype;
389
390
391
392
393
394
          cur->implicit_out[k] = tb->implicit;

          /* statistics */
          int count = scheduler_get_number_relation(s, ta, tb);
          cur->number_link[k] = count;
          cur->number_rank[k] = 1;
395

lhausamm's avatar
lhausamm committed
396
397
398
399
          break;
        }

        /* already written */
400
401
        if (cur->type_out[k] == tb->type &&
            cur->subtype_out[k] == tb->subtype) {
lhausamm's avatar
lhausamm committed
402
403
404
405
406
          break;
        }

        k += 1;
      }
407

408
409
410
      /* MAX_NUMBER_DEP is too small */
      if (k == MAX_NUMBER_DEP)
        error("Not enough memory, please increase MAX_NUMBER_DEP");
411
412
    }
  }
lhausamm's avatar
lhausamm committed
413

414
415
416
417
#ifdef WITH_MPI
  /* create MPI operator */
  MPI_Datatype data_type;
  task_dependency_define(&data_type);
418

419
  MPI_Op sum;
420
  MPI_Op_create(task_dependency_sum, /* commute */ 1, &sum);
Matthieu Schaller's avatar
Matthieu Schaller committed
421

422
423
  /* create recv buffer */
  struct task_dependency *recv = NULL;
424

425
  if (s->nodeID == 0) {
426
427
    recv = (struct task_dependency *)malloc(nber_tasks *
                                            sizeof(struct task_dependency));
428
429
430

    /* reset counter */
    for (int i = 0; i < nber_tasks; i++) {
431
432
433
      for (int j = 0; j < MAX_NUMBER_DEP; j++) {
        /* Use number_link as indicator of the existance of a relation */
        recv[i].number_link[j] = -1;
434
435
436
      }
    }
  }
lhausamm's avatar
lhausamm committed
437

438
  /* Do the reduction */
439
440
441
  int test =
      MPI_Reduce(task_dep, recv, nber_tasks, data_type, sum, 0, MPI_COMM_WORLD);
  if (test != MPI_SUCCESS) error("MPI reduce failed");
442

443
444
445
446
447
448
  /* free some memory */
  if (s->nodeID == 0) {
    free(task_dep);
    task_dep = recv;
  }
#endif
449

450
451
452
453
454
455
456
457
  if (s->nodeID == 0) {
    /* Create file */
    char *filename = "dependency_graph.csv";
    FILE *f = fopen(filename, "w");
    if (f == NULL) error("Error opening dependency graph file.");

    /* Write header */
    fprintf(f, "# %s\n", git_revision());
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
    fprintf(
        f,
        "task_in,task_out,implicit_in,implicit_out,mpi_in,mpi_out,cluster_in,"
        "cluster_out,number_link,number_rank\n");

    for (int i = 0; i < nber_tasks; i++) {
      for (int j = 0; j < MAX_NUMBER_DEP; j++) {
        /* Does this link exists */
        if (task_dep[i].number_link[j] == -1) {
          continue;
        }

        /* Define a few variables */
        int ta_type = task_dep[i].type_in;
        int ta_subtype = task_dep[i].subtype_in;
        int ta_implicit = task_dep[i].implicit_in;

        int tb_type = task_dep[i].type_out[j];
        int tb_subtype = task_dep[i].subtype_out[j];
        int tb_implicit = task_dep[i].implicit_out[j];

        int count = task_dep[i].number_link[j];
        int number_rank = task_dep[i].number_rank[j];

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

        /* construct line */
        task_get_full_name(ta_type, ta_subtype, ta_name);
        task_get_full_name(tb_type, tb_subtype, tb_name);

        /* Check if MPI */
        int ta_mpi = 0;
        if (ta_type == task_type_send || ta_type == task_type_recv) ta_mpi = 1;

        int tb_mpi = 0;
        if (tb_type == task_type_send || tb_type == task_type_recv) tb_mpi = 1;

        /* Get group name */
        char ta_cluster[20];
        char tb_cluster[20];
        task_get_group_name(ta_type, ta_subtype, ta_cluster);
        task_get_group_name(tb_type, tb_subtype, tb_cluster);

        fprintf(f, "%s,%s,%d,%d,%d,%d,%s,%s,%d,%d\n", ta_name, tb_name,
                ta_implicit, tb_implicit, ta_mpi, tb_mpi, ta_cluster,
                tb_cluster, count, number_rank);
506
507
      }
    }
508
509
510
    /* Close the file */
    fclose(f);
  }
511
512

  /* Be clean */
513
  free(task_dep);
Matthieu Schaller's avatar
Matthieu Schaller committed
514

515
  if (verbose && s->nodeID == 0)
Matthieu Schaller's avatar
Matthieu Schaller committed
516
    message("Printing task graph took %.3f %s.",
Matthieu Schaller's avatar
Matthieu Schaller committed
517
            clocks_from_ticks(getticks() - tic), clocks_getunit());
518
519
}

520
/**
521
 * @brief Split a hydrodynamic task if too large.
522
 *
523
524
 * @param t The #task
 * @param s The #scheduler we are working in.
525
 */
526
static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) {
527

528
529
530
  /* Iterate on this task until we're done with it. */
  int redo = 1;
  while (redo) {
531

532
533
    /* Reset the redo flag. */
    redo = 0;
534

Loic Hausammann's avatar
Loic Hausammann committed
535
    /* Empty task? */
536
    if ((t->ci == NULL) || (t->type == task_type_pair && t->cj == NULL) ||
537
        t->ci->hydro.count == 0 || (t->cj != NULL && t->cj->hydro.count == 0)) {
538
      t->type = task_type_none;
539
540
      t->subtype = task_subtype_none;
      t->cj = NULL;
541
542
543
      t->skip = 1;
      break;
    }
544

545
546
    /* Self-interaction? */
    if (t->type == task_type_self) {
547

548
549
550
551
552
      /* Get a handle on the cell involved. */
      struct cell *ci = t->ci;

      /* Foreign task? */
      if (ci->nodeID != s->nodeID) {
553
        t->skip = 1;
554
        break;
555
556
      }

557
      /* Is this cell even split and the task does not violate h ? */
558
      if (cell_can_split_self_hydro_task(ci)) {
559

560
        /* Make a sub? */
561
        if (scheduler_dosub && ci->hydro.count < space_subsize_self_hydro) {
562

563
564
565
566
567
          /* convert to a self-subtask. */
          t->type = task_type_sub_self;

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

569
570
571
572
573
574
575
576
          /* 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++)
577
            if (ci->progeny[k] != NULL && ci->progeny[k]->hydro.count)
578
              scheduler_splittask_hydro(
579
                  scheduler_addtask(s, task_type_self, t->subtype, 0, 0,
580
                                    ci->progeny[k], NULL),
581
582
                  s);

583
584
          /* Make a task for each pair of progeny */
          for (int j = 0; j < 8; j++)
585
            if (ci->progeny[j] != NULL && ci->progeny[j]->hydro.count)
586
              for (int k = j + 1; k < 8; k++)
587
                if (ci->progeny[k] != NULL && ci->progeny[k]->hydro.count)
588
589
                  scheduler_splittask_hydro(
                      scheduler_addtask(s, task_type_pair, t->subtype,
590
                                        sub_sid_flag[j][k], 0, ci->progeny[j],
591
592
                                        ci->progeny[k]),
                      s);
593
        }
594
      } /* Cell is split */
595

596
    } /* Self interaction */
597

598
599
    /* Pair interaction? */
    else if (t->type == task_type_pair) {
600

601
602
603
      /* Get a handle on the cells involved. */
      struct cell *ci = t->ci;
      struct cell *cj = t->cj;
604

605
606
607
608
609
      /* Foreign task? */
      if (ci->nodeID != s->nodeID && cj->nodeID != s->nodeID) {
        t->skip = 1;
        break;
      }
610

611
612
613
      /* 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
614
      const int sid = space_getsid(s->space, &ci, &cj, shift);
615

616
617
618
619
620
621
#ifdef SWIFT_DEBUG_CHECKS
      if (sid != t->flags)
        error("Got pair task with incorrect flags: sid=%d flags=%lld", sid,
              t->flags);
#endif

622
      /* Should this task be split-up? */
Matthieu Schaller's avatar
Matthieu Schaller committed
623
624
      if (cell_can_split_pair_hydro_task(ci) &&
          cell_can_split_pair_hydro_task(cj)) {
625
626

        /* Replace by a single sub-task? */
627
        if (scheduler_dosub && /* Use division to avoid integer overflow. */
628
629
            ci->hydro.count * sid_scale[sid] <
                space_subsize_pair_hydro / cj->hydro.count &&
630
            !sort_is_corner(sid)) {
631
632
633
634
635

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

          /* Otherwise, split it. */
636
637
        } else {

638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
          /* 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;
654
              scheduler_splittask_hydro(
655
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
656
                                    ci->progeny[7], cj->progeny[1]),
657
                  s);
658
              scheduler_splittask_hydro(
659
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
660
                                    ci->progeny[6], cj->progeny[1]),
661
                  s);
662
              scheduler_splittask_hydro(
663
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
664
                                    ci->progeny[7], cj->progeny[0]),
665
666
667
668
669
670
671
672
673
674
675
676
677
                  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;
678
              scheduler_splittask_hydro(
679
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
680
                                    ci->progeny[7], cj->progeny[2]),
681
                  s);
682
              scheduler_splittask_hydro(
683
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
684
                                    ci->progeny[5], cj->progeny[2]),
685
                  s);
686
              scheduler_splittask_hydro(
687
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
688
                                    ci->progeny[7], cj->progeny[0]),
689
690
691
692
693
694
695
                  s);
              break;

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

            case 5: /* (  1 ,  0 , -1 ) */
              t->ci = ci->progeny[4];
              t->cj = cj->progeny[1];
              t->flags = 5;
762
              scheduler_splittask_hydro(
763
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
764
                                    ci->progeny[6], cj->progeny[3]),
765
                  s);
766
              scheduler_splittask_hydro(
767
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
768
                                    ci->progeny[4], cj->progeny[3]),
769
                  s);
770
              scheduler_splittask_hydro(
771
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
772
                                    ci->progeny[6], cj->progeny[1]),
773
774
775
776
777
778
779
780
781
782
783
784
785
                  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;
786
              scheduler_splittask_hydro(
787
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
788
                                    ci->progeny[5], cj->progeny[2]),
789
                  s);
790
              scheduler_splittask_hydro(
791
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
792
                                    ci->progeny[4], cj->progeny[2]),
793
                  s);
794
              scheduler_splittask_hydro(
795
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
796
                                    ci->progeny[5], cj->progeny[3]),
797
798
799
800
801
802
803
804
805
806
807
808
809
                  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;
810
              scheduler_splittask_hydro(
811
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
812
                                    ci->progeny[7], cj->progeny[4]),
813
                  s);
814
              scheduler_splittask_hydro(
815
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
816
                                    ci->progeny[3], cj->progeny[4]),
817
                  s);
818
              scheduler_splittask_hydro(
819
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
820
                                    ci->progeny[7], cj->progeny[0]),
821
822
823
824
825
826
827
                  s);
              break;

            case 10: /* (  0 ,  1 ,  0 ) */
              t->ci = ci->progeny[2];
              t->cj = cj->progeny[0];
              t->flags = 10;
828
              scheduler_splittask_hydro(
829
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
830
                                    ci->progeny[3], cj->progeny[0]),
831
                  s);
832
              scheduler_splittask_hydro(
833
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
834
                                    ci->progeny[6], cj->progeny[0]),
835
                  s);
836
              scheduler_splittask_hydro(
837
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
838
                                    ci->progeny[7], cj->progeny[0]),
839
                  s);
840
              scheduler_splittask_hydro(
841
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
842
                                    ci->progeny[2], cj->progeny[1]),
843
                  s);
844
              scheduler_splittask_hydro(
845
                  scheduler_addtask(s, task_type_pair, t->subtype, 10, 0,
846
                                    ci->progeny[3], cj->progeny[1]),
847
                  s);
848
              scheduler_splittask_hydro(
849
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
850
                                    ci->progeny[6], cj->progeny[1]),
851
                  s);
852
              scheduler_splittask_hydro(
853
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
854
                                    ci->progeny[7], cj->progeny[1]),
855
                  s);
856
              scheduler_splittask_hydro(
857
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
858
                                    ci->progeny[2], cj->progeny[4]),
859
                  s);
860
              scheduler_splittask_hydro(
861
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
862
                                    ci->progeny[3], cj->progeny[4]),
863
                  s);
864
              scheduler_splittask_hydro(
865
                  scheduler_addtask(s, task_type_pair, t->subtype, 10, 0,
866
                                    ci->progeny[6], cj->progeny[4]),
867
                  s);
868
              scheduler_splittask_hydro(
869
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
870
                                    ci->progeny[7], cj->progeny[4]),
871
                  s);
872
              scheduler_splittask_hydro(
873
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
874
                                    ci->progeny[2], cj->progeny[5]),
875
                  s);
876
              scheduler_splittask_hydro(
877
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
878
                                    ci->progeny[3], cj->progeny[5]),
879
                  s);
880
              scheduler_splittask_hydro(
881
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
882
                                    ci->progeny[6], cj->progeny[5]),
883
                  s);
884
              scheduler_splittask_hydro(
885
                  scheduler_addtask(s, task_type_pair, t->subtype, 10, 0,
886
                                    ci->progeny[7], cj->progeny[5]),
887
888
889
890
891
892
893
                  s);
              break;

            case 11: /* (  0 ,  1 , -1 ) */
              t->ci = ci->progeny[2];
              t->cj = cj->progeny[1];
              t->flags = 11;
894
              scheduler_splittask_hydro(
895
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
896
                                    ci->progeny[6], cj->progeny[5]),
897
                  s);