Skip to content
Snippets Groups Projects
multipoles.h 9.96 KiB


struct multipole {

#ifdef QUADRUPOLES
  /* Quadrupole */
  float M_200;
  float M_020;
  float M_002;
  float M_110;
  float M_101;
  float M_011;
#endif
  /* CoM */
  double M_100;
  double M_010;
  double M_001;
 
  /* Mass */
  float M_000;
};


struct fieldTensor {

#ifdef QUADRUPOLES
  float F_200;
  float F_020;
  float F_002;
  float F_110;
  float F_101;
  float F_011;
#endif
  float F_100;
  float F_010;
  float F_001;

  float F_000;
};


static inline void initFieldTensor(struct fieldTensor f) {

  f.F_000 = 0.f;

  f.F_100 = f.F_010 = f.F_001 = 0.f;

#ifdef QUADRUPOLES
  f.F_200 = f.F_020 = f.F_002 = 0.f;
  f.F_110 = f.F_101 = f.F_011 = 0.f;
#endif

}


/******************************
 * Derivatives of the potential
 * 
 * All assume inv_r = 1/sqrt(r_x^2 + r_y^2 + r_z^2)
 ******************************/

/* 0-th order */
static inline double D_000(double r_x, double r_y, double r_z, double inv_r) {  // phi(r)

   return  inv_r; 
}

/* 1-st order */
static inline double D_100(double r_x, double r_y, double r_z, double inv_r) {  // d/dx phi(r)
  return -r_x * inv_r * inv_r * inv_r; 
}  

static inline double D_010(double r_x, double r_y, double r_z, double inv_r) {  // d/dy phi(r)

  return -r_y * inv_r * inv_r * inv_r; 
}  

static inline double D_001(double r_x, double r_y, double r_z, double inv_r) {  // d/dz phi(r)

  return -r_z * inv_r * inv_r * inv_r; 
}

/* 2-nd order */
static inline double D_200(double r_x, double r_y, double r_z, double inv_r) {  // d2/dxdx phi(r)
  
  double inv_r2 = inv_r * inv_r;
  double inv_r3 = inv_r * inv_r2;
  double inv_r5 = inv_r3 * inv_r2;
  return 3. * r_x * r_x * inv_r5 - inv_r3;
}

static inline double D_020(double r_x, double r_y, double r_z, double inv_r) {  // d2/dydy phi(r)
  
  double inv_r2 = inv_r * inv_r;
  double inv_r3 = inv_r * inv_r2;
  double inv_r5 = inv_r3 * inv_r2;
  return 3. * r_y * r_y * inv_r5 - inv_r3;
}

static inline double D_002(double r_x, double r_y, double r_z, double inv_r) {  // d2/dzdz phi(r)
  
  double inv_r2 = inv_r * inv_r;
  double inv_r3 = inv_r * inv_r2;
  double inv_r5 = inv_r3 * inv_r2;
  return 3. * r_z * r_z * inv_r5 - inv_r3;
}

static inline double D_110(double r_x, double r_y, double r_z, double inv_r) {  // d2/dxdy phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  return 3. * r_x * r_y * inv_r5;
}

static inline double D_101(double r_x, double r_y, double r_z, double inv_r) {  // d2/dxdz phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  return 3. * r_x * r_z * inv_r5;
}

static inline double D_011(double r_x, double r_y, double r_z, double inv_r) {  // d2/dydz phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  return 3. * r_y * r_z * inv_r5;
}



/* 3-rd order */
static inline double D_300(double r_x, double r_y, double r_z, double inv_r) {  // d3/dxdxdx phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  double inv_r7 = inv_r5 * inv_r2;
  return -15. * r_x * r_x * r_x * inv_r7 + 9. * r_x * inv_r5;
}
static inline double D_030(double r_x, double r_y, double r_z, double inv_r) {  // d3/dydydy phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  double inv_r7 = inv_r5 * inv_r2;
  return -15. * r_y * r_y * r_y * inv_r7 + 9. * r_y * inv_r5;
}

static inline double D_003(double r_x, double r_y, double r_z, double inv_r) {  // d3/dzdzdz phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  double inv_r7 = inv_r5 * inv_r2;
  return -15. * r_z * r_z * r_z * inv_r7 + 9. * r_z * inv_r5;
}

static inline double D_210(double r_x, double r_y, double r_z, double inv_r) {  // d3/dxdxdy phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  double inv_r7 = inv_r5 * inv_r2;
  return -15. * r_x * r_x * r_y * inv_r7 + 3. * r_y * inv_r5;
}

static inline double D_201(double r_x, double r_y, double r_z, double inv_r) {  // d3/dxdxdz phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  double inv_r7 = inv_r5 * inv_r2;
  return -15. * r_x * r_x * r_z * inv_r7 + 3. * r_z * inv_r5;
}

static inline double D_120(double r_x, double r_y, double r_z, double inv_r) {  // d3/dxdydy phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  double inv_r7 = inv_r5 * inv_r2;
  return -15. * r_x * r_y * r_y * inv_r7 + 3. * r_x * inv_r5;
}

static inline double D_021(double r_x, double r_y, double r_z, double inv_r) {  // d3/dydydz phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  double inv_r7 = inv_r5 * inv_r2;
  return -15. * r_y * r_y * r_z * inv_r7 + 3. * r_z * inv_r5;
}

static inline double D_102(double r_x, double r_y, double r_z, double inv_r) {  // d3/dxdzdz phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  double inv_r7 = inv_r5 * inv_r2;
  return -15. * r_x * r_z * r_z * inv_r7 + 3. * r_x * inv_r5;
}

static inline double D_012(double r_x, double r_y, double r_z, double inv_r) {  // d3/dydzdz phi(r)

  double inv_r2 = inv_r * inv_r;
  double inv_r5 = inv_r2 * inv_r2 * inv_r;
  double inv_r7 = inv_r5 * inv_r2;
  return -15. * r_y * r_z * r_z * inv_r7 + 3. * r_y * inv_r5;
}


static inline double D_111(double r_x, double r_y, double r_z, double inv_r) {  // d3/dxdydz phi(r)

  double inv_r3 = inv_r * inv_r * inv_r;
  double inv_r7 = inv_r3 * inv_r3 * inv_r;
  return -15. * r_x * r_z * r_z * inv_r7;
}


/************************************************
 * Field tensor calculation for the accelerations
 ************************************************/


static inline void computeFieldTensors_x(double r_x, double r_y, double r_z, double inv_r, struct multipole A, struct fieldTensor* B)
{

  B->F_000 += A.M_000 * D_100(r_x, r_y, r_z, inv_r);

#ifdef QUADRUPOLES
  B->F_000 += A.M_200 * D_300(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_020 * D_120(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_002 * D_102(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_110 * D_210(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_011 * D_111(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_101 * D_201(r_x, r_y, r_z, inv_r);
#endif
  
  B->F_100 += A.M_000 * D_200(r_x, r_y, r_z, inv_r);
  B->F_010 += A.M_000 * D_110(r_x, r_y, r_z, inv_r);
  B->F_001 += A.M_000 * D_101(r_x, r_y, r_z, inv_r);
  
#ifdef QUADRUPOLES
  B->F_200 += A.M_000 * D_300(r_x, r_y, r_z, inv_r);
  B->F_020 += A.M_000 * D_120(r_x, r_y, r_z, inv_r);
  B->F_002 += A.M_000 * D_102(r_x, r_y, r_z, inv_r);
  B->F_110 += A.M_000 * D_210(r_x, r_y, r_z, inv_r);
  B->F_101 += A.M_000 * D_201(r_x, r_y, r_z, inv_r);
  B->F_011 += A.M_000 * D_111(r_x, r_y, r_z, inv_r);
#endif

}

static inline void computeFieldTensors_y(double r_x, double r_y, double r_z, double inv_r, struct multipole A, struct fieldTensor* B)
{

  B->F_000 += A.M_000 * D_010(r_x, r_y, r_z, inv_r);

#ifdef QUADRUPOLES
  B->F_000 += A.M_200 * D_210(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_020 * D_030(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_002 * D_012(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_110 * D_120(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_011 * D_021(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_101 * D_111(r_x, r_y, r_z, inv_r);
#endif
  
  B->F_100 += A.M_000 * D_110(r_x, r_y, r_z, inv_r);
  B->F_010 += A.M_000 * D_020(r_x, r_y, r_z, inv_r);
  B->F_001 += A.M_000 * D_011(r_x, r_y, r_z, inv_r);
  
#ifdef QUADRUPOLES
  B->F_200 += A.M_000 * D_210(r_x, r_y, r_z, inv_r);
  B->F_020 += A.M_000 * D_030(r_x, r_y, r_z, inv_r);
  B->F_002 += A.M_000 * D_012(r_x, r_y, r_z, inv_r);
  B->F_110 += A.M_000 * D_120(r_x, r_y, r_z, inv_r);
  B->F_101 += A.M_000 * D_111(r_x, r_y, r_z, inv_r);
  B->F_011 += A.M_000 * D_021(r_x, r_y, r_z, inv_r);
#endif

}

static inline void computeFieldTensors_z(double r_x, double r_y, double r_z, double inv_r, struct multipole A, struct fieldTensor* B)
{

  B->F_000 += A.M_000 * D_001(r_x, r_y, r_z, inv_r);

#ifdef QUADRUPOLES
  B->F_000 += A.M_200 * D_201(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_020 * D_021(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_002 * D_003(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_110 * D_111(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_011 * D_012(r_x, r_y, r_z, inv_r);
  B->F_000 += A.M_101 * D_102(r_x, r_y, r_z, inv_r);
#endif
  
  B->F_100 += A.M_000 * D_101(r_x, r_y, r_z, inv_r);
  B->F_010 += A.M_000 * D_011(r_x, r_y, r_z, inv_r);
  B->F_001 += A.M_000 * D_002(r_x, r_y, r_z, inv_r);
  
#ifdef QUADRUPOLES
  B->F_200 += A.M_000 * D_201(r_x, r_y, r_z, inv_r);
  B->F_020 += A.M_000 * D_021(r_x, r_y, r_z, inv_r);
  B->F_002 += A.M_000 * D_003(r_x, r_y, r_z, inv_r);
  B->F_110 += A.M_000 * D_111(r_x, r_y, r_z, inv_r);
  B->F_101 += A.M_000 * D_102(r_x, r_y, r_z, inv_r);
  B->F_011 += A.M_000 * D_012(r_x, r_y, r_z, inv_r);
#endif

}



static inline void shiftAndAddTensor(struct fieldTensor A, struct fieldTensor* B, double dx, double dy, double dz)
{
  B->F_000 += A.F_000;
  B->F_000 += dx * A.F_100;
  B->F_000 += dy * A.F_010; 
  B->F_000 += dz * A.F_001;

#ifdef QUADRUPOLES
  B->F_000 += 0.5f * dx * dx * A.F_200;
  B->F_000 += 0.5f * dy * dy * A.F_020;
  B->F_000 += 0.5f * dz * dz * A.F_002;
  B->F_000 += 0.5f * dx * dy * A.F_110;
  B->F_000 += 0.5f * dx * dz * A.F_101;
  B->F_000 += 0.5f * dy * dz * A.F_011;
#endif

  B->F_100 += A.F_100;
  B->F_010 += A.F_010; 
  B->F_001 += A.F_001; 

#ifdef QUADRUPOLES
  B->F_100 += dx * A.F_200 + dy * A.F_110 + dz * A.F_101;
  B->F_010 += dx * A.F_110 + dy * A.F_020 + dz * A.F_011;
  B->F_001 += dx * A.F_101 + dy * A.F_011 + dz * A.F_002;

  B->F_200 += A.F_200;
  B->F_020 += A.F_020;
  B->F_002 += A.F_002;
  B->F_110 += A.F_110;
  B->F_101 += A.F_101;
  B->F_011 += A.F_011;
#endif
  
}




static inline float applyFieldAcceleration(struct fieldTensor B, double dx, double dy, double dz)
{
  float a = 0.f;

  a += B.F_000;

  //a += dx * B.F_100;
  //a += dy * B.F_010;
  //a += dz * B.F_001;

#ifdef QUADRUPOLES
  a += 0.5f * dx * dx * B.F_200;
  a += 0.5f * dy * dy * B.F_020;
  a += 0.5f * dz * dz * B.F_002;
  a += 0.5f * dx * dy * B.F_110;
  a += 0.5f * dx * dz * B.F_101;
  a += 0.5f * dy * dz * B.F_011;
#endif

  return a;
}