12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- """Basic testing to ensure the chosen timestep is sensible and to probe
- the symplectic character of the integrator."""
- import matplotlib.pyplot as plt
- import numpy as np
- from scipy.signal import savgol_filter
- from analysis import utils
- def calculatePotentialEnergy(r_vec, v_vec, mass, soft=0.):
- """Calculates the potential energy of a set of masses.
- It is an adaptation of the acceleration routines.
- """
- mask = mass!=0
- massMassive = mass[mask]
- rMassive_vec = r_vec[mask]
- mass_mat = massMassive.reshape(1, -1, 1)
- r_ten = rMassive_vec.reshape(1, -1, 3) - r_vec.reshape(-1, 1, 3)
- r_mat = np.linalg.norm(r_ten, axis=-1, keepdims=True)
- # Avoid self interactions and divisions by 0
- mass_mat = np.where(r_mat == 0, np.zeros_like(mass_mat), mass_mat)
- r_mat = np.where(r_mat == 0, np.ones_like(r_mat), r_mat)
- PE = -mass_mat/(r_mat + soft)
- # Add all contributions but do not sum them twice
- PE = np.sum(PE, axis=1)[:,0]/2 * mass
- energy = PE + 1/2 * np.linalg.norm(v_vec, axis=-1)**2 * mass
- return np.sum(energy)
- '''PE = np.sum(PE, axis=1)[:,0]
- print((mass==0)[:5])
- print('PE', PE[:5], (1/2 * np.linalg.norm(v_vec, axis=-1)**2)[:5])
- energy = PE + 1/2 * np.linalg.norm(v_vec, axis=-1)**2
- return np.sum(energy[mass==0])'''
- #calculatePotentialEnergy(np.array([[0,0,0],[1,0,0], [2,0,0]]), np.array([1,1, 0]), soft=0.)
- f, ax = plt.subplots(1, 1)
- for name, label, factor, color in zip(['dt1E-2', 'dt1E-3', 'dt1E-4'],
- [r'$dt=10^{-2}$', r'$dt=10^{-3}$', r'$dt=10^{-4}$'],
- [1, 10, 100],
- ['cornflowerblue', 'darkorange', '#75d2aa']):
- time = []
- errors = []
- # Use start of the simulation as ground truth
- truth = utils.loadData(name, 10*factor)
- truthEnergy = calculatePotentialEnergy(truth['r_vec'], truth['v_vec'], truth['mass'], soft=0.1)
- for n in np.linspace(10, 1000, 100):
- # Load the data
- data = utils.loadData(name, int(n*factor))
- # Find the deviation
- time.append(data['t'])
- # Energies per unit mass
- energy = calculatePotentialEnergy(data['r_vec'], data['v_vec'], data['mass'], soft=0.1)
- errors.append(np.abs(energy - truthEnergy)/np.abs(truthEnergy))
- # Plot
- errors = savgol_filter(errors, 11, 3) # Smooth
- ax.plot(time, errors, color=color, label=label)
- # Styling
- utils.stylizePlot([ax])
- utils.setAxes(ax, x='Time', y='Relative energy error',
- xcoords=(.85,-0.08), ycoords=(-0.1,.75))
- ax.set_yscale('log')
- ax.set_xlim(0, time[-1])
- ax.set_ylim(1E-4, None)
- ax.axvline(x=3.55, linestyle='--', linewidth=1, color='black')
- plt.legend(loc='upper left')
- plt.show()
-
|