Published
Edited
Jul 18, 2021
7 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
configurations = {
let configurations = {};

// Experimental - you gotta uncomment the line redefining `nodes`
// near the top of the definition of `orbit` to access this.
// configurations.experimental = [
// { m: 4, x: 0, y: 0, vx: 0, vy: -1 },
// { m: 2, x: 1, y: 0, vx: 0, vy: 0.8824172416557946 },
// { m: 1, x: 1.7186229732164608, y: 0, vx: 0, vy: 2.235165516688411 }
// ];
// configurations.experimental.xmin = -.5;
// configurations.experimental.xmax = 2;
// configurations.experimental.ymin = -1;
// configurations.experimental.ymax = 1;
// configurations.experimental.steps_per_frame = 4;
// configurations.experimental.dt = 0.001;
// configurations.experimental.delay = 1;

// Two bodies with equal masses
configurations.twoEqual = [
{ m: 4, x: 0, y: 0, vx: 0, vy: -1 / Math.sqrt(2) },
{ m: 4, x: 1, y: 0, vx: 0, vy: 1 / Math.sqrt(2) }
];
configurations.twoEqual.xmin = -0.2;
configurations.twoEqual.xmax = 1.2;
configurations.twoEqual.ymin = -1 / 2;
configurations.twoEqual.ymax = 1 / 2;
configurations.twoEqual.steps_per_frame = 1;
configurations.twoEqual.dt = 0.001;
configurations.twoEqual.delay = 0;

// Two bodies with unequal masses
configurations.twoUnequal = [
{ m: 1, x: 1, y: 0, vx: 0, vy: 2 },
{ m: 20, x: 0, y: 0, vx: 0, vy: -0.1 }
];
configurations.twoUnequal.xmin = -0.2;
configurations.twoUnequal.xmax = 1.2;
configurations.twoUnequal.ymin = -0.4;
configurations.twoUnequal.ymax = 0.4;
configurations.twoUnequal.steps_per_frame = 1;
configurations.twoUnequal.dt = 0.001;
configurations.twoUnequal.delay = 0;

// A symmetric, Eulerian central configuration
// All three points stay on a line segment with one point
// at the center (of mass) and the others revolving around it.
configurations.eulerianSymmetricCentralConfiguration = [
{ m: 4, x: 0, y: 0, vx: 0, vy: -1 },
{ m: 0.5, x: 0.5, y: 0, vx: 0, vy: 0 },
{ m: 4, x: 1, y: 0, vx: 0, vy: 1 }
];
configurations.eulerianSymmetricCentralConfiguration.xmin = -0.2;
configurations.eulerianSymmetricCentralConfiguration.xmax = 1.2;
configurations.eulerianSymmetricCentralConfiguration.ymin = -1 / 2;
configurations.eulerianSymmetricCentralConfiguration.ymax = 1 / 2;
configurations.eulerianSymmetricCentralConfiguration.steps_per_frame = 1;
configurations.eulerianSymmetricCentralConfiguration.dt = 0.001;
configurations.eulerianSymmetricCentralConfiguration.delay = 0;
configurations.eulerianSymmetricCentralConfiguration.period = 844;

// An Eulerian asymmetric central configuration
// All three points stay on a line segment but
// the middle point is not at the center of mass.
configurations.eulerianAsymmetricCentralConfiguration = [
{ m: 100, x: 0, y: 0, vx: 0, vy: -0.618 },
{ m: 10, x: 1, y: 0, vx: 0, vy: 5.419013137068794 },
{ m: 1, x: 1.3629038801971198, y: 0, vx: 0, vy: 7.609868629312047 }
];
configurations.eulerianAsymmetricCentralConfiguration.xmin = -1;
configurations.eulerianAsymmetricCentralConfiguration.xmax = 2;
configurations.eulerianAsymmetricCentralConfiguration.ymin = -1.3;
configurations.eulerianAsymmetricCentralConfiguration.ymax = 1.3;
configurations.eulerianAsymmetricCentralConfiguration.steps_per_frame = 1;
configurations.eulerianAsymmetricCentralConfiguration.dt = 0.001;
configurations.eulerianAsymmetricCentralConfiguration.delay = 5;
configurations.eulerianAsymmetricCentralConfiguration.period = 293;

configurations.threeUnequal = (function() {
let nodes = [
{ m: 20, x: 0, y: 0, vx: 0, vy: -0.1 },
{ m: 1, x: 1, y: 0, vx: 0, vy: 2 },
{ m: 0.0001, x: 1.5, y: 0, vx: 0, vy: 3.5 }
];
nodes.xmin = -1;
nodes.xmax = 2;
nodes.ymin = -1.4;
nodes.ymax = 1.4;
nodes.steps_per_frame = 5;
nodes.dt = 0.001;
nodes.delay = 25;
return nodes;
})();

// Lagrange
configurations.lagrange = (function() {
let nodes = [
{ m: 4, x: 0, y: 0, vx: 0, vy: -1 / Math.sqrt(2) },
{ m: 4, x: 1, y: 0, vx: 0, vy: 1 / Math.sqrt(2) },
{
m: 0.0000001,
x: 1 / 2,
y: Math.sqrt(3) / 2,
vx: -Math.sqrt(3 / 2),
vy: 0
}
];
nodes.xmin = -0.2;
nodes.xmax = 1.2;
nodes.ymin = -0.2;
nodes.ymax = 1;
nodes.steps_per_frame = 20;
nodes.dt = 0.0001;
nodes.delay = 5;
nodes.period = 4 * 480;
return nodes;
})();

// Perturbed Lagrange
configurations.perturbedLagrange = (function() {
let nodes = [
{ m: 4, x: 0, y: 0, vx: 0, vy: -1 / Math.sqrt(2) },
{ m: 4, x: 1, y: 0, vx: 0, vy: 1 / Math.sqrt(2) },
{
m: 0.0000001,
x: 1 / 2 + 0.001,
y: Math.sqrt(3) / 2,
vx: -Math.sqrt(3 / 2),
vy: 0
}
];
nodes.xmin = -0.2;
nodes.xmax = 1.2;
nodes.ymin = -0.2;
nodes.ymax = 1;
nodes.steps_per_frame = 20;
nodes.dt = 0.0001;
nodes.delay = 5;
nodes.period = 4 * 480;
return nodes;
})();

// Figure 8
configurations.figure8 = (function() {
let nodes = [
{
m: 1,
x: -0.97000436,
y: 0.24308753,
vx: 0.4662036850,
vy: 0.4323657300
},
{ m: 1, x: 0, y: 0, vx: -0.93240737, vy: -0.86473146 },
{
m: 1,
x: 0.97000436,
y: -0.24308753,
vx: 0.4662036850,
vy: 0.4323657300
}
];
nodes.xmin = -1.2;
nodes.xmax = 1.2;
nodes.ymin = -0.6;
nodes.ymax = 0.6;
nodes.steps_per_frame = 1;
nodes.track_length = 150;
nodes.dt = 0.01;
nodes.delay = 0;
return nodes;
})();

// Sun, Planet, Moon (seems stable)
configurations.sunPlanetMoon = [
{ m: 4, x: 0, y: 0, vx: 0, vy: -0.5 },
{ m: 0.00001, x: 4 / 5, y: 0, vx: 0, vy: 0 },
{ m: 1, x: 1, y: 0, vx: 0, vy: 2 }
];
configurations.sunPlanetMoon.xmin = -1.4;
configurations.sunPlanetMoon.xmax = 1.4;
configurations.sunPlanetMoon.ymin = -1.4;
configurations.sunPlanetMoon.ymax = 1.4;
configurations.sunPlanetMoon.steps_per_frame = 5;
configurations.sunPlanetMoon.dt = 0.001;
configurations.sunPlanetMoon.delay = 5;

// http://three-body.ipb.ac.rs/bsol.php?id=0
configurations.threeBody0 = (function() {
let nodes = [
{ m: 1, x: -0.9892620043, y: 0, vx: 0, vy: 1.9169244185 },
{ m: 1, x: 2.2096177241, y: 0, vx: 0, vy: 0.1910268738 },
{ m: 1, x: -1.2203557197, y: 0, vx: 0, vy: -2.1079512924 }
];
nodes.xmin = -2.3;
nodes.xmax = 2.3;
nodes.ymin = -1;
nodes.ymax = 1;
nodes.steps_per_frame = 1;
nodes.track_length = 150;
nodes.dt = 0.01;
nodes.delay = 0;
return nodes;
})();

// http://three-body.ipb.ac.rs/bsol.php?id=11
configurations.threeBody11 = (function() {
let nodes = [
{ m: 1, x: -0.337076702, y: 0, vx: 0, vy: 0.9174260238 },
{ m: 1, x: 2.1164029743, y: 0, vx: 0, vy: -0.0922665014 },
{ m: 1, x: -1.7793262723, y: 0, vx: 0, vy: -0.8251595224 }
];
nodes.xmin = -2.3;
nodes.xmax = 2.3;
nodes.ymin = -2.3;
nodes.ymax = 2.3;
nodes.steps_per_frame = 3;
nodes.track_length = 150;
nodes.dt = 0.01;
nodes.delay = 0;
return nodes;
})();

// http://three-body.ipb.ac.rs/bsol.php?id=18
configurations.threeBody18 = (function() {
let nodes = [
{ m: 1, x: 0.8920281421, y: 0, vx: 0, vy: 0.9957939373 },
{ m: 1, x: -0.6628498947, y: 0, vx: 0, vy: -1.6191613336 },
{ m: 1, x: -0.2291782474, y: 0, vx: 0, vy: 0.6233673964 }
];
nodes.xmin = -1.2;
nodes.xmax = 1.2;
nodes.ymin = -1;
nodes.ymax = 1;
nodes.steps_per_frame = 1;
nodes.track_length = 150;
nodes.dt = 0.01;
nodes.delay = 0;
return nodes;
})();

// 3-4-5 triangle
configurations.threeFourFive = (function() {
let nodes = [
{ m: 3, x: 1, y: 3, vx: 0, vy: 0 },
{ m: 4, x: -2, y: -1, vx: 0, vy: 0 },
{ m: 5, x: 1, y: -1, vx: 0, vy: 0 }
];
nodes.xmin = -6;
nodes.xmax = 6;
nodes.ymin = -6;
nodes.ymax = 6;
nodes.aspect = (nodes.ymax - nodes.ymin) / (nodes.xmax - nodes.xmin);
nodes.steps_per_frame = 1000;
nodes.dt = 0.00005;
nodes.delay = 1;
return nodes;
})();

configurations.circle7 = circular_configuration(7);

configurations.semiRandom = (function() {
let n1 = 3;
let s1 = 0.2083785248428932;
let n2 = 4;
let s2 = 0.3889050449181679;
let n3 = 3;
let s3 = 0.9968774001773553;
let n4 = 4;
let s4 = 0.2990274913092489;
let nodes = random_configuration(n4, s4);
return nodes;
})();

return configurations;
}
Insert cell
commentary = ({
twoEqual: "Two equal masses in mutal orbit",
twoUnequal: "A basic star/planet model",
eulerianSymmetricCentralConfiguration:
'A <a target="_blank" href="http://www.scholarpedia.org/article/Central_configurations">central configuration</a> is a special arrangment that remains geometrical similar to it\'s initial shape. In the simplest instance, two large masses revolve around an object at the center of mass. The three masses lie on a line segment throughout the evolution.',
eulerianAsymmetricCentralConfiguration:
'In this <a target="_blank" href="http://www.scholarpedia.org/article/Central_configurations">central configuration</a>, the three masses are 100, 10, and 1. They revolve around the center of mass. ',
sunPlanetMoon: "A moon in orbit around a large planet in orbit around a sun.",
lagrange:
'<a target="_blank" href="https://en.wikipedia.org/wiki/Lagrange_point">Lagrange found another type of central configuration</a> whose objects lie at the vertices of an equilateral triangle. In the example here, there are two large bodies are mutual orbit. The central configuration is completed by very small third mass.',
perturbedLagrange:
'While stable, the basin of attraction of a Lagrange point can be quite small. Thus, we can move the small point a small amount and lose stability.',
figure8:
'There are a surprising number of surprising solutions to the three body problem. I learned of this one from <a target="_blank" href="http://three-body.ipb.ac.rs/sol.php?id=1">The Three Body Gallery</a>.',
threeBody0:
'Another from <a target="_blank" href="http://three-body.ipb.ac.rs/bsol.php?id=0">The Three Body Gallery</a>',
threeBody11:
'Another from <a target="_blank" href="http://three-body.ipb.ac.rs/bsol.php?id=11">The Three Body Gallery</a>',
threeBody18:
'Another from <a target="_blank" href="http://three-body.ipb.ac.rs/bsol.php?id=18">The Three Body Gallery</a>',
threeFourFive:
'When three equal masses are placed at rest the vertices of a 3-4-5 triangle, things get a little crazy',
semiRandom: "Generally, a few objects placed at rest don't play nice.",
circle7:
'If we place seven objects of equal mass placed evenly around a circle with a little velocity tangential to the circle, the result can be stable.'
})
Insert cell
Insert cell
function F(nodes) {
let G = 1;
let n = nodes.length;
function x_accel(s, i, j) {
let m2 = nodes[j].m;
let x1 = s[i];
let y1 = s[i + n];
let x2 = s[j];
let y2 = s[j + n];
return (m2 * (x2 - x1)) / ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** (3 / 2);
}
function y_accel(s, i, j) {
let m2 = nodes[j].m;
let x1 = s[i];
let y1 = s[i + n];
let x2 = s[j];
let y2 = s[j + n];
return (m2 * (y2 - y1)) / ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** (3 / 2);
}
function xpp(s, i) {
return (
G *
d3.sum(
d3.range(n).map(function(j) {
if (j != i) {
return x_accel(s, i, j);
} else {
return 0;
}
})
)
);
}
function ypp(s, i) {
return (
G *
d3.sum(
d3.range(n).map(function(j) {
if (j != i) {
return y_accel(s, i, j);
} else {
return 0;
}
})
)
);
}
function F(s, t) {
return s
.slice(2 * n, 3 * n)
.concat(s.slice(3 * n, 4 * n))
.concat(d3.range(n).map(i => xpp(s, i)))
.concat(d3.range(n).map(i => ypp(s, i)));
}
return F;
}
Insert cell
Insert cell
function random_object(seed) {
return {
m: d3.randomUniform.source(d3.randomLcg(seed))(1, 10)(),
x: d3.randomUniform.source(d3.randomLcg(seed / 2))(-4, 4)(),
y: d3.randomUniform.source(d3.randomLcg(seed / 3))(-4, 4)(),
vx: 0, //d3.randomUniform.source(d3.randomLcg(seed / 4))(-4, 4)(),
vy: 0 //d3.randomUniform.source(d3.randomLcg(seed / 5))(-4, 4)()
};
}
Insert cell
function random_configuration(k, seed) {
let nodes = d3.range(k).map((_, i) => random_object(seed / i));
nodes.xmin = -8;
nodes.xmax = 8;
nodes.ymin = -8;
nodes.ymax = 8;
nodes.steps_per_frame = 1000;
nodes.dt = 0.00005;
nodes.delay = 5;
nodes.cnt_max = 5000;
return nodes;
}
Insert cell
function circular_configuration(k) {
let nodes = d3.range(k).map(i => ({
m: 1,
x: Math.cos((2 * Math.PI * i) / k),
y: Math.sin((2 * Math.PI * i) / k),
vx: -Math.sin((2 * Math.PI * i) / k) / 3,
vy: Math.cos((2 * Math.PI * i) / k) / 3
}));
nodes.xmin = -2;
nodes.xmax = 2;
nodes.ymin = -2;
nodes.ymax = 2;
nodes.steps_per_frame = 50;
nodes.dt = 0.001;
nodes.delay = 5;
if (k == 3) {
nodes.period = 169;
nodes.delay = 10;
nodes.dt = 0.001;
nodes.steps_per_frame = 20;
} else if (k == 4) {
nodes.period = 124;
nodes.delay = 10;
nodes.dt = 0.001;
nodes.steps_per_frame = 20;
} else if (k == 5) {
nodes.period = 100;
nodes.delay = 15;
nodes.dt = 0.001;
nodes.steps_per_frame = 20;
} else if (k == 6) {
nodes.period = 86;
nodes.delay = 15;
nodes.dt = 0.001;
nodes.steps_per_frame = 20;
} else if (k == 7) {
nodes.period = 610;
nodes.delay = 2;
nodes.dt = 0.0005;
nodes.steps_per_frame = 5;
}
return nodes;
}
Insert cell
Insert cell
import { select } from "@jashkenas/inputs"
Insert cell
import { rk4_multi_step } from '@mcmcclur/runge-kutta-for-systems-of-odes'
Insert cell
d3 = require('d3-selection@2', 'd3-array@2', 'd3-random@2', 'd3-shape@2', 'd3-scale@2', 'd3-scale-chromatic@2')
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more