def test_trailingwleadingimpact_error(): #Imports from galpy.df import streamgapdf from galpy.orbit import Orbit from galpy.potential import LogarithmicHaloPotential from galpy.actionAngle import actionAngleIsochroneApprox from galpy.util import conversion #for unit conversions lp = LogarithmicHaloPotential(normalize=1., q=0.9) aAI = actionAngleIsochroneApprox(pot=lp, b=0.8) prog_unp_peri = Orbit([ 2.6556151742081835, 0.2183747276300308, 0.67876510797240575, -2.0143395648974671, -0.3273737682604374, 0.24218273922966019 ]) V0, R0 = 220., 8. sigv = 0.365 * (10. / 2.)**(1. / 3.) # km/s with pytest.raises(ValueError) as excinfo: dum= streamgapdf(sigv/V0,progenitor=prog_unp_peri,pot=lp,aA=aAI, leading=False,nTrackChunks=26, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0, impactb=0., subhalovel=numpy.array([6.82200571,132.7700529, 149.4174464])/V0, timpact=0.88/conversion.time_in_Gyr(V0,R0), impact_angle=2.34, GM=10.**-2.\ /conversion.mass_in_1010msol(V0,R0), rs=0.625/R0) return None
def parse_times(times, age): if 'sampling' in times: nsam = int(times.split('sampling')[0]) return [ float(ti) / conversion.time_in_Gyr(vo, ro) for ti in numpy.arange(1, nsam + 1) / (nsam + 1.) * age ] return [ float(ti) / conversion.time_in_Gyr(vo, ro) for ti in times.split(',') ]
def test_time_in_Gyr(): #Test the scaling, should scale as position/velocity vofid, rofid = 200., 8. assert numpy.fabs(0.5 * conversion.time_in_Gyr(vofid, rofid) / conversion.time_in_Gyr(2. * vofid, rofid) - 1.) < 10.**-10., 'time_in_Gyr did not work as expected' assert numpy.fabs(2. * conversion.time_in_Gyr(vofid, rofid) / conversion.time_in_Gyr(vofid, 2 * rofid) - 1.) < 10.**-10., 'time_in_Gyr did not work as expected' return None
def test_ChandrasekharDynamicalFrictionForce_constLambda(): # Test that the ChandrasekharDynamicalFrictionForce with constant Lambda # agrees with analytical solutions for circular orbits: # assuming that a mass remains on a circular orbit in an isothermal halo # with velocity dispersion sigma and for constant Lambda: # r_final^2 - r_initial^2 = -0.604 ln(Lambda) GM/sigma t # (e.g., B&T08, p. 648) from galpy.util import conversion from galpy.orbit import Orbit ro, vo = 8., 220. # Parameters GMs = 10.**9. / conversion.mass_in_msol(vo, ro) const_lnLambda = 7. r_init = 2. dt = 2. / conversion.time_in_Gyr(vo, ro) # Compute lp = potential.LogarithmicHaloPotential(normalize=1., q=1.) cdfc= potential.ChandrasekharDynamicalFrictionForce(\ GMs=GMs,const_lnLambda=const_lnLambda, dens=lp) # don't provide sigmar, so it gets computed using galpy.df.jeans o = Orbit([r_init, 0., 1., 0., 0., 0.]) ts = numpy.linspace(0., dt, 1001) o.integrate(ts, [lp, cdfc], method='odeint') r_pred = numpy.sqrt(o.r()**2. - 0.604 * const_lnLambda * GMs * numpy.sqrt(2.) * dt) assert numpy.fabs( r_pred - o.r(ts[-1]) ) < 0.01, 'ChandrasekharDynamicalFrictionForce with constant lnLambda for circular orbits does not agree with analytical prediction' return None
def test_ChandrasekharDynamicalFrictionForce_varLambda(): # Test that dynamical friction with variable Lambda for small r ranges # gives ~ the same result as using a constant Lambda that is the mean of # the variable lambda # Also tests that giving an axisymmetric list of potentials for the # density works from galpy.util import conversion from galpy.orbit import Orbit ro, vo = 8., 220. # Parameters GMs = 10.**9. / conversion.mass_in_msol(vo, ro) r_init = 3. dt = 2. / conversion.time_in_Gyr(vo, ro) # Compute evolution with variable ln Lambda cdf= potential.ChandrasekharDynamicalFrictionForce(\ GMs=GMs,rhm=0.125, dens=potential.MWPotential2014,sigmar=lambda r: 1./numpy.sqrt(2.)) o = Orbit([r_init, 0., 1., 0., 0., 0.]) ts = numpy.linspace(0., dt, 1001) o.integrate(ts, [potential.MWPotential2014, cdf], method='odeint') lnLs = numpy.array([ cdf.lnLambda(r, v) for (r, v) in zip( o.r(ts), numpy.sqrt(o.vx(ts)**2. + o.vy(ts)**2. + o.vz(ts)**2.)) ]) cdfc= potential.ChandrasekharDynamicalFrictionForce(\ GMs=GMs,rhm=0.125,const_lnLambda=numpy.mean(lnLs), dens=potential.MWPotential2014,sigmar=lambda r: 1./numpy.sqrt(2.)) oc = o() oc.integrate(ts, [potential.MWPotential2014, cdfc], method='odeint') assert numpy.fabs( oc.r(ts[-1]) - o.r(ts[-1]) ) < 0.05, 'ChandrasekharDynamicalFrictionForce with variable lnLambda for a short radial range is not close to the calculation using a constant lnLambda' return None
def test_sanders15_setup(): #Imports from galpy.df import streamdf, streamgapdf from galpy.orbit import Orbit from galpy.potential import LogarithmicHaloPotential from galpy.actionAngle import actionAngleIsochroneApprox from galpy.util import conversion #for unit conversions lp = LogarithmicHaloPotential(normalize=1., q=0.9) aAI = actionAngleIsochroneApprox(pot=lp, b=0.8) prog_unp_peri = Orbit([ 2.6556151742081835, 0.2183747276300308, 0.67876510797240575, -2.0143395648974671, -0.3273737682604374, 0.24218273922966019 ]) global sdf_sanders15 V0, R0 = 220., 8. sigv = 0.365 * (10. / 2.)**(1. / 3.) # km/s sdf_sanders15= streamgapdf(sigv/V0,progenitor=prog_unp_peri,pot=lp,aA=aAI, leading=False,nTrackChunks=26, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0, impactb=0., subhalovel=numpy.array([6.82200571,132.7700529, 149.4174464])/V0, timpact=0.88/conversion.time_in_Gyr(V0,R0), impact_angle=-2.34, GM=10.**-2.\ /conversion.mass_in_1010msol(V0,R0), rs=0.625/R0) assert not sdf_sanders15 is None, 'sanders15 streamgapdf setup did not work' # Also setup the unperturbed model global sdf_sanders15_unp sdf_sanders15_unp= streamdf(sigv/V0,progenitor=prog_unp_peri,pot=lp,aA=aAI, leading=False,nTrackChunks=26, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0) assert not sdf_sanders15_unp is None, \ 'sanders15 unperturbed streamdf setup did not work' return None
def test_units(): # Import changed becaose of bovy_conversion --> conversion name change from galpy.util import conversion print(conversion.force_in_pcMyr2(220., 8.)) #pc/Myr^2 assert numpy.fabs(conversion.force_in_pcMyr2(220., 8.) - 6.32793804994) < 10.**-4., 'unit conversion has changed' print(conversion.dens_in_msolpc3(220., 8.)) #Msolar/pc^3 # Loosen tolerances including mass bc of 0.025% change in Msun in astropyv2 assert numpy.fabs((conversion.dens_in_msolpc3(220., 8.) - 0.175790330079) / 0.175790330079) < 0.0003, 'unit conversion has changed' print(conversion.surfdens_in_msolpc2(220., 8.)) #Msolar/pc^2 assert numpy.fabs( (conversion.surfdens_in_msolpc2(220., 8.) - 1406.32264063) / 1406.32264063) < 0.0003, 'unit conversion has changed' print(conversion.mass_in_1010msol(220., 8.)) #10^10 Msolar assert numpy.fabs((conversion.mass_in_1010msol(220., 8.) - 9.00046490005) / 9.00046490005) < 0.0003, 'unit conversion has changed' print(conversion.freq_in_Gyr(220., 8.)) #1/Gyr assert numpy.fabs(conversion.freq_in_Gyr(220., 8.) - 28.1245845523) < 10.**-4., 'unit conversion has changed' print(conversion.time_in_Gyr(220., 8.)) #Gyr assert numpy.fabs(conversion.time_in_Gyr(220., 8.) - 0.0355560807712 ) < 10.**-4., 'unit conversion has changed' return None
def run_orbitIntegration_comparison(orb,pot,tmax,vo,ro,tol=0.01): # Integrate in galpy ts= numpy.linspace(0.,tmax/conversion.time_in_Gyr(vo,ro),1001) orb.integrate(ts,pot) # Integrate with amuse x,y,z,vx,vy,vz=integrate_amuse(orb,pot,tmax | units.Gyr, vo,ro) # Read and compare xdiff= numpy.fabs((x-orb.x(ts[-1]))/x) ydiff= numpy.fabs((y-orb.y(ts[-1]))/y) zdiff= numpy.fabs((z-orb.z(ts[-1]))/z) vxdiff= numpy.fabs((vx-orb.vx(ts[-1]))/vx) vydiff= numpy.fabs((vy-orb.vy(ts[-1]))/vy) vzdiff= numpy.fabs((vz-orb.vz(ts[-1]))/vz) assert xdiff < tol, 'galpy and amuse orbit integration inconsistent for x by %g' % xdiff assert ydiff < tol, 'galpy and amuse orbit integration inconsistent for y by %g' % ydiff assert zdiff < tol, 'galpy and amuse orbit integration inconsistent for z by %g' % zdiff assert vxdiff < tol, 'galpy and amuse orbit integration inconsistent for vx by %g' % vxdiff assert vydiff < tol, 'galpy and amuse orbit integration inconsistent for vy by %g' % vydiff assert vzdiff < tol, 'galpy and amuse orbit integration inconsistent for vz by %g' % vzdiff return None
def setup_mockgd1model(leading=True, pot=MWPotential2014, timpact=None, Zsun=0.025, hernquist=True, isob=0.8, age=9., sigv=0.46, singleImpact=False, length_factor=1., **kwargs): aAI = actionAngleIsochroneApprox(pot=pot, b=isob) obs = Orbit.from_name("GD1") if timpact is None: sdf = streamdf(sigv / 220., progenitor=obs, pot=pot, aA=aAI, leading=leading, nTrackChunks=11, vsun=[-11.1, 244., 7.25], Zsun=Zsun, tdisrupt=age / conversion.time_in_Gyr(V0, R0), vo=V0, ro=R0) elif singleImpact: sdf = streamgapdf(sigv / 220., progenitor=obs, pot=pot, aA=aAI, leading=leading, nTrackChunks=11, vsun=[-11.1, 244., 7.25], Zsun=Zsun, tdisrupt=age / conversion.time_in_Gyr(V0, R0), vo=V0, ro=R0, timpact=timpact, spline_order=3, hernquist=hernquist, **kwargs) else: sdf = streampepperdf(sigv / 220., progenitor=obs, pot=pot, aA=aAI, leading=leading, nTrackChunks=101, vsun=[-11.1, 244., 7.25], Zsun=Zsun, tdisrupt=age / conversion.time_in_Gyr(V0, R0), vo=V0, ro=R0, timpact=timpact, spline_order=1, hernquist=hernquist, length_factor=length_factor) sdf.turn_physical_off() #original #obs.turn_physical_off() return sdf
class Snapshot(): MLU = 8. #kpc MVU = 220. #km/s MTU = time_in_Gyr(MVU, MLU) * 1000. #Myr MMU = mass_in_msol(MVU, MLU) # msol def __init__(self, Filename, Np, hf=0.4, df=0.5, bf=0.1, Nslice=10, dt=0.0078125, frac=True): self.Filename = Filename self.Np = Np if frac: self.Nh = int(self.Np * hf) self.Nd = int(self.Np * df) self.Nb = int(self.Np * bf) else: self.Nh = hf self.Nd = df self.Nb = bf self._step = int((self.Filename.split('_')[3]).split('.')[0]) self._Nslice = Nslice self._dt = dt self.t = self._step * dt self._COM = self.calc_COM() self._rot = self.calc_AngMom() def calc_COM(self): mtot = 0 COMraw = np.zeros(3) for i in range(self._Nslice): offset = int(i * int(np.ceil(self.Np / self._Nslice))) count = int(np.ceil(self.Np / self._Nslice)) if offset + count > self.Np: count = self.Np - offset with open(self.Filename, 'rb') as f: mxv = np.fromfile(f, dtype='f4', offset=offset * 4 * 7, count=count * 7) mxv = np.reshape(mxv, (count, 7)).astype('f8') mtot += np.sum(mxv[:, 0]) COMraw += np.sum(mxv[:, 0][:, None] * (mxv[:, 1:4]), axis=0) del mxv return COMraw / mtot def calc_AngMom(self): Ltot = np.zeros(3) for i in range(self._Nslice): with open(self.Filename, 'rb') as f: mxv = np.fromfile( f, dtype='f4', offset=(self.Nh * 7 + i * 7 * int(self.Nd / self._Nslice)) * 4, count=7 * int(self.Nd / self._Nslice)) mxv = np.reshape(mxv, (int(len(mxv) / 7), 7)) Ltot += np.sum(np.cross((mxv[:, 1:4] - self._COM), mxv[:, 0][:, None] * mxv[:, 4:]), axis=0) Ltot = Ltot / np.sqrt(np.sum(Ltot**2)) rot = self.calc_Rot_matrix(Ltot) del mxv return rot @staticmethod def calc_Rot_matrix(AngMom): hyz = np.sqrt(AngMom[1]**2 + AngMom[2]**2) costh = AngMom[2] / hyz sinth = AngMom[1] / hyz Rx = np.array([[1, 0, 0], [0, costh, -sinth], [0, sinth, costh]]) Lmid = np.matmul(Rx, AngMom) hxz = np.sqrt(Lmid[0]**2 + Lmid[2]**2) cosph = Lmid[2] / hxz sinph = -Lmid[0] / hxz Ry = np.array([[cosph, 0, sinph], [0, 1, 0], [-sinph, 0, cosph]]) return np.matmul(Ry, Rx) def calc_density(self, bins=(90, 90, 90), lim=(30., 30., 10.), adjust=True): Ntot = np.zeros(bins) for i in range(self._Nslice): with open(self.Filename, 'rb') as f: mxv = np.fromfile(f, dtype='f4', offset=i * 7 * int(self.Np / self._Nslice) * 4, count=7 * int(self.Np / self._Nslice)) mxv = np.reshape(mxv, (int(len(mxv) / 7), 7)) if adjust: mxv[:, 1:] = self.adjust(mxv[:, 1:]) N, edges = np.histogramdd(mxv[:, 1:4], bins=bins, range=((-lim[0], lim[0]), (-lim[1], lim[1]), (-lim[2], lim[2])), weights=mxv[:, 0]) Ntot += N del mxv self.N = Ntot self.Nedge = edges return Ntot, edges def adjust(self, particles, vel=True): particles[:, :3] = np.matmul(self._rot, particles[:, :3].T - self._COM[:, None]).T if vel: particles[:, 3:] = np.matmul(self._rot, particles[:, 3:].T).T return particles def sample(self, frac=0.1): ncomp = [self.Nh, self.Nd, self.Nb] sample = np.empty([0, 7]) for i, n in enumerate(ncomp): for j in range(self._Nslice): offset = int(np.sum( ncomp[:i])) + j * int(np.ceil(n / self._Nslice)) count = int(np.ceil(n / self._Nslice)) if offset + count > np.sum(ncomp[:i + 1]): count = np.sum(ncomp[:i + 1]) - offset with open(self.Filename, 'rb') as f: mxv = np.fromfile(f, dtype='f4', offset=offset * 7 * 4, count=7 * count) mxv = np.reshape(mxv, (int(len(mxv) / 7), 7)) indx = np.random.choice(count, int(count * frac), replace=False) sample = np.vstack( [sample, np.reshape(mxv[indx], (len(indx), 7))]) sample[:, 0] /= frac sample[:, 1:] = self.sample(frac=frac) return sample def calc_vrot(self, Rs=np.linspace(0.01, 5., 51), sample=True, frac=0.01): try: return self.vrot except: if sample: sample = self.sample(frac=frac) else: with open(self.Filename, 'rb') as f: sample = np.fromfile(f, dtype='f4', offset=4 * 7 * (self.Nh + self.Nd), count=7 * self.Nb) sample = np.reshape(sample, (self.Nb, 7)) sample = self.adjust(sample) Nh = len(sample[tuple([sample[:, 0] == sample[0, 0]])]) f = pb.new(dm=Nh, star=len(sample[:, 0]) - Nh) f['mass'] = sample[:, 0] / self.MMU f['pos'] = sample[:, 1:4] / self.MLU f['vel'] = sample[:, 4:] / self.MVU f['eps'] = np.ones(len(sample)) * 0.05 / self.MLU sp = galpy.potential.SnapshotRZPotential(f, num_threads=10) vrot = galpy.potential.calcRotcurve(sp, Rs, phi=0.) self.vrot = vrot self._Rs = Rs return vrot def calc_potential(self, sample=True, frac=0.01, a=[27.68, 3.41, 0.536], N=[5, 15, 3], L=[5, 15, 3]): try: print('data/equil_potential_coefficients_N' + str(N[0]) + str(N[1]) + str(N[2]) + '.txt') with open( 'data/equil_potential_coefficients_N' + str(N[0]) + str(N[1]) + str(N[2]) + '.txt', 'rb') as f: Acos, Asin = np.load(f, allow_pickle=True) pot = [ SCFPotential(Acos=Acos[i], Asin=Asin[i], a=a[i] / 8.) for i in range(3) ] except: ncomp = [self.Nh, self.Nd, self.Nb] Acos, Asin = np.empty((2, 3), dtype='object') pot = np.empty(3, dtype='object') fullsample = self.sample(frac=frac) masses = list(set(fullsample[:, 0])) for i, n in enumerate(ncomp): samples = fullsample[tuple([fullsample[:, 0] == masses[i]])] Acos[i], Asin[i] = scf_compute_coeffs_nbody( samples[:, 1:4].T / self.MLU, samples[:, 0] / self.MMU, N[i], L[i], a=a[i] / 8.) pot[i] = SCFPotential(Acos=Acos[i], Asin=Asin[i], a=a[i] / 8.) coeff = np.vstack([Acos, Asin]) with open( 'data/equil_potential_coefficients_N' + str(N[0]) + str(N[1]) + str(N[2]) + '.txt', 'wb') as f: np.save(f, coeff) self.pot = list(pot) return list(pot) def analyze_SN(self, Rcyl, X=8.1, Y=0, correct=True, zrange=[-2, 2], nbins=51): calc = True try: for i, sn in enumerate(self.SN): if (sn.Rcyl == Rcyl) * (sn.X == X) * (sn.Y == Y): # If you want a finer grid, replace the old coarser grid if (nbins > sn.nbins): self.SN[i] = SolarNeighbourhood( self, Rcyl, X, Y, correct, zrange, nbins) calc = False # If it already exists, don't do it again else: calc = False else: continue if calc: self.SN = np.append( self.SN, SolarNeighbourhood(self, Rcyl, X, Y, correct, zrange, nbins)) except: self.SN = np.array( [SolarNeighbourhood(self, Rcyl, X, Y, correct, zrange, nbins)]) def plot_density(self, plot_origin=False, save=False, adjust=True): try: self.N except: self.calc_density(adjust=adjust) fig, [ax1, ax2] = plt.subplots(2, sharex=True, gridspec_kw={'height_ratios': [3, 1]}, figsize=[5, 7]) ax1.imshow(np.log(np.sum(self.N, axis=2).T), cmap='Greys', extent=[-30, 30, -30, 30]) ax2.imshow(np.log(np.sum(self.N, axis=1).T), cmap='Greys', extent=[-30, 30, -10, 10]) if plot_origin: ax1.plot(0., 0., 'or') ax2.plot(0., 0., 'or') ax2.set_xlabel(r'$x \,\mathrm{(kpc)}$') ax1.set_ylabel(r'$y \,\mathrm{(kpc)}$') ax2.set_ylabel(r'$z \,\mathrm{(kpc)}$') fig.subplots_adjust(hspace=0) txt = ax1.annotate(r'$t=%.0f\,\mathrm{Myr}$' % (np.round(self.t, 0)), (0.95, 0.95), xycoords='axes fraction', horizontalalignment='right', verticalalignment='top', size=18.) if save: plt.savefig('plots/Density' + str(np.round(self.t, 0) + '.pdf', bbox_inches='tight'))
def test_sanders15_leading_setup(): #Imports from galpy.df import streamdf, streamgapdf from galpy.orbit import Orbit from galpy.potential import LogarithmicHaloPotential, PlummerPotential from galpy.actionAngle import actionAngleIsochroneApprox from galpy.util import conversion #for unit conversions lp = LogarithmicHaloPotential(normalize=1., q=0.9) aAI = actionAngleIsochroneApprox(pot=lp, b=0.8) prog_unp_peri = Orbit([ 2.6556151742081835, 0.2183747276300308, 0.67876510797240575, -2.0143395648974671, -0.3273737682604374, 0.24218273922966019 ]) global sdfl_sanders15 V0, R0 = 220., 8. sigv = 0.365 * (10. / 2.)**(1. / 3.) # km/s # Use a Potential object for the impact pp= PlummerPotential(amp=10.**-2.\ /conversion.mass_in_1010msol(V0,R0), b=0.625/R0) import warnings from galpy.util import galpyWarning with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always", galpyWarning) sdfl_sanders15= streamgapdf(sigv/V0,progenitor=prog_unp_peri, pot=lp,aA=aAI, leading=True,nTrackChunks=26, nTrackChunksImpact=29, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0, impactb=0., subhalovel=numpy.array([49.447319, 116.179436, 155.104156])/V0, timpact=0.88/conversion.time_in_Gyr(V0,R0), impact_angle=2.09, subhalopot=pp, nKickPoints=290, deltaAngleTrackImpact=4.5, multi=True) # test multi # Should raise warning bc of deltaAngleTrackImpact, might raise others raisedWarning = False for wa in w: raisedWarning = ( str(wa.message) == "WARNING: deltaAngleTrackImpact angle range large compared to plausible value" ) if raisedWarning: break assert raisedWarning, 'deltaAngleTrackImpact warning not raised when it should have been' assert not sdfl_sanders15 is None, 'sanders15 trailing streamdf setup did not work' # Also setup the unperturbed model global sdfl_sanders15_unp sdfl_sanders15_unp= streamdf(sigv/V0,progenitor=prog_unp_peri, pot=lp,aA=aAI, leading=True,nTrackChunks=26, nTrackIterations=1, sigMeanOffset=4.5, tdisrupt=10.88\ /conversion.time_in_Gyr(V0,R0), Vnorm=V0,Rnorm=R0) assert not sdfl_sanders15_unp is None, \ 'sanders15 unperturbed streamdf setup did not work' return None
def run_orbitIntegration_comparison(orb, pot, tmax, vo, ro, isList=False, tol=0.01): # Integrate in galpy ts = numpy.linspace(0., tmax / conversion.time_in_Gyr(vo, ro), 1001) orb.integrate(ts, pot) # Now setup a NEMO snapshot in the correct units ([x] = kpc, [v] = kpc/Gyr) numpy.savetxt('orb.dat', numpy.array([[10.**-6.,orb.x(),orb.y(),orb.z(), orb.vx(use_physical=False)\ *conversion.velocity_in_kpcGyr(vo,ro), orb.vy(use_physical=False)\ *conversion.velocity_in_kpcGyr(vo,ro), orb.vz(use_physical=False)\ *conversion.velocity_in_kpcGyr(vo,ro)]])) # Now convert to NEMO format try: convert_to_nemo('orb.dat', 'orb.nemo') finally: os.remove('orb.dat') # Integrate with gyrfalcON try: if isList: integrate_gyrfalcon('orb.nemo', 'orb_evol.nemo', tmax, potential.nemo_accname(pot), potential.nemo_accpars(pot, vo, ro)) else: integrate_gyrfalcon('orb.nemo', 'orb_evol.nemo', tmax, pot.nemo_accname(), pot.nemo_accpars(vo, ro)) finally: os.remove('orb.nemo') os.remove('gyrfalcON.log') # Convert back to ascii try: convert_from_nemo('orb_evol.nemo', 'orb_evol.dat') finally: os.remove('orb_evol.nemo') # Read and compare try: nemodata = numpy.loadtxt('orb_evol.dat', comments='#') xdiff = numpy.fabs((nemodata[-1, 1] - orb.x(ts[-1])) / nemodata[-1, 1]) ydiff = numpy.fabs((nemodata[-1, 2] - orb.y(ts[-1])) / nemodata[-1, 2]) zdiff = numpy.fabs((nemodata[-1, 3] - orb.z(ts[-1])) / nemodata[-1, 3]) vxdiff = numpy.fabs( (nemodata[-1, 4] - orb.vx(ts[-1], use_physical=False) * conversion.velocity_in_kpcGyr(vo, ro)) / nemodata[-1, 4]) vydiff = numpy.fabs( (nemodata[-1, 5] - orb.vy(ts[-1], use_physical=False) * conversion.velocity_in_kpcGyr(vo, ro)) / nemodata[-1, 5]) vzdiff = numpy.fabs( (nemodata[-1, 6] - orb.vz(ts[-1], use_physical=False) * conversion.velocity_in_kpcGyr(vo, ro)) / nemodata[-1, 6]) assert xdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for x by %g' % xdiff assert ydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for y by %g' % ydiff assert zdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for z by %g' % zdiff assert vxdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vx by %g' % vxdiff assert vydiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vy by %g' % vydiff assert vzdiff < tol, 'galpy and NEMO gyrfalcON orbit integration inconsistent for vz by %g' % vzdiff finally: os.remove('orb_evol.dat') return None