void p2p (PointAccum *one, PointAccum *other) { if (one != other) { VsgVector3d tmp; VsgVector3d tmp1; VsgVector3d tmp2; gdouble r, inv_r, inv_r3; /* destination - source */ vsg_vector3d_sub (&one->vector, &other->vector, &tmp); r = vsg_vector3d_norm (&tmp); if (r > epsilon) { inv_r = 1. / r; inv_r3 = inv_r*inv_r*inv_r; /* one->accum += inv_r * other->density; */ vsg_vector3d_scalp (&tmp, - inv_r3*other->density, &tmp1); vsg_vector3d_add (&one->field, &tmp1, &one->field); /* other->accum += inv_r * one->density; */ vsg_vector3d_scalp (&tmp, inv_r3*one->density, &tmp2); vsg_vector3d_add (&other->field, &tmp2, &other->field); /* g_printerr ("%d : p2p %d %d ", rk, one->id, other->id); */ /* vsg_vector3d_write (&one->vector, stderr); */ /* g_printerr (" "); */ /* vsg_vector3d_write (&one->field, stderr); */ /* g_printerr ("\n"); */ } } }
static void p2p (PointAccum *one, PointAccum *other) { if (one != other) { VsgVector3d tmp; VsgVector3d tmp1; VsgVector3d tmp2; gdouble r, inv_r, inv_r3; /* destination - source */ vsg_vector3d_sub (&one->vector, &other->vector, &tmp); r = vsg_vector3d_norm (&tmp); if (r > epsilon) { inv_r = 1. / r; inv_r3 = inv_r*inv_r*inv_r; /* one->accum += inv_r * other->density; */ vsg_vector3d_scalp (&tmp, - inv_r3*other->density, &tmp1); vsg_vector3d_add (&one->field, &tmp1, &one->field); /* other->accum += inv_r * one->density; */ vsg_vector3d_scalp (&tmp, inv_r3*one->density, &tmp2); vsg_vector3d_add (&other->field, &tmp2, &other->field); } } }
gcomplex128 newtonpot (VsgVector3d *vec) { VsgVector3d tmp; vsg_vector3d_sub (vec, &p, &tmp); return 1. / vsg_vector3d_norm (&tmp); }
/** * aran_development3d_local_evaluate: * @devel_node: tree node info of @devel. * @devel: an #AranDevelopment3d. * @pos: evaluation position. * * Evaluates the local part of @devel at @pos. * * Returns: value of local part of @devel(@pos). */ gcomplex128 aran_development3d_local_evaluate (const VsgPRTree3dNodeInfo *devel_node, AranDevelopment3d *devel, const VsgVector3d *pos) { VsgVector3d tmp; vsg_vector3d_sub (pos, &devel_node->center, &tmp); return aran_spherical_seriesd_evaluate (devel->local, &tmp); }
void newtongrad (VsgVector3d *vec, VsgVector3d *grad) { gdouble r; vsg_vector3d_sub (vec, &p, grad); r = vsg_vector3d_norm (grad); vsg_vector3d_scalp (grad, 1./ (r*r*r), grad); }
/** * aran_development3d_local_gradient_evaluate: * @devel_node: tree node info of @devel. * @devel: an #AranDevelopment3d. * @pos: evaluation position. * @grad: result gradient. * * Evaluates the gradient of the local part of @devel at @pos. */ void aran_development3d_local_gradient_evaluate (const VsgPRTree3dNodeInfo *devel_node, AranDevelopment3d *devel, const VsgVector3d *pos, VsgVector3d *grad) { VsgVector3d tmp; vsg_vector3d_sub (pos, &devel_node->center, &tmp); aran_spherical_seriesd_local_gradient_evaluate (devel->local, &tmp, grad); }
static gdouble kernel (PointAccum *one, PointAccum *other) { VsgVector3d tmp; gdouble inv_r; /* destination - source */ vsg_vector3d_sub (&one->vector, &other->vector, &tmp); inv_r = 1. / vsg_vector3d_norm (&tmp); return inv_r * one->density; }
static vsgrloc3 _sphere_loc3 (Sphere *sphere, VsgVector3d *center) { VsgVector3d tmp; gdouble dist; vsgloc3 centerpos; vsgrloc3 ret; vsg_vector3d_sub (center, &sphere->center, &tmp); dist = vsg_vector3d_norm (&tmp); if (dist <= sphere->radius) return VSG_RLOC3_MASK; ret = 0; centerpos = vsg_vector3d_vector3d_locfunc (&sphere->center, center); /* g_printerr ("%d: {c=", rk); */ /* vsg_vector3d_write (&sphere->center, stderr); */ /* g_printerr (" r=%g} ref=", sphere->radius); */ /* vsg_vector3d_write (center, stderr); */ ret |= VSG_RLOC3_COMP (centerpos); /* g_printerr (" / 0x%X", ret); */ if (fabs (tmp.x) <= sphere->radius) { vsgloc3 itmp = centerpos ^ VSG_LOC3_X; ret |= VSG_RLOC3_COMP (itmp); /* g_printerr (" / x<rad 0x%X (%x %x)", itmp, centerpos, VSG_LOC3_X); */ } if (fabs (tmp.y) <= sphere->radius) { vsgloc3 itmp = centerpos ^ VSG_LOC3_Y; ret |= VSG_RLOC3_COMP (itmp); /* g_printerr (" / y<rad 0x%X (%x %x)", itmp, centerpos, VSG_LOC3_Y); */ } if (fabs (tmp.z) <= sphere->radius) { vsgloc3 itmp = centerpos ^ VSG_LOC3_Z; ret |= VSG_RLOC3_COMP (itmp); /* g_printerr (" / y<rad 0x%X (%x %x)", itmp, centerpos, VSG_LOC3_Y); */ } /* g_printerr (" => 0x%X\n", ret); */ return ret; }
static AranSphericalSeriesd *create_taylor (guint deg, VsgVector3d *center, VsgVector3d *p) { AranSphericalSeriesd *ass; gint l, m; const guint size = ((deg+1)*(deg+2))/2; gcomplex128 harmonics[size]; gdouble r, cost, sint, cosp, sinp; gcomplex128 expp; gdouble fact, inv_r; VsgVector3d tmp; ass = aran_spherical_seriesd_new (deg, 0); aran_spherical_seriesd_set_zero (ass); vsg_vector3d_sub (p, center, &tmp); vsg_vector3d_to_spherical_internal (&tmp, &r, &cost, &sint, &cosp, &sinp); expp = cosp + G_I * sinp; aran_spherical_harmonic_evaluate_multiple_internal (deg, cost, sint, expp, harmonics); *aran_spherical_seriesd_get_term (ass, 0, 0) = 0.; inv_r = 1./ r; fact = inv_r; for (l=0; l<=deg; l ++) { gcomplex128 term; term = fact * (4.*G_PI / (l+l+1.)) * *aran_spherical_harmonic_multiple_get_term (l, 0, harmonics); *aran_spherical_seriesd_get_term (ass, l, 0) = conj (term); for (m=1; m<=l; m ++) { term = fact * (4.*G_PI / (l+l+1.)) * *aran_spherical_harmonic_multiple_get_term (l, m, harmonics); *aran_spherical_seriesd_get_term (ass, l, m) = conj (term); } fact *= inv_r; } return ass; }
static void p2m (PointAccum *particle, const VsgVector3d *center, AranDevelopment3d *devel) { VsgVector3d tmp; guint deg = aran_spherical_seriesd_get_negdeg (devel->multipole); gint l, m; gcomplex128 harmonics[((deg+1)*(deg+2))/2]; gdouble r, cost, sint, cosp, sinp; gcomplex128 expp; gdouble fact; vsg_vector3d_sub (&particle->vector, center, &tmp); vsg_vector3d_to_spherical_internal (&tmp, &r, &cost, &sint, &cosp, &sinp); expp = cosp + G_I * sinp; aran_spherical_harmonic_evaluate_multiple_internal (deg, cost, sint, expp, harmonics); *aran_spherical_seriesd_get_term (devel->multipole, 0, 0) += 0.; fact = particle->density; for (l=0; l<deg; l ++) { gcomplex128 *ptr; gcomplex128 term; term = fact * (4.*G_PI / (l+l+1.)) * *aran_spherical_harmonic_multiple_get_term (l, 0, harmonics); ptr = aran_spherical_seriesd_get_term (devel->multipole, -l-1, 0); ptr[0] += conj (term); for (m=1; m<=l; m ++) { term = fact * (4.*G_PI / (l+l+1.)) * *aran_spherical_harmonic_multiple_get_term (l, m, harmonics); ptr[m] += conj (term); } fact *= r; } }
/** * aran_spherical_seriesd_to_local: * @src: source expansion series. * @xsrc: @src center. * @dst: destination expansion series. * @xdst: @dst center. * * Like aran_spherical_seriesd_translate() except the multipole part of * @src is transformed into a local expansion in @dst. */ void aran_spherical_seriesd_to_local (const AranSphericalSeriesd * src, const VsgVector3d * xsrc, AranSphericalSeriesd * dst, const VsgVector3d * xdst) { VsgVector3d tmp; gdouble r, cost, sint, cosp, sinp; vsg_vector3d_sub (xdst, xsrc, &tmp); vsg_vector3d_to_spherical_internal (&tmp, &r, &cost, &sint, &cosp, &sinp); aran_local_translate (src, dst, r, cost, sint, cosp, sinp); if (src->negdeg > 0) { aran_multipole_to_local (src, dst, r, cost, sint, cosp, sinp); } }
void check_point_field (PointAccum *point, gint *ret) { gint i; gdouble err; gdouble denom; PointAccum *check; VsgVector3d tmp; i = point->id; check = &check_points[i]; denom = vsg_vector3d_norm (&check->field); vsg_vector3d_sub (&point->field, &check->field, &tmp); err = vsg_vector3d_norm (&tmp); if (denom > 0.) err /= denom; maxerr = MAX (maxerr, fabs (err)); if (fabs (err) > err_lim || !finite (err)) { g_printerr ("%d : Field simulation error: %d relative=(%e) " "pos=(%f,%f,%f)\n" " computed=(%f,%f,%f) " "exact=(%f,%f,%f)\n", rk, i, fabs(err), point->vector.x, point->vector.y, point->vector.z, point->field.x, point->field.y, point->field.z, check->field.x, check->field.y, check->field.z); (*ret) ++; } /* else */ /* { */ /* g_printerr ("%d : Field simulation ok: %d relative=(%e) exact=(%f,%f,%f)\n", */ /* rk, i, fabs(err), check->field.x, check->field.y, check->field.z); */ /* } */ }
/** * aran_spherical_seriesd_translate_rotate: * @src: source expansion series. * @xsrc: @src center. * @dst: destination expansion series. * @xdst: @dst center. * * Performs the same operation as aran_spherical_seriesd_translate() but * with the "Point and Shoot" algorithm which achieves O(p^3) complexity. */ void aran_spherical_seriesd_translate_rotate (const AranSphericalSeriesd *src, const VsgVector3d *xsrc, AranSphericalSeriesd *dst, const VsgVector3d *xdst) { gint l; guint8 nd = MAX (dst->negdeg, src->negdeg); guint8 pd = MAX (dst->posdeg, src->posdeg); guint8 lmax = MAX (pd+1, nd); gcomplex128 expma[lmax]; gcomplex128 expa; AranWigner *aw; VsgVector3d dir; gdouble r, theta, phi; gdouble cost = 1.; AranSphericalSeriesd *rot = (AranSphericalSeriesd *) g_alloca (ARAN_SPHERICAL_SERIESD_SIZE (src->posdeg, src->negdeg)); AranSphericalSeriesd *trans = (AranSphericalSeriesd *) g_alloca (ARAN_SPHERICAL_SERIESD_SIZE (dst->posdeg, dst->negdeg)); /* create work AranSphericalSeriesd */ memcpy (rot, src, sizeof (AranSphericalSeriesd)); memcpy (trans, dst, sizeof (AranSphericalSeriesd)); aran_spherical_seriesd_set_zero (rot); aran_spherical_seriesd_set_zero (trans); /* get translation vector */ vsg_vector3d_sub (xdst, xsrc, &dir); if (dir.z < 0.) { cost = -1.; vsg_vector3d_scalp (&dir, -1., &dir); } /* get rotation angles */ vsg_vector3d_to_spherical (&dir, &r, &theta, &phi); /* prepare rotation tools: AranWigner + complex exponentials arrays */ aw = aran_wigner_repo_lookup (theta); aran_wigner_require (aw, lmax); expa = cos (-phi) - G_I * sin (-phi); expma[0] = 1.; for (l = 1; l < lmax; l++) { expma[l] = expma[l - 1] * expa; } /* rotate src */ _buffer_rotate_ab (aw, src->posdeg, expma, _spherical_seriesd_get_pos_term (src, 0, 0), _spherical_seriesd_get_pos_term (rot, 0, 0)); if (src->negdeg > 0) { _buffer_rotate_ab (aw, src->negdeg - 1, expma, _spherical_seriesd_get_neg_term (src, 0, 0), _spherical_seriesd_get_neg_term (rot, 0, 0)); } /* aran_spherical_seriesd_rotate (src, -phi, theta, 0., rot); */ /* translate src to dst center */ aran_spherical_seriesd_translate_vertical (rot, trans, r, cost, 1., 0.); /* rotate back and accumulate into dst */ _buffer_rotate_ab_inverse (aw, dst->posdeg, expma, _spherical_seriesd_get_pos_term (trans, 0, 0), _spherical_seriesd_get_pos_term (dst, 0, 0)); if (dst->negdeg > 0) { _buffer_rotate_ab_inverse (aw, dst->negdeg - 1, expma, _spherical_seriesd_get_neg_term (trans, 0, 0), _spherical_seriesd_get_neg_term (dst, 0, 0)); } /* aran_spherical_seriesd_rotate_inverse (trans, -phi, theta, 0., dst); */ }
static void check (const gchar *log, AranSphericalSeriesd *ass, gdouble radius, VsgVector3d *center, void (*f) (VsgVector3d *x, VsgVector3d *grad)) { guint i, j, k; gdouble t, p; gdouble err; gdouble r, cost, sint, cosp, sinp; gcomplex128 dr, dt, dp; for (i=0; i<N ; i ++) { p = 2.*G_PI * i/(N-1.); cosp = cos (p); sinp = sin (p); for (j=0; j<N; j ++) { t = G_PI * j/(N-1.); cost = cos (t); sint = sin (t); for (k=0; k<N; k ++) { VsgVector3d vec; VsgVector3d vref; VsgVector3d vres; VsgVector3d verr; r = radius * k/(N-1.); vsg_vector3d_from_spherical_internal (&vec, r, cost, sint, cosp, sinp); /* aran_spherical_seriesd_gradient_evaluate (ass, &vec, */ /* &vres); */ aran_spherical_seriesd_gradient_evaluate_internal (ass, r, cost, sint, cosp, sinp, &dr, &dt, &dp); local_to_cartesian (r, cost, sint, cosp, sinp, creal (dr), creal (dt), creal (dp), &vres); vsg_vector3d_scalp (&vres, -1., &vres); vsg_vector3d_add (&vec, center, &vec); f (&vec, &vref); vsg_vector3d_sub (&vref, &vres, &verr); err = vsg_vector3d_norm (&verr) / vsg_vector3d_norm (&vref); if (fabs (err) > epsilon || !finite (err)) { g_printerr ("Error %s (%f,%f,%f) : " \ "(%f,%f,%f) != (%f,%f,%f) -> %e\n", log, r, t, p, /* vec.x, vec.y, vec.z, */ vref.x, vref.y, vref.z, vres.x, vres.y, vres.z, fabs (err)); } } } } }
int main (int argc, char **argv) { VsgVector3d lbound = {-TR, -TR, -TR}; VsgVector3d ubound = {TR, TR, TR}; PointAccum **points; VsgPRTree3d *prtree; AranSolver3d *solver; int ret = 0; guint i; aran_init(); parse_args (argc, argv); points = g_malloc0 (np * sizeof (PointAccum *)); prtree = vsg_prtree3d_new_full (&lbound, &ubound, (VsgPoint3dLocFunc) vsg_vector3d_vector3d_locfunc, (VsgPoint3dDistFunc) vsg_vector3d_dist, (VsgRegion3dLocFunc) NULL, maxbox); solver = aran_solver3d_new (prtree, ARAN_TYPE_DEVELOPMENT3D, aran_development3d_new (0, order), (AranZeroFunc) aran_development3d_set_zero); aran_solver3d_set_functions (solver, (AranParticle2ParticleFunc3d) p2p, (AranParticle2MultipoleFunc3d) p2m, m2m, m2l, l2l, (AranLocal2ParticleFunc3d)l2p); _distribution (points, solver); /* g_printerr ("ok depth = %d size = %d\n", */ /* aran_solver3d_depth (solver), */ /* aran_solver3d_point_count (solver)); */ if (direct) _direct (points, np); else aran_solver3d_solve (solver); /* vsg_prtree3d_write (prtree, stderr); */ aran_solver3d_free (solver); if (check) { gint i, j; for (i=0; i<np; i ++) { PointAccum *particle = points[i]; PointAccum check; VsgVector3d tmp; gdouble err, denom; memcpy (&check, particle, sizeof (PointAccum)); /* check.accum = 0.; */ check.field = VSG_V3D_ZERO; for (j=0; j<np; j ++) { p2p_one_way (&check, points[j]); } denom = vsg_vector3d_norm (&check.field); vsg_vector3d_sub (&particle->field, &check.field, &tmp); err = vsg_vector3d_norm (&tmp); if (denom > 0.) err /= denom; if (fabs (err) > err_lim) { g_printerr ("Field simulation error: %d relative=(%e) " "pos=(%f,%f,%f)\n" " computed=(%f,%f,%f) " "exact=(%f,%f,%f)\n", i, fabs(err), particle->vector.x, particle->vector.y, particle->vector.z, particle->field.x, particle->field.y, particle->field.z, check.field.x, check.field.y, check.field.z); /* g_printerr (" pc=%f pe=%f\n", */ /* creal (particle->accum), */ /* creal (check.accum)); */ ret ++; } } } for (i=0; i<np; i++) { g_free (points[i]); } g_free (points); return ret; }