From 7a4188aa27dda55e8ec1f87d7b71a1a5b29e935e Mon Sep 17 00:00:00 2001 From: Matthieu Schaller <matthieu.schaller@durham.ac.uk> Date: Thu, 17 Apr 2014 17:46:37 +0000 Subject: [PATCH] The construction of the tree now explicitely avoid empty cells. No need to check whether a cell is empty during the tree walk. --- examples/test_bh_sorted.c | 436 ++++++++++++++++++-------------------- 1 file changed, 207 insertions(+), 229 deletions(-) diff --git a/examples/test_bh_sorted.c b/examples/test_bh_sorted.c index 5aa8ea2..f5381b3 100644 --- a/examples/test_bh_sorted.c +++ b/examples/test_bh_sorted.c @@ -49,10 +49,10 @@ struct part { double x[3]; //union { - float a[3]; - float a_legacy[3]; - // }; - float a_exact[3]; + float a[3]; + float a_legacy[3]; + float a_exact[3]; + //}; float mass; int id; } __attribute__((aligned(32))); @@ -429,6 +429,8 @@ struct cell *cell_get() { return res; } + + /** * @brief Sort the parts into eight bins along the given pivots and * fill the multipoles. Also adds the hierarchical resources @@ -451,8 +453,6 @@ void cell_split(struct cell *c, struct qsched *s) { /* Set the root cell. */ if (root == NULL) { root = c; - // c->depth = 0; - // c->parent = 0; c->sibling = 0; } @@ -474,14 +474,10 @@ void cell_split(struct cell *c, struct qsched *s) { /* Create the progeny. */ for (k = 0; k < 8; k++) { progenitors[k] = cp = cell_get(); - // cp->parent = c; - // cp->depth = c->depth + 1; cp->loc[0] = c->loc[0]; cp->loc[1] = c->loc[1]; cp->loc[2] = c->loc[2]; - cp->h = c->h / 2; - cp->h = c->h / 2; - cp->h = c->h / 2; + cp->h = c->h * 0.5; cp->res = qsched_addres(s, qsched_owner_none, c->res); if (k & 4) cp->loc[0] += cp->h; if (k & 2) cp->loc[1] += cp->h; @@ -489,7 +485,7 @@ void cell_split(struct cell *c, struct qsched *s) { } /* Init the pivots. */ - for (k = 0; k < 3; k++) pivot[k] = c->loc[k] + c->h / 2; + for (k = 0; k < 3; k++) pivot[k] = c->loc[k] + c->h * 0.5; /* Split along the x-axis. */ i = 0; @@ -552,8 +548,18 @@ void cell_split(struct cell *c, struct qsched *s) { progenitors[k]->parts = &c->parts[left[k]]; } + /* Find the first non-empty progenitor */ + for ( k = 0; k < 8 ; k++ ) + if ( progenitors[k]->count > 0) + { + c->firstchild = progenitors[k]; + //message( "first child= %d", k); + break; + } + if ( c->firstchild == NULL ) error( "Cell has been split but all progenitors have 0 particles" ); + /* Prepare the pointers. */ - for (k = 0; k < 7; k++) { + for (k = 0; k < 8; k++) { /* Find the next non-empty sibling */ for (kk = k + 1; kk < 8; ++kk) { @@ -567,23 +573,10 @@ void cell_split(struct cell *c, struct qsched *s) { if (kk == 8) progenitors[k]->sibling = c->sibling; } - /* Last progenitor links to the next sibling */ - progenitors[7]->sibling = c->sibling; - /* Recurse. */ - for (k = 0; k < 8; k++) cell_split(progenitors[k], s); - - - /* for ( k = 0; k < 7 ; k++ ) */ - /* if ( progenitors[k]->count > 0) */ - /* { */ - /* c->firstchild = progenitors[k]; */ - /* break; */ - /* } */ - /* if ( k == 8 ) error( "Cell has been split but all progenitors have 0 particles" ); */ - - c->firstchild = progenitors[0]; - + for (k = 0; k < 8; k++) + if (progenitors[k]->count > 0) + cell_split(progenitors[k], s); /* Link the COM tasks. */ for (k = 0; k < 8; k++) @@ -666,14 +659,9 @@ static inline void iact_pair_pc(struct cell *ci, struct cell *cj) { struct part *parts = ci->parts; /* Early abort? */ - if (count == 0 || cj->count == 0) return; - - /* message( "ci=[%.3e,%.3e,%.3e], cj=[%.3e,%.3e,%.3e], h=%.3e/%.3e.", - ci->loc[0], ci->loc[1], ci->loc[2], - cj->loc[0], cj->loc[1], cj->loc[2], - ci->h, cj->h ); */ + if (count == 0 || cj->count == 0) + error( "Empty cell!" ); -#if ICHECK >= 0 /* Sanity check. */ if (cj->new.mass == 0.0) { @@ -686,11 +674,6 @@ static inline void iact_pair_pc(struct cell *ci, struct cell *cj) { error("com does not seem to have been set."); } - /* Correctness check */ - if (cj->new.mass != cj->legacy.mass) - error("Calculation of the CoM is wrong! m_new=%e m_legacy=%e", cj->new.mass, - cj->legacy.mass); -#endif /* Init the com's data. */ for (k = 0; k < 3; k++) com[k] = cj->new.com[k]; @@ -739,55 +722,55 @@ static inline void iact_pair_direct_unsorted(struct cell *ci, struct cell *cj) { float dx[3], ai[3], mi, mj, r2, w, ir; - /* Loop over all particles in ci... */ - for (i = 0; i < count_i; i++) { - - /* Init the ith particle's data. */ - for (k = 0; k < 3; k++) { - xi[k] = parts_i[i].x[k]; - ai[k] = 0.0f; - } - mi = parts_i[i].mass; + /* Loop over all particles in ci... */ + for (i = 0; i < count_i; i++) { - /* Loop over every following particle. */ - for (j = 0; j < count_j; j++) { - - /* Compute the pairwise distance. */ - for (r2 = 0.0, k = 0; k < 3; k++) { - dx[k] = xi[k] - parts_j[j].x[k]; - r2 += dx[k] * dx[k]; - } + /* Init the ith particle's data. */ + for (k = 0; k < 3; k++) { + xi[k] = parts_i[i].x[k]; + ai[k] = 0.0f; + } + mi = parts_i[i].mass; - /* Apply the gravitational acceleration. */ - ir = 1.0f / sqrtf(r2); - w = const_G * ir * ir * ir; - mj = parts_j[j].mass; - for (k = 0; k < 3; k++) { - float wdx = w * dx[k]; - parts_j[j].a[k] += wdx * mi; - ai[k] -= wdx * mj; - } + /* Loop over every following particle. */ + for (j = 0; j < count_j; j++) { + + /* Compute the pairwise distance. */ + for (r2 = 0.0, k = 0; k < 3; k++) { + dx[k] = xi[k] - parts_j[j].x[k]; + r2 += dx[k] * dx[k]; + } + /* Apply the gravitational acceleration. */ + ir = 1.0f / sqrtf(r2); + w = const_G * ir * ir * ir; + mj = parts_j[j].mass; + for (k = 0; k < 3; k++) { + float wdx = w * dx[k]; + parts_j[j].a[k] += wdx * mi; + ai[k] -= wdx * mj; + } + #if ICHECK >= 0 - if (parts_i[i].id == ICHECK) - printf("[NEW] Interaction with particle id= %d (pair i)\n", - parts_j[j].id); - - if (parts_j[j].id == ICHECK) - printf("[NEW] Interaction with particle id= %d (pair j) h_i= %f h_j= " - "%f ci= %p cj= %p count_i= %d count_j= %d d_i= %d d_j= %d\n", - parts_i[i].id, ci->h, cj->h, ci, cj, count_i, count_j, ci->res, - cj->res); + if (parts_i[i].id == ICHECK) + printf("[NEW] Interaction with particle id= %d (pair i)\n", + parts_j[j].id); + + if (parts_j[j].id == ICHECK) + printf("[NEW] Interaction with particle id= %d (pair j) h_i= %f h_j= " + "%f ci= %p cj= %p count_i= %d count_j= %d d_i= %d d_j= %d\n", + parts_i[i].id, ci->h, cj->h, ci, cj, count_i, count_j, ci->res, + cj->res); #endif - } /* loop over every other particle. */ - + } /* loop over every other particle. */ + /* Store the accumulated acceleration on the ith part. */ - for (k = 0; k < 3; k++) parts_i[i].a[k] += ai[k]; - - } /* loop over all particles. */ - + for (k = 0; k < 3; k++) parts_i[i].a[k] += ai[k]; + + } /* loop over all particles. */ + } @@ -810,142 +793,142 @@ static inline void iact_pair_direct_sorted(struct cell *ci, struct cell *cj) { float dx[3], ai[3], mi, mj, r2, w, ir; - /* Get the sorted indices and stuff. */ - struct index *ind_i, *ind_j; - float corr; - double com[3] = {0.0, 0.0, 0.0}; - float com_mass = 0.0; - get_axis(&ci, &cj, &ind_i, &ind_j, &corr); - count_i = ci->count; - parts_i = ci->parts; - cih = ci->h; - count_j = cj->count; - parts_j = cj->parts; - cjh = cj->h; - - /* Distance along the axis as of which we will use a multipole. */ - float d_max = cjh / dist_min / corr; - - /* Loop over all particles in ci... */ - for (i = count_i - 1; i >= 0; i--) { - + /* Get the sorted indices and stuff. */ + struct index *ind_i, *ind_j; + float corr; + double com[3] = {0.0, 0.0, 0.0}; + float com_mass = 0.0; + get_axis(&ci, &cj, &ind_i, &ind_j, &corr); + count_i = ci->count; + parts_i = ci->parts; + cih = ci->h; + count_j = cj->count; + parts_j = cj->parts; + cjh = cj->h; + + /* Distance along the axis as of which we will use a multipole. */ + float d_max = cjh / dist_min / corr; + + /* Loop over all particles in ci... */ + for (i = count_i - 1; i >= 0; i--) { + + /* Get the sorted index. */ + int pid = ind_i[i].ind; + float di = ind_i[i].d; + + /* Init the ith particle's data. */ + for (k = 0; k < 3; k++) { + xi[k] = parts_i[pid].x[k]; + ai[k] = 0.0; + } + mi = parts_i[pid].mass; + + /* Loop over every following particle within d_max along the axis. */ + for (j = 0; j < count_j && (ind_j[j].d - di) < d_max; j++) { + /* Get the sorted index. */ - int pid = ind_i[i].ind; - float di = ind_i[i].d; - - /* Init the ith particle's data. */ + int pjd = ind_j[j].ind; + + /* Compute the pairwise distance. */ + for (r2 = 0.0, k = 0; k < 3; k++) { + dx[k] = xi[k] - parts_j[pjd].x[k]; + r2 += dx[k] * dx[k]; + } + + /* Apply the gravitational acceleration. */ + ir = 1.0f / sqrtf(r2); + w = const_G * ir * ir * ir; + mj = parts_j[pjd].mass; for (k = 0; k < 3; k++) { - xi[k] = parts_i[pid].x[k]; - ai[k] = 0.0; + float wdx = w * dx[k]; + parts_j[pjd].a[k] += wdx * mi; + ai[k] -= wdx * mj; } - mi = parts_i[pid].mass; - - /* Loop over every following particle within d_max along the axis. */ - for (j = 0; j < count_j && (ind_j[j].d - di) < d_max; j++) { - - /* Get the sorted index. */ - int pjd = ind_j[j].ind; - - /* Compute the pairwise distance. */ - for (r2 = 0.0, k = 0; k < 3; k++) { - dx[k] = xi[k] - parts_j[pjd].x[k]; - r2 += dx[k] * dx[k]; - } - - /* Apply the gravitational acceleration. */ - ir = 1.0f / sqrtf(r2); - w = const_G * ir * ir * ir; - mj = parts_j[pjd].mass; - for (k = 0; k < 3; k++) { - float wdx = w * dx[k]; - parts_j[pjd].a[k] += wdx * mi; - ai[k] -= wdx * mj; - } - + #if ICHECK >= 0 - if (parts_i[pid].id == ICHECK) - printf("[NEW] Interaction with particle id= %d (pair i)\n", - parts_j[pjd].id); - - if (parts_j[j].id == ICHECK) - printf("[NEW] Interaction with particle id= %d (pair j) h_i= %f h_j= " - "%f ci= %p cj= %p count_i= %d count_j= %d d_i= %d d_j= %d\n", - parts_i[pid].id, cih, cjh, ci, cj, count_i, count_j, ci->res, - cj->res); + if (parts_i[pid].id == ICHECK) + printf("[NEW] Interaction with particle id= %d (pair i)\n", + parts_j[pjd].id); + + if (parts_j[j].id == ICHECK) + printf("[NEW] Interaction with particle id= %d (pair j) h_i= %f h_j= " + "%f ci= %p cj= %p count_i= %d count_j= %d d_i= %d d_j= %d\n", + parts_i[pid].id, cih, cjh, ci, cj, count_i, count_j, ci->res, + cj->res); #endif - } /* loop over every other particle. */ - + } /* loop over every other particle. */ + /* Add any remaining particles to the COM. */ - for (int jj = j; jj < count_j; jj++) { - int pjd = ind_j[jj].ind; - mj = parts_j[pjd].mass; - com[0] += mj * parts_j[pjd].x[0]; - com[1] += mj * parts_j[pjd].x[1]; - com[2] += mj * parts_j[pjd].x[2]; - com_mass += mj; - } - - /* Shrink count_j to the latest valid particle. */ - count_j = j; - - /* Interact part_i with the center of mass. */ - if (com_mass > 0.0) { - float icom_mass = 1.0f / com_mass; - for (r2 = 0.0, k = 0; k < 3; k++) { - dx[k] = xi[k] - com[k] * icom_mass; - r2 += dx[k] * dx[k]; - } - ir = 1.0f / sqrtf(r2); - w = const_G * ir * ir * ir; - for (k = 0; k < 3; k++) ai[k] -= w * dx[k] * com_mass; + for (int jj = j; jj < count_j; jj++) { + int pjd = ind_j[jj].ind; + mj = parts_j[pjd].mass; + com[0] += mj * parts_j[pjd].x[0]; + com[1] += mj * parts_j[pjd].x[1]; + com[2] += mj * parts_j[pjd].x[2]; + com_mass += mj; + } + + /* Shrink count_j to the latest valid particle. */ + count_j = j; + + /* Interact part_i with the center of mass. */ + if (com_mass > 0.0) { + float icom_mass = 1.0f / com_mass; + for (r2 = 0.0, k = 0; k < 3; k++) { + dx[k] = xi[k] - com[k] * icom_mass; + r2 += dx[k] * dx[k]; } - - /* Store the accumulated acceleration on the ith part. */ - for (k = 0; k < 3; k++) parts_i[pid].a[k] += ai[k]; - - } /* loop over all particles in ci. */ - + ir = 1.0f / sqrtf(r2); + w = const_G * ir * ir * ir; + for (k = 0; k < 3; k++) ai[k] -= w * dx[k] * com_mass; + } + + /* Store the accumulated acceleration on the ith part. */ + for (k = 0; k < 3; k++) parts_i[pid].a[k] += ai[k]; + + } /* loop over all particles in ci. */ + /* Loop over the particles in cj, catch the COM interactions. */ - count_j = cj->count; - int last_i = 0; - com[0] = 0.0; - com[1] = 0.0; - com[2] = 0.0; - com_mass = 0.0f; - d_max = cih / dist_min / corr; - for (j = 0; j < count_j; j++) { - - /* Get the sorted index. */ - int pjd = ind_j[j].ind; - float dj = ind_j[j].d; - - /* Fill the COM with any new particles. */ - for (i = last_i; i < count_i && (dj - ind_i[i].d) > d_max; i++) { - int pid = ind_i[i].ind; - mi = parts_i[pid].mass; - com[0] += parts_i[pid].x[0] * mi; - com[1] += parts_i[pid].x[1] * mi; - com[2] += parts_i[pid].x[2] * mi; - com_mass += mi; - } - - /* Set the new last_i to the last particle checked. */ - last_i = i; - - /* Interact part_j with the COM. */ - if (com_mass > 0.0) { - float icom_mass = 1.0f / com_mass; - for (r2 = 0.0, k = 0; k < 3; k++) { - dx[k] = com[k] * icom_mass - parts_j[pjd].x[k]; - r2 += dx[k] * dx[k]; - } - ir = 1.0f / sqrtf(r2); - w = const_G * ir * ir * ir; - for (k = 0; k < 3; k++) parts_j[pjd].a[k] += w * dx[k] * com_mass; + count_j = cj->count; + int last_i = 0; + com[0] = 0.0; + com[1] = 0.0; + com[2] = 0.0; + com_mass = 0.0f; + d_max = cih / dist_min / corr; + for (j = 0; j < count_j; j++) { + + /* Get the sorted index. */ + int pjd = ind_j[j].ind; + float dj = ind_j[j].d; + + /* Fill the COM with any new particles. */ + for (i = last_i; i < count_i && (dj - ind_i[i].d) > d_max; i++) { + int pid = ind_i[i].ind; + mi = parts_i[pid].mass; + com[0] += parts_i[pid].x[0] * mi; + com[1] += parts_i[pid].x[1] * mi; + com[2] += parts_i[pid].x[2] * mi; + com_mass += mi; + } + + /* Set the new last_i to the last particle checked. */ + last_i = i; + + /* Interact part_j with the COM. */ + if (com_mass > 0.0) { + float icom_mass = 1.0f / com_mass; + for (r2 = 0.0, k = 0; k < 3; k++) { + dx[k] = com[k] * icom_mass - parts_j[pjd].x[k]; + r2 += dx[k] * dx[k]; } + ir = 1.0f / sqrtf(r2); + w = const_G * ir * ir * ir; + for (k = 0; k < 3; k++) parts_j[pjd].a[k] += w * dx[k] * com_mass; } - + } + } @@ -961,28 +944,25 @@ void iact_pair(struct cell *ci, struct cell *cj) { int k; int count_i = ci->count, count_j = cj->count; - double center_i[3], center_j[3], dx[3]; + double center_i, center_j, dx[3]; double min_dist, cih = ci->h, cjh = cj->h; struct cell *cp; /* Early abort? */ - if (count_i == 0 || count_j == 0) { - // message( "Empty cell !" ); - return; - } + if (count_i == 0 || count_j == 0) + error( "Empty cell !" ); + /* Sanity check */ if (ci == cj) - error("The impossible has happened: pair interaction between a cell and " - "itself."); // debug - - /* Cell centers */ - for (k = 0; k < 3; k++) center_i[k] = ci->loc[k] + 0.5 * cih; - for (k = 0; k < 3; k++) center_j[k] = cj->loc[k] + 0.5 * cjh; + error( "The impossible has happened: pair interaction between a cell and " + "itself." ); /* Distance between the cell centers */ for (k = 0; k < 3; k++) { - dx[k] = fabs(center_i[k] - center_j[k]); + center_i = ci->loc[k] + 0.5 * cih; + center_j = cj->loc[k] + 0.5 * cjh; + dx[k] = fabs(center_i - center_j); } min_dist = cih + cjh; @@ -1036,10 +1016,9 @@ void iact_self(struct cell *c) { struct cell *cp, *cps; /* Early abort? */ - if (count == 0) return; + if (count == 0) + error( "Empty cell !" ); - /* message( "cell=[%.3e,%.3e,%.3e], h=%.3e.", - c->loc[0], c->loc[1], c->loc[2], c->h ); */ /* If the cell is split, interact each progeny with itself, and with each of its siblings. */ @@ -1116,12 +1095,13 @@ void create_tasks(struct qsched *s, struct cell *ci, struct cell *cj) { int k; qsched_task_t tid; - double center_i[3], center_j[3], dx[3]; + double center_i, center_j, dx[3]; double min_dist, cih, cjh; struct cell *data[2], *cp, *cps; /* If either cell is empty, stop. */ - if (ci->count == 0 || (cj != NULL && cj->count == 0)) return; + if (ci->count == 0 || (cj != NULL && cj->count == 0)) + error( "Empty cell !" ); /* Single cell? */ if (cj == NULL) { @@ -1166,13 +1146,11 @@ void create_tasks(struct qsched *s, struct cell *ci, struct cell *cj) { cih = ci->h; cjh = cj->h; - /* Cell centers */ - for (k = 0; k < 3; k++) center_i[k] = ci->loc[k] + 0.5 * cih; - for (k = 0; k < 3; k++) center_j[k] = cj->loc[k] + 0.5 * cjh; - /* Distance between the cell centers */ for (k = 0; k < 3; k++) { - dx[k] = fabs(center_i[k] - center_j[k]); + center_i = ci->loc[k] + 0.5 * cih; + center_j = cj->loc[k] + 0.5 * cjh; + dx[k] = fabs(center_i - center_j); } min_dist = cih + cjh; -- GitLab