diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index a5791306752c92bbe63985d029594178faae7213..978986fdc57827f46ea25aa6d81b6c2e5ba06c2c 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -79,8 +79,8 @@ DomainDecomposition: initial_grid_x: 10 # (Optional) Grid size if the "grid" strategy is chosen. initial_grid_y: 10 # "" initial_grid_z: 10 # "" - repartition_type: task_weights # (Optional) The re-decomposition strategy: "none", "task_weights", "particle_weights", - # "edge_task_weights" or "hybrid_weights". + repartition_type: task_costs # (Optional) The re-decomposition strategy: "none", "task_costs", "particle_weights", + # "edge_task_costs", "hybrid_weights" or "bin_weights" trigger: 0.05 # (Optional) Fractional (<1) CPU time difference between MPI ranks required to trigger a # new decomposition, or number of steps (>1) between decompositions minfrac: 0.9 # (Optional) Fractional of all particles that should be updated in previous step when diff --git a/src/debug.c b/src/debug.c index fa0cd14a8c15f188c8ebc0c2ed9e29a79b73cb77..368c5cbb08003b2f1a45d276c3942bbd35a02012 100644 --- a/src/debug.c +++ b/src/debug.c @@ -316,7 +316,7 @@ static void dumpCells_map(struct cell *c, void *data) { * for all cells to a simple text file. * * @param prefix base output filename, result is written to - * <prefix>_<rank>_<step>.dat + * %prefix%_%rank%_%step%.dat * @param s the space holding the cells to dump. * @param rank node ID of MPI rank, or 0 if not relevant. * @param step the current engine step, or some unique integer. diff --git a/src/partition.c b/src/partition.c index 5ac70205a77998aff59b24df2aaafc9406b5aa99..7fabc3cdfda185f5bb813aba0924178913c6e839 100644 --- a/src/partition.c +++ b/src/partition.c @@ -63,10 +63,13 @@ const char *initial_partition_name[] = { /* Simple descriptions of repartition types for reports. */ const char *repartition_name[] = { - "no", "METIS edge and vertex time weighted cells", - "METIS particle count vertex weighted cells", - "METIS time edge weighted cells", - "METIS particle count vertex and time edge cells"}; + "none", + "METIS edge and vertex cost weights", + "METIS particle count vertex weights", + "METIS cost edge weights", + "METIS particle count vertex and cost edge weights", + "METIS vertex costs and edge delta timebin weights", +}; /* Local functions, if needed. */ static int check_complete(struct space *s, int verbose, int nregions); @@ -476,15 +479,16 @@ static void pick_metis(struct space *s, int nregions, int *vertexw, int *edgew, * @param partweights whether particle counts will be used as vertex weights. * @param bothweights whether vertex and edge weights will be used, otherwise * only edge weights will be used. + * @param timebins use timebins as edge weights. * @param nodeID our nodeID. * @param nr_nodes the number of nodes. * @param s the space of cells holding our local particles. * @param tasks the completed tasks from the last engine step for our node. * @param nr_tasks the number of tasks. */ -static void repart_edge_metis(int partweights, int bothweights, int nodeID, - int nr_nodes, struct space *s, struct task *tasks, - int nr_tasks) { +static void repart_edge_metis(int partweights, int bothweights, int timebins, + int nodeID, int nr_nodes, struct space *s, + struct task *tasks, int nr_tasks) { /* Create weight arrays using task ticks for vertices and edges (edges * assume the same graph structure as used in the part_ calls). Note that @@ -599,42 +603,39 @@ static void repart_edge_metis(int partweights, int bothweights, int nodeID, if (cj->nodeID == nodeID) weights_v[cjd] += 0.5 * w; } - /* Add weights to edge for all cells based on the expected interaction - * time. We want to avoid having active cells on the edges, so we cut - * for that. */ - int dti = num_time_bins - get_time_bin(ci->ti_end_min); - int dtj = num_time_bins - get_time_bin(cj->ti_end_min); - - int kk; - for (kk = 26 * cid; inds[kk] != cjd; kk++) - ; - - /* If a foreign cell we repeat the interaction remotely, so these get - * 1/2 of the local time bin weight. */ - int dt; - if (ci->nodeID == nodeID) - dt = dti + dtj/2; - else - dt = dtj/2; - dt = dti + dtj; - dt = (1<<dt); - - wtot[1] += dt; - weights_e[kk] += dt; - - /* cj */ - for (kk = 26 * cjd; inds[kk] != cid; kk++) - ; - if (cj->nodeID == nodeID) - dt = dtj + dti/2; - else - dt = dti/2; - - dt = dti + dtj; - dt = (1<<dt); - - wtot[1] += dt; - weights_e[kk] += dt; + if (timebins) { + /* Add weights to edge for all cells based on the expected + * interaction time (calculated as the time to the last expected + * time) as we want to avoid having active cells on the edges, so we + * cut for that. Note that weight is added to the local and remote + * cells, as we want to keep both away from any cuts. */ + int dti = num_time_bins - get_time_bin(ci->ti_end_min); + int dtj = num_time_bins - get_time_bin(cj->ti_end_min); + int dt = (1<<(dti + dtj)); + + /* ci */ + int kk; + for (kk = 26 * cid; inds[kk] != cjd; kk++); + wtot[1] += dt; + weights_e[kk] += dt; + + /* cj */ + for (kk = 26 * cjd; inds[kk] != cid; kk++); + wtot[1] += dt; + weights_e[kk] += dt; + } else { + + /* Add weights from task costs to the edge. */ + + /* ci */ + int kk; + for (kk = 26 * cid; inds[kk] != cjd; kk++); + weights_e[kk] += w; + + /* cj */ + for (kk = 26 * cjd; inds[kk] != cid; kk++); + weights_e[kk] += w; + } } } } @@ -705,7 +706,8 @@ static void repart_edge_metis(int partweights, int bothweights, int nodeID, } } - /* Now edge weights. Unlikely these will ever need scaling. */ + /* Now edge weights. XXX need to balance weights if very different in + * range. */ wmin[1] = wmax[1]; wmax[1] = 0; for (int k = 0; k < nr_cells; k++) { @@ -838,35 +840,26 @@ void partition_repartition(struct repartition *reparttype, int nodeID, #if defined(WITH_MPI) && defined(HAVE_METIS) - if (reparttype->type == REPART_METIS_BOTH || - reparttype->type == REPART_METIS_EDGE || - reparttype->type == REPART_METIS_VERTEX_EDGE) { + if (reparttype->type == REPART_METIS_VERTEX_COSTS_EDGE_COSTS) { + repart_edge_metis(1, 1, 0, nodeID, nr_nodes, s, tasks, nr_tasks); - int partweights; - int bothweights; - if (reparttype->type == REPART_METIS_VERTEX_EDGE) - partweights = 1; - else - partweights = 0; + } else if (reparttype->type == REPART_METIS_EDGE_COSTS) { + repart_edge_metis(0, 0, 0, nodeID, nr_nodes, s, tasks, nr_tasks); - if (reparttype->type == REPART_METIS_BOTH) - bothweights = 1; - else - bothweights = 0; + } else if (reparttype->type == REPART_METIS_VERTEX_COUNTS_EDGE_COSTS) { + repart_edge_metis(1, 0, 0, nodeID, nr_nodes, s, tasks, nr_tasks); - repart_edge_metis(partweights, bothweights, nodeID, nr_nodes, s, tasks, - nr_tasks); - - } else if (reparttype->type == REPART_METIS_VERTEX) { + } else if (reparttype->type == REPART_METIS_VERTEX_COSTS_EDGE_TIMEBINS) { + repart_edge_metis(1, 1, 1, nodeID, nr_nodes, s, tasks, nr_tasks); + } else if (reparttype->type == REPART_METIS_VERTEX_COUNTS) { repart_vertex_metis(s, nodeID, nr_nodes); } else if (reparttype->type == REPART_NONE) { - /* Doing nothing. */ } else { - error("Unknown repartition type"); + error("Impossible repartition type"); } #else error("SWIFT was not compiled with METIS support."); @@ -1020,7 +1013,7 @@ void partition_init(struct partition *partition, /* Defaults make use of METIS if available */ #ifdef HAVE_METIS - const char *default_repart = "task_weights"; + const char *default_repart = "task_costs"; const char *default_part = "simple_metis"; #else const char *default_repart = "none"; @@ -1086,22 +1079,25 @@ void partition_init(struct partition *partition, break; #ifdef HAVE_METIS case 't': - repartition->type = REPART_METIS_BOTH; + repartition->type = REPART_METIS_VERTEX_COSTS_EDGE_COSTS; break; case 'e': - repartition->type = REPART_METIS_EDGE; + repartition->type = REPART_METIS_EDGE_COSTS; break; case 'p': - repartition->type = REPART_METIS_VERTEX; + repartition->type = REPART_METIS_VERTEX_COUNTS; break; case 'h': - repartition->type = REPART_METIS_VERTEX_EDGE; + repartition->type = REPART_METIS_VERTEX_COUNTS_EDGE_COSTS; + break; + case 'b': + repartition->type = REPART_METIS_VERTEX_COSTS_EDGE_TIMEBINS; break; default: message("Invalid choice of re-partition type '%s'.", part_type); error( - "Permitted values are: 'none', 'task_weights', 'particle_weights'," - "'edge_task_weights' or 'hybrid_weights'"); + "Permitted values are: 'none', 'task_costs', 'particle_weights'," + "'edge_task_costs', 'hybrid_weights' or 'bin_weights'"); #else default: message("Invalid choice of re-partition type '%s'.", part_type); diff --git a/src/partition.h b/src/partition.h index 03523b165a930b085224e458ac0dd8c8232a578d..e7668f56fd8a1b1bb16ce41f3ba61be58df5371c 100644 --- a/src/partition.h +++ b/src/partition.h @@ -43,10 +43,11 @@ struct partition { /* Repartition type to use. */ enum repartition_type { REPART_NONE = 0, - REPART_METIS_BOTH, - REPART_METIS_VERTEX, - REPART_METIS_EDGE, - REPART_METIS_VERTEX_EDGE + REPART_METIS_VERTEX_COSTS_EDGE_COSTS, + REPART_METIS_VERTEX_COUNTS, + REPART_METIS_EDGE_COSTS, + REPART_METIS_VERTEX_COUNTS_EDGE_COSTS, + REPART_METIS_VERTEX_COSTS_EDGE_TIMEBINS, }; /* Repartition preferences. */