def calculate_orbital_parameters(xGC_norm, yGC_norm, zGC_norm, vxGC_norm, vyGC_norm, vzGC_norm, inttime, numsteps): # agama convention x_agama = xGC_norm y_agama = yGC_norm z_agama = zGC_norm vx_agama = vxGC_norm vy_agama = vyGC_norm vz_agama = vzGC_norm R_agama = numpy.sqrt(x_agama**2 + y_agama**2) vR_agama = (x_agama * vx_agama + y_agama * vy_agama) / R_agama vT_agama = -(x_agama * vy_agama - y_agama * vx_agama) / R_agama phi_agama = numpy.arctan2(y_agama, x_agama) inttime = 1. numsteps = 300 times = numpy.linspace(0, inttime, numsteps) times_c, c_orb_car = agama.orbit( ic=[x_agama, y_agama, z_agama, vx_agama, vy_agama, vz_agama], potential=potentialTotal_local, time=inttime, trajsize=numsteps) #print(c_orb_car[:,0]) x = c_orb_car[:, 0] y = c_orb_car[:, 1] z = c_orb_car[:, 2] vx = c_orb_car[:, 3] vy = c_orb_car[:, 4] vz = c_orb_car[:, 5] R = numpy.sqrt(x**2 + y**2) r = numpy.sqrt(x**2 + y**2 + z**2) rmin = numpy.min(r) rmax = numpy.max(r) zmax = numpy.max(numpy.fabs(z)) ecc = (rmax - rmin) / (rmax + rmin) return rmin, rmax, zmax, ecc
def run_orbit(ic): color = numpy.random.random( size=3) * 0.8 #plt.get_cmap('mist')(numpy.random.random()) time, orbit = agama.orbit(ic=ic, potential=pot, time=100 * pot.Tcirc(ic), trajsize=20000) x = orbit[:, 0] if Lz == 0 else (orbit[:, 0]**2 + orbit[:, 1]**2)**0.5 vx = orbit[:, 3] if Lz == 0 else (orbit[:, 0] * orbit[:, 3] + orbit[:, 1] * orbit[:, 4]) / x z = orbit[:, 2] vz = orbit[:, 5] splx = agama.CubicSpline(time, x, der=vx) splz = agama.CubicSpline(time, z, der=vz) hits = (z[:-1] <= 0) * ( z[1:] > 0) # segments which contain points in the surface of section tcross = numpy.array([ scipy.optimize.brentq(splz, time[i], time[i + 1]) for i in numpy.where(hits)[0] ]) axorb.plot(x[:10000], z[:10000], color=color, lw=0.5, alpha=0.5) axpss.plot(splx(tcross), splx(tcross, 1), 'o', color=color, mew=0, ms=1.5)
def main(args: Optional[list] = None, opts: Optional[argparse.Namespace] = None): """Script Function. Parameters ---------- args : list, optional an optional single argument that holds the sys.argv list, except for the script name (e.g., argv[1:]) opts : Namespace, optional pre-constructed results of parsed args if not None, used ONLY if args is None """ if opts is not None and args is None: pass else: if opts is not None: warnings.warn("Not using `opts` because `args` are given") parser = make_parser() opts = parser.parse_args(args) foutname = DATA + "result_orbits.txt" if not os.path.isfile(foutname): # STEP 1: create Monte Carlo realizations of position and velocity of each cluster, # sampling from their measured uncertainties. # this file should have been produced by run_fit.py tab = np.loadtxt(DATA + "summary.txt", dtype=str) names = tab[:, 0] # 0th column is the cluster name (string) tab = tab[:, 1:].astype(float) # remaining columns are numbers ra0 = tab[:, 0] # coordinates of cluster centers [deg] dec0 = tab[:, 1] dist0 = tab[:, 2] # distance [kpc] vlos0 = tab[:, 3] # line-of-sight velocity [km/s] vlose = tab[:, 4] # its error estimate pmra0 = tab[:, 7] # mean proper motion [mas/yr] pmdec0 = tab[:, 8] pmrae = tab[:, 9] # its uncertainty pmdece = tab[:, 10] pmcorr = tab[:, 11] # correlation coefficient for errors in two PM components vlose = np.maximum( vlose, 2.0) # assumed error of at least 2 km/s on line-of-sight velocity diste = (dist0 * 0.46 * 0.1 ) # assumed error of 0.1 mag in distance modulus # create bootstrap samples np.random.seed(42) # ensure repeatability of random samples nboot = 100 # number of bootstrap samples for each cluster nclust = len(tab) ra = np.repeat(ra0, nboot) dec = np.repeat(dec0, nboot) pmra = np.repeat(pmra0, nboot) pmdec = np.repeat(pmdec0, nboot) for i in range(nclust): # draw PM realizations from a correlated 2d gaussian for each cluster A = np.random.normal(size=nboot) B = (np.random.normal(size=nboot) * (1 - pmcorr[i]**2)**0.5 + A * pmcorr[i]) pmra[i * nboot:(i + 1) * nboot] += pmrae[i] * A pmdec[i * nboot:(i + 1) * nboot] += pmdece[i] * B vlos = np.repeat(vlos0, nboot) + np.hstack( [np.random.normal(scale=e, size=nboot) for e in vlose]) dist = np.repeat(dist0, nboot) + np.hstack( [np.random.normal(scale=e, size=nboot) for e in diste]) # convert coordinates from heliocentric (ra,dec,dist,PM,vlos) to Galactocentric (kpc and km/s) u.kms = u.km / u.s c_sky = coord.ICRS( ra=ra * u.degree, dec=dec * u.degree, pm_ra_cosdec=pmra * u.mas / u.yr, pm_dec=pmdec * u.mas / u.yr, distance=dist * u.kpc, radial_velocity=vlos * u.kms, ) c_gal = c_sky.transform_to( coord.Galactocentric( galcen_distance=8.2 * u.kpc, galcen_v_sun=coord.CartesianDifferential([10.0, 248.0, 7.0] * u.kms), )) pos = np.column_stack( (c_gal.x / u.kpc, c_gal.y / u.kpc, c_gal.z / u.kpc)) vel = np.column_stack( (c_gal.v_x / u.kms, c_gal.v_y / u.kms, c_gal.v_z / u.kms)) # add uncertainties from the solar position and velocity pos[:, 0] += np.random.normal( scale=0.1, size=nboot * nclust) # uncertainty in solar distance from Galactic center vel[:, 0] += np.random.normal(scale=1.0, size=nboot * nclust) # uncertainty in solar velocity vel[:, 1] += np.random.normal(scale=3.0, size=nboot * nclust) vel[:, 2] += np.random.normal(scale=1.0, size=nboot * nclust) pos[:, 0] *= ( -1 ) # revert back to normal orientation of coordinate system (solar position at x=+8.2) vel[:, 0] *= -1 # same for velocity posvel = np.column_stack((pos, vel)).value np.savetxt(DATA + "posvel.txt", posvel, fmt="%.6g") # STEP 2: compute the orbits, min/max galactocentric radii, and actions, for all Monte Carlo samples print(agama.setUnits( length=1, velocity=1, mass=1)) # units: kpc, km/s, Msun; time unit ~ 1 Gyr potential = agama.Potential( DATA + "McMillan17.ini") # MW potential from McMillan(2017) # compute orbits for each realization of initial conditions, # integrated for 100 dynamical times or 20 Gyr (whichever is lower) print( "Computing orbits for %d realizations of cluster initial conditions" % len(posvel)) inttime = np.minimum(20.0, potential.Tcirc(posvel) * 100) orbits = agama.orbit(ic=posvel, potential=potential, time=inttime, trajsize=1000)[:, 1] rmin = np.zeros(len(orbits)) rmax = np.zeros(len(orbits)) for i, o in enumerate(orbits): r = np.sum(o[:, 0:3]**2, axis=1)**0.5 rmin[i] = np.min(r) if len(r) > 0 else np.nan rmax[i] = np.max(r) if len(r) > 0 else np.nan # replace nboot samples rmin/rmax with their median and 68% confidence intervals for each cluster rmin = np.nanpercentile(rmin.reshape(nclust, nboot), [16, 50, 84], axis=1) rmax = np.nanpercentile(rmax.reshape(nclust, nboot), [16, 50, 84], axis=1) # compute actions for the same initial conditions actfinder = agama.ActionFinder(potential) actions = actfinder(posvel) # again compute the median and 68% confidence intervals for each cluster actions = np.nanpercentile(actions.reshape(nclust, nboot, 3), [16, 50, 84], axis=1) # compute the same confidence intervals for the total energy energy = potential.potential( posvel[:, 0:3]) + 0.5 * np.sum(posvel[:, 3:6]**2, axis=1) energy = np.percentile(energy.reshape(nclust, nboot), [16, 50, 84], axis=1) # write the orbit parameters, actions and energy - one line per cluster, with the median and uncertainties fileout = open(foutname, "w") fileout.write( "# Name \t pericenter[kpc] \t apocenter[kpc] \t" + " Jr[kpc*km/s] \t Jz[kpc*km/s] \t Jphi[kpc*km/s] \t Energy[km^2/s^2] \n" ) for i in range(nclust): fileout.write(("%-15s" + "\t%7.2f" * 6 + "\t%7.0f" * 12 + "\n") % ( names[i], rmin[0, i], rmin[1, i], rmin[2, i], rmax[0, i], rmax[1, i], rmax[2, i], actions[0, i, 0], actions[1, i, 0], actions[2, i, 0], actions[0, i, 1], actions[1, i, 1], actions[2, i, 1], actions[0, i, 2], actions[1, i, 2], actions[2, i, 2], energy[0, i], energy[1, i], energy[2, i], )) fileout.close()
def test(gpot, Gpot, Apot, test_hessian=False): ''' gpot is the native gala potential; Gpot is the same one accessed through wrapper; Apot is the equivalent native agama potential ''' print("\nTesting G=%s and A=%s" % (repr(Gpot), repr(Apot))) #0. retrieve dimensional factors for converting the output of agama-related methods # to the potential's unit system (assuming it is identical for both potentials) lu = Gpot.units['length'] pu = Gpot.units['energy'] / Gpot.units['mass'] fu = Gpot.units['length'] / Gpot.units['time']**2 du = Gpot.units['mass'] / Gpot.units['length']**3 #1. test that the values of potential coincide, using both interfaces print("G energy vs potential: %.3g" % numpy.max( abs(Gpot.energy(points.T) / Gpot.potential(points) / pu - 1))) print("A energy vs potential: %.3g" % numpy.max( abs(Apot.energy(points.T) / Apot.potential(points) / pu - 1))) print("G energy vs A energy: %.3g" % numpy.max(abs(Gpot.energy(points.T) / Apot.energy(points.T) - 1))) #2. test the accelerations - these don't exactly match, # because agama evaluates them by finite-differencing if initialized from a "foreign" gala potential print("G acceleration vs force: %.3g" % numpy.max( abs(Gpot.acceleration(points.T).T / Gpot.force(points) / fu - 1))) print("A acceleration vs force: %.3g" % numpy.max( abs(Apot.acceleration(points.T).T / Apot.force(points) / fu - 1))) print( "G gradient vs A gradient: %.3g" % numpy.max(abs(Gpot.gradient(points.T) / Apot.gradient(points.T) - 1))) #3. test the hessian print("G forceDeriv vs A forceDeriv: %.3g" % numpy.max( abs(Gpot.forceDeriv(points)[1] / Apot.forceDeriv(points)[1] - 1))) print("G hessian vs A hessian: %.3g" % numpy.max(abs(Gpot.hessian(points.T) / Apot.hessian(points.T) - 1))) #4. test density - again no exact match since it is computed by finite differences in Gpot print("G density [gala] vs [agama]: %.3g" % numpy.max( abs(Gpot.density(points.T) / Gpot.agamadensity(points) / du - 1))) print("A density [gala] vs [agama]: %.3g" % numpy.max( abs(Apot.density(points.T) / Apot.agamadensity(points) / du - 1))) print("G density vs A density: %.3g" % numpy.max(abs(Gpot.density(points.T) / Apot.density(points.T) - 1))) #5. test orbit integration using both gala and agama routines with either potential # create some initial conditions for orbits: # take the positions and assign velocity to be comparable to circular velocity at each point ic = numpy.hstack((points, numpy.random.normal(size=points.shape) * Apot.circular_velocity(points.T)[:, None])) t0 = time.time() g_orb_g = gpot.integrate_orbit( ic.T, dt=10, n_steps=100, Integrator=gala.integrate.DOPRI853Integrator, Integrator_kwargs=dict(rtol=1e-8, atol=0)) t1 = time.time() g_orb_G = Gpot.integrate_orbit( ic.T, dt=10, n_steps=100, Integrator=gala.integrate.DOPRI853Integrator, Integrator_kwargs=dict(rtol=1e-8, atol=0)) t2 = time.time() g_orb_A = Apot.integrate_orbit( ic.T, dt=10, n_steps=100, Integrator=gala.integrate.DOPRI853Integrator, Integrator_kwargs=dict(rtol=1e-8, atol=0)) t3 = time.time() a_orb_G = numpy.dstack( agama.orbit(potential=Gpot, ic=ic, time=1000, trajsize=101, dtype=float)[:, 1]) t4 = time.time() a_orb_A = numpy.dstack( agama.orbit(potential=Apot, ic=ic, time=1000, trajsize=101, dtype=float)[:, 1]) t5 = time.time() print("gala orbit integration for g (native): %.4g s" % (t1 - t0) + ", G (wrapper): %.4g s" % (t2 - t1) + ", A: %.4g s" % (t3 - t2)) print("agama orbit integration for G: %.4g s" % (t4 - t3) + ", A: %.4g s" % (t5 - t4)) deltaEg = numpy.max(abs(g_orb_G.energy()[-1] / g_orb_G.energy()[0] - 1)) Eainit = Apot.potential( a_orb_A[0, 0:3].T) + 0.5 * numpy.sum(a_orb_A[0, 3:6]**2, axis=0) Eafinal = Apot.potential( a_orb_A[-1, 0:3].T) + 0.5 * numpy.sum(a_orb_A[-1, 3:6]**2, axis=0) deltaEa = numpy.max(abs(Eafinal / Eainit - 1)) # shape of the output is different: for gala, it is 3 x nsteps x norbits; for agama (dstack'ed) - nsteps x 6 x norbits g_orb_G = g_orb_G.xyz.reshape(3, len(g_orb_G.t), len(ic)) g_orb_A = g_orb_A.xyz.reshape(3, len(g_orb_A.t), len(ic)) a_orb_G = numpy.swapaxes(a_orb_G * lu, 0, 1)[0:3] # now the shape is 3 x nsteps x norbits a_orb_A = numpy.swapaxes(a_orb_A * lu, 0, 1)[0:3] maxrad = numpy.max( numpy.sum(a_orb_A**2, axis=0)**0.5, axis=0) # normalization factor for relative deviations in position print("gala orbits G vs A: %.3g" % numpy.max(numpy.sum(abs(g_orb_G - g_orb_A), axis=0) / maxrad)) print("agama orbits G vs A: %.3g" % numpy.max(numpy.sum(abs(a_orb_G - a_orb_A), axis=0) / maxrad)) print("gala vs agama: %.3g" % numpy.max(numpy.sum(abs(g_orb_G - a_orb_G), axis=0) / maxrad)) print("energy error in gala: %.3g, agama: %.3g" % (deltaEg, deltaEa)) # illustrate that the hessian is broken (?) - compute it once for all points, then for each point in a loop if test_hessian: print( "Checking vectorization of hessian for G: the two arrays should be equivalent, but they are not" ) print("Vectorized:\n", Gpot.hessian(points.T)) print("Pointwise:\n", numpy.dstack([Gpot.hessian(point) for point in points])) print( "Checking vectorization of hessian for A: the two arrays should be equivalent" ) print("Vectorized:\n", Apot.hessian(points.T)) print("Pointwise:\n", numpy.dstack([Apot.hessian(point) for point in points]))
def compare(ic, inttime, numsteps): g_orb_obj = galpy.orbit.Orbit([ic[0],ic[3],ic[5],ic[1],ic[4],ic[2]]) times = numpy.linspace(0, inttime, numsteps) dt = time.time() g_orb_obj.integrate(times, g_pot) g_orb = g_orb_obj.getOrbit() print 'Time to integrate orbit in galpy: %s s' % (time.time()-dt) dt = time.time() c_orb_car = agama.orbit(ic=[ic[0],0,ic[1],ic[3],ic[5],ic[4]], pot=w_pot._pot, time=inttime, step=inttime/numsteps) print 'Time to integrate orbit in Agama: %s s' % (time.time()-dt) times_c = numpy.linspace(0,inttime,len(c_orb_car[:,0])) ### make it compatible with galpy's convention (native output is in cartesian coordinates) c_orb = c_orb_car*1.0 c_orb[:,0] = (c_orb_car[:,0]**2+c_orb_car[:,1]**2)**0.5 c_orb[:,3] = c_orb_car[:,2] ### in galpy, this is the only tool that can estimate interfocal distance, ### but it requires the orbit to be computed first delta = estimateDeltaStaeckel(g_orb[:,0], g_orb[:,3], pot=g_pot) print "interfocal distance Delta=",delta ### plot the orbit(s) in R,z plane, along with the prolate spheroidal coordinate grid plt.axes([0.05, 0.55, 0.45, 0.45]) plotCoords(delta, 1.5) plt.plot(g_orb[:,0],g_orb[:,3], 'b', label='galpy') # R,z plt.plot(c_orb[:,0],c_orb[:,3], 'g', label='Agama') # R,z plt.xlabel("R/8kpc") plt.ylabel("z/8kpc") plt.xlim(0, 1.2) plt.ylim(-1,1) plt.legend() ### plot R(t), z(t) plt.axes([0.55, 0.55, 0.45, 0.45]) plt.plot(times, g_orb[:,0], label='R') plt.plot(times, g_orb[:,3], label='z') plt.xlabel("t") plt.ylabel("R,z") plt.legend() plt.xlim(0,50) ### create galpy action/angle finder for the given value of Delta ### note: using c=False in the routine below is much slower but apparently more accurate, ### comparable to the Agama for the same value of delta g_actfinder = galpy.actionAngle.actionAngleStaeckel(pot=g_pot, delta=delta, c=True) ### find the actions for each point of the orbit dt = time.time() g_act = g_actfinder(g_orb[:,0],g_orb[:,1],g_orb[:,2],g_orb[:,3],g_orb[:,4],fixed_quad=True) print 'Time to compute actions in galpy: %s s' % (time.time()-dt) ### use the Agama action routine for the same value of Delta as in galpy dt = time.time() c_act = agama.actions(point=c_orb_car, pot=w_pot._pot, ifd=delta) # explicitly specify interfocal distance print 'Time to compute actions in Agama: %s s' % (time.time()-dt) ### use the Agama action finder (initialized at the beginning) that automatically determines the best value of Delta dt = time.time() a_act = c_actfinder(c_orb_car) # use the interfocal distance estimated by action finder print 'Time to compute actions in Agama: %s s' % (time.time()-dt) ### plot Jr vs Jz plt.axes([0.05, 0.05, 0.45, 0.45]) plt.plot(g_act[0],g_act[2], label='galpy') plt.plot(c_act[:,0],c_act[:,1], label=r'Agama,$\Delta='+str(delta)+'$') plt.plot(a_act[:,0],a_act[:,1], label=r'Agama,$\Delta=$auto') plt.xlabel("$J_r$") plt.ylabel("$J_z$") plt.legend() ### plot Jr(t) and Jz(t) plt.axes([0.55, 0.05, 0.45, 0.45]) plt.plot(times, g_act[0], label='galpy', c='b') plt.plot(times, g_act[2], c='b') plt.plot(times_c, c_act[:,0], label='Agama,$\Delta='+str(delta)+'$', c='g') plt.plot(times_c, c_act[:,1], c='g') plt.plot(times_c, a_act[:,0], label='Agama,$\Delta=$auto', c='r') plt.plot(times_c, a_act[:,1], c='r') plt.text(0, c_act[0,0], '$J_r$', fontsize=16) plt.text(0, c_act[0,1], '$J_z$', fontsize=16) plt.xlabel("t") plt.ylabel("$J_r, J_z$") plt.legend(loc='center right') plt.xlim(0,50) plt.show()
numpy.savetxt('posvel.txt', posvel, fmt='%.6g') # STEP 2: compute the orbits, min/max galactocentric radii, and actions, for all Monte Carlo samples import agama print(agama.setUnits(length=1, velocity=1, mass=1)) # units: kpc, km/s, Msun; time unit ~ 1 Gyr potential = agama.Potential( 'McMillan17.ini') # MW potential from McMillan(2017) # compute orbits for each realization of initial conditions, # integrated for 100 dynamical times or 20 Gyr (whichever is lower) print("Computing orbits for %d realizations of cluster initial conditions" % len(posvel)) inttime = numpy.minimum(20., potential.Tcirc(posvel) * 100) orbits = agama.orbit(ic=posvel, potential=potential, time=inttime, trajsize=1000)[:, 1] rmin = numpy.zeros(len(orbits)) rmax = numpy.zeros(len(orbits)) for i, o in enumerate(orbits): r = numpy.sum(o[:, 0:3]**2, axis=1)**0.5 rmin[i] = numpy.min(r) if len(r) > 0 else numpy.nan rmax[i] = numpy.max(r) if len(r) > 0 else numpy.nan # replace nboot samples rmin/rmax with their median and 68% confidence intervals for each cluster rmin = numpy.nanpercentile(rmin.reshape(nclust, nboot), [16, 50, 84], axis=1) rmax = numpy.nanpercentile(rmax.reshape(nclust, nboot), [16, 50, 84], axis=1) # compute actions for the same initial conditions actfinder = agama.ActionFinder(potential) actions = actfinder(posvel) # again compute the median and 68% confidence intervals for each cluster
# compute some orbits in the axisymmetric and perturbed potentials # (the latter rotating with pattern speed Omega) R0 = 3.0 V0 = ( -R0 * pot_disk.force(R0, 0, 0)[0])**0.5 # circular velocity at the given radius # note that we set the pattern speed to a negative value, so that the spirals are trailing Omega = -0.8 * V0 / R0 ic = [-R0, 0.0, 0.0, 0.0, 0.9 * V0, 0.1 * V0 ] # and make the angular momentum negative as well (i.e.prograde) time = 20 * R0 / V0 nsteps = 200 # trajectories are stored in the rotating frame t, orbit_disk = agama.orbit(potential=pot_disk, ic=ic, time=time, trajsize=nsteps, Omega=Omega) _, orbit_spir = agama.orbit(potential=pot_total, ic=ic, time=time, trajsize=nsteps, Omega=Omega) # convert the trajectories to the inertial frame cosa, sina = numpy.cos(t * Omega), numpy.sin(t * Omega) orbit_disk_x = orbit_disk[:, 0] * cosa - orbit_disk[:, 1] * sina orbit_disk_y = orbit_disk[:, 1] * cosa + orbit_disk[:, 0] * sina orbit_spir_x = orbit_spir[:, 0] * cosa - orbit_spir[:, 1] * sina orbit_spir_y = orbit_spir[:, 1] * cosa + orbit_spir[:, 0] * sina # plot the animated orbit and rotating potential
def cost_function_Zej(x_, y_, z_, vx_, vy_, vz_): #normalize position #normalize flip velocity vx_ = -vx_ vy_ = -vy_ vz_ = -vz_ inttime_back_Myr = _inttime_back_Myr #numpy.sqrt(x_**2 + y_**2 + z_**2)*_R0_norm*2.0/(numpy.sqrt(vx_**2 + vy_**2 + vz_**2)*_V0_norm/1000.) inttime_back_ = inttime_back_Myr * ( numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) #Roughly: 102Myr = 3.14 if _R0_norm=8 and _V0_norm=240 times_c, c_orb_car = agama.orbit(ic=[x_, y_, z_, vx_, vy_, vz_], potential=c_pot, time=inttime_back_, trajsize=5000) #xGC_kpc = _R0 * c_orb_car[:,0] #yGC_kpc = _R0 * c_orb_car[:,1] zGC_kpc_tmp = _R0 * c_orb_car[:, 2] #vxGC_kms = _V0 * c_orb_car[:,3] #vyGC_kms = _V0 * c_orb_car[:,4] #vzGC_kms = _V0 * c_orb_car[:,5] # most recent ejection flag_dc = 0 i_dc = 0 time_dc = 0. z_i = zGC_kpc_tmp[0] z_iplus1 = zGC_kpc_tmp[1] for i in range(len(zGC_kpc_tmp) - 1): z_i = zGC_kpc_tmp[i] z_iplus1 = zGC_kpc_tmp[i + 1] i_dc = i time_dc = times_c[i] if (z_i * z_iplus1 < 0.): flag_dc = 1 break print(times_c[i_dc], z_i) print(times_c[i_dc + 1], z_iplus1) #assert((z_i*z_iplus1<=0.) or (z_i>10.)) inttime_back_ = 1.05 * times_c[i_dc + 1] # backward orbit until the most recent disc crossing times_c, c_orb_car = agama.orbit(ic=[x_, y_, z_, vx_, vy_, vz_], potential=c_pot, time=inttime_back_, trajsize=3000) xGC_kpc = _R0 * c_orb_car[:, 0] yGC_kpc = _R0 * c_orb_car[:, 1] zGC_kpc = _R0 * c_orb_car[:, 2] vxGC_kms = _V0 * c_orb_car[:, 3] vyGC_kms = _V0 * c_orb_car[:, 4] vzGC_kms = _V0 * c_orb_car[:, 5] xGC_kpc_func = scipy.interpolate.interp1d(times_c, xGC_kpc, kind='cubic') yGC_kpc_func = scipy.interpolate.interp1d(times_c, yGC_kpc, kind='cubic') zGC_kpc_func = scipy.interpolate.interp1d(times_c, zGC_kpc, kind='cubic') vxGC_kpc_func = scipy.interpolate.interp1d(times_c, vxGC_kms, kind='cubic') vyGC_kpc_func = scipy.interpolate.interp1d(times_c, vyGC_kms, kind='cubic') vzGC_kpc_func = scipy.interpolate.interp1d(times_c, vzGC_kms, kind='cubic') # distance from ejection location (x_ej,y_ej) distance2_from_disc_kpc_func = lambda x: (zGC_kpc_func(x)**2) result2 = scipy.optimize.minimize_scalar(distance2_from_disc_kpc_func, bounds=(times_c[0], times_c[-1]), method='bounded') #print ('%lf %lf %lf' % (muellstar_test, mubee_test, rGC_kpc_func_2(result2.x))) x_ej = xGC_kpc_func(result2.x) y_ej = yGC_kpc_func(result2.x) z_ej = zGC_kpc_func(result2.x) vx_ej = -vxGC_kpc_func(result2.x) vy_ej = -vyGC_kpc_func(result2.x) vz_ej = -vzGC_kpc_func(result2.x) flightTime_Myr = (result2.x) / (numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) return x_ej, y_ej, z_ej, vx_ej, vy_ej, vz_ej, flightTime_Myr
def calculate_orbital_shape_PAST(xGC_norm, yGC_norm, zGC_norm, vxGC_norm, vyGC_norm, vzGC_norm, inttime, numsteps): # agama convention # already normalized position x_agama = xGC_norm y_agama = yGC_norm z_agama = zGC_norm # FLIP already normalized velocity vx_agama = -vxGC_norm vy_agama = -vyGC_norm vz_agama = -vzGC_norm inttime_back_Myr = _inttime_back_Myr inttime_back_ = inttime_back_Myr * ( numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) #Roughly: 102Myr = 3.14 if _R0_norm=8 and _V0_norm=240 inttime = inttime_back_ numsteps = 3000 times = numpy.linspace(0, inttime, numsteps) times_c, c_orb_car = agama.orbit( ic=[x_agama, y_agama, z_agama, vx_agama, vy_agama, vz_agama], potential=potentialTotal_local, time=inttime, trajsize=numsteps) #print(c_orb_car[:,0]) x = c_orb_car[:, 0] y = c_orb_car[:, 1] z = c_orb_car[:, 2] vx = c_orb_car[:, 3] vy = c_orb_car[:, 4] vz = c_orb_car[:, 5] R = numpy.sqrt(x**2 + y**2) r = numpy.sqrt(x**2 + y**2 + z**2) out_filename = 'timeMyr_x_y_z_vx_vy_vz_vR_vTHETA_vPHI__Orbit__AsObserved_LAMOSThvs%d.txt' % ( LAMOSTHVSid) outfile = open(out_filename, 'a') outfile.write( '#(orbit in the past)\n#time_Myr x y z vx vy vz vR vTHETA vPHI [all normalized by (x,v)=(1 kpc, 1 km/s)]\n' ) for i in range(len(x)): #flip the time to get the correct time Time_Myr = (-1.) * times_c[i] / (numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) #position x_ = x[i] * _R0 y_ = y[i] * _R0 z_ = z[i] * _R0 #re-flip the velocity to get the velocity in the past vx_ = -vx[i] * _V0 vy_ = -vy[i] * _V0 vz_ = -vz[i] * _V0 R_, phi_, vR_, vTHETA_, vPHI_ = cartesian_2_cylindrical( x_, y_, z_, vx_, vy_, vz_) printline = '%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n' % ( Time_Myr, x_, y_, z_, vx_, vy_, vz_, vR_, vTHETA_, vPHI_) outfile.write(printline) return None
def compare(ic, inttime, numsteps): times = numpy.linspace(0, inttime, numsteps) ### integrate the orbit in galpy using MWPotential2014 from galpy g_orb_obj = galpy.orbit.Orbit([ic[0], ic[3], ic[5], ic[1], ic[4], ic[2]]) dt = time.time() g_orb_obj.integrate(times, g_pot) g_orb = g_orb_obj.getOrbit() print('Time to integrate orbit in galpy: %.4g s' % (time.time() - dt)) ### integrate the orbit with the galpy routine, but using Agama potential instead ### (much slower because of repeated transfer of control between C++ and Python dt = time.time() g_orb_obj.integrate(times[:numsteps // 10], a_pot) a_orb = g_orb_obj.getOrbit() print( 'Time to integrate 1/10th of the orbit in galpy using Agama potential: %.4g s' % (time.time() - dt)) ### integrate the same orbit (note different calling conventions - cartesian coordinates as input) ### using both the orbit integration routine and the potential from Agama - much faster dt = time.time() times_c, c_orb_car = agama.orbit(ic=[ic[0],0,ic[1],ic[3],ic[5],ic[4]], \ potential=a_pot, time=inttime, trajsize=numsteps) print('Time to integrate orbit in Agama: %.4g s' % (time.time() - dt)) ### make it compatible with galpy's convention (native output is in cartesian coordinates) c_orb = c_orb_car * 1.0 c_orb[:, 0] = (c_orb_car[:, 0]**2 + c_orb_car[:, 1]**2)**0.5 c_orb[:, 3] = c_orb_car[:, 2] ### in galpy, this is the only tool that can estimate focal distance, ### but it requires the orbit to be computed first delta = float( galpy.actionAngle.estimateDeltaStaeckel(g_pot, g_orb[:, 0], g_orb[:, 3])) print('Focal distance estimated from the entire trajectory: Delta=%.4g' % delta) ### plot the orbit(s) in R,z plane, along with the prolate spheroidal coordinate grid plt.figure(figsize=(12, 8)) plt.axes([0.04, 0.54, 0.45, 0.45]) plotCoords(delta, 1.5) plt.plot(g_orb[:, 0], g_orb[:, 3], 'b', label='galpy') # R,z plt.plot(c_orb[:, 0], c_orb[:, 3], 'g', label='Agama') plt.plot(a_orb[:, 0], a_orb[:, 3], 'r', label='galpy using Agama potential') plt.xlabel("R/8kpc") plt.ylabel("z/8kpc") plt.xlim(0, 1.2) plt.ylim(-1, 1) plt.legend(loc='lower left', frameon=False) ### create galpy action/angle finder for the given value of Delta ### note: using c=False in the routine below is much slower but apparently more accurate, ### comparable to the Agama for the same value of delta g_actfinder = galpy.actionAngle.actionAngleStaeckel(pot=g_pot, delta=delta, c=True) ### find the actions for each point of the orbit using galpy action finder dt = time.time() g_act = g_actfinder(g_orb[:, 0], g_orb[:, 1], g_orb[:, 2], g_orb[:, 3], g_orb[:, 4], fixed_quad=True) print('Time to compute actions in galpy: %.4g s' % (time.time() - dt)) print('Jr = %.6g +- %.4g, Jz = %.6g +- %.4g' % \ (numpy.mean(g_act[0]), numpy.std(g_act[0]), numpy.mean(g_act[2]), numpy.std(g_act[2]))) ### use the Agama action routine for the same value of Delta as in galpy - ### the result is almost identical but computed much faster dt = time.time() c_act = agama.actions(point=c_orb_car, potential=a_pot, fd=delta) # explicitly specify focal distance print( 'Time to compute actions in Agama using Galpy-estimated focal distance: %.4g s' % (time.time() - dt)) print('Jr = %.6g +- %.4g, Jz = %.6g +- %.4g' % \ (numpy.mean(c_act[:,0]), numpy.std(c_act[:,0]), numpy.mean(c_act[:,1]), numpy.std(c_act[:,1]))) ### use the Agama action finder (initialized at the beginning) that automatically determines ### the best value of Delta (same computational cost as the previous one) dt = time.time() a_act = a_actfinder( c_orb_car) # use the focal distance estimated by action finder print( 'Time to compute actions in Agama using pre-initialized focal distance: %.4g s' % (time.time() - dt)) print('Jr = %.6g +- %.4g, Jz = %.6g +- %.4g' % \ (numpy.mean(a_act[:,0]), numpy.std(a_act[:,0]), numpy.mean(a_act[:,1]), numpy.std(a_act[:,1]))) ### use the interpolated Agama action finder (initialized at the beginning) - less accurate but faster dt = time.time() i_act = i_actfinder(c_orb_car) print( 'Time to compute actions in Agama with interpolated action finder: %.4g s' % (time.time() - dt)) print('Jr = %.6g +- %.4g, Jz = %.6g +- %.4g' % \ (numpy.mean(i_act[:,0]), numpy.std(i_act[:,0]), numpy.mean(i_act[:,1]), numpy.std(i_act[:,1]))) ### plot Jr vs Jz plt.axes([0.54, 0.54, 0.45, 0.45]) plt.plot(g_act[0], g_act[2], c='b', label='galpy') plt.plot(c_act[:, 0], c_act[:, 1], c='g', label=r'Agama,$\Delta=%.4f$' % delta) plt.plot(a_act[:, 0], a_act[:, 1], c='r', label=r'Agama,$\Delta=$auto') plt.plot(i_act[:, 0], i_act[:, 1], c='c', label=r'Agama,interpolated') plt.xlabel("$J_r$") plt.ylabel("$J_z$") plt.legend(loc='lower left', frameon=False) ### plot Jr(t) and Jz(t) plt.axes([0.04, 0.04, 0.95, 0.45]) plt.plot(times, g_act[0], c='b', label='galpy') plt.plot(times, g_act[2], c='b') plt.plot(times_c, c_act[:, 0], c='g', label='Agama,$\Delta=%.4f$' % delta) plt.plot(times_c, c_act[:, 1], c='g') plt.plot(times_c, a_act[:, 0], c='r', label='Agama,$\Delta=$auto') plt.plot(times_c, a_act[:, 1], c='r') plt.plot(times_c, i_act[:, 0], c='c', label='Agama,interpolated') plt.plot(times_c, i_act[:, 1], c='c') plt.text(0, c_act[0, 0], '$J_r$', fontsize=16) plt.text(0, c_act[0, 1], '$J_z$', fontsize=16) plt.xlabel("t") plt.ylabel("$J_r, J_z$") plt.legend(loc='center right', ncol=2, frameon=False) #plt.ylim(0.14,0.25) plt.xlim(0, 50) plt.show()
for i in range(len(gridr)): print("%s: mass= %g" % (target[i], rhs[i])) # construct initial conditions for the orbit library: # use the anisotropic Jeans eqs to set the (approximate) shape of the velocity ellipsoid and the mean v_phi; beta = 0.0 # velocity anisotropy in R/z plane: >0 - sigma_R>sigma_z, <0 - reverse. kappa = 0.8 # sets the amount of rotation v_phi vs. dispersion sigma_phi; 1 is rather fast rotation, 0 - no rot. initcond, _ = potstars.sample(10000, potential=pot, beta=beta, kappa=kappa) # integration time is 100 orbital periods inttimes = 100 * pot.Tcirc(initcond) # integrate all orbits, storing the recorded density data and trajectories data, trajs = agama.orbit(potential=pot, ic=initcond, time=inttimes, trajsize=100, targets=target) # assemble the matrix equation which contains two blocks: # total mass, discretized density # a single value for the total mass constraint, each orbit contributes 1 to it mass = potstars.totalMass() data0 = numpy.ones((len(initcond), 1)) # solve the matrix equation for orbit weights weights = agama.solveOpt(matrix=(data0.T, data.T), rhs=([mass], rhs), rpenl=([numpy.inf], numpy.ones(len(rhs)) * numpy.inf), xpenq=numpy.ones(len(initcond)))
ax[0].plot(r, (-r * pot_axi[1].force(xyz)[:, 0])**0.5, 'y', label='halo') ax[0].plot(r, (-r * pot_axi.force(xyz)[:, 0])**0.5, 'r', label='total') ax[0].legend(loc='lower right', frameon=False) ax[0].set_xlabel('radius [kpc]') ax[0].set_ylabel('circular velocity [km/s]') # integrate and show a few orbits numorbits = 10 numpy.random.seed(42) ic = numpy.random.normal(size=(numorbits, 6)) * numpy.array( [2.0, 0.0, 0.4, 50., 40., 30.]) ic[:, 0] += -6. ic[:, 4] += 220 orbits = agama.orbit(potential=pot, ic=ic, time=10., trajsize=1000, Omega=-39.0)[:, 1] bar_angle = -25.0 * numpy.pi / 180 # orientation of the bar w.r.t. the Sun sina, cosa = numpy.sin(bar_angle), numpy.cos(bar_angle) rmax = 10.0 # plotting range cmap = plt.get_cmap('mist') for i, o in enumerate(orbits): ax[1].plot(o[:, 0] * cosa - o[:, 1] * sina, o[:, 0] * sina + o[:, 1] * cosa, color=cmap(i * 1.0 / numorbits), lw=0.5) ax[1].plot(-8.2, 0.0, 'ko', ms=5) # Solar position ax[1].text(-8.0, 0.0, 'Sun') ax[1].set_xlabel('x [kpc]') ax[1].set_ylabel('y [kpc]')
return numpy.column_stack( (o[:, 0] * numpy.cos(om * t) + o[:, 1] * numpy.sin(om * t), o[:, 1] * numpy.cos(om * t) - o[:, 0] * numpy.sin(om * t), o[:, 2], o[:, 3] * numpy.cos(om * t) + o[:, 4] * numpy.sin(om * t), o[:, 4] * numpy.cos(om * t) - o[:, 3] * numpy.sin(om * t), o[:, 5])) # variant 1: set up two fixed point masses (Sun and super-Earth of mass 0.001 Msun), # and integrate the test-particle orbit in the rotating frame, in which Sun&Earth are stationary p1 = agama.Potential( dict(type='plummer', mass=0.999, scaleradius=0, center="0.001,0,0"), # Sun dict(type='plummer', mass=0.001, scaleradius=0, center="-.999,0,0")) # Earth (very massive one) t1, o1 = agama.orbit(potential=p1, ic=[r0, 0, 0, 0, v0, 0], time=tmax, trajsize=501, Omega=om) E1 = p1.potential(o1[:, 0:3]) + 0.5 * numpy.sum( o1[:, 3:6]**2, axis=1) - (o1[:, 0] * o1[:, 4] - o1[:, 1] * o1[:, 3]) * om ax[0].plot(o1[:, 0], o1[:, 1]) ax[1].plot(t1 * tu, o1[:, 0], c='b') ax[1].plot(t1 * tu, o1[:, 1], c='b', dashes=[3, 2]) ax[2].plot(t1 * tu, E1, label='Two fixed point masses in rotating frame') # variant 2: same setup, but now make the two point masses move on circular orbits, # and integrate the orbit of the test particle in the inertial frame tt = numpy.linspace(0, tmax, 2001) numpy.savetxt( 'tmp_center1', numpy.column_stack(
def compare(ic, inttime, numsteps): times = numpy.linspace(0, inttime, numsteps) times1 = times[:numsteps // 10] # compute only 1/10th of the orbit to save time in galpy ### integrate the orbit in galpy using the native MWPotential2014 from galpy g_orb_obj = galpy.orbit.Orbit(ic) dt = time.time() g_orb_obj.integrate(times, g_pot_native) g_orb_g_native = g_orb_obj.getOrbit() print( 'Time to integrate the orbit in galpy, using galpy-native potential [1]: %.4g s' % (time.time() - dt)) ### integrate the orbit again with the galpy routine, but now using the chimera potential ### representing a galpy-native underlying potential. ### since galpy has no idea that this potential has a C implementation, it switches to a slower ### pure-Python integration algorithm, so to save time, we compute only 1/10th of the orbit dt = time.time() g_orb_obj.integrate(times1, g_pot_hybrid) g_orb_g_hybrid = g_orb_obj.getOrbit() print( 'Time to integrate 1/10th of the orbit in galpy, using galpy-hybrid potential [2]: %.4g s' % (time.time() - dt)) ### integrate the orbit with the galpy routine, but using the chimera potential ### representing an agama-native underlying potential instead ### (also much slower because of repeated transfer of control between C++ and Python) dt = time.time() g_orb_obj.integrate(times1, a_pot_hybrid) g_orb_a_hybrid = g_orb_obj.getOrbit() print( 'Time to integrate 1/10th of the orbit in galpy, using agama-hybrid potential [3]: %.4g s' % (time.time() - dt)) ### integrate the orbit with the agama routine, using the galpy-native potential through the chimera ### (note different calling conventions and the use of cartesian coordinates) dt = time.time() a_orb_g_hybrid = agama.orbit(potential=g_pot_hybrid, time=inttime, trajsize=numsteps, ic=toCar(ic))[1] print( 'Time to integrate the orbit in agama, using galpy-hybrid potential [4]: %.4g s' % (time.time() - dt)) ### integrate the orbit in a native agama potential approximation constructed from the galpy potential dt = time.time() a_orb_g_approx = agama.orbit(potential=g_pot_approx, time=inttime, trajsize=numsteps, ic=toCar(ic))[1] print( 'Time to integrate the orbit in agama, using galpy-approx potential [5]: %.4g s' % (time.time() - dt)) ### using both the orbit integration routine and the native potential from agama - much faster dt = time.time() a_orb_a_native = agama.orbit(potential=a_pot_native, time=inttime, trajsize=numsteps, ic=toCar(ic))[1] print( 'Time to integrate the orbit in agama, using agama-native potential [6]: %.4g s' % (time.time() - dt)) ### the same but with the chimera potential representing an agama-native potential ### (should be identical to the above, since in both cases the same underlying C++ object is used) dt = time.time() a_orb_a_hybrid = agama.orbit(potential=a_pot_hybrid, time=inttime, trajsize=numsteps, ic=toCar(ic))[1] print( 'Time to integrate the orbit in agama, using agama-hybrid potential [7]: %.4g s' % (time.time() - dt)) ### compare the differences between the orbits computed in different ways ### (both the potentials and integration routines are not exactly equivalent); ### use only common initial segment (1/10th of the orbit) for comparison print('Differences between orbits: ' + '[1]-[2]=%g, ' % numpy.max( numpy.abs(toCar(g_orb_g_native[:len(times1)]) - toCar(g_orb_g_hybrid)) ) + '[1]-[3]=%g, ' % numpy.max( numpy.abs(toCar(g_orb_g_native[:len(times1)]) - toCar(g_orb_a_hybrid))) + '[1]-[4]=%g, ' % numpy.max( numpy.abs(toCar(g_orb_g_native) - a_orb_g_hybrid)[:len(times1)]) + '[1]-[5]=%g, ' % numpy.max( numpy.abs(toCar(g_orb_g_native) - a_orb_g_approx)[:len(times1)]) + '[1]-[6]=%g, ' % numpy.max( numpy.abs(toCar(g_orb_g_native) - a_orb_a_native)[:len(times1)]) + '[6]-[4]=%g, ' % numpy.max(numpy.abs(a_orb_a_native - a_orb_g_hybrid)[:len(times1)]) + '[6]-[7]=%g' % numpy.max(numpy.abs(a_orb_a_native - a_orb_a_hybrid)[:len(times1)]) ) # should be zero ### convert the orbits to the same galpy coordinate convention gg_orb = g_orb_g_native # it's already in this convention ga_orb = g_orb_a_hybrid ag_orb = toCyl(a_orb_g_hybrid) aa_orb = toCyl(a_orb_a_native) ### in galpy, this is the only tool that can estimate focal distance, ### but it requires the orbit to be computed first delta = float( galpy.actionAngle.estimateDeltaStaeckel(g_pot_hybrid, gg_orb[:, 0], gg_orb[:, 3])) print('Focal distance estimated from the entire trajectory: Delta=%.4g' % delta) ### plot the orbit(s) in R,z plane, along with the prolate spheroidal coordinate grid plt.figure(figsize=(12, 8)) plt.axes([0.06, 0.56, 0.43, 0.43]) plotCoords(delta, 1.5) plt.plot(gg_orb[:, 0], gg_orb[:, 3], 'b', label='galpy native') # R,z plt.plot(aa_orb[:, 0], aa_orb[:, 3], 'g', label='agama native', dashes=[4, 2]) plt.plot(ag_orb[:, 0], ag_orb[:, 3], 'y', label='agama using galpy potential', dashes=[1, 1]) plt.plot(ga_orb[:, 0], ga_orb[:, 3], 'r', label='galpy using agama potential') plt.xlabel("R/8kpc") plt.ylabel("z/8kpc") plt.xlim(0, 1.2) plt.ylim(-1, 1) plt.legend(loc='lower left', ncol=2) ### create galpy action/angle finder for the given value of Delta ### note: using c=False in the routine below is much slower but apparently more accurate, ### comparable to the agama for the same value of delta g_actfinder = galpy.actionAngle.actionAngleStaeckel(pot=g_pot_native, delta=delta, c=True) ### find the actions for each point of the orbit using galpy action finder dt = time.time() g_act = g_actfinder(gg_orb[:, 0], gg_orb[:, 1], gg_orb[:, 2], gg_orb[:, 3], gg_orb[:, 4], fixed_quad=True) print('Time to compute actions in galpy: %.4g s' % (time.time() - dt)) print('Jr = %.6g +- %.4g, Jz = %.6g +- %.4g' % \ (numpy.mean(g_act[0]), numpy.std(g_act[0]), numpy.mean(g_act[2]), numpy.std(g_act[2]))) ### use the agama action routine for the same value of Delta as in galpy (explicity specify focal distance): ### the result is almost identical but computed much faster dt = time.time() c_act = agama.actions(point=a_orb_a_hybrid, potential=a_pot_hybrid, fd=delta) print( 'Time to compute actions in agama using galpy-estimated focal distance: %.4g s' % (time.time() - dt)) print('Jr = %.6g +- %.4g, Jz = %.6g +- %.4g' % \ (numpy.mean(c_act[:,0]), numpy.std(c_act[:,0]), numpy.mean(c_act[:,1]), numpy.std(c_act[:,1]))) ### use the agama action finder (initialized at the beginning) that automatically determines ### the best value of Delta (same computational cost as the previous one) dt = time.time() a_act = a_actfinder( a_orb_a_hybrid) # use the focal distance estimated by action finder print( 'Time to compute actions in agama using pre-initialized focal distance: %.4g s' % (time.time() - dt)) print('Jr = %.6g +- %.4g, Jz = %.6g +- %.4g' % \ (numpy.mean(a_act[:,0]), numpy.std(a_act[:,0]), numpy.mean(a_act[:,1]), numpy.std(a_act[:,1]))) ### use the interpolated agama action finder (initialized at the beginning) - less accurate but faster dt = time.time() i_act = i_actfinder(a_orb_a_hybrid) print( 'Time to compute actions in agama with interpolated action finder: %.4g s' % (time.time() - dt)) print('Jr = %.6g +- %.4g, Jz = %.6g +- %.4g' % \ (numpy.mean(i_act[:,0]), numpy.std(i_act[:,0]), numpy.mean(i_act[:,1]), numpy.std(i_act[:,1]))) ### plot Jr vs Jz plt.axes([0.55, 0.56, 0.43, 0.43]) plt.plot(g_act[0], g_act[2], c='b', label='galpy') plt.plot(c_act[:, 0], c_act[:, 1], c='g', label=r'agama, $\Delta=%.4f$' % delta, dashes=[4, 2]) plt.plot(a_act[:, 0], a_act[:, 1], c='r', label=r'agama, $\Delta=$auto') plt.plot(i_act[:, 0], i_act[:, 1], c='c', label=r'agama, interpolated') plt.xlabel("$J_r$") plt.ylabel("$J_z$") plt.legend(loc='lower left', frameon=False) ### plot Jr(t) and Jz(t) plt.axes([0.06, 0.06, 0.92, 0.43]) plt.plot(times, g_act[0], c='b', label='galpy') plt.plot(times, g_act[2], c='b') plt.plot(times, c_act[:, 0], c='g', label='agama, $\Delta=%.4f$' % delta, dashes=[4, 2]) plt.plot(times, c_act[:, 1], c='g', dashes=[4, 2]) plt.plot(times, a_act[:, 0], c='r', label='agama, $\Delta=$auto') plt.plot(times, a_act[:, 1], c='r') plt.plot(times, i_act[:, 0], c='c', label='agama, interpolated') plt.plot(times, i_act[:, 1], c='c') plt.text(0, c_act[0, 0], '$J_r$', fontsize=16) plt.text(0, c_act[0, 1], '$J_z$', fontsize=16) plt.xlabel("t") plt.ylabel("$J_r, J_z$") plt.legend(loc='center right', ncol=2, frameon=False) #plt.ylim(0.14,0.25) plt.xlim(0, 50) plt.show()
ax = plt.subplots(2, 2, figsize=(15, 10))[1] pot = agama.Potential(type='Plummer', mass=10, axisratioz=.6) act = [1.0, 2.0, 3.0] # Jr, Jz, Jphi - some fiducial values am = agama.ActionMapper(pot, act) # J,theta -> x,v (Torus), with the given actions af = agama.ActionFinder(pot) # x,v -> J,theta (Staeckel fudge) t = numpy.linspace(0, 100, 1001) # construct the orbit using Torus xv_torus = am( numpy.column_stack((am.Omegar * t, am.Omegaz * t, am.Omegaphi * t))) ax[0, 0].plot((xv_torus[:, 0]**2 + xv_torus[:, 1]**2)**0.5, xv_torus[:, 2], label='torus') # construct the orbit by numerically integrating the equations of motion _, xv_orbit = agama.orbit(ic=xv_torus[0], potential=pot, time=t[-1], trajsize=len(t)) ax[0, 0].plot((xv_orbit[:, 0]**2 + xv_orbit[:, 1]**2)**0.5, xv_orbit[:, 2], label='orbit') # compute actions for the torus orbit using Staeckel approximation J, theta, Omega = af(xv_torus, angles=True) ax[0, 1].plot(t, J, label='J,torus') ax[1, 1].plot(t, Omega, label='Omega,torus') ax[1, 0].plot(t, theta, label='theta,torus') # same for the actual orbit J, theta, Omega = af(xv_orbit, angles=True) ax[0, 1].plot(t, J, label='J,orbit') ax[1, 1].plot(t, Omega, label='Omega,orbit') ax[1, 0].plot(t, theta, label='theta,orbit') ax[0, 0].legend()
tar_shell = agama.Target(type='KinemShell', gridr=gridr, degree=1) degree = 2 # B-spline degree for LOSVD representation (2 or 3 are strongly recommended) tar_losvd = agama.Target(type='LOSVD', degree=degree, apertures=poly, gridx=gridx, gridv=gridv, symmetry='s') # generate N-body samples from the model, # and integrate orbits with (some of) these initial conditions xv, mass = gm.sample(1000000) ic = xv[:10000] # use only a subset of ICs, to save time mat_dens, mat_shell, mat_losvd = agama.orbit( potential=pot, ic=ic, time=100 * pot.Tcirc(ic), targets=[tar_dens, tar_shell, tar_losvd]) # as the IC were drawn from the actual DF of the model, # we expect that all orbits have the same weight in the model orbitweight = pot.totalMass() / len(ic) # now apply the targets to several kinds of objects: print("Applying Targets to various objects (takes time)...") # 1) collection of orbits, summing up equally-weighted contributions of all orbits dens_orb = numpy.sum(mat_dens, axis=0) * orbitweight shell_orb = numpy.sum(mat_shell, axis=0) * orbitweight losvd_orb = numpy.sum(mat_losvd, axis=0) * orbitweight # 2) the entire model (df + potential) dens_df = tar_dens(gm)
def calculate_orbital_shape(xGC_norm, yGC_norm, zGC_norm, vxGC_norm, vyGC_norm, vzGC_norm, inttime, numsteps): # agama convention x_agama = xGC_norm y_agama = yGC_norm z_agama = zGC_norm vx_agama = vxGC_norm vy_agama = vyGC_norm vz_agama = vzGC_norm R_agama = numpy.sqrt(x_agama**2 + y_agama**2) vR_agama = (x_agama * vx_agama + y_agama * vy_agama) / R_agama vT_agama = -(x_agama * vy_agama - y_agama * vx_agama) / R_agama phi_agama = numpy.arctan2(y_agama, x_agama) inttime_back_Myr = _inttime_back_Myr #numpy.sqrt(x_**2 + y_**2 + z_**2)*_R0_norm*2.0/(numpy.sqrt(vx_**2 + vy_**2 + vz_**2)*_V0_norm/1000.) inttime_back_ = inttime_back_Myr * ( numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) #Roughly: 102Myr = 3.14 if _R0_norm=8 and _V0_norm=240 numsteps = 3000 times = numpy.linspace(0, inttime, numsteps) times_c, c_orb_car = agama.orbit( ic=[x_agama, y_agama, z_agama, vx_agama, vy_agama, vz_agama], potential=potentialTotal_local, time=inttime, trajsize=numsteps) #print(c_orb_car[:,0]) x = c_orb_car[:, 0] y = c_orb_car[:, 1] z = c_orb_car[:, 2] vx = c_orb_car[:, 3] vy = c_orb_car[:, 4] vz = c_orb_car[:, 5] R = numpy.sqrt(x**2 + y**2) r = numpy.sqrt(x**2 + y**2 + z**2) out_filename = 'x_y_z_vx_vy_vz_vR_vTHETA_vPHI__Orbit__AsObserved_LAMOSThvs%d.txt' % ( LAMOSTHVSid) outfile = open(out_filename, 'a') outfile.write( '# x y z vx vy vz vR vTHETA vPHI [all normalized by (x,v)=(1 kpc, 1 km/s)]\n' ) for i in range(len(x)): x_ = x[i] * _R0 y_ = y[i] * _R0 z_ = z[i] * _R0 vx_ = vx[i] * _V0 vy_ = vy[i] * _V0 vz_ = vz[i] * _V0 R_, phi_, vR_, vTHETA_, vPHI_ = cartesian_2_cylindrical( x_, y_, z_, vx_, vy_, vz_) printline = '%lf %lf %lf %lf %lf %lf %lf %lf %lf\n' % ( x_, y_, z_, vx_, vy_, vz_, vR_, vTHETA_, vPHI_) outfile.write(printline) return None
def compare(ic, inttime, numsteps): g_orb_obj = galpy.orbit.Orbit([ic[0],ic[3],ic[5],ic[1],ic[4],ic[2]]) times = numpy.linspace(0, inttime, numsteps) dt = time.time() g_orb_obj.integrate(times, g_pot) g_orb = g_orb_obj.getOrbit() print 'Time to integrate orbit in galpy: %s s' % (time.time()-dt) dt = time.time() times_c, c_orb_car = agama.orbit(ic=[ic[0],0,ic[1],ic[3],ic[5],ic[4]], potential=w_pot._pot, time=inttime, trajsize=numsteps) print 'Time to integrate orbit in Agama: %s s' % (time.time()-dt) ### make it compatible with galpy's convention (native output is in cartesian coordinates) c_orb = c_orb_car*1.0 c_orb[:,0] = (c_orb_car[:,0]**2+c_orb_car[:,1]**2)**0.5 c_orb[:,3] = c_orb_car[:,2] ### in galpy, this is the only tool that can estimate focal distance, ### but it requires the orbit to be computed first delta = estimateDeltaStaeckel(g_pot, g_orb[:,0], g_orb[:,3]) print "interfocal distance Delta=",delta ### plot the orbit(s) in R,z plane, along with the prolate spheroidal coordinate grid plt.axes([0.05, 0.55, 0.45, 0.45]) plotCoords(delta, 1.5) plt.plot(g_orb[:,0],g_orb[:,3], 'b', label='galpy') # R,z plt.plot(c_orb[:,0],c_orb[:,3], 'g', label='Agama') # R,z plt.xlabel("R/8kpc") plt.ylabel("z/8kpc") plt.xlim(0, 1.2) plt.ylim(-1,1) plt.legend() ### plot R(t), z(t) plt.axes([0.55, 0.55, 0.45, 0.45]) plt.plot(times, g_orb[:,0], label='R') plt.plot(times, g_orb[:,3], label='z') plt.xlabel("t") plt.ylabel("R,z") plt.legend() plt.xlim(0,50) ### create galpy action/angle finder for the given value of Delta ### note: using c=False in the routine below is much slower but apparently more accurate, ### comparable to the Agama for the same value of delta g_actfinder = galpy.actionAngle.actionAngleStaeckel(pot=g_pot, delta=delta, c=True) ### find the actions for each point of the orbit dt = time.time() g_act = g_actfinder(g_orb[:,0],g_orb[:,1],g_orb[:,2],g_orb[:,3],g_orb[:,4],fixed_quad=True) print 'Time to compute actions in galpy: %s s' % (time.time()-dt) ### use the Agama action routine for the same value of Delta as in galpy dt = time.time() c_act = agama.actions(point=c_orb_car, potential=w_pot._pot, fd=delta) # explicitly specify focal distance print 'Time to compute actions in Agama using Galpy-estimated focal distance: %s s' % (time.time()-dt) ### use the Agama action finder (initialized at the beginning) that automatically determines the best value of Delta dt = time.time() a_act = c_actfinder(c_orb_car) # use the focal distance estimated by action finder print 'Time to compute actions in Agama using pre-initialized focal distance: %s s' % (time.time()-dt) ### use the interpolated Agama action finder (initialized at the beginning) - less accurate but faster dt = time.time() i_act = i_actfinder(c_orb_car) print 'Time to compute actions in Agama with interpolated action finder: %s s' % (time.time()-dt) ### plot Jr vs Jz plt.axes([0.05, 0.05, 0.45, 0.45]) plt.plot(g_act[0],g_act[2], label='galpy') plt.plot(c_act[:,0],c_act[:,1], label=r'Agama,$\Delta='+str(delta)+'$') plt.plot(a_act[:,0],a_act[:,1], label=r'Agama,$\Delta=$auto') plt.plot(i_act[:,0],i_act[:,1], label=r'Agama,interpolated') plt.xlabel("$J_r$") plt.ylabel("$J_z$") plt.legend(loc='lower left') ### plot Jr(t) and Jz(t) plt.axes([0.55, 0.05, 0.45, 0.45]) plt.plot(times, g_act[0], label='galpy', c='b') plt.plot(times, g_act[2], c='b') plt.plot(times_c, c_act[:,0], label='Agama,$\Delta='+str(delta)+'$', c='g') plt.plot(times_c, c_act[:,1], c='g') plt.plot(times_c, a_act[:,0], label='Agama,$\Delta=$auto', c='r') plt.plot(times_c, a_act[:,1], c='r') plt.plot(times_c, i_act[:,0], label='Agama,interpolated', c='c') plt.plot(times_c, i_act[:,1], c='c') plt.text(0, c_act[0,0], '$J_r$', fontsize=16) plt.text(0, c_act[0,1], '$J_z$', fontsize=16) plt.xlabel("t") plt.ylabel("$J_r, J_z$") plt.legend(loc='center right') plt.ylim(0.14,0.25) plt.xlim(0,50) plt.show()
def calculate_star_and_LMC_orbits_PAST(xGC_norm, yGC_norm, zGC_norm, vxGC_norm, vyGC_norm, vzGC_norm): #, inttime, numsteps): # agama convention # already normalized position x_agama = xGC_norm y_agama = yGC_norm z_agama = zGC_norm # FLIP already normalized velocity vx_agama = -vxGC_norm vy_agama = -vyGC_norm vz_agama = -vzGC_norm inttime_back_Myr = _inttime_back_Myr inttime_back_ = inttime_back_Myr * ( numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) #Roughly: 102Myr = 3.14 if _R0_norm=8 and _V0_norm=240 inttime = inttime_back_ numsteps = 3000 times = numpy.linspace(0, inttime, numsteps) times_c, c_orb_car = agama.orbit( ic=[x_agama, y_agama, z_agama, vx_agama, vy_agama, vz_agama], potential=potentialTotal_local, time=inttime, trajsize=numsteps) #print(c_orb_car[:,0]) x = c_orb_car[:, 0] y = c_orb_car[:, 1] z = c_orb_car[:, 2] vx = c_orb_car[:, 3] vy = c_orb_car[:, 4] vz = c_orb_car[:, 5] R = numpy.sqrt(x**2 + y**2) r = numpy.sqrt(x**2 + y**2 + z**2) #LMC position in the MW-center coordinate system. xLMC_norm, yLMC_norm, zLMC_norm, vxLMC_norm, vyLMC_norm, vzLMC_norm = get_LMC_6D( ) # already normalized position xLMC_agama = xLMC_norm yLMC_agama = yLMC_norm zLMC_agama = zLMC_norm # FLIP already normalized velocity vxLMC_agama = -vxLMC_norm vyLMC_agama = -vyLMC_norm vzLMC_agama = -vzLMC_norm #The same orbit integration as the target star times_cLMC, c_orb_carLMC = agama.orbit(ic=[ xLMC_agama, yLMC_agama, zLMC_agama, vxLMC_agama, vyLMC_agama, vzLMC_agama ], potential=potentialTotal_local, time=inttime, trajsize=numsteps) xLMC = c_orb_carLMC[:, 0] yLMC = c_orb_carLMC[:, 1] zLMC = c_orb_carLMC[:, 2] vxLMC = c_orb_carLMC[:, 3] vyLMC = c_orb_carLMC[:, 4] vzLMC = c_orb_carLMC[:, 5] t_dmin_Myr = 99999. dmin_kpc = 99999. #out_filename = 'timeMyr_x_y_z_vx_vy_vz__timeMyr_xLMC_yLMC_zLMC_vxLMC_vyLMC_vzLMC__timeMyr_dx_dy_dz_dvx_dvy_dvz__AsObserved.txt' #outfile = open(out_filename,'a') #outfile.write('#(orbit in the past)\n#[time_Myr x y z vx vy vz] [time_Myr x y z vx vy vz]LMC [time_Myr x y z vx vy vz]diff\n') for i in range(len(x)): #flip the time to get the correct time Time_Myr = (-1.) * times_c[i] / (numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) #position x_ = x[i] * _R0 y_ = y[i] * _R0 z_ = z[i] * _R0 #re-flip the velocity to get the velocity in the past vx_ = -vx[i] * _V0 vy_ = -vy[i] * _V0 vz_ = -vz[i] * _V0 #flip the time to get the correct time Time_Myr_LMC = (-1.) * times_c[i] / (numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) #position xL_ = xLMC[i] * _R0 yL_ = yLMC[i] * _R0 zL_ = zLMC[i] * _R0 #re-flip the velocity to get the velocity in the past vxL_ = -vxLMC[i] * _V0 vyL_ = -vyLMC[i] * _V0 vzL_ = -vzLMC[i] * _V0 #flip the time to get the correct time Time_Myr_LMC = (-1.) * times_c[i] / (numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) #relative position dx_ = x_ - xL_ dy_ = y_ - yL_ dz_ = z_ - zL_ dvx_ = vx_ - vxL_ dvy_ = vy_ - vxL_ dvz_ = vz_ - vxL_ d_kpc = numpy.sqrt(dx_**2 + dy_**2 + dz_**2) * _R0 dv_kms = numpy.sqrt(dvx_**2 + dvy_**2 + dvz_**2) * _V0 if (d_kpc < dmin_kpc): t_dmin_Myr = Time_Myr #print(t_dmin_Myr, d_kpc) """ printline='%lf %.3lf %.3lf %.3lf %.3lf %.3lf %.3lf %lf %.3lf %.3lf %.3lf %.3lf %.3lf %.3lf %lf %.3lf %.3lf %.3lf %.3lf %.3lf %.3lf\n' % (Time_Myr, x_, y_, z_, vx_, vy_, vz_, Time_Myr_LMC, xL_, yL_, zL_, vxL_, vyL_, vzL_, Time_Myr, dx_, dy_, dz_, dvx_, dvy_, dvz_ ) """ #outfile.write(printline) x_func = scipy.interpolate.interp1d(times_c, x, kind='cubic') y_func = scipy.interpolate.interp1d(times_c, y, kind='cubic') z_func = scipy.interpolate.interp1d(times_c, z, kind='cubic') vx_func = scipy.interpolate.interp1d(times_c, vx, kind='cubic') vy_func = scipy.interpolate.interp1d(times_c, vy, kind='cubic') vz_func = scipy.interpolate.interp1d(times_c, vz, kind='cubic') xLMC_func = scipy.interpolate.interp1d(times_c, xLMC, kind='cubic') yLMC_func = scipy.interpolate.interp1d(times_c, yLMC, kind='cubic') zLMC_func = scipy.interpolate.interp1d(times_c, zLMC, kind='cubic') vxLMC_func = scipy.interpolate.interp1d(times_c, vxLMC, kind='cubic') vyLMC_func = scipy.interpolate.interp1d(times_c, vyLMC, kind='cubic') vzLMC_func = scipy.interpolate.interp1d(times_c, vzLMC, kind='cubic') # distance from ejection location (x_ej,y_ej) distance2_from_LMC_kpc_func = lambda x: (_R0**2 * ( (x_func(x) - xLMC_func(x))**2 + (y_func(x) - yLMC_func(x))**2 + (z_func(x) - zLMC_func(x))**2)) result2 = scipy.optimize.minimize_scalar(distance2_from_LMC_kpc_func, bounds=(times_c[0], times_c[-1]), method='bounded') x_ej = x_func(result2.x) * _R0 y_ej = y_func(result2.x) * _R0 z_ej = z_func(result2.x) * _R0 vx_ej = -vx_func(result2.x) * _V0 vy_ej = -vy_func(result2.x) * _V0 vz_ej = -vz_func(result2.x) * _V0 xLMC_ej = xLMC_func(result2.x) * _R0 yLMC_ej = yLMC_func(result2.x) * _R0 zLMC_ej = zLMC_func(result2.x) * _R0 vxLMC_ej = -vxLMC_func(result2.x) * _V0 vyLMC_ej = -vyLMC_func(result2.x) * _V0 vzLMC_ej = -vzLMC_func(result2.x) * _V0 dx_ej = x_ej - xLMC_ej dy_ej = y_ej - yLMC_ej dz_ej = z_ej - zLMC_ej dvx_ej = vx_ej - vxLMC_ej dvy_ej = vy_ej - vyLMC_ej dvz_ej = vz_ej - vzLMC_ej dmin_kpc = numpy.sqrt(distance2_from_LMC_kpc_func(result2.x)) dv_kms = numpy.sqrt(dvx_ej**2 + dvy_ej**2 + dvz_ej**2) Time_Myr_ej = (result2.x) / (numpy.pi / (102.396349 * (240. / _V0) * (_R0 / 8.))) out_filename = 'timeMyr_dmin_dv__timeMyr_x_y_z_vx_vy_vz__timeMyr_xLMC_yLMC_zLMC_vxLMC_vyLMC_vzLMC__timeMyr_dx_dy_dz_dvx_dvy_dvz__AsObserved_LAMOSThvs%d.txt' % ( LAMOSTHVSid) outfile = open(out_filename, 'a') printline = '%.3lf %.3lf %.3lf %.3lf %.3lf %.3lf %.3lf %.3lf %.3lf %.3lf %lf %.3lf %.3lf %.3lf %.3lf %.3lf %.3lf %lf %.3lf %.3lf %.3lf %.3lf %.3lf %.3lf\n' % ( Time_Myr_ej, dmin_kpc, dv_kms, Time_Myr_ej, x_ej, y_ej, z_ej, vx_ej, vy_ej, vz_ej, Time_Myr_ej, xLMC_ej, yLMC_ej, zLMC_ej, vxLMC_ej, vyLMC_ej, vzLMC_ej, Time_Myr_ej, dx_, dy_, dz_, dvx_, dvy_, dvz_) outfile.write(printline) outfile.close() print('---') print(Time_Myr_ej, dmin_kpc, dv_kms) print('===') return Time_Myr_ej, dmin_kpc, dv_kms
def runComponent(comp, pot): """ run the orbit integration, optimization, and construction of an N-body model for a given component of the Schwarzschild model """ if comp.has_key('trajsize'): result = agama.orbit(potential=pot, ic=comp['ic'], time=comp['inttime'], \ targets=comp['targets'], trajsize=comp['trajsize']) traj = result[-1] else: result = agama.orbit(potential=pot, ic=comp['ic'], time=comp['inttime'], targets=comp['targets']) if type(result) == numpy.array: result = (result, ) # targets[0] is density, targets[1], if provided, is kinematics matrix = list() rhs = list() rpenl = list() matrix.append(result[0].T) rhs.append(comp['targets'][0].values()) mass = rhs[0][-1] # the last constraint is the total mass avgrhs = mass / len(rhs[0]) # typical constraint magnitude rpenl.append(numpy.ones_like(rhs[0]) / avgrhs) if len(comp['targets']) == 2 and comp.has_key('beta'): numrow = len(comp['targets'][1]) / 2 matrix.append(result[1].T[0:numrow] * 2 * (1 - comp['beta']) - result[1].T[numrow:2 * numrow]) rhs.append(numpy.zeros(numrow)) rpenl.append(numpy.ones(numrow) * 10.) avgweight = mass / len(comp['ic']) xpenq = numpy.ones(len(comp['ic'])) / avgweight**2 / len(comp['ic']) * 0.1 weights = agama.optsolve(matrix=matrix, rhs=rhs, rpenl=rpenl, xpenq=xpenq) # check for any outstanding constraints for t in range(len(matrix)): delta = matrix[t].dot(weights) - rhs[t] norm = 1e-4 * abs(comp['targets'][t].values()) + 1e-8 for c, d in enumerate(delta): if abs(d) > norm[c]: print "Constraint", t, " #", c, "not satisfied:", comp[ 'targets'][t][c], d print "Entropy:", -sum(weights * numpy.log(weights+1e-100)) / mass + numpy.log(avgweight), \ " # of useful orbits:", len(numpy.where(weights >= avgweight)[0]), "/", len(comp['ic']) # create an N-body model if needed if comp.has_key('nbody'): status, particles = agama.sampleOrbitLibrary(comp['nbody'], traj, weights) if not status: indices, trajsizes = particles print "reintegrating", len( indices), "orbits; max # of sampling points is", max(trajsizes) traj[indices] = agama.orbit(potential=pot, ic=comp['ic'][indices], \ time=comp['inttime'][indices], trajsize=trajsizes) status, particles = agama.sampleOrbitLibrary( comp['nbody'], traj, weights) if not status: print "Failed to produce output N-body model" comp['nbodymodel'] = particles # output comp['weights'] = weights comp['densitydata'] = result[0] if len(matrix) == 2: comp['kinemdata'] = result[1] if comp.has_key('trajsize'): comp['traj'] = traj return comp
def runComponent(comp, pot): """ run the orbit integration, optimization, and construction of an N-body model for a given component of the Schwarzschild model """ if hasattr(comp, 'trajsize'): result = agama.orbit(potential=pot, ic=comp.ic, time=comp.inttime, Omega=comp.Omega, targets=comp.targets, trajsize=comp.trajsize) traj = result[-1] else: result = agama.orbit(potential=pot, ic=comp.ic, time=comp.inttime, Omega=comp.Omega, targets=comp.targets) traj = None if type(result) == numpy.array: result = (result, ) # targets[0] is density, targets[1], if provided, is kinematics matrix = list() rhs = list() rpenl = list() mass = comp.density.totalMass() # density constraints matrix.append(result[0].T) rhs.append(comp.targets[0](comp.density)) avgrhs = mass / len(rhs[0]) # typical magnitude of density constraints rpenl.append(numpy.ones_like(rhs[0]) / avgrhs) # kinematic constraints if len(comp.targets) == 2 and hasattr(comp, 'beta'): numrow = len(comp.targets[1]) // 2 matrix.append(result[1].T[0:numrow] * 2 * (1 - comp.beta) - result[1].T[numrow:2 * numrow]) rhs.append(numpy.zeros(numrow)) rpenl.append(numpy.ones(numrow)) # total mass constraint matrix.append(numpy.ones((len(comp.ic), 1)).T) rhs.append(numpy.array([mass])) rpenl.append(numpy.array([numpy.inf])) # regularization (penalty for unequal weights) avgweight = mass / len(comp.ic) xpenq = numpy.ones(len(comp.ic)) / avgweight**2 / len(comp.ic) * 0.1 # solve the linear equation for weights weights = agama.solveOpt(matrix=matrix, rhs=rhs, rpenl=rpenl, xpenq=xpenq) # check for any outstanding constraints for t in range(len(matrix)): delta = matrix[t].dot(weights) - rhs[t] norm = 1e-4 * abs(rhs[t]) + 1e-8 for c, d in enumerate(delta): if abs(d) > norm[c]: print("Constraint %i:%i not satisfied: %s, val=%.4g, dif=%.4g" % \ (t, c, comp.targets[t][c], rhs[t][c], d)) print("Entropy: %f, # of useful orbits: %i / %i" %\ ( -sum(weights * numpy.log(weights+1e-100)) / mass + numpy.log(avgweight), \ len(numpy.where(weights >= avgweight)[0]), len(comp.ic))) # create an N-body model if needed if hasattr(comp, 'nbody'): status, particles = agama.sampleOrbitLibrary(comp.nbody, traj, weights) if not status: indices, trajsizes = particles print("reintegrating %i orbits; max # of sampling points is %i" % (len(indices), max(trajsizes))) traj[indices] = agama.orbit(potential=pot, ic=comp.ic[indices], \ time=comp.inttime[indices], trajsize=trajsizes) status, particles = agama.sampleOrbitLibrary( comp.nbody, traj, weights) if not status: print("Failed to produce output N-body model") comp.nbodymodel = particles # output comp.weights = weights comp.densitydata = result[0] if len(comp.targets) >= 2: comp.kinemdata = result[1] if not traj is None: comp.traj = traj
target1 = agama.Target(type='DensityClassicLinear', gridr=agama.nonuniformGrid(25, 0.1, 20.0), \ axisratioy=0.8, axisratioz=0.6, stripsPerPane=2) # target2 is discretized kinematic constraint (we will enforce velocity isotropy) target2 = agama.Target(type='KinemShell', gridR=agama.nonuniformGrid(15, 0.2, 10.0), degree=1) # construct initial conditions for the orbit library initcond, weightprior = den.sample(5000, potential=pot) # integration time is 50 orbital periods inttimes = 50 * pot.Tcirc(initcond) # integrate all orbits, storing the recorded data corresponding to each target # in the data1 and data2 arrays, and the trajectories - in trajs data1, data2, trajs = agama.orbit(potential=pot, ic=initcond, time=inttimes, \ trajsize=101, targets=[target1,target2]) # assemble the matrix equation which contains three blocks: # total mass, discretized density, and velocity anisotropy # a single value for the total mass constraint, each orbit contributes 1 to it mass = den.totalMass() data0 = numpy.ones((len(initcond), 1)) # discretized density profile to be used as the density constraint rhs1 = target1(den) # data2 is kinematic data: for each orbit (row) it contains # Ngrid values of rho sigma_r^2, then the same number of values of rho sigma_t^2; # we combine them into a single array of Ngrid values that enforce isotropy (sigma_t^2 - 2 sigma_r^2 = 0) Ngrid = len(target2) // 2