Skip to content

Commit 77ec976

Browse files
committed
Added the 2.5 PN terms
Accelerations are computed up to 2.5PN including 1PN cross-terms Energy is calculated up to 2.5PN including 1PN cross-terms Momentum is calculated up to 1PN inclusind 1PN cross-terms
1 parent c9257cb commit 77ec976

File tree

2 files changed

+231
-90
lines changed

2 files changed

+231
-90
lines changed

src/EIHPerturbation.cpp

Lines changed: 220 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -6,123 +6,263 @@
66

77
using namespace std;
88

9+
// This is the computation of the full EIH equations in 1PN limit. The equations are based
10+
// on (Will 2014) section 3. See Arxiv:1312.1289v3
11+
// The higher order terms that are added are found in REF
12+
913
void EIHPerturbation::CalculateAccelerations(Model *model, int thread_id, int num_threads)
1014
{
1115
ParticleSetView &all = model->GetAllParticles();
1216
Real c2_recipr = 1 / (m_SpeedOfLight * m_SpeedOfLight);
13-
17+
Real c4_recipr = c2_recipr * c2_recipr;
18+
Real c5_recipr = c4_recipr / m_SpeedOfLight;
19+
// The primary double loop includes all direct interactions between the masses
1420
for (Particle &a : Strided(all, thread_id, num_threads))
1521
{
1622
for (Particle &b : all)
1723
{
24+
// No summation over the particle interacting with itself
1825
if (a == b)
1926
continue;
20-
27+
28+
//
29+
// Compute the differences in position and velocity
2130
Vec x_ab = a.pos - b.pos;
2231
Vec v_ab = a.vel - b.vel;
23-
24-
Real r_ab2 = x_ab.SquaredNorm();
25-
Real r_ab = sqrt(r_ab2);
26-
Real r_ab3 = r_ab * r_ab2;
27-
28-
Vec n_ab = x_ab / r_ab;
29-
Real m_a_over_r_ab = a.mass / r_ab;
30-
Real m_b_over_r_ab = b.mass / r_ab;
31-
Real m_b_over_r_ab3 = b.mass / r_ab3;
32-
33-
Real v_b_dot_n_ab = b.vel.Dot(n_ab);
34-
35-
a.acc_pert += c2_recipr * v_ab * (m_b_over_r_ab3 * x_ab.Dot(4*a.vel - 3*b.vel));
36-
37-
Real temp = 4 * m_b_over_r_ab;
38-
temp += 5 * m_a_over_r_ab;
39-
temp -= a.vel.SquaredNorm();
40-
temp += 4 * a.vel.Dot(b.vel);
41-
temp -= 2 * b.vel.SquaredNorm();
42-
temp += 1.5 * v_b_dot_n_ab * v_b_dot_n_ab;
43-
32+
// compute the distances and its powers
33+
Real r_ab2 = x_ab.SquaredNorm(); // PN0.0
34+
Real r_ab = sqrt(r_ab2); // PN1.0
35+
Real r_ab3 = r_ab * r_ab2; // PN1.0
36+
// Compute the normal vector, and mass to distance ratios
37+
Vec n_ab = x_ab / r_ab; // PN0.0
38+
Real m_a_over_r_ab = a.mass / r_ab; // PN1.0
39+
Real m_b_over_r_ab = b.mass / r_ab; // PN1.0
40+
Real m_b_over_r_ab3 = b.mass / r_ab3; // PN1.0
41+
Real m_b_over_r_ab2 = b.mass / r_ab2; // PN1.0
42+
43+
// Compute the inner products used in the equations
44+
Real v_b_dot_n_ab = b.vel.Dot(n_ab); // PN1.0
45+
Real v_a_dot_v_b = a.vel.Dot(b.vel); // PN1.0
46+
Real v_a_dot_v_a = a.vel.SquaredNorm(); // PN1.0
47+
Real v_b_dot_v_b = b.vel.SquaredNorm(); // PN1.0
48+
Real square_v_a_dot_v_a = v_a_dot_v_a * v_a_dot_v_a; // PN1.0
49+
Real square_v_b_dot_v_b = b.vel.SquaredNorm() * b.vel.SquaredNorm(); // PN1.0
50+
Real v_a_dot_n_ab = a.vel.Dot(n_ab); // PN2.0
51+
Real square_v_a_dot_v_b = a.vel.Dot(b.vel) * a.vel.Dot(b.vel); // PN2.0
52+
Real square_v_b_dot_n_ab = v_b_dot_n_ab * v_b_dot_n_ab; // PN2.0
53+
Real square_v_a_dot_n_ab = v_a_dot_n_ab * v_a_dot_n_ab; // PN2.0
54+
Real cubed_v_b_dot_n_ab = square_v_b_dot_n_ab * v_b_dot_n_ab; // PN2.0
55+
Real quarted_v_b_dot_n_ab = square_v_b_dot_n_ab * square_v_b_dot_n_ab; // PN2.0
56+
57+
// Where does the PN 0.0 term apply?
58+
// PN 1.0
59+
Real temp = 5.0 * m_a_over_r_ab;
60+
temp += 4.0 * m_b_over_r_ab;
61+
temp += 1.5 * v_a_dot_n_ab;
62+
temp -= v_a_dot_v_a;
63+
temp += 4.0 * v_a_dot_v_b;
64+
temp -= 2.0 * v_b_dot_v_b;
65+
66+
// Include the cross terms between all particle a and particles b and c.
4467
for (Particle &c : all)
4568
{
69+
// No summation over the particles interacting with themselves
4670
if (a == c || b == c)
4771
continue;
48-
72+
4973
Vec x_bc = b.pos - c.pos;
5074
Vec x_ac = a.pos - c.pos;
51-
75+
5276
Real r_bc2 = x_bc.SquaredNorm();
5377
Real r_bc = sqrt(r_bc2);
5478
Real r_bc3 = r_bc2 * r_bc;
5579
Real r_ac = x_ac.Norm();
56-
80+
Real n_bc = x_bc / r_bc;
81+
5782
Real m_c_over_r_bc3 = c.mass / r_bc3;
58-
83+
// Add the 3 cross terms
5984
temp += c.mass / r_bc;
60-
temp += 4 * c.mass / r_ac;
85+
temp += 4.0 * c.mass / r_ac;
6186
temp -= 0.5 * m_c_over_r_bc3 * x_ab.Dot(x_bc);
62-
87+
// Seperately add the 7/2 cross term (since it does not scale with m_b_over_r_ab3)
6388
a.acc_pert -= c2_recipr * x_bc * (3.5 * m_b_over_r_ab * m_c_over_r_bc3);
6489
}
65-
66-
a.acc_pert += c2_recipr * x_ab * (m_b_over_r_ab3 * temp);
90+
// Add the 1st PN in the v_ab direction
91+
a.acc_pert += c2_recipr * v_ab * (m_b_over_r_ab2 * (4.0 * v_a_dot_n_ab - 3.0 * v_b_dot_n_ab));
92+
// Add the sum of the pair and cross terms in the n_ab direction
93+
a.acc_pert += c2_recipr * n_ab * (m_b_over_r_ab2 * temp);
94+
95+
// PN 2.0
96+
Real inv_r_ab2 = 1.0 / r_ab2; // computing inverse and reusing it
97+
Real temp = -14.25 * a.mass * a.mass * inv_r_ab2; // 57/4
98+
temp -= 34.5 * a.mass * b.mass * inv_r_ab2; // 69/2
99+
temp -= 9.0 * b.mass * b.mass * inv_r_ab2; // 9
100+
temp -= 1.875 * quarted_v_b_dot_n_ab; // 16/8
101+
temp += 1.5 * square_v_b_dot_n_ab * v_a_dot_v_a; // 3/2
102+
temp -= 6.0 * square_v_b_dot_v_b * v_a_dot_v_b; // 6
103+
temp -= 2.0 * square_v_a_dot_v_b; // 2
104+
temp += 4.5 * square_v_b_dot_n_ab * v_b_dot_n_ab; // 9/2
105+
temp += 4.0 * v_a_dot_v_b * v_b_dot_v_b; // 4
106+
temp -= 2.0 * v_b_dot_v_b; // 2
107+
// Compute longer terms with new dummy variable
108+
Real temp2 = 19.5 * square_v_a_dot_n_ab; // 39/2
109+
temp2 -= 39.0 * v_a_dot_n_ab * v_b_dot_n_ab; // 39
110+
temp2 += 8.5 * square_v_b_dot_n_ab; // 17/2
111+
temp2 -= 3.75 * v_a_dot_v_a; // 15/4
112+
temp2 += 2.5 * v_a_dot_v_b; // 5/2
113+
temp2 += 1.25 * v_b_dot_v_b; // 5/4
114+
temp += a.mass / r_ab * temp2;
115+
// Next long term
116+
Real temp2 = 2.0 * square_v_a_dot_n_ab; // 2
117+
temp2 -= 4.0 * v_a_dot_n_ab * v_b_dot_n_ab; // 4
118+
temp2 -= 6.0 * square_v_b_dot_n_ab; // 6
119+
temp2 -= 8.0 * v_a_dot_v_b; // 8
120+
temp2 += 4.0 * v_b_dot_v_b; // 4
121+
temp += b.mass / r_ab * temp2;
122+
// Add the 2.0 PN contributions in n_ab
123+
a.acc_pert += c4_recipr * n_ab * (m_b_over_r_ab2 * temp);
124+
// Compute the v_ab contributions
125+
Real temp = m_b_over_r_ab * (-2.0 * v_a_dot_n_ab - 2.0 * v_b_dot_n_ab); // 2, 2
126+
temp += m_a_over_r_ab * (-15.75 * v_a_dot_n_ab + 13.75 * v_b_dot_n_ab); // -63/4, 55/4
127+
temp += 6.0 * v_a_dot_n_ab * square_v_b_dot_n_ab; // 6
128+
temp += 4.5 * cubed_v_b_dot_n_ab; // 9/2
129+
temp += v_b_dot_n_ab * v_a_dot_v_a; // 1
130+
temp -= 4.0 * v_a_dot_n_ab * v_a_dot_v_b; // -4
131+
temp += 4.0 * v_b_dot_n_ab * v_a_dot_v_b; // +4
132+
temp += 4.0 * v_a_dot_n_ab * v_b_dot_v_b; // +4
133+
temp -= 5.0 * v_b_dot_n_ab * v_b_dot_v_b; // -5
134+
a.acc_pert += c4_recipr * v_ab * (m_b_over_r_ab2 * temp);
135+
136+
// PN 2.5
137+
Real m_a_m_b_over_r_ab3 = a.mass * b.mass / r_ab3;
138+
Real v_ab_dot_n_ab = v_ab.Dot(n_ab);
139+
Real v_ab_dot_v_ab = v_ab.SquaredNorm();
140+
// Compute the n_ab terms for PN 2.5
141+
Real temp = 52.0 / 3.0 * b.mass / r_ab * v_ab_dot_n_ab; // 52/3
142+
temp -= 6.0 * a.mass / r_ab * v_ab_dot_n_ab; // 6
143+
temp += 3.0 * (v_ab_dot_n_ab)*v_ab_dot_v_ab; // 3
144+
a.acc_pert += c5_recipr * n_ab * (0.8 * m_a_m_b_over_r_ab3 * temp);
145+
Real temp = 2.0 * a.mass / r_ab; // 2
146+
temp -= 8.0 * b.mass / r_ab; // 8
147+
temp -= v_ab_dot_v_ab; // 1
148+
a.acc_pert += c5_recipr * v_ab * (0.8 * m_a_m_b_over_r_ab3 * temp);
67149
}
68150
}
69-
}
70151

71-
Real EIHPerturbation::GetEnergy(Model *model)
72-
{
73-
ParticleSetView &all = model->GetAllParticles();
74-
Real energy = 0;
75-
76-
for (Particle &a : all)
152+
Real EIHPerturbation::GetEnergy(Model * model)
77153
{
78-
Vec v_a = a.vel;
79-
Real v_a2 = v_a.SquaredNorm();
80-
81-
Real energypart = 0.375 * v_a2*v_a2;
82-
for (Particle &b : all)
154+
ParticleSetView &all = model->GetAllParticles();
155+
Real energy = 0;
156+
Real c2_recipr = 1 / (m_SpeedOfLight * m_SpeedOfLight);
157+
Real c4_recipr = c2_recipr * c2_recipr;
158+
159+
for (Particle &a : all)
83160
{
84-
if (a == b)
85-
continue;
86-
87-
Real r_ab = sqrt((a.pos - b.pos).SquaredNorm());
88-
Real m_b_over_r_ab = b.mass / r_ab;
89-
Vec n_ab = (a.pos - b.pos) / r_ab;
90-
91-
energypart += 1.5 * v_a2 * m_b_over_r_ab;
92-
93-
Real temp = 7*a.vel.Dot(b.vel);
94-
temp += a.vel.Dot(n_ab) * b.vel.Dot(n_ab);
95-
energypart -= 0.25 * m_b_over_r_ab * temp;
96-
97-
for (Particle &c : all)
161+
Vec v_a = a.vel;
162+
Real v_a_dot_v_a = v_a.SquaredNorm();
163+
Real square_v_a_dot_v_a = v_a_dot_v_a * v_a_dot_v_a; // PN1.0
164+
// 1PN kinetic term
165+
energy += c2_recipr * a.mass * 0 .375 * v_a_dot_v_a * v_a_dot_v_a;
166+
// 2PN kinetic term
167+
energy += c4_recipr * a.mass * 0.3125 * v_a_dot_v_a * v_a_dot_v_a * v_a_dot_v_a;
168+
for (Particle &b : all)
98169
{
99-
// Note: it could be b == c, which is not clear in Will (2014a)
100-
if (a == c)
170+
if (a == b)
101171
continue;
102-
103-
Real r_ac = (a.pos - c.pos).Norm();
104-
energypart += 0.5 * m_b_over_r_ab * c.mass / r_ac;
172+
173+
// Compute the differences in position and velocity
174+
Vec x_ab = a.pos - b.pos;
175+
Vec v_ab = a.vel - b.vel;
176+
// compute the distances and its powers
177+
Real r_ab2 = x_ab.SquaredNorm(); // PN0.0
178+
Real r_ab = sqrt(r_ab2); // PN1.0
179+
Real r_ab3 = r_ab * r_ab2; // PN1.0
180+
// Compute the normal vector, and mass to distance ratios
181+
Vec n_ab = x_ab / r_ab; // PN0.0
182+
Real m_a_over_r_ab = a.mass / r_ab; // PN1.0
183+
Real ma_am_b_over_r_ab = a.mass * b.mass / r_ab; // PN1.0
184+
Real ma_m_b_over_r_ab3 = a.mass * b.mass / r_ab3; // PN1.0
185+
Real ma_m_b_over_r_ab2 = a.mass * b.mass / r_ab2; // PN1.0
186+
Real m_b_over_r_ab = b.mass / r_ab; // PN1.0
187+
188+
// Compute the inner products used in the equations
189+
Real v_b_dot_n_ab = b.vel.Dot(n_ab); // PN1.0
190+
Real v_a_dot_v_b = a.vel.Dot(b.vel); // PN1.0
191+
Real v_b_dot_v_b = b.vel.SquaredNorm(); // PN1.0
192+
Real square_v_b_dot_v_b = b.vel.SquaredNorm() * b.vel.SquaredNorm(); // PN1.0
193+
Real v_a_dot_n_ab = a.vel.Dot(n_ab); // PN2.0
194+
Real square_v_b_dot_n_ab = v_b_dot_n_ab * v_b_dot_n_ab; // PN2.0
195+
Real square_v_a_dot_n_ab = v_a_dot_n_ab * v_a_dot_n_ab; // PN2.0
196+
Real cubed_v_a_dot_n_ab = square_v_a_dot_n_ab * v_a_dot_n_ab; // PN2.0
197+
Real quarted_v_b_dot_n_ab = square_v_b_dot_n_ab * square_v_b_dot_n_ab; // PN2.0
198+
199+
// 1PN terms
200+
Real energypart = 1.5 * va_dot_va * m_b_over_r_ab;
201+
Real energytemp = 7.0 * a.vel.Dot(b.vel);
202+
energytemp += a.vel.Dot(n_ab) * b.vel.Dot(n_ab);
203+
energypart -= 0.25 * m_b_over_r_ab * energytemp;
204+
// 1PN cross terms
205+
for (Particle &c : all)
206+
{
207+
// Note: it could be b == c, which is not clear in Will (2014a)
208+
if (a == c)
209+
continue;
210+
211+
Real r_ac = (a.pos - c.pos).Norm();
212+
energypart += 0.5 * m_b_over_r_ab * c.mass / r_ac;
213+
}
214+
// ADD 1PN terms
215+
energy += c2_recipr * energypart * a.mass;
216+
// 2PN terms
217+
Real energypart = -0.5 * m_a_over_r_ab * m_a_over_r_ab;
218+
energypart -= 2.375 * m_a_over_r_ab * m_b_over_r_ab;
219+
energypart += 0.375 * cubed_v_a_dot_n_ab * v_b_dot_n_ab;
220+
energypart += 0.1875 * square_v_a_dot_n_ab * square_v_b_dot_n_ab;
221+
energypart -= 1.125 * v_a_dot_n_ab * v_b_dot_n_ab * v_a_dot_v_a;
222+
energypart -= 1.625 * square_v_b_dot_n_ab * v_a_dot_v_a;
223+
energypart += 2.625 * square_v_a_dot_v_a;
224+
energypart += 1.625 * square_v_a_dot_n_ab * v_a_dot_v_b;
225+
energypart += 0.75 * v_a_dot_n_ab * v_b_dot_n_ab * v_a_dot_v_b;
226+
energypart -= 6.875 * v_a_dot_v_a * v_a_dot_v_b;
227+
energypart += 2.125 * v_a_dot_v_b * v_a_dot_v_b;
228+
energypart += 1.9375 * v_a_dot_v_a * v_b_dot_v_b;
229+
Real energytemp = 7.25 * square_v_a_dot_n_ab;
230+
energytemp -= 3.25 * v_a_dot_n_ab * v_b_dot_n_ab;
231+
energytemp += 0.5 * square_v_b_dot_n_ab;
232+
energytemp += 1.5 * v_a_dot_v_a;
233+
energytemp += 1.75 * v_b_dot_v_b;
234+
energypart += energytemp * m_a_over_r_ab;
235+
energy += a.mass * c4_recipr * energypart * m_b_over_r_ab;
105236
}
106237
}
107-
108-
energy += energypart * a.mass;
238+
return energy;
109239
}
110-
111-
energy /= m_SpeedOfLight * m_SpeedOfLight;
112240

113-
return energy;
114-
}
115-
116-
Vec EIHPerturbation::GetLinearMomentum(Model *model)
117-
{
118-
// TODO
119-
ParticleSetView &all = model->GetAllParticles();
120-
Vec momentum = Vec::Zero();
121-
122-
for (Particle &p : all)
241+
Vec EIHPerturbation::GetLinearMomentum(Model * model)
123242
{
124-
momentum += p.mass * p.vel;
243+
// This term is computed up to 1PN with cross terms
244+
ParticleSetView &all = model->GetAllParticles();
245+
Vec momentum = Vec::Zero();
246+
Real c2_recipr = 1 / (m_SpeedOfLight * m_SpeedOfLight);
247+
248+
for (Particle &a : all)
249+
{
250+
// 0PN
251+
momentum += a.mass * a.vel;
252+
// 1PN
253+
Real v_a_dot_v_a = v_a.SquaredNorm();
254+
Vec momentumpart = v_a_dot_v_a * a.vel;
255+
for (Particle &b : all)
256+
{
257+
if (b == a)
258+
continue;
259+
Vec x_ab = a.pos - b.pos;
260+
Real r_ab = x_ab.Norm();
261+
Vec n_ab = x_ab / r_ab;
262+
momentumpart -= b.mass / r_ab * a.vel;
263+
momentumpart -= b.mass / r_ab * (a.vel.Dot(n_ab)) * n_ab
264+
}
265+
momentum += 0.5 * c2_recipr * a.mass * momentumpart
266+
}
267+
return momentum;
125268
}
126-
127-
return momentum;
128-
}

0 commit comments

Comments
 (0)