diff --git a/examples/test.c b/examples/test.c index 8ee735a57f006ca59a8e30fbf07811628e378adb..aaa8ac160c731336144a82ddb86bb932ecacef0a 100644 --- a/examples/test.c +++ b/examples/test.c @@ -784,8 +784,8 @@ int main(int argc, char *argv[]) { /* Initialize the engine with this space. */ tic = getticks(); message("nr_nodes is %i.", nr_nodes); - engine_init(&e, &s, dt_max, nr_threads, nr_queues, nr_nodes, myrank, - ENGINE_POLICY | engine_policy_steal); + engine_init(&e, &s, dt_max, nr_threads, nr_queues, nr_nodes, myrank , + ENGINE_POLICY | engine_policy_steal | engine_policy_paranoid); if (myrank == 0) message("engine_init took %.3f ms.", ((double)(getticks() - tic)) / CPU_TPS * 1000); diff --git a/src/debug.c b/src/debug.c index d55d5443457fe3be41f6d1983a1eca8d7ab99f3c..0ebbd44ae03ffc6ddfabab78e577335f0b9bbe5a 100644 --- a/src/debug.c +++ b/src/debug.c @@ -20,8 +20,20 @@ #include <stdio.h> -#include "const.h" -#include "part.h" +/* This object's header. */ +#include "debug.h" + +/** + * @brief Dump the information pertaining to the given cell. + */ + +void print_cell(struct cell *c) { + printf( + "## Cell 0x%0zx: loc=[%.3e,%.3e,%.3e], h=[%.3e,%.3e,%.3e], depth=%i, " + "split=%i, maxdepth=%i.\n", + (size_t)c, c->loc[0], c->loc[1], c->loc[2], c->h[0], c->h[1], c->h[2], + c->depth, c->split, c->maxdepth); +} /** * @brief Looks for the particle with the given id and prints its information to diff --git a/src/debug.h b/src/debug.h index ddd33d527e4f4fde967344a3f4f63ea98df0e37a..42269fc267e6d5721990b992c92c515a5764f6a9 100644 --- a/src/debug.h +++ b/src/debug.h @@ -23,7 +23,7 @@ #include "cell.h" #include "part.h" - +void print_cell(struct cell *c); void printParticle(struct part *parts, long long int i, int N); void printgParticle(struct gpart *parts, long long int i, int N); void printParticle_single(struct part *p); diff --git a/src/engine.c b/src/engine.c index fcecde15fb70997ca13c8c0f27a210ea7cffffdd..90c0e124143438145349d41db667bc8cabd7a52d 100644 --- a/src/engine.c +++ b/src/engine.c @@ -62,6 +62,79 @@ /** The rank of the engine as a global variable (for messages). */ int engine_rank; +/** + * @brief Check if a single particle is OK. + * + * @return Zero if all checks passed, non-zero otherwise. + */ +int engine_check_part(struct part *p) { + if (p == NULL || p->mass == 0.0f || p->h == 0.0f) { + message("Bad particle data."); + printParticle_single(p); + return 1; + } else if (p->x[0] == 0.0 && p->x[1] == 0.0 && p->x[2] == 0.0) { + message("Bad particle location."); + printParticle_single(p); + return 1; + } else { + return 0; + } +} + +/** + * @brief Check if a cell's data is reasonable, also check if its particles + * are OK. + * + * @return Zero if all checks passed, non-zero otherwise. + */ + +void engine_check_cell(struct cell *c, void *data) { + /* Check the cell data. */ + if (c->count == 0) { + print_cell(c); + error("Empty cell."); + } + + /* Check the particles. */ + for (int k = 0; k < c->count; k++) { + if (engine_check_part(&c->parts[k])) { + print_cell(c); + error("Bad particle in cell."); + } + } + + /* Check that the progeny, if any, contain all the particles. */ + if (c->split) { + int count = 0; + for (int k = 0; k < 8; k++) { + if (c->progeny[k] != NULL) { + count += c->progeny[k]->count; + } + } + if (count != c->count) { + print_cell(c); + error("Progeny cell counts don't add up."); + } + } +} + +/** + * @brief Runs a series of checks to make sure we have no bad particles. + */ + +void engine_check(struct engine *e) { + /* Check all particles directly. */ + struct space *s = e->s; + for (int k = 0; k < s->nr_parts; k++) { + if (engine_check_part(&s->parts[k])) { + error("Bad particle s->parts[%i], aborting.", k); + } + } + + /* Check each cell in the space. */ + space_map_cells_post(s, 1, &engine_check_cell, NULL); +} + /** * @brief Link a density/force task to a cell. * @@ -1720,6 +1793,7 @@ void hassorted(struct cell *c) { * * @param e The #engine. */ + void engine_step(struct engine *e) { int k; @@ -1733,6 +1807,11 @@ void engine_step(struct engine *e) { TIMER_TIC2 + if (e->policy & engine_policy_paranoid) { + message("Checking system sanity..."); + engine_check(e); + } + /* Get the maximum dt. */ if (e->policy & engine_policy_multistep) { dt_step = 2.0f * dt; @@ -1766,6 +1845,11 @@ void engine_step(struct engine *e) { // printParticle(parts, k); // printParticle( e->s->parts , 3392063069037 , e->s->nr_parts ); + if (e->policy & engine_policy_paranoid) { + message("Checking system sanity..."); + engine_check(e); + } + /* Re-distribute the particles amongst the nodes? */ if ( e->forcerepart ) engine_repartition( e ); @@ -1775,6 +1859,11 @@ void engine_step(struct engine *e) { engine_check(e); } + if (e->policy & engine_policy_paranoid) { + message("Checking system sanity..."); + engine_check(e); + } + /* Prepare the space. */ engine_prepare(e); @@ -1792,6 +1881,11 @@ void engine_step(struct engine *e) { (1 << task_type_grav_up) | (1 << task_type_grav_down) | (1 << task_type_link)); + if (e->policy & engine_policy_paranoid) { + message("Checking system sanity..."); + engine_check(e); + } + TIMER_TOC(timer_runners); // engine_single_force( e->s->dim , 8328423931905 , e->s->parts , diff --git a/src/engine.h b/src/engine.h index 65aa028401344f953d7a23a5c83c030278bbdcb7..caa286e7d3c518c0aba84fd9da1b6ff9ef6a78f4 100644 --- a/src/engine.h +++ b/src/engine.h @@ -41,6 +41,7 @@ #define engine_policy_cputight 64 #define engine_policy_mpi 128 #define engine_policy_setaffinity 256 +#define engine_policy_paranoid 512 #define engine_queue_scale 1.2 #define engine_maxtaskspercell 128 diff --git a/src/space.c b/src/space.c index eeb42f328f3a91439110c832fea93798862869a6..157850080b148233168be26789d5be0110dc7938 100644 --- a/src/space.c +++ b/src/space.c @@ -844,7 +844,7 @@ static void rec_map_cells_post(struct cell *c, int full, } /** - * @brief Map a function to all particles in a aspace. + * @brief Map a function to all particles in a space. * * @param s The #space we are working in. * @param full Map to all cells, including cells with sub-cells.