probably faulty but running at least
This commit is contained in:
parent
e9587e2e97
commit
b130f68a44
@ -1,18 +1,18 @@
|
||||
# N-Body project - Checklist
|
||||
|
||||
### Task 1
|
||||
- [ ] Compute characteristic quantities/scales
|
||||
- [x] Compute characteristic quantities/scales
|
||||
- [x] Compare analytical model and particle density distribution
|
||||
- [ ] Compute forces through nbody simulation
|
||||
- [x] Compute forces through nbody simulation
|
||||
- [x] vary softening length and compare results
|
||||
- [x] compare with the analytical expectation from Newtons 2nd law
|
||||
- [ ] compute the relaxation time
|
||||
- [x] compute the relaxation time
|
||||
|
||||
### Task 2 (particle mesh)
|
||||
- [ ] Choose reasonable units
|
||||
- [ ] Implement force computation on mesh
|
||||
- [ ] Find optimal mesh size
|
||||
- [ ] Compare with direct nbody simulation
|
||||
- [~x] Implement force computation on mesh
|
||||
- [x] Find optimal mesh size
|
||||
- [x] Compare with direct nbody simulation
|
||||
- [ ] Time integration for direct method AND mesh method
|
||||
|
||||
|
||||
|
483
nbody/copy.ipynb
Normal file
483
nbody/copy.ipynb
Normal file
File diff suppressed because one or more lines are too long
@ -42,7 +42,7 @@
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"16:03:58 - utils.load - Loaded 50010 rows and 10 columns from data/data.txt\n"
|
||||
"08:59:02 - utils.load - Loaded 50010 rows and 10 columns from data/data.txt\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -104,8 +104,8 @@
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"16:04:00 - task1 - Considering a globular cluster - total mass of particles: 4622219.258999999, maximum radius of particles: 724.689657812915\n",
|
||||
"16:04:00 - utils.units - Set scales: M_SCALE = 0.022 solMass, R_SCALE = 0.028 pc\n"
|
||||
"08:59:04 - task1 - Considering a globular cluster - total mass of particles: 4622219.258999999, maximum radius of particles: 724.689657812915\n",
|
||||
"08:59:04 - utils.units - Set scales: M_SCALE = 0.022 solMass, R_SCALE = 0.028 pc\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -206,7 +206,7 @@
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"16:04:00 - utils.particles - Found mean interparticle distance: 0.010402746349924056\n"
|
||||
"08:59:05 - utils.particles - Found mean interparticle distance: 0.010402746349924056\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -235,56 +235,6 @@
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"## compare the two force calculations\\n# since the forces were computed for each particle, rather than comparing them directly we compare the relative error in the magnitude and direction of the forces\\n\\n\\n# f_diff = f_nsquare_1e - f_analytical\\nf_diff = f_nsquare_2e - f_analytical\\ndiff_mag = np.linalg.norm(f_diff, axis=1)\\n\\n\\n# plot the distribution of the error\\n# create 4 stacked histograms, sharing the same x axis\\nfig, ax = plt.subplots(4, sharex=True)\\nax[0].hist(diff_mag, bins=NBINS)\\nax[0].set_title('Magnitude of the force difference')\\nax[0].set_yscale('log')\\n\\nax[1].hist(f_diff[:,0], bins=NBINS)\\nax[1].set_title('X component of the force difference')\\nax[1].set_yscale('log')\\n\\nax[2].hist(f_diff[:,1], bins=NBINS)\\nax[2].set_title('Y component of the force difference')\\nax[2].set_yscale('log')\\n\\nax[3].hist(f_diff[:,2], bins=NBINS)\\nax[3].set_title('Z component of the force difference')\\nax[3].set_yscale('log')\\n\\nplt.title('Error in forces')\\nplt.show()\\n\""
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\"\"\"## compare the two force calculations\n",
|
||||
"# since the forces were computed for each particle, rather than comparing them directly we compare the relative error in the magnitude and direction of the forces\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# f_diff = f_nsquare_1e - f_analytical\n",
|
||||
"f_diff = f_nsquare_2e - f_analytical\n",
|
||||
"diff_mag = np.linalg.norm(f_diff, axis=1)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# plot the distribution of the error\n",
|
||||
"# create 4 stacked histograms, sharing the same x axis\n",
|
||||
"fig, ax = plt.subplots(4, sharex=True)\n",
|
||||
"ax[0].hist(diff_mag, bins=NBINS)\n",
|
||||
"ax[0].set_title('Magnitude of the force difference')\n",
|
||||
"ax[0].set_yscale('log')\n",
|
||||
"\n",
|
||||
"ax[1].hist(f_diff[:,0], bins=NBINS)\n",
|
||||
"ax[1].set_title('X component of the force difference')\n",
|
||||
"ax[1].set_yscale('log')\n",
|
||||
"\n",
|
||||
"ax[2].hist(f_diff[:,1], bins=NBINS)\n",
|
||||
"ax[2].set_title('Y component of the force difference')\n",
|
||||
"ax[2].set_yscale('log')\n",
|
||||
"\n",
|
||||
"ax[3].hist(f_diff[:,2], bins=NBINS)\n",
|
||||
"ax[3].set_title('Z component of the force difference')\n",
|
||||
"ax[3].set_yscale('log')\n",
|
||||
"\n",
|
||||
"plt.title('Error in forces')\n",
|
||||
"plt.show()\n",
|
||||
"\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
@ -347,15 +297,15 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"16:04:17 - task1 - Crossing time for half mass system: 1.7e-06 pc(3/2) / solMass(1/2)\n",
|
||||
"16:04:17 - task1 - Direct estimate of the relaxation timescale: 0.00078 pc(3/2) / solMass(1/2)\n"
|
||||
"08:59:24 - task1 - Crossing time for half mass system: 1.7e-06 pc(3/2) / solMass(1/2)\n",
|
||||
"08:59:24 - task1 - Direct estimate of the relaxation timescale: 0.00078 pc(3/2) / solMass(1/2)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
File diff suppressed because one or more lines are too long
@ -47,6 +47,24 @@ def n_body_forces(particles: np.ndarray, G: float, softening: float = 0):
|
||||
return forces
|
||||
|
||||
|
||||
def n_body_forces_basic(particles: np.ndarray, G: float, softening: float = 0):
|
||||
if particles.shape[1] != 4:
|
||||
raise ValueError("Particles array must have 4 columns: x, y, z, m")
|
||||
|
||||
x_vec = particles[:, 0:3]
|
||||
masses = particles[:, 3]
|
||||
n = particles.shape[0]
|
||||
forces = np.zeros((n, 3))
|
||||
for i in range(n):
|
||||
for j in range(n):
|
||||
if i == j:
|
||||
continue # keep the value at zero
|
||||
r_vec = x_vec[j] - x_vec[i]
|
||||
r = np.linalg.norm(r_vec)
|
||||
f = - G * masses[i] * masses[j] * r_vec / (r**3 + softening**3)
|
||||
forces[i] += f
|
||||
|
||||
return forces
|
||||
|
||||
def analytical_forces(particles: np.ndarray):
|
||||
"""
|
||||
|
@ -16,10 +16,9 @@ def ode_setup(particles: np.ndarray, force_function: callable) -> tuple[np.ndarr
|
||||
if particles.shape[1] != 7:
|
||||
raise ValueError("Particles array must have 7 columns: x, y, z, vx, vy, vz, m")
|
||||
|
||||
# for scipy integrators we need to flatten array which contains 7 columns for now
|
||||
# we don't really care how we reshape as long as we unflatten consistently afterwards
|
||||
# for the integrators we need to flatten array which contains 7 columns for now
|
||||
# we don't really care how we reshape as long as we unflatten consistently
|
||||
particles = particles.reshape(-1, copy=False, order='A')
|
||||
# this is consistent with the unflattening in to_particles()!
|
||||
logger.debug(f"Reshaped 7 columns into {particles.shape=}")
|
||||
|
||||
def f(y, t):
|
||||
@ -30,32 +29,34 @@ def ode_setup(particles: np.ndarray, force_function: callable) -> tuple[np.ndarr
|
||||
y = to_particles(y)
|
||||
# now y has shape (n, 7), with columns x, y, z, vx, vy, vz, m
|
||||
|
||||
|
||||
forces = force_function(y[:, [0, 1, 2, -1]])
|
||||
|
||||
# compute the accelerations
|
||||
masses = y[:, -1]
|
||||
a = forces / masses[:, None]
|
||||
# the [:, None] is to force broadcasting in order to divide each row of forces by the corresponding mass
|
||||
# a.flatten()
|
||||
|
||||
# replace some values in y:
|
||||
dydt = np.zeros_like(y)
|
||||
# the position columns become the velocities
|
||||
# the velocity columns become the accelerations
|
||||
y[:, 0:3] = y[:, 3:6]
|
||||
y[:, 3:6] = a
|
||||
dydt[:, 0:3] = y[:, 3:6]
|
||||
dydt[:, 3:6] = a
|
||||
# the masses remain unchanged
|
||||
dydt[:, -1] = masses
|
||||
|
||||
# flatten the array again
|
||||
y = y.reshape(-1, copy=False, order='A')
|
||||
return y
|
||||
# logger.debug(f"As particles: {y}")
|
||||
dydt = dydt.reshape(-1, copy=False, order='A')
|
||||
|
||||
# logger.debug(f"As column: {y}")
|
||||
return dydt
|
||||
|
||||
return particles, f
|
||||
|
||||
|
||||
def to_particles(y: np.ndarray) -> np.ndarray:
|
||||
"""
|
||||
Converts the 1D array y into a 2D array IN PLACE
|
||||
Converts the 1D array y into a 2D array
|
||||
The new shape is (n, 7) where n is the number of particles.
|
||||
The columns are x, y, z, vx, vy, vz, m
|
||||
"""
|
||||
@ -64,10 +65,21 @@ def to_particles(y: np.ndarray) -> np.ndarray:
|
||||
|
||||
n = y.size // 7
|
||||
y = y.reshape((n, 7), copy=False, order='F')
|
||||
logger.debug(f"Unflattened array into {y.shape=}")
|
||||
# logger.debug(f"Unflattened array into {y.shape=}")
|
||||
return y
|
||||
|
||||
|
||||
def to_particles_3d(y: np.ndarray) -> np.ndarray:
|
||||
"""
|
||||
Converts the 2D sol array with one vector per timestep into a 3D array:
|
||||
2d particles (nx7) x nsteps
|
||||
"""
|
||||
n_steps = y.shape[0]
|
||||
n_particles = y.shape[1] // 7
|
||||
y = y.reshape((n_steps, n_particles, 7), copy=False, order='F')
|
||||
# logger.debug(f"Unflattened array into {y.shape=}")
|
||||
return y
|
||||
|
||||
|
||||
def runge_kutta_4(y0 : np.ndarray, t : float, f, dt : float):
|
||||
k1 = f(y0, t)
|
||||
|
@ -2,8 +2,8 @@ import logging
|
||||
|
||||
logging.basicConfig(
|
||||
## set logging level
|
||||
level = logging.DEBUG,
|
||||
# level = logging.INFO,
|
||||
level=logging.INFO,
|
||||
format = '%(asctime)s - %(name)s - %(message)s',
|
||||
datefmt = '%H:%M:%S'
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user