Skip to content
Snippets Groups Projects
Commit 12232492 authored by Matthieu Schaller's avatar Matthieu Schaller
Browse files

Updated version of the multipole calculation where the matrix is computed on...

Updated version of the multipole calculation where the matrix is computed on the fly. Algorithm is now O(N).
parent f95e3e08
No related branches found
No related tags found
No related merge requests found
...@@ -189,99 +189,97 @@ static inline void dipole_iact(const struct dipole *d, const float *x, ...@@ -189,99 +189,97 @@ static inline void dipole_iact(const struct dipole *d, const float *x,
struct multipole { struct multipole {
float mass; float mass;
float mu[3]; /* Centre of Mass */ float mu[3]; /* Centre of Mass */
float Q_00, Q_11, Q_22, Q_01, Q_12, Q_02; float sigma_00, sigma_11, sigma_22, sigma_01, sigma_02, sigma_12;
}; };
static inline void multipole_reset(struct multipole *d) { static inline void multipole_reset(struct multipole *d) {
for (int k = 0; k < 3; k++) d->mu[k] = 0.0; d->mu[0] = 0.0;
d->mu[1] = 0.0;
d->mu[2] = 0.0;
d->Q_00 = 0.; d->sigma_00 = 0.0;
d->Q_11 = 0.; d->sigma_11 = 0.0;
d->Q_22 = 0.; d->sigma_22 = 0.0;
d->Q_01 = 0.; d->sigma_01 = 0.0;
d->Q_02 = 0.; d->sigma_02 = 0.0;
d->Q_12 = 0.; d->sigma_12 = 0.0;
d->mass = 0.0; d->mass = 0.0;
} }
static inline void multipole_add_com(struct multipole *d, const float *x, float mass) { static inline void multipole_add(struct multipole *d, const float *x, float mass) {
for (int k = 0; k < 3; k++) d->mu[k] += x[k] * mass; d->mu[0] += x[0] * mass;
d->mass += mass; d->mu[1] += x[1] * mass;
} d->mu[2] += x[2] * mass;
static inline void multipole_add_matrix(struct multipole *d, const float *x, float mass) {
float r2, dx[3];
int k;
/* Distance from CoM */ d->sigma_00 += mass * x[0] * x[0];
for ( k = 0; k < 3; ++k) d->sigma_11 += mass * x[1] * x[1];
dx[k] = x[k] - d->mu[k] / d->mass; d->sigma_22 += mass * x[2] * x[2];
d->sigma_01 += mass * x[0] * x[1];
r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; d->sigma_02 += mass * x[0] * x[2];
d->sigma_12 += mass * x[1] * x[2];
/* Now fill in the matrix */
d->Q_00 += ((3. * mass * dx[0] * dx[0]) - (mass * r2));
d->Q_11 += ((3. * mass * dx[1] * dx[1]) - (mass * r2));
d->Q_22 += ((3. * mass * dx[2] * dx[2]) - (mass * r2));
d->Q_01 += 3. * mass * dx[0] * dx[1];
d->Q_02 += 3. * mass * dx[0] * dx[2];
d->Q_12 += 3. * mass * dx[1] * dx[2];
d->mass += mass;
} }
static inline void multipole_print(struct multipole* d) {
/* early abort */
if (d->mass == 0.) return;
message("M : %f", d->mass);
message("CoM: %f %f %f", d->mu[0] / d->mass, d->mu[1] / d->mass, d->mu[2] / d->mass);
message("Q: %f %f %f", d->Q_00, d->Q_01, d->Q_02 );
message(" %f %f %f", d->Q_01, d->Q_11, d->Q_12 );
message(" %f %f %f", d->Q_02, d->Q_12, d->Q_22 );
}
static inline void multipole_iact(struct multipole *d, const float *x, float* a) { static inline void multipole_iact(struct multipole *d, const float *x, float* a) {
int k; int k;
float r2,ir,w, dx[3]; float r2,ir,w, dx[3], mu[3];
float Q_00, Q_11, Q_22, Q_01, Q_02, Q_12;
/* early abort */ /* early abort */
if (d->mass == 0.) return; if (d->mass == 0.) return;
float inv_mass = 1. / d->mass; float inv_mass = 1. / d->mass;
/* Construct CoM */
for ( k = 0 ; k < 3 ; ++k ) mu[k] = d->mu[k] * inv_mass;
/* Temporary quantity */
dx[0] = d->sigma_00 - d->mass*mu[0]*mu[0]; /* Abusing a so far unused */
dx[1] = d->sigma_11 - d->mass*mu[1]*mu[1]; /* variable temporarily... */
dx[2] = d->sigma_22 - d->mass*mu[2]*mu[2];
/* Construct quadrupole matrix */
Q_00 = 2.f*dx[0] - dx[1] - dx[2];
Q_11 = 2.f*dx[1] - dx[0] - dx[2];
Q_22 = 2.f*dx[2] - dx[0] - dx[1];
Q_01 = d->sigma_01 - d->mass*mu[0]*mu[1];
Q_02 = d->sigma_02 - d->mass*mu[0]*mu[2];
Q_12 = d->sigma_12 - d->mass*mu[1]*mu[2];
Q_01 *= 3.f;
Q_02 *= 3.f;
Q_12 *= 3.f;
/* Compute the distance to the CoM. */ /* Compute the distance to the CoM. */
for (r2 = 0.0f, k = 0; k < 3; k++) { for (r2 = 0.0f, k = 0; k < 3; k++) {
dx[k] = x[k] - d->mu[k] * inv_mass; dx[k] = x[k] - mu[k];
r2 += dx[k] * dx[k]; r2 += dx[k] * dx[k];
} }
ir = 1.0f / sqrtf(r2); ir = 1.0f / sqrtf(r2);
/* Compute the acceleration from the monopole */ /* Compute the acceleration from the monopole */
w = const_G * ir * ir * ir * d->mass; w = const_G * ir * ir * ir * d->mass;
for (k = 0; k < 3; k++) a[k] -= w * dx[k]; for (k = 0; k < 3; k++) a[k] -= w * dx[k];
/* Compute the acceleration from the quadrupole */ /* Compute some helpful terms */
float w1 = const_G * ir * ir * ir * ir * ir; float w1 = const_G * ir * ir * ir * ir * ir;
float w2 = -2.5f * const_G * ir * ir * ir * ir * ir * ir * ir; float w2 = -2.5f * const_G * ir * ir * ir * ir * ir * ir * ir;
float xi = 0.; float xi = 0.;
xi += dx[0] * dx[0] * d->Q_00; xi += dx[0] * dx[0] * Q_00;
xi += dx[1] * dx[1] * d->Q_11; xi += dx[1] * dx[1] * Q_11;
xi += dx[2] * dx[2] * d->Q_22; xi += dx[2] * dx[2] * Q_22;
xi += 2.f * dx[0] * dx[1] * d->Q_01; xi += 2.f * dx[0] * dx[1] * Q_01;
xi += 2.f * dx[0] * dx[2] * d->Q_02; xi += 2.f * dx[0] * dx[2] * Q_02;
xi += 2.f * dx[1] * dx[2] * d->Q_12; xi += 2.f * dx[1] * dx[2] * Q_12;
a[0] += w2 * xi * dx[0] + w1 * (dx[0]*d->Q_00 + dx[1]*d->Q_01 + dx[2]*d->Q_02); /* Compute the acceleration from the quadrupole */
a[1] += w2 * xi * dx[1] + w1 * (dx[0]*d->Q_01 + dx[1]*d->Q_11 + dx[2]*d->Q_12); a[0] += w2 * xi * dx[0] + w1 * (dx[0]*Q_00 + dx[1]*Q_01 + dx[2]*Q_02);
a[2] += w2 * xi * dx[2] + w1 * (dx[0]*d->Q_02 + dx[1]*d->Q_12 + dx[2]*d->Q_22); a[1] += w2 * xi * dx[1] + w1 * (dx[0]*Q_01 + dx[1]*Q_11 + dx[2]*Q_12);
a[2] += w2 * xi * dx[2] + w1 * (dx[0]*Q_02 + dx[1]*Q_12 + dx[2]*Q_22);
} }
...@@ -1940,44 +1938,33 @@ static inline void iact_pair_direct_sorted_multipole(struct cell *ci, ...@@ -1940,44 +1938,33 @@ static inline void iact_pair_direct_sorted_multipole(struct cell *ci,
} /* loop over every other particle. */ } /* loop over every other particle. */
/* Reset the multipole */
multipole_reset(&multi);
/* Add any remaining particles to the COM. */ /* Add any remaining particles to the COM. */
for (int jj = j; jj < count_j; jj++) { for (int jj = j; jj < count_j; jj++) {
multipole_add_com(&multi, parts_j[jj].x, parts_j[jj].mass); multipole_add(&multi, parts_j[jj].x, parts_j[jj].mass);
} }
for (int jj = j; jj < count_j; jj++) {
multipole_add_matrix(&multi, parts_j[jj].x, parts_j[jj].mass);
}
/* message("Multipole for part %d:", parts_i[i].id); */
/* multipole_print(&dip[l]); */
/* Shrink count_j to the latest valid particle. */ /* Shrink count_j to the latest valid particle. */
//count_j = j; count_j = j;
/* Interact part_i with the center of mass. */ /* Interact part_i with the center of mass. */
multipole_iact(&multi, xi, ai); multipole_iact(&multi, xi, ai);
/* #if ICHECK >= 0 */ #if ICHECK >= 0
/* if (parts_i[i].id == ICHECK) */ if (parts_i[i].id == ICHECK)
/* message("Interaction with multipole"); //, parts_j[j].id ); */ message("Interaction with multipole"); //, parts_j[j].id );
/* #endif */ #endif
#ifdef COUNTERS #ifdef COUNTERS
++count_direct_sorted_pm_i; ++count_direct_sorted_pm_i;
#endif #endif
//message(" i=%d done", i)
/* Store the accumulated acceleration on the ith part. */ /* Store the accumulated acceleration on the ith part. */
for (k = 0; k < 3; k++) parts_i[i].a[k] += ai[k]; for (k = 0; k < 3; k++) parts_i[i].a[k] += ai[k];
} /* loop over all particles in ci. */ } /* loop over all particles in ci. */
//message( "OK i");
/* Re-init some values. */ /* Re-init some values. */
count_j = cj->count; count_j = cj->count;
...@@ -1987,26 +1974,16 @@ static inline void iact_pair_direct_sorted_multipole(struct cell *ci, ...@@ -1987,26 +1974,16 @@ static inline void iact_pair_direct_sorted_multipole(struct cell *ci,
/* Loop over the particles in cj, catch the COM interactions. */ /* Loop over the particles in cj, catch the COM interactions. */
for (j = 0; j < count_j; j++) { for (j = 0; j < count_j; j++) {
multipole_reset(&multi);
/* Get the sorted index. */ /* Get the sorted index. */
float dj = parts_j[j].d; float dj = parts_j[j].d;
/* Fill the COM with any new particles. */ /* Fill the COM with any new particles. */
for (i = last_i; i < count_i && (dj - parts_i[i].d) > d_max; i++) { for (i = last_i; i < count_i && (dj - parts_i[i].d) > d_max; i++) {
multipole_add_com(&multi, parts_i[i].x, parts_i[i].mass); multipole_add(&multi, parts_i[i].x, parts_i[i].mass);
} }
for (i = last_i; i < count_i && (dj - parts_i[i].d) > d_max; i++) {
multipole_add_matrix(&multi, parts_i[i].x, parts_i[i].mass);
}
/* message("Multipole for part %d:", parts_j[j].id); */
/* multipole_print(&multi); */
/* Set the new last_i to the last particle checked. */ /* Set the new last_i to the last particle checked. */
//last_i = i; last_i = i;
/* Interact part_j with the COM. */ /* Interact part_j with the COM. */
multipole_iact(&multi, parts_j[j].x, parts_j[j].a); multipole_iact(&multi, parts_j[j].x, parts_j[j].a);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment