diff --git a/examples/test_bh_new.c b/examples/test_bh_new.c index 89c8caf3c9f49f5631fef378b7fc669bc97cb366..0fabd158cbaaf8cd5e53a03e2967ab4d57103ef2 100644 --- a/examples/test_bh_new.c +++ b/examples/test_bh_new.c @@ -37,16 +37,17 @@ /* Some local constants. */ #define cell_pool_grow 1000 -#define cell_maxparts 100 -#define task_limit 1e8 +#define cell_maxparts 128 +#define task_limit 1 #define const_G 1 // 6.6738e-8 #define dist_min 0.5 /* Used for legacy walk only */ #define dist_cutoff_ratio 1.5 #define ICHECK -1 -#define NO_SANITY_CHECKS +#define SANITY_CHECKS #define NO_COM_AS_TASK #define NO_COUNTERS +#define QUADRUPOLES /** Data structure for the particles. */ struct part { @@ -67,11 +68,21 @@ struct part_local { } __attribute__((aligned(32))); struct multipole { + +#ifdef QUADRUPOLES + double I[3][3]; +#endif + double com[3]; float mass; }; struct multipole_local { + +#ifdef QUADRUPOLES + float I[3][3]; +#endif + float com[3]; float mass; }; @@ -103,7 +114,7 @@ struct cell { int res, com_tid; struct index *indices; -} __attribute__((aligned(128))); +};// __attribute__((aligned(256))); /** Task types. */ enum task_type { @@ -173,6 +184,15 @@ void comp_com(struct cell *c) { struct part *parts = c->parts; double com[3] = {0.0, 0.0, 0.0}, mass = 0.0; +#ifdef QUADRUPOLES + double I[3][3] = {{0.0, 0.0, 0.0} , {0.0, 0.0, 0.0} , {0.0, 0.0, 0.0} }; +#endif + +#ifdef SANITY_CHECKS + if ( count == 0 ) + error("CoM computed for an empty cell"); +#endif + if (c->split) { /* Loop over the projenitors and collect the multipole information. */ @@ -182,9 +202,29 @@ void comp_com(struct cell *c) { com[1] += cp->new.com[1] * cp_mass; com[2] += cp->new.com[2] * cp_mass; mass += cp_mass; + +#ifdef QUADRUPOLES + I[0][0] += cp->new.I[0][0]; + I[0][1] += cp->new.I[0][1]; + I[0][2] += cp->new.I[0][2]; + I[1][0] += cp->new.I[1][0]; + I[1][1] += cp->new.I[1][1]; + I[1][2] += cp->new.I[1][2]; + I[2][0] += cp->new.I[2][0]; + I[2][1] += cp->new.I[2][1]; + I[2][2] += cp->new.I[2][2]; +#endif + } - /* Otherwise, collect the multipole from the particles. */ + /* Final operation for the COM */ + float imass = 1.0f / mass; + com[0] *= imass; + com[1] *= imass; + com[2] *= imass; + + + /* Otherwise, collect the multipole from the particles. */ } else { for (k = 0; k < count; k++) { @@ -193,22 +233,47 @@ void comp_com(struct cell *c) { com[1] += parts[k].x[1] * p_mass; com[2] += parts[k].x[2] * p_mass; mass += p_mass; + +#ifdef QUADRUPOLES + I[0][0] += parts[k].x[0] * parts[k].x[0] * p_mass; + I[0][1] += parts[k].x[0] * parts[k].x[1] * p_mass; + I[0][2] += parts[k].x[0] * parts[k].x[2] * p_mass; + I[1][0] += parts[k].x[1] * parts[k].x[0] * p_mass; + I[1][1] += parts[k].x[1] * parts[k].x[1] * p_mass; + I[1][2] += parts[k].x[1] * parts[k].x[2] * p_mass; + I[2][0] += parts[k].x[2] * parts[k].x[0] * p_mass; + I[2][1] += parts[k].x[2] * parts[k].x[1] * p_mass; + I[2][2] += parts[k].x[2] * parts[k].x[2] * p_mass; +#endif + } - } - /* Store the COM data, if any was collected. */ - if (mass > 0.0) { + /* Final operation for the COM */ float imass = 1.0f / mass; - c->new.com[0] = com[0] * imass; - c->new.com[1] = com[1] * imass; - c->new.com[2] = com[2] * imass; - c->new.mass = mass; - } else { - c->new.com[0] = 0.0; - c->new.com[1] = 0.0; - c->new.com[2] = 0.0; - c->new.mass = 0.0; + com[0] *= imass; + com[1] *= imass; + com[2] *= imass; } + + /* Store the multipole data */ + c->new.mass = mass; + c->new.com[0] = com[0]; + c->new.com[1] = com[1]; + c->new.com[2] = com[2]; + + +#ifdef QUADRUPOLES + c->new.I[0][0] = I[0][0]; + c->new.I[0][1] = I[0][1]; + c->new.I[0][2] = I[0][2]; + c->new.I[1][0] = I[1][0]; + c->new.I[1][1] = I[1][1]; + c->new.I[1][2] = I[1][2]; + c->new.I[2][0] = I[2][0]; + c->new.I[2][1] = I[2][1]; + c->new.I[2][2] = I[2][2]; +#endif + } /** @@ -427,7 +492,7 @@ static inline void make_interact_pc(struct part_local *parts, int part_count, struct multipole_local mults[8], int mult_count) { int i, j, k; - float dx[3] = {0.0, 0.0, 0.0}, r2, ir, w; + float dx[3] = {0.0, 0.0, 0.0}, r2, ir, mrinv3; #ifdef SANITY_CHECKS @@ -455,8 +520,37 @@ static inline void make_interact_pc(struct part_local *parts, int part_count, /* Apply the gravitational acceleration. */ ir = 1.0f / sqrtf(r2); - w = mults[j].mass * const_G * ir * ir * ir; - for (k = 0; k < 3; k++) parts[i].a[k] += w * dx[k]; + mrinv3 = mults[j].mass * const_G * ir * ir * ir; + +#ifndef QUADRUPOLES + + parts[i].a[0] += mrinv3 * dx[0]; + parts[i].a[1] += mrinv3 * dx[1]; + parts[i].a[2] += mrinv3 * dx[2]; + +#else + + float mrinv5 = mrinv3 * ir * ir; + float mrinv7 = mrinv5 * ir * ir; + + float D1 = -mrinv3; + float D2 = 3.f * mrinv5; + float D3 = -15.f * mrinv7; + + float q = mults[j].I[0][0] + mults[j].I[1][1] + mults[j].I[2][2]; + float qRx = mults[j].I[0][0]*dx[0] + mults[j].I[0][1]*dx[1] + mults[j].I[0][2]*dx[2]; + float qRy = mults[j].I[1][0]*dx[0] + mults[j].I[1][1]*dx[1] + mults[j].I[1][2]*dx[2]; + float qRz = mults[j].I[2][0]*dx[0] + mults[j].I[2][1]*dx[1] + mults[j].I[2][2]*dx[2]; + float qRR = qRx * dx[0] + qRy * dx[1] + qRz * dx[2]; + float C = D1 + 0.5f * D2 * q + 0.5f * D3 * qRR; + + parts[i].a[0] -= C * dx[0] + D2 * qRx; + parts[i].a[1] -= C * dx[1] + D2 * qRy; + parts[i].a[2] -= C * dx[2] + D2 * qRz; + + /* message(" %f %f %f", C * dx[0] + D2 * qRx, C * dx[1] + D2 * qRy, C * dx[2] + D2 * qRz); */ + +#endif } /* loop over every multipoles. */ } /* loop over every particle. */ @@ -517,6 +611,21 @@ static inline void iact_pair_pc(struct cell *ci, struct cell *cj) { mult_local[mult_count].com[2] = cps->new.com[2] - cp->loc[2]; mult_local[mult_count].mass = cps->new.mass; +#ifdef QUADRUPOLES + + /* Final operation to get the quadrupoles */ + double imass = 1. / cps->new.mass; + mult_local[mult_count].I[0][0] = cps->new.I[0][0]*imass - cps->new.com[0] * cps->new.com[0]; + mult_local[mult_count].I[0][1] = cps->new.I[0][1]*imass - cps->new.com[0] * cps->new.com[1]; + mult_local[mult_count].I[0][2] = cps->new.I[0][2]*imass - cps->new.com[0] * cps->new.com[2]; + mult_local[mult_count].I[1][0] = cps->new.I[1][0]*imass - cps->new.com[1] * cps->new.com[0]; + mult_local[mult_count].I[1][1] = cps->new.I[1][1]*imass - cps->new.com[1] * cps->new.com[1]; + mult_local[mult_count].I[1][2] = cps->new.I[1][2]*imass - cps->new.com[1] * cps->new.com[2]; + mult_local[mult_count].I[2][0] = cps->new.I[2][0]*imass - cps->new.com[2] * cps->new.com[0]; + mult_local[mult_count].I[2][1] = cps->new.I[2][1]*imass - cps->new.com[2] * cps->new.com[1]; + mult_local[mult_count].I[2][2] = cps->new.I[2][2]*imass - cps->new.com[2] * cps->new.com[2]; +#endif + mult_count++; } } @@ -1172,13 +1281,14 @@ void interact_exact(int N, struct part *parts, int monitor) { */ void test_bh(int N, int nr_threads, int runs, char *fileName) { - int i, k; + int i,j, k; struct cell *root; struct part *parts; FILE *file; struct qsched s; ticks tic, toc_run, tot_setup = 0, tot_run = 0; int countMultipoles = 0, countPairs = 0, countCoMs = 0; + // double I[3][3] = {{0., 0., 0.},{0., 0., 0.},{0., 0., 0.}}; /* Runner function. */ void runner(int type, void * data) { @@ -1231,6 +1341,23 @@ void test_bh(int N, int nr_threads, int runs, char *fileName) { parts[k].a_legacy[1] = 0.0; parts[k].a_legacy[2] = 0.0; } + j++; + /* for (i = 0; i < 4; i++) { */ + /* for (j = 0; j < 4; j++) { */ + /* for (k = 0; k < 4; k++) { */ + /* int l = 16*i + 4*j + k; */ + /* parts[l].id = l; */ + /* parts[l].x[0] = 0.125 + 0.25 * i; */ + /* parts[l].x[1] = 0.125 + 0.25 * j; */ + /* parts[l].x[2] = 0.125 + 0.25 * k; */ + /* parts[l].mass = 1.; */ + /* parts[l].a_legacy[0] = 0.0; */ + /* parts[l].a_legacy[1] = 0.0; */ + /* parts[l].a_legacy[2] = 0.0; */ + + /* } */ + /* } */ + /* } */ /* Otherwise, read them from a file. */ } else { @@ -1274,7 +1401,7 @@ void test_bh(int N, int nr_threads, int runs, char *fileName) { } message("Average number of parts per leaf is %f.", ((double)N) / nr_leaves); -#if ICHECK > 0 +#if 1 //ICHECK > 0 printf("----------------------------------------------------------\n"); /* Do a N^2 interactions calculation */ @@ -1355,10 +1482,43 @@ void test_bh(int N, int nr_threads, int runs, char *fileName) { tot_run += toc_run - tic; } - message("[check] root mass= %f %f", root->legacy.mass, root->new.mass); - message("[check] root CoMx= %f %f", root->legacy.com[0], root->new.com[0]); - message("[check] root CoMy= %f %f", root->legacy.com[1], root->new.com[1]); - message("[check] root CoMz= %f %f", root->legacy.com[2], root->new.com[2]); + /* for (k = 0; k < N; ++k) { */ + /* I[0][0] += parts[k].mass * parts[k].x[0] * parts[k].x[0]; */ + /* I[0][1] += parts[k].mass * parts[k].x[0] * parts[k].x[1]; */ + /* I[0][2] += parts[k].mass * parts[k].x[0] * parts[k].x[2]; */ + /* I[1][0] += parts[k].mass * parts[k].x[1] * parts[k].x[0]; */ + /* I[1][1] += parts[k].mass * parts[k].x[1] * parts[k].x[1]; */ + /* I[1][2] += parts[k].mass * parts[k].x[1] * parts[k].x[2]; */ + /* I[2][0] += parts[k].mass * parts[k].x[2] * parts[k].x[0]; */ + /* I[2][1] += parts[k].mass * parts[k].x[2] * parts[k].x[1]; */ + /* I[2][2] += parts[k].mass * parts[k].x[2] * parts[k].x[2]; */ + /* } */ + + /* for (k = 0; k < N; ++k) { */ + /* I[0][0] = I[0][0] / root->new.mass - root->new.com[0]*root->new.com[0]; */ + /* I[0][1] = I[0][1] / root->new.mass - root->new.com[0]*root->new.com[1]; */ + /* I[0][2] = I[0][2] / root->new.mass - root->new.com[0]*root->new.com[2]; */ + /* I[1][0] = I[1][0] / root->new.mass - root->new.com[1]*root->new.com[0]; */ + /* I[1][1] = I[1][1] / root->new.mass - root->new.com[1]*root->new.com[1]; */ + /* I[1][2] = I[1][2] / root->new.mass - root->new.com[1]*root->new.com[2]; */ + /* I[2][0] = I[2][0] / root->new.mass - root->new.com[2]*root->new.com[0]; */ + /* I[2][1] = I[2][1] / root->new.mass - root->new.com[2]*root->new.com[1]; */ + /* I[2][2] = I[2][2] / root->new.mass - root->new.com[2]*root->new.com[2]; */ + + /* } */ + + /* message("[check] root mass= %f %f", root->legacy.mass, root->new.mass); */ + /* message("[check] root CoMx= %f %f", root->legacy.com[0], root->new.com[0]); */ + /* message("[check] root CoMy= %f %f", root->legacy.com[1], root->new.com[1]); */ + /* message("[check] root CoMz= %f %f", root->legacy.com[2], root->new.com[2]); */ + /* message(" | %f %f %f |", root->new.I[0][0], root->new.I[0][1], root->new.I[0][2]); */ + /* message("In=| %f %f %f |", root->new.I[1][0], root->new.I[1][1], root->new.I[1][2]); */ + /* message(" | %f %f %f |", root->new.I[2][0], root->new.I[2][1], root->new.I[2][2]); */ + /* message("------------------------------------------------") */ + /* message(" | %f %f %f |", I[0][0], I[0][1], I[0][2]); */ + /* message("I =| %f %f %f |", I[1][0], I[1][1], I[1][2]); */ + /* message(" | %f %f %f |", I[2][0], I[2][1], I[2][2]); */ + #if ICHECK >= 0 for (i = 0; i < N; ++i) if (root->parts[i].id == ICHECK)