"""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()