def test_monotonic_incomplete_bridge(): # Test the monotonic bridge where not all the particles are shared f1 = pynbody.new(dm=10) f2 = pynbody.new(dm=9) f1['iord'] = np.arange(0, 10) f2['iord'] = np.array([0, 1, 2, 4, 5 ,6, 7, 8, 9]) b = pynbody.bridge.OrderBridge(f1, f2, monotonic=False) assert (b(f1[:5])['iord'] == np.array([0, 1, 2, 4])).all()
def test_order_bridge(): f1 = pynbody.new(dm=1000) f2 = pynbody.new(dm=3000) f1['iord'] = np.arange(5, 2005, 2, dtype=int) f2['iord'] = np.arange(3000, dtype=int) b = pynbody.bridge.OrderBridge(f1, f2) h1 = f1[:50:2] assert b(h1).ancestor is f2 assert (b(h1)['iord'] == h1['iord']).all
def test_family_morphing(): f1 = pynbody.new(dm=5, gas=5) f2 = pynbody.new(dm=10) # set dm and gas iords separately as it's possible the new command initialises them out of order f1.dm['iord'] = np.arange(0,5) f1.gas['iord'] = np.arange(5,10) f2['iord'] = np.array([0,2,4,6,8,1,3,5,7,9]) b = pynbody.bridge.OrderBridge(f1,f2,monotonic=False,allow_family_change=True) assert (b(f2).dm['iord']==np.array([0,2,4,1,3])).all() assert (b(f2).gas['iord'] == np.array([6, 8, 5, 7, 9])).all()
def setup(): global f, h f = pynbody.new(dm=1000, star=500, gas=500, order='gas,dm,star') f['pos'] = np.random.normal(scale=1.0, size=f['pos'].shape) f['vel'] = np.random.normal(scale=1.0, size=f['vel'].shape) f['mass'] = np.random.uniform(1.0, 10.0, size=f['mass'].shape) f.gas['rho'] = np.ones(500, dtype=float)
def test_interpsnapshotKeplerPotential_normalize_units(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 4. s['eps']= 0. s['pos'].units= 'kpc' s['vel'].units= 'km s**-1' sp= potential.InterpSnapshotRZPotential(s, rgrid=(0.01,3.,201), zgrid=(0.,0.2,201), logR=False, interpPot=True, zsym=True) #Currently unnormalized assert numpy.fabs(sp.Rforce(1.,0.)+4.) < 10.**-7., "InterpSnapShotPotential that is assumed to be unnormalized doesn't behave as expected" # Normalize sp.normalize(R0=1.) assert numpy.fabs(sp.Rforce(1.,0.)+1.) < 10.**-7., "InterpSnapShotPotential that is assumed to be normalized doesn't behave as expected" # De normalize sp.denormalize() assert numpy.fabs(sp.Rforce(1.,0.)+4.) < 10.**-7., "InterpSnapShotPotential that is assumed to be normalized doesn't behave as expected" # Also test when R0 =/= 1 sp.normalize(R0=2.) assert numpy.fabs(sp.Rforce(1.,0.)+1.) < 10.**-7., "InterpSnapShotPotential that is assumed to be normalized doesn't behave as expected" # De normalize sp.denormalize() assert numpy.fabs(sp.Rforce(1.,0.)+4.) < 10.**-7., "InterpSnapShotPotential that is assumed to be normalized doesn't behave as expected" return None
def test_interpsnapshotKeplerPotential_eval(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 1. s['eps']= 0. sp= potential.InterpSnapshotRZPotential(s, rgrid=(0.01,2.,201), zgrid=(0.,0.2,201), logR=False, interpPot=True, zsym=True, numcores=1) kp= potential.KeplerPotential(amp=1.) #should be the same #This just tests on the grid rs= numpy.linspace(0.01,2.,21) zs= numpy.linspace(-0.2,0.2,41) for r in rs: for z in zs: assert numpy.fabs((sp(r,z)-kp(r,z))/kp(r,z)) < 10.**-10., 'RZPot interpolation w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g)' % (r,z) #This tests within the grid rs= numpy.linspace(0.01,2.,10) zs= numpy.linspace(-0.2,0.2,20) for r in rs: for z in zs: assert numpy.fabs((sp(r,z)-kp(r,z))/kp(r,z)) < 10.**-5., 'RZPot interpolation w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g) by %g' % (r,z,numpy.fabs((sp(r,z)-kp(r,z))/kp(r,z))) #Test all at the same time to use vector evaluation mr,mz= numpy.meshgrid(rs,zs) mr= mr.flatten() mz= mz.flatten() assert numpy.all(numpy.fabs((sp(mr,mz)-kp(mr,mz))/kp(mr,mz)) < 10.**-5.), 'RZPot interpolation w/ interpRZPotential fails for vector input' return None
def test_float_kd(): f = pynbody.load("testdata/test_g2_snap") del f.properties['boxsize'] assert f.dm['mass'].dtype==f.dm['pos'].dtype==np.float32 assert f.dm['smooth'].dtype==np.float32 # make double copy g = pynbody.new(len(f.dm)) g.dm['pos']=f.dm['pos'] g.dm['mass']=f.dm['mass'] assert g.dm['mass'].dtype==g.dm['pos'].dtype==g.dm['smooth'].dtype==np.float64 # check smoothing lengths agree (they have been calculated differently # using floating/double routines) npt.assert_allclose(f.dm['smooth'],g.dm['smooth'],rtol=1e-4) npt.assert_allclose(f.dm['rho'],g.dm['rho'],rtol=1e-4) # check all combinations of float/double smoothing double_ar = np.ones(len(f.dm),dtype=np.float64) float_ar = np.ones(len(f.dm),dtype=np.float32) double_double = g.dm.kdtree.sph_mean(double_ar,32) double_float = g.dm.kdtree.sph_mean(float_ar,32) float_double = f.dm.kdtree.sph_mean(double_ar,32) float_float = f.dm.kdtree.sph_mean(float_ar,32) # take double-double as 'gold standard' (though of course if any of these # fail it could also be a problem with the double-double case) npt.assert_allclose(double_double,double_float,rtol=1e-4) npt.assert_allclose(double_double,float_double,rtol=1e-4) npt.assert_allclose(double_double,float_float,rtol=1e-4)
def test_interpsnapshotKeplerPotential_eval_naz(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 1. s['eps']= 0. sp= potential.InterpSnapshotRZPotential(s, rgrid=(0.01,2.,51), zgrid=(0.,0.2,51), logR=False, interpPot=True, zsym=True, numcores=1) spaz= potential.InterpSnapshotRZPotential(s, rgrid=(0.01,2.,51), zgrid=(0.,0.2,51), logR=False, interpPot=True, zsym=True, numcores=1,nazimuths=12) #This just tests on the grid rs= numpy.linspace(0.01,2.,21) zs= numpy.linspace(-0.2,0.2,41) for r in rs: for z in zs: assert numpy.fabs((sp(r,z)-spaz(r,z))/sp(r,z)) < 10.**-10., 'RZPot interpolation w/ InterpSnapShotPotential of KeplerPotential with different nazimuths fails at (R,z) = (%g,%g)' % (r,z) #This tests within the grid, with vector evaluation rs= numpy.linspace(0.01,2.,10) zs= numpy.linspace(-0.2,0.2,20) mr,mz= numpy.meshgrid(rs,zs) mr= mr.flatten() mz= mz.flatten() assert numpy.all(numpy.fabs((sp(mr,mz)-spaz(mr,mz))/sp(mr,mz)) < 10.**-5.), 'RZPot interpolation w/ interpRZPotential with different nazimimuths fails for vector input' return None
def test_interpsnapshotKeplerPotential_z2deriv(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 2. s['eps']= 0. sp= potential.InterpSnapshotRZPotential(s, rgrid=(0.01,2.,101), zgrid=(0.,0.2,101), logR=False, interpPot=True, interpverticalfreq=True, zsym=True) kp= potential.KeplerPotential(amp=2.) #should be the same #This just tests on the grid rs= numpy.linspace(0.01,2.,21)[1:] zs= numpy.linspace(-0.2,0.2,41) for r in rs: for z in zs: assert numpy.fabs((sp.z2deriv(r,z)-kp.z2deriv(r,z))/kp.z2deriv(r,z)) < 10.**-4., 'RZPot interpolation of z2deriv w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g) by %g' % (r,z,numpy.fabs((sp.z2deriv(r,z)-kp.z2deriv(r,z))/kp.z2deriv(r,z))) #This tests within the grid rs= numpy.linspace(0.01,2.,10)[1:] zs= numpy.linspace(-0.2,0.2,20) for r in rs: for z in zs: assert numpy.fabs((sp.z2deriv(r,z)-kp.z2deriv(r,z))/kp.z2deriv(r,z)) < 2.*10.**-4., 'RZPot interpolation of z2deriv w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g) by %g' % (r,z,numpy.fabs((sp.z2deriv(r,z)-kp.z2deriv(r,z))/kp.z2deriv(r,z))) return None
def test_interpsnapshotKeplerpotential_Rzderiv(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 2. s['eps']= 0. sp= potential.InterpSnapshotRZPotential(s, rgrid=(0.01,2.,101), zgrid=(0.,0.2,101), logR=False, interpPot=True, interpepifreq=True, interpverticalfreq=True, zsym=True) kp= potential.KeplerPotential(amp=2.) #should be the same #This just tests on the grid rs= numpy.linspace(0.01,2.,21)[1:] zs= numpy.linspace(-0.2,0.2,41) zs= zs[zs != 0.]# avoid zero # Test, but give small |z| a less constraining for r in rs: for z in zs: assert numpy.fabs((sp.Rzderiv(r,z)-kp.Rzderiv(r,z))/kp.Rzderiv(r,z)) < 10.**-4.*(1.+19.*(numpy.fabs(z) < 0.05)), 'RZPot interpolation of Rzderiv w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g) by %g; value is %g' % (r,z,numpy.fabs((sp.Rzderiv(r,z)-kp.Rzderiv(r,z))/kp.Rzderiv(r,z)),kp.Rzderiv(r,z)) #This tests within the grid rs= numpy.linspace(0.01,2.,10)[1:] zs= numpy.linspace(-0.2,0.2,20) for r in rs: for z in zs: assert numpy.fabs((sp.Rzderiv(r,z)-kp.Rzderiv(r,z))/kp.Rzderiv(r,z)) < 10.**-4.*(1.+19.*(numpy.fabs(z) < 0.05)), 'RZPot interpolation of Rzderiv w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g) by %g' % (r,z,numpy.fabs((sp.Rzderiv(r,z)-kp.Rzderiv(r,z))/kp.Rzderiv(r,z))) return None
def __init__(self, **kwargs): self.__kwargs = kwargs self.__profile = kwargs.get('profile', density_profiles.alphabetagamma) self.__drhodr = kwargs.get('drhodr', density_profiles.dalphabetagammadr) self.__d2rhodr2 = kwargs.get('d2rhodr2', density_profiles.d2alphabetagammadr2) self.__pars = kwargs.get('pars', {'alpha': 1., 'beta': 3., 'gamma': 1., 'c': 10., 'factor': 0.1}) if self.__profile == density_profiles.alphabetagamma and self.__pars['beta'] <= 3.: if 'factor' not in self.__pars.keys(): self.__pars['factor'] = 0.1 self.__m_vir = kwargs.get('m_vir', '1e12 Msol') self.__m_vir = units.Unit(self.__m_vir) self.__h = kwargs.get('h', 0.7) self.__overden = kwargs.get('overden', 200.) self.__r_vir = tools.calc_r_vir(self.__m_vir, self.__h, self.__overden) self.__r_s = self.__r_vir/self.__pars['c'] self.__n_particles = int(kwargs.get('n_particles', 1e5)) self.__logxmax_rho = np.log10(self.__pars['c']) + 2. # Make sure to sample well inside the gravitational softening self.__logxmin_rho = self.__logxmax_rho - .5*np.log10(self.__n_particles) - 3. self.__logxmin_dist_func = kwargs.get('logxmin_dist_func', -3.) self.__logxmax_dist_func = kwargs.get('logxmax_dist_func', 14.) self.__n_sample_rho = int(kwargs.get('n_sample_rho', 1e4)) self.__n_sample_dist_func = int(kwargs.get('n_sample_dist_func', 1e2)) self.__n_sample_dist_func_rho = int(kwargs.get('n_sample_dist_func_rho', 1e4)) self.__random_seed = kwargs.get('random_seed', 4) if 'prng' in kwargs.keys(): self.__prng = kwargs['prng'] else: self.__prng = np.random.RandomState(self.__random_seed) self.__spline_order = kwargs.get('spline_order', 3) self.__progress_bar = kwargs.get('progress_bar', False) self.__no_bulk_vel = kwargs.get('no_bulk_vel', True) self.__x_rho = np.logspace(self.__logxmin_rho, self.__logxmax_rho, self.__n_sample_rho) self.__f_bary = kwargs.get('f_bary', 0.1) self.__mu = kwargs.get('mu', 1.3) self.__spin_parameter = kwargs.get('spin_parameter', 0.04) self.__rot_balanced = kwargs.get('rot_balanced', False) # Different gas profiles are not yet implemented or successfully tested self.__gas_profile = self.__profile self.__gas_pars = self.__pars #self.__gas_profile = kwargs.get('gas_profile', density_profiles.alphabetagamma) #self.__gas_pars = kwargs.get('gas_pars', {'alpha': 1., 'beta': 3., 'gamma': 1., # 'c': 10., 'factor': 0.1}) self.__r_s_gas = self.__r_vir/self.__gas_pars['c'] #self.__vel_prof = kwargs.get('vel_prof', None) self.__vel_pars = kwargs.get('vel_pars', {'rs_v': array.SimArray(1., 'kpc'), 'c': self.__pars['c'], 'prefac': 1., 'factor': 1.}) self.__n_gas_particles = int(kwargs.get('n_gas_particles', self.__n_particles)) self.__ang_mom_prof = kwargs.get('ang_mom_prof', am_profiles.bullock_prof) self.__ang_mom_pars = kwargs.get('ang_mom_pars', {'mu': self.__mu}) self.__fname = kwargs.get('fname', 'halo.out') # Careful here: as of now, only the output as tipsy files has been successfully tested self.__type = {'gadget': gadget.GadgetSnap, 'grafic': grafic.GrafICSnap, 'nchilada': nchilada.NchiladaSnap, 'ramses': ramses.RamsesSnap, 'tipsy': tipsy.TipsySnap}[kwargs.get('type', 'tipsy')] self.sim = new(dm=self.__n_particles, gas=self.__n_gas_particles) self.sim.physical_units()
def test_family_filter(): f = pynbody.new(dm=100,gas=100) f_dm = f.dm f_dm_filter = f[pynbody.filt.FamilyFilter(pynbody.family.dm)] f_gas = f.gas f_gas_filter = f[pynbody.filt.FamilyFilter(pynbody.family.gas)] assert (f_dm.get_index_list(f) == f_dm_filter.get_index_list(f)).all() assert (f_gas.get_index_list(f) == f_gas_filter.get_index_list(f)).all()
def test_one_family_promotion(): fx = pynbody.new(dm=10) fx.dm['bla'] = np.arange(10) # should have been made as a full-simulation array assert 'bla' in fx.keys() fx['bla'] del fx
def setup(): global f f = pynbody.new(1000) f['pos'] = np.random.normal(scale=1.0, size=f['pos'].shape) f['vel'] = np.random.normal(scale=1.0, size=f['vel'].shape) f['mass'] = np.random.uniform(1.0, 10.0, size=f['mass'].shape) f['pos'].units = 'kpc' f['vel'].units = 'km s^-1' f['mass'].units = 'Msol'
def test_pickle() : import pickle f = pynbody.new(10) f['blob']=np.arange(10) s = f[[3,6,7]] assert (s['blob']==[3,6,7]).all(), "Preliminary check to testing pickle failed!" reloaded = pickle.loads(pickle.dumps(s['blob'])) assert (reloaded==[3,6,7]).all(), "Unpickled array had incorrect contents"
def setup(): global f, original f = pynbody.new(dm=1000) f['pos'] = np.random.normal(scale=1.0, size=f['pos'].shape) f['vel'] = np.random.normal(scale=1.0, size=f['vel'].shape) f['mass'] = np.random.uniform(1.0, 10.0, size=f['mass'].shape) original = copy.deepcopy(f)
def test_aform_saturation(): """Test that NaN is returned when tform cannot be calculated from aform""" ipoints = pynbody.analysis.cosmology._interp_points f = pynbody.new(ipoints + 1) f['aform'] = np.linspace(0.0,1.1,ipoints+1)-0.05 tf = f['tform'][::100] assert tf[0]!=tf[0] # nan outside range assert tf[-1]!=tf[-1] # nan outside range assert (tf[1:-1]==tf[1:-1]).all() # no nans inside range
def init_snapshot(IC): """ Initialize a snapshot for the IC object. Requires that positions have been created. Also sets: * pos * metals * temp * mass * star eps Parameters ---------- IC : ICobj Returns ------- snapshot : SimSnap """ # Get required settings from IC settings = IC.settings # particle positions r = IC.pos.r xyz = IC.pos.xyz nParticles = IC.pos.nParticles m_star = settings.physical.M m_disk = IC.sigma.m_disk m_disk = match_units(m_disk, m_star)[0] m_particles = m_disk / float(nParticles) metals = settings.snapshot.metals # re-scale the particles (allows making of lo-mass disk) m_particles *= settings.snapshot.mScale # Handle units units = setup_units(m_star, r) if xyz.units != r.units: xyz.convert_units(units['x']) # Initialize arrays snapshot = pynbody.new(star=1,gas=nParticles) snapshot['vel'].units = units['v'] snapshot['eps'] = SimArray(0.01, units['x']) snapshot['rho'] = 0. snapshot['metals'] = metals # Assign array values snapshot.gas['pos'] = xyz snapshot.gas['temp'] = IC.T(r) snapshot.gas['mass'] = m_particles snapshot.star['pos'] = 0. snapshot.star['mass'] = m_star # Estimate the star's softening length as the closest particle distance/2 snapshot.star['eps'] = r.min()/2. return snapshot
def test_potential_profile_fp32(): f = pynbody.new(100) coords = np.random.normal(size=(100,3)) del f['pos'] del f['mass'] f['pos'] = np.array(coords,dtype=np.float32) f['eps'] = np.ones(100,dtype=np.float32) f['mass'] = np.ones(100,dtype=np.float32) p = pynbody.analysis.profile.Profile(f, nbins=50) p['pot']
def test_gravity_float(): f = pynbody.new(100) np.random.seed(0) coords = np.random.normal(size=(100,3)) del f['pos'] del f['mass'] f['pos'] = np.array(coords,dtype=np.float32) f['eps'] = np.ones(100,dtype=np.float32) f['mass'] = np.ones(100,dtype=np.float32) pynbody.gravity.calc.all_direct(f)
def test_family_array_null_slice(): """Regression test for issue where getting a family array for an IndexedSubSnap containing no members of that family - would erroneously return the entire family array""" test = pynbody.new(dm=10, star=10, order='dm,star') test.star['TestFamilyArray'] = 1.0 assert len(test[[1,3,5,7]].star)==0 # this always succeeded assert len(test[[1,3,5,7]].star['mass'])==0 # this always succeeded assert len(test[1:9:2].star['TestFamilyArray'])==0 # this always succeeded assert len(test[[1, 3, 5, 11,13]].star['TestFamilyArray']) == 2 # this always succeeded assert len(test[[1,3,5,7]].star['TestFamilyArray'])==0 # this would fail
def test_a_to_t(): """Test scalefactor -> time conversion for accuracy. See also issue #479""" f = pynbody.new() # for default cosmology ipoints = pynbody.analysis.cosmology._interp_points interp_a = np.linspace(0.005, 1.0, ipoints+1) # enough values to force interpolation rather than direct calculation interp_z = 1./interp_a - 1. interp_t = pynbody.analysis.cosmology.age(f, z=interp_z) direct_aform = interp_a[::100] z = 1./direct_aform-1. direct_tform = pynbody.analysis.cosmology.age(f,z) npt.assert_almost_equal(direct_tform, interp_t[::100], decimal=4)
def test_snapshotKeplerPotential_hash(): # Test that hashing the previous grid works # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 1. s['eps']= 0. sp= potential.SnapshotRZPotential(s) kp= potential.KeplerPotential(amp=1.) #should be the same assert numpy.fabs(sp(1.,0.)-kp(1.,0.)) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' assert numpy.fabs(sp(1.,0.)-kp(1.,0.)) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' return None
def test_write() : f2 = pynbody.new(dm=10,star=10,gas=20) f2.dm['test_array']=np.ones(10) f2['x']=np.arange(0,40) f2['vx']=np.arange(40,80) f2.write(fmt=pynbody.tipsy.TipsySnap, filename="testdata/test_out.tipsy") f3 = pynbody.load("testdata/test_out.tipsy") assert all(f3['x']==f2['x']) assert all(f3['vx']==f3['vx']) assert all(f3.dm['test_array']==f2.dm['test_array'])
def test_snapshotKeplerPotential_zforce_naz(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 1. s['eps']= 0. sp= potential.SnapshotRZPotential(s,num_threads=1) spaz= potential.SnapshotRZPotential(s,num_threads=1,nazimuths=12) assert numpy.fabs(sp.zforce(1.,0.)-spaz.zforce(1.,0.)) < 10.**-8., 'SnapshotRZPotential with single unit mass for naz=4 does not agree with naz=12' assert numpy.fabs(sp.zforce(0.5,0.)-spaz.zforce(0.5,0.)) < 10.**-8., 'SnapshotRZPotential with single unit mass for naz=4 does not agree with naz=12' assert numpy.fabs(sp.zforce(1.,0.5)-spaz.zforce(1.,0.5)) < 10.**-8., 'SnapshotRZPotential with single unit mass for naz=4 does not agree with naz=12' assert numpy.fabs(sp.zforce(1.,-0.5)-spaz.zforce(1.,-0.5)) < 10.**-8., 'SnapshotRZPotential with single unit mass for naz=4 does not agree with naz=12' return None
def test_snapshotKeplerPotential_zforce_array(): # Test evaluating the snapshotPotential with array input # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 1. s['eps']= 0. sp= potential.SnapshotRZPotential(s) kp= potential.KeplerPotential(amp=1.) #should be the same rs= numpy.ones(3)*0.5+0.5 zs= (numpy.zeros(3)-1.)/2. assert numpy.all(numpy.fabs(sp.zforce(rs,zs)-kp.zforce(rs,zs)) < 10.**-8.), 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' return None
def test_snapshotKeplerPotential_grid(): # Test that evaluating on a grid works # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 2. s['eps']= 0. sp= potential.SnapshotRZPotential(s) kp= potential.KeplerPotential(amp=2.) #should be the same rs= numpy.arange(3)+1 zs= 0.1 assert numpy.all(numpy.fabs(sp(rs,zs)-kp(rs,zs)) < 10.**-8.), 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' return None
def test_ndim_issue_399(): f = pynbody.new(10) f_sub = f[[1,2,3,6]] f['blob'] = np.arange(10) assert f['blob'].ndim==1 assert f_sub['blob'].ndim==1 f['blob_3d'] = np.zeros((10,3)) assert f['blob_3d'].ndim==2 assert f['blob_3d'].shape==(10,3) assert f_sub['blob_3d'].ndim==2 assert f_sub['blob_3d'].shape==(4,3)
def test_snapshotKeplerPotential_eval(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 1. s['eps']= 0. sp= potential.SnapshotRZPotential(s,num_threads=1) kp= potential.KeplerPotential(amp=1.) #should be the same assert numpy.fabs(sp(1.,0.)-kp(1.,0.)) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' assert numpy.fabs(sp(0.5,0.)-kp(0.5,0.)) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' assert numpy.fabs(sp(1.,0.5)-kp(1.,0.5)) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' assert numpy.fabs(sp(1.,-0.5)-kp(1.,-0.5)) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' return None
def test_nonmonotonic_transfer_matrix(): # test the case where a non-monotonic bridge between two simulations is queries for particle transfer f1 = pynbody.new(dm=10) f2 = pynbody.new(dm=10) f1['iord'] = np.arange(0,10) f2['iord'] = np.array([0,2,4,6,8,1,3,5,7,9],dtype=np.int32) # 100% of mass in group 1 transfers to group 1 # 80% of mass in group 0 transfers to group 0 # 20% of mass in group 0 transfers to group 1 f1['grp'] = np.array([0,0,0,0,0,1,1,1,1,1],dtype=np.int32) f2['grp'] = np.array([0,0,0,0,1,1,1,1,1,1],dtype=np.int32)[f2['iord']] b = pynbody.bridge.OrderBridge(f1,f2,monotonic=False) h1 = pynbody.halo.GrpCatalogue(f1) h2 = pynbody.halo.GrpCatalogue(f2) xfer = b.catalog_transfer_matrix(0,1,h1,h2) assert (xfer==[[4,1],[0,5]]).all()
def get_final_density(input_linear_field, output_resolution=None, time=0.025): """Starting from a linear field, generate the equivalent non-linear field under the Zeldovich approximation at the specified time. If the output resolution is not specified, it is chosen to match in the input resolution. Output is both returned as a numpy array and displayed in a matplotlib window.""" assert input_linear_field.shape[0] == input_linear_field.shape[1] N = len(input_linear_field) if not output_resolution: output_resolution = N x, y = get_evolved_particle_positions(input_linear_field, time) f = pynbody.new(len(x)) f['x'] = x - N / 2 f['y'] = y - N / 2 f['mass'] = 1.0 f['mass'].units = "kg" f['x'].units = "cm" return pynbody.plot.sph.image(f, width=N, resolution=output_resolution, units="kg cm^-2")
def test_snapshotKeplerPotential_eval(): # Set up a snapshot with just one unit mass at the origin s = pynbody.new(star=1) s['mass'] = 1. s['eps'] = 0. sp = potential.SnapshotRZPotential(s, num_threads=1) kp = potential.KeplerPotential(amp=1.) #should be the same assert numpy.fabs( sp(1., 0.) - kp(1., 0.) ) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' assert numpy.fabs( sp(0.5, 0.) - kp(0.5, 0.) ) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' assert numpy.fabs( sp(1., 0.5) - kp(1., 0.5) ) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' assert numpy.fabs( sp(1., -0.5) - kp(1., -0.5) ) < 10.**-8., 'SnapshotRZPotential with single unit mass does not correspond to KeplerPotential' return None
def test_interpsnapshotKeplerPotential_logR_eval(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 1. s['eps']= 0. sp= potential.InterpSnapshotRZPotential(s, rgrid=(numpy.log(0.01),numpy.log(20.), 251), logR=True, zgrid=(0.,0.2,201), interpPot=True, zsym=True) kp= potential.KeplerPotential(amp=1.) #should be the same rs= numpy.linspace(0.02,16.,20) zs= numpy.linspace(-0.15,0.15,40) mr,mz= numpy.meshgrid(rs,zs) mr= mr.flatten() mz= mz.flatten() assert numpy.all(numpy.fabs((sp(mr,mz)-kp(mr,mz))/kp(mr,mz)) < 10.**-5.), 'RZPot interpolation w/ interpRZPotential fails for vector input, w/ logR at (R,z) = (%f,%f) by %g' % (mr[numpy.argmax(numpy.fabs((sp(mr,mz)-kp(mr,mz))/kp(mr,mz)))],mz[numpy.argmax(numpy.fabs((sp(mr,mz)-kp(mr,mz))/kp(mr,mz)))],numpy.amax(numpy.fabs((sp(mr,mz)-kp(mr,mz))/kp(mr,mz)))) return None
def test_snapshotKeplerPotential_zforce_naz(): # Set up a snapshot with just one unit mass at the origin s = pynbody.new(star=1) s['mass'] = 1. s['eps'] = 0. sp = potential.SnapshotRZPotential(s, num_threads=1) spaz = potential.SnapshotRZPotential(s, num_threads=1, nazimuths=12) assert numpy.fabs( sp.zforce(1., 0.) - spaz.zforce(1., 0.) ) < 10.**-8., 'SnapshotRZPotential with single unit mass for naz=4 does not agree with naz=12' assert numpy.fabs( sp.zforce(0.5, 0.) - spaz.zforce(0.5, 0.) ) < 10.**-8., 'SnapshotRZPotential with single unit mass for naz=4 does not agree with naz=12' assert numpy.fabs( sp.zforce(1., 0.5) - spaz.zforce(1., 0.5) ) < 10.**-8., 'SnapshotRZPotential with single unit mass for naz=4 does not agree with naz=12' assert numpy.fabs( sp.zforce(1., -0.5) - spaz.zforce(1., -0.5) ) < 10.**-8., 'SnapshotRZPotential with single unit mass for naz=4 does not agree with naz=12' return None
def test_interpsnapshotKeplerPotential_noc_eval(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 1. s['eps']= 0. sp= potential.InterpSnapshotRZPotential(s, rgrid=(0.01,2.,201), zgrid=(0.,0.2,201), logR=False, interpPot=True, zsym=True, enable_c=False) kp= potential.KeplerPotential(amp=1.) #should be the same #Test all at the same time to use vector evaluation rs= numpy.linspace(0.01,2.,10) zs= numpy.linspace(-0.2,0.2,20) mr,mz= numpy.meshgrid(rs,zs) mr= mr.flatten() mz= mz.flatten() assert numpy.all(numpy.fabs((sp(mr,mz)-kp(mr,mz))/kp(mr,mz)) < 10.**-5.), 'RZPot interpolation w/ interpRZPotential fails for vector input, without enable_c' return None
def test_write(): f2 = pynbody.new(gas=20, star=11, dm=9, order='gas,dm,star') f2.dm['test_array'] = np.ones(9) f2['x'] = np.arange(0, 40) f2['vx'] = np.arange(40, 80) f2.properties['a'] = 0.5 f2.properties['time'] = 12.0 f2.write(fmt=pynbody.tipsy.TipsySnap, filename="testdata/test_out.tipsy") f3 = pynbody.load("testdata/test_out.tipsy") assert all(f3['x'] == f2['x']) assert all(f3['vx'] == f3['vx']) assert all(f3.dm['test_array'] == f2.dm['test_array']) assert f3.properties['a'] == 0.5 # this looks strange, but it's because the .param file in the testdata folder implies a cosmological tipsy snap # whereas we have just written the snapshot asserting it is non-cosmological f2.write(fmt=pynbody.tipsy.TipsySnap, filename="testdata/test_out.tipsy", cosmological=False) f3 = pynbody.load("testdata/test_out.tipsy") assert f3.properties['a'] == 12
def test_interpsnapshotKeplerPotential_eval_naz(): # Set up a snapshot with just one unit mass at the origin s = pynbody.new(star=1) s['mass'] = 1. s['eps'] = 0. sp = potential.InterpSnapshotRZPotential(s, rgrid=(0.01, 2., 51), zgrid=(0., 0.2, 51), logR=False, interpPot=True, zsym=True, numcores=1) spaz = potential.InterpSnapshotRZPotential(s, rgrid=(0.01, 2., 51), zgrid=(0., 0.2, 51), logR=False, interpPot=True, zsym=True, numcores=1, nazimuths=12) #This just tests on the grid rs = numpy.linspace(0.01, 2., 21) zs = numpy.linspace(-0.2, 0.2, 41) for r in rs: for z in zs: assert numpy.fabs( (sp(r, z) - spaz(r, z)) / sp(r, z) ) < 10.**-10., 'RZPot interpolation w/ InterpSnapShotPotential of KeplerPotential with different nazimuths fails at (R,z) = (%g,%g)' % ( r, z) #This tests within the grid, with vector evaluation rs = numpy.linspace(0.01, 2., 10) zs = numpy.linspace(-0.2, 0.2, 20) mr, mz = numpy.meshgrid(rs, zs) mr = mr.flatten() mz = mz.flatten() assert numpy.all( numpy.fabs((sp(mr, mz) - spaz(mr, mz)) / sp(mr, mz)) < 10.**-5. ), 'RZPot interpolation w/ interpRZPotential with different nazimimuths fails for vector input' return None
def test_interpsnapshotKeplerPotential_eval(): # Set up a snapshot with just one unit mass at the origin s = pynbody.new(star=1) s['mass'] = 1. s['eps'] = 0. sp = potential.InterpSnapshotRZPotential(s, rgrid=(0.01, 2., 201), zgrid=(0., 0.2, 201), logR=False, interpPot=True, zsym=True, numcores=1) kp = potential.KeplerPotential(amp=1.) #should be the same #This just tests on the grid rs = numpy.linspace(0.01, 2., 21) zs = numpy.linspace(-0.2, 0.2, 41) for r in rs: for z in zs: assert numpy.fabs( (sp(r, z) - kp(r, z)) / kp(r, z) ) < 10.**-10., 'RZPot interpolation w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g)' % ( r, z) #This tests within the grid rs = numpy.linspace(0.01, 2., 10) zs = numpy.linspace(-0.2, 0.2, 20) for r in rs: for z in zs: assert numpy.fabs( (sp(r, z) - kp(r, z)) / kp(r, z) ) < 10.**-5., 'RZPot interpolation w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g) by %g' % ( r, z, numpy.fabs((sp(r, z) - kp(r, z)) / kp(r, z))) #Test all at the same time to use vector evaluation mr, mz = numpy.meshgrid(rs, zs) mr = mr.flatten() mz = mz.flatten() assert numpy.all( numpy.fabs((sp(mr, mz) - kp(mr, mz)) / kp(mr, mz)) < 10.**-5. ), 'RZPot interpolation w/ interpRZPotential fails for vector input' return None
def test_interpsnapshotKeplerPotential_verticalfreq(): # Set up a snapshot with just one unit mass at the origin s= pynbody.new(star=1) s['mass']= 2. s['eps']= 0. sp= potential.InterpSnapshotRZPotential(s, rgrid=(0.01,2.,101), zgrid=(0.,0.2,101), logR=False, interpPot=True, interpverticalfreq=True, zsym=True) kp= potential.KeplerPotential(normalize=2.) #should be the same #This just tests on the grid rs= numpy.linspace(0.01,2.,21)[1:] for r in rs: assert numpy.fabs((sp.verticalfreq(r)-kp.verticalfreq(r))/kp.verticalfreq(r)) < 10.**-4., 'RZPot interpolation of verticalfreq w/ InterpSnapShotPotential of KeplerPotential fails at R = %g by %g' % (r,numpy.fabs((sp.verticalfreq(r)-kp.verticalfreq(r))/kp.verticalfreq(r))) #This tests within the grid rs= numpy.linspace(0.01,2.,10)[1:] for r in rs: assert numpy.fabs((sp.verticalfreq(r)-kp.verticalfreq(r))/kp.verticalfreq(r)) < 10.**-4., 'RZPot interpolation of verticalfreq w/ InterpSnapShotPotential of KeplerPotential fails at R = %g by %g' % (r,numpy.fabs((sp.verticalfreq(r)-kp.verticalfreq(r))/kp.verticalfreq(r))) return None
def test_dimensionful_comparison(): # check that dimensionful units compare correctly # see issue 130 a1 = SA(np.ones(2), 'kpc') a2 = SA(np.ones(2) * 2, 'pc') assert (a2 < a1).all() assert not (a2 > a1).any() a2 = SA(np.ones(2) * 1000, 'pc') assert (a1 == a2).all() assert (a2 <= a2).all() a2 = SA(np.ones(2), 'Msol') try: a2 < a1 assert False, "Comparison should have failed - incompatible units" except pynbody.units.UnitsException: pass a2 = SA(np.ones(2)) try: a2 < a1 assert False, "Comparison should have failed - incompatible units" except pynbody.units.UnitsException: pass assert (a1 < pynbody.units.Unit("0.5 Mpc")).all() assert (a1 > pynbody.units.Unit("400 pc")).all() # now check with subarrays x = pynbody.new(10) x['a'] = SA(np.ones(10), 'kpc') x['b'] = SA(2 * np.ones(10), 'pc') y = x[[1, 2, 5]] assert (y['b'] < y['a']).all() assert not (y['b'] > y['a']).any()
def test_interpsnapshotKeplerPotential_normalize_units(): # Set up a snapshot with just one unit mass at the origin s = pynbody.new(star=1) s['mass'] = 4. s['eps'] = 0. s['pos'].units = 'kpc' s['vel'].units = 'km s**-1' sp = potential.InterpSnapshotRZPotential(s, rgrid=(0.01, 3., 201), zgrid=(0., 0.2, 201), logR=False, interpPot=True, zsym=True) #Currently unnormalized assert numpy.fabs( sp.Rforce(1., 0.) + 4. ) < 10.**-7., "InterpSnapShotPotential that is assumed to be unnormalized doesn't behave as expected" # Normalize sp.normalize(R0=1.) assert numpy.fabs( sp.Rforce(1., 0.) + 1. ) < 10.**-7., "InterpSnapShotPotential that is assumed to be normalized doesn't behave as expected" # De normalize sp.denormalize() assert numpy.fabs( sp.Rforce(1., 0.) + 4. ) < 10.**-7., "InterpSnapShotPotential that is assumed to be normalized doesn't behave as expected" # Also test when R0 =/= 1 sp.normalize(R0=2.) assert numpy.fabs( sp.Rforce(1., 0.) + 1. ) < 10.**-7., "InterpSnapShotPotential that is assumed to be normalized doesn't behave as expected" # De normalize sp.denormalize() assert numpy.fabs( sp.Rforce(1., 0.) + 4. ) < 10.**-7., "InterpSnapShotPotential that is assumed to be normalized doesn't behave as expected" return None
def test_sim_propagation(): f = pynbody.new(10) f['blob'] = 0 # check arrays remember their simulation assert f['blob'].sim is f assert f[::2]['blob'].sim is f assert f[[1, 2, 5]]['blob'].sim.ancestor is f assert f[[1, 2, 5]]['blob'].sim is not f # if we do anything that constructs a literal SimArray, the simulation # reference jumps up to be the main snapshot since we can't keep track # of what SubSnap it came from in generality assert pynbody.array.SimArray(f[[1, 2, 5]]['blob']).sim is f assert (f[[1, 2, 5]]['blob']).sum().sim is f # the reference should be weak: check X = f['blob'] assert X.sim is f del f gc.collect() assert X.sim is None
def test_interpsnapshotKeplerPotential_z2deriv(): # Set up a snapshot with just one unit mass at the origin s = pynbody.new(star=1) s['mass'] = 2. s['eps'] = 0. sp = potential.InterpSnapshotRZPotential(s, rgrid=(0.01, 2., 101), zgrid=(0., 0.2, 101), logR=False, interpPot=True, interpverticalfreq=True, zsym=True) kp = potential.KeplerPotential(amp=2.) #should be the same #This just tests on the grid rs = numpy.linspace(0.01, 2., 21)[1:] zs = numpy.linspace(-0.2, 0.2, 41) for r in rs: for z in zs: assert numpy.fabs( (sp.z2deriv(r, z) - kp.z2deriv(r, z)) / kp.z2deriv(r, z) ) < 10.**-4., 'RZPot interpolation of z2deriv w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g) by %g' % ( r, z, numpy.fabs( (sp.z2deriv(r, z) - kp.z2deriv(r, z)) / kp.z2deriv(r, z))) #This tests within the grid rs = numpy.linspace(0.01, 2., 10)[1:] zs = numpy.linspace(-0.2, 0.2, 20) for r in rs: for z in zs: assert numpy.fabs( (sp.z2deriv(r, z) - kp.z2deriv(r, z)) / kp.z2deriv(r, z) ) < 2. * 10.**-4., 'RZPot interpolation of z2deriv w/ InterpSnapShotPotential of KeplerPotential fails at (R,z) = (%g,%g) by %g' % ( r, z, numpy.fabs( (sp.z2deriv(r, z) - kp.z2deriv(r, z)) / kp.z2deriv(r, z))) return None
def test_float_kd(): f = pynbody.load("testdata/test_g2_snap") del f.properties['boxsize'] assert f.dm['mass'].dtype == f.dm['pos'].dtype == np.float32 assert f.dm['smooth'].dtype == np.float32 # make double copy g = pynbody.new(len(f.dm)) g.dm['pos'] = f.dm['pos'] g.dm['mass'] = f.dm['mass'] assert g.dm['mass'].dtype == g.dm['pos'].dtype == g.dm[ 'smooth'].dtype == np.float64 # check smoothing lengths agree (they have been calculated differently # using floating/double routines) npt.assert_allclose(f.dm['smooth'], g.dm['smooth'], rtol=1e-4) npt.assert_allclose(f.dm['rho'], g.dm['rho'], rtol=1e-4) # check all combinations of float/double smoothing double_ar = np.ones(len(f.dm), dtype=np.float64) float_ar = np.ones(len(f.dm), dtype=np.float32) double_double = g.dm.kdtree.sph_mean(double_ar, 32) double_float = g.dm.kdtree.sph_mean(float_ar, 32) float_double = f.dm.kdtree.sph_mean(double_ar, 32) float_float = f.dm.kdtree.sph_mean(float_ar, 32) # take double-double as 'gold standard' (though of course if any of these # fail it could also be a problem with the double-double case) npt.assert_allclose(double_double, double_float, rtol=1e-4) npt.assert_allclose(double_double, float_double, rtol=1e-4) npt.assert_allclose(double_double, float_float, rtol=1e-4)
def test_family_array_sim(): """Test that the simulation of a family array is a family slice""" test = pynbody.new(dm=10, star=10) test.dm._create_array('mass') assert test.dm['mass'].sim == test.dm
def wave1d(rho0=1., dustFrac0=0.5, drho=1e-4, v0=1e-4, gamma=5./3, cs=1., ngas=100, L=1., tStop=5e-4, nSmooth=5, nPeriods=1): r""" Generate a 1D dusty-gas wave as in Price & Laibe 2015. I've only gotten this to work with the M4Kernel and nSmooth = 4 or 5. Other kernels or nSmooth create noisy garbage Default params are stored in 'wave_defaults.param' and can be overridden in 'user_wave_defaults.param' This applies perturbations like: .. math:: \rho(z) &= \rho_0 (1 + \delta\rho\sin{(2 \pi N z/L)}) \\ v(z) &= v_0 \sin{(2 \pi N z/L)} \\ P(z) &= P_0 + c_s v_0 \rho_0 \sin{(2 \pi N z/L)} [1 + (\delta\rho/2) \sin{(2 \pi N z/L)}] Which makes a wave moving to the right at the speed of sound :math:`c_s`. The pressure perturbation is derived from the density and velocity perturbations using the momentum equation and assuming sinewaves travelling to the right at cs Parameters ---------- All parameters listed are in code units! rho0: float Base total density. :math:`\rho_0` dustFrac: float Dust fraction of the gas. drho: float Fractional amplitude of density perturbation v0: float Velocity perturbation amplitude gamma: float Adiabatic index cs: float Sound speed ngas: int Number of particles L: float Length of the periodic box tStop: float Stopping time of the dust nSmooth: int Number of neighbors for smoothing nPeriods: float or int Number of wave periods to fit in the box Returns ------- snapshot: pynbody SimSnap ICs for the simulation. they will also be saved to disk param: dict Runtime params. Also saved to a .param file paramname: str Path to the saved param file """ args = locals() nDim = 1 pickle.dump(args, open(argname, 'w'), 2) print 'Saved args to:', argname param = testdust.utils.loadDefaultParam(defaultParam1D, userDefaults1D) # ------------------------------------------- # Parse input param file # ------------------------------------------- # Get units units = diskpy.pychanga.units_from_param(param) # filenames fname = param['achInFile'] outparam = param['achOutName'] + '.param' molecularWeight = param['dMeanMolWeight'] # ------------------------------------------- # Set-up # ------------------------------------------- mass = rho0/(L * float(ngas)) # Give everything units v0 = SimArray(v0, units['v_unit']) cs = SimArray(cs, units['v_unit']) rho0 = SimArray(rho0, units['rho_unit']) L = SimArray(L, units['l_unit']) mass = SimArray(mass, units['m_unit']) tStop = SimArray(tStop, units['t_unit']) molecularWeight = SimArray(molecularWeight, 'm_p') # Initialize snapshot snap = pynbody.new(gas=ngas) # Initialize arrays for key in ('temp', 'rho', 'dustFrac', 'pos', 'mass'): snap[key] = 0. k = 2 * np.pi * nPeriods/L # ------------------------------------------- # Positions and mass # ------------------------------------------- z = wavePos(ngas, drho, L, nPeriods) snap['z'] = z snap['mass'] = mass # ------------------------------------------- # Temperature # ------------------------------------------- P0 = rho0 * (cs**2)/gamma P = P0 + cs * v0 * rho0 * np.sin(k * z) * (1 + 0.5 * drho * np.sin(k * z)) rho = rho0 * (1 + drho * np.sin(k * z)) T = molecularWeight * P/(kB * (1-dustFrac0) * rho) T.convert_units('K') print 'Temp:', T snap['temp'] = T # ------------------------------------------- # Velocity profile # ------------------------------------------- vz = v0 * np.sin(2*np.pi*snap['z']*nPeriods/L) v = SimArray(np.zeros([ngas, 3]), vz.units) v[:,2] = vz snap['vel'] = v # ------------------------------------------- # Dust stuff # ------------------------------------------- # Dust mass grainDensity = rho0*cs*tStop*np.sqrt(8/np.pi/gamma)/units['l_unit'] grainDensity.convert_units(units['rho_unit']) param['dDustSize'] = 1. param['dDustGrainDensity'] = float(grainDensity) # Define dust fraction snap['dustFrac'] = dustFrac0 * np.ones(ngas) # Estimate density and eps snap['rho'] snap['eps'] = 100 * L/ngas**(nDim/3.) # ------------------------------------------- # Write out # ------------------------------------------- testdust.utils.setupParamBounds(param, [float(L)]) param['nSmooth'] = nSmooth param['dConstGamma'] = gamma # Write out snapshot and paramfile snap.write(fmt=pynbody.tipsy.TipsySnap, filename=fname, double_pos=True, \ double_vel=True) print 'Saved snapshot to:', fname diskpy.utils.configsave(param, outparam, 'param') print 'Saved .param to:', outparam return snap, param, outparam
def test_reject_unsuitable_rockstar_files(): fwrong = pynbody.new(dm=2097152) fwrong.properties['z'] = 0 with pytest.raises(RuntimeError): hwrong = fwrong.halos()
import pynbody import numpy as np from pynbody.array import SimArray if __name__ == '__main__': f = pynbody.new(star=8) mass_prefactor = 1e4 f['pos'] = SimArray(np.array([ [-2, 2, 2], [-2, 2, -2], [-2, -2, 2], [-2, -2, -2], [ 2, -2, 2], [ 2, -2, -2], [ 2, 2, 2], [ 2, 2, -2]] )*0.8, units='kpc') f['vel'] = SimArray(np.array([[0, 0, -60],[0,0,80]]*4), units='km s**-1') f['mass'] = SimArray([1e-10]*8, units='1e10 Msol') * mass_prefactor # f.properties['time'] = 14 * pynbody.units.Unit('s kpc km**-1') # the 1 minus part is because in the output time is set to 1 in internal units , so that the age is 1 minus the tform. f['tform'] = 1 * pynbody.units.Unit('s kpc km**-1') - SimArray([1,1]*2+[1,4]*2, units='Gyr') print(f['tform']) f['feh'] = SimArray([-1.22,-1.22]+[0.29, -1.22]*2 + [-1.22, -1.22]) f.properties['boxsize'] = 1000 * pynbody.units.kpc print(f.properties) pynbody.config['sph']['smooth-particles'] = 1
def snapshot_gen(ICobj): """ Generates a tipsy snapshot from the initial conditions object ICobj. Returns snapshot, param snapshot: tipsy snapshot param: dictionary containing info for a .param file Note: Code has been edited (dflemin3) such that now it returns a snapshot for a circumbinary disk where initial conditions generated assuming star at origin of mass M. After gas initialized, replaced star at origin with binary system who's center of mass lies at the origin and who's mass m1 +m2 = M """ print 'Generating snapshot...' # Constants G = SimArray(1.0,'G') # ------------------------------------ # Load in things from ICobj # ------------------------------------ print 'Accessing data from ICs' settings = ICobj.settings # snapshot file name snapshotName = settings.filenames.snapshotName paramName = settings.filenames.paramName # particle positions r = ICobj.pos.r xyz = ICobj.pos.xyz # Number of particles nParticles = ICobj.pos.nParticles # molecular mass m = settings.physical.m # star mass m_star = settings.physical.M.copy() # disk mass m_disk = ICobj.sigma.m_disk.copy() m_disk = match_units(m_disk, m_star)[0] # mass of the gas particles m_particles = m_disk / float(nParticles) # re-scale the particles (allows making of low-mass disk) m_particles *= settings.snapshot.mScale # ------------------------------------------------- # Assign output # ------------------------------------------------- print 'Assigning data to snapshot' # Get units all set up m_unit = m_star.units pos_unit = r.units if xyz.units != r.units: xyz.convert_units(pos_unit) # time units are sqrt(L^3/GM) t_unit = np.sqrt((pos_unit**3)*np.power((G*m_unit), -1)).units # velocity units are L/t v_unit = (pos_unit/t_unit).ratio('km s**-1') # Make it a unit, save value for future conversion v_unit_vel = v_unit #Ensure v_unit_vel is the same as what I assume it is. assert(np.fabs(AddBinary.VEL_UNIT-v_unit_vel)<AddBinary.SMALL),"VEL_UNIT not equal to ChaNGa unit! Why??" v_unit = pynbody.units.Unit('{0} km s**-1'.format(v_unit)) # Other settings metals = settings.snapshot.metals star_metals = metals # Generate snapshot # Note that empty pos, vel, and mass arrays are created in the snapshot snapshot = pynbody.new(star=1,gas=nParticles) snapshot['vel'].units = v_unit snapshot['eps'] = 0.01*SimArray(np.ones(nParticles+1, dtype=np.float32), pos_unit) snapshot['metals'] = SimArray(np.zeros(nParticles+1, dtype=np.float32)) snapshot['rho'] = SimArray(np.zeros(nParticles+1, dtype=np.float32)) snapshot.gas['pos'] = xyz snapshot.gas['temp'] = ICobj.T(r) snapshot.gas['mass'] = m_particles snapshot.gas['metals'] = metals snapshot.star['pos'] = SimArray([[ 0., 0., 0.]],pos_unit) snapshot.star['vel'] = SimArray([[ 0., 0., 0.]], v_unit) snapshot.star['mass'] = m_star snapshot.star['metals'] = SimArray(star_metals) # Estimate the star's softening length as the closest particle distance #snapshot.star['eps'] = r.min() # Make param file param = make_param(snapshot, snapshotName) param['dMeanMolWeight'] = m gc.collect() # CALCULATE VELOCITY USING calc_velocity.py. This also estimates the # gravitational softening length eps print 'Calculating circular velocity' preset = settings.changa_run.preset max_particles = global_settings['misc']['max_particles'] calc_velocity.v_xy(snapshot, param, changa_preset=preset, max_particles=max_particles) gc.collect() # ------------------------------------------------- # Estimate time step for changa to use # ------------------------------------------------- # Save param file configsave(param, paramName, 'param') # Save snapshot snapshot.write(filename=snapshotName, fmt=pynbody.tipsy.TipsySnap) # est dDelta dDelta = ICgen_utils.est_time_step(paramName, preset) param['dDelta'] = dDelta # ------------------------------------------------- # Create director file # ------------------------------------------------- # largest radius to plot r_director = float(0.9 * r.max()) # Maximum surface density sigma_min = float(ICobj.sigma(r_director)) # surface density at largest radius sigma_max = float(ICobj.sigma.input_dict['sigma'].max()) # Create director dict director = make_director(sigma_min, sigma_max, r_director, filename=param['achOutName']) ## Save .director file #configsave(director, directorName, 'director') #Now that velocities and everything are all initialized for gas particles, create new snapshot to return in which #single star particle is replaced by 2, same units as above snapshotBinary = pynbody.new(star=2,gas=nParticles) snapshotBinary['eps'] = 0.01*SimArray(np.ones(nParticles+2, dtype=np.float32), pos_unit) snapshotBinary['metals'] = SimArray(np.zeros(nParticles+2, dtype=np.float32)) snapshotBinary['vel'].units = v_unit snapshotBinary['pos'].units = pos_unit snapshotBinary['mass'].units = snapshot['mass'].units snapshotBinary['rho'] = SimArray(np.zeros(nParticles+2, dtype=np.float32)) #Assign gas particles with calculated/given values from above snapshotBinary.gas['pos'] = snapshot.gas['pos'] snapshotBinary.gas['vel'] = snapshot.gas['vel'] snapshotBinary.gas['temp'] = snapshot.gas['temp'] snapshotBinary.gas['rho'] = snapshot.gas['rho'] snapshotBinary.gas['eps'] = snapshot.gas['eps'] snapshotBinary.gas['mass'] = snapshot.gas['mass'] snapshotBinary.gas['metals'] = snapshot.gas['metals'] #Load Binary system obj to initialize system binsys = ICobj.settings.physical.binsys x1,x2,v1,v2 = binsys.generateICs() #Put velocity in sim units #!!! Note: v_unit_vel will always be 29.785598165 km/s when m_unit = Msol and r_unit = 1 AU in kpc!!! #conv = v_unit_vel #km/s in sim units #v1 /= conv #v2 /= conv #Assign position, velocity assuming CCW orbit snapshotBinary.star[0]['pos'] = SimArray(x1,pos_unit) snapshotBinary.star[0]['vel'] = SimArray(v1,v_unit) snapshotBinary.star[1]['pos'] = SimArray(x2,pos_unit) snapshotBinary.star[1]['vel'] = SimArray(v2,v_unit) #Set stellar masses #Set Mass units #Create simArray for mass, convert units to simulation mass units priMass = SimArray(binsys.m1,m_unit) secMass = SimArray(binsys.m2,m_unit) snapshotBinary.star[0]['mass'] = priMass snapshotBinary.star[1]['mass'] = secMass snapshotBinary.star['metals'] = SimArray(star_metals) #Estimate stars' softening length as fraction of distance to COM d = np.sqrt(AddBinary.dotProduct(x1-x2,x1-x2)) snapshotBinary.star[0]['eps'] = SimArray(math.fabs(d)/4.0,pos_unit) snapshotBinary.star[1]['eps'] = SimArray(math.fabs(d)/4.0,pos_unit) print 'Wrapping up' # Now set the star particle's tform to a negative number. This allows # UW ChaNGa treat it as a sink particle. snapshotBinary.star['tform'] = -1.0 #Set Sink Radius to be mass-weighted average of Roche lobes of two stars r1 = AddBinary.calcRocheLobe(binsys.m1/binsys.m2,binsys.a) r2 = AddBinary.calcRocheLobe(binsys.m2/binsys.m1,binsys.a) p = strip_units(binsys.m1/(binsys.m1 + binsys.m2)) r_sink = (r1*p) + (r2*(1.0-p)) param['dSinkBoundOrbitRadius'] = r_sink param['dSinkRadius'] = r_sink param['dSinkMassMin'] = 0.9 * strip_units(secMass) param['bDoSinks'] = 1 return snapshotBinary, param, director
def dOmSqdr(r): m = simpson( starpot, r, 0, 100 ) #derivative of omega squared I think? thesis is not entirely clear about this return G * (starpot(r) / r**3 - 3 * m / r**4) # # How these functions should be used in the end # starList = genPartList(10.5, 2000, 1000, expDist, expDistVel) dmList = genPartList(84.0, 18000, 1000, expDist, expDistVel) # # noahSim = pyn.new(star=len(starList[0]), dm=len(dmList[0])) #,dm=len(dmList[0])) # noahSim['pos'].units = 'kpc' #maybe there's something off with the units? noahSim['vel'].units = 'km s^-1' noahSim['mass'].units = 'Msol' # sl2 = np.asarray( starList[2] ) #translating from one file format to another: functions will take np arrays, but not lists dl2 = np.asarray(starList[2]) # # # Setting position, velocity, softening length, mass, and potential for stars # noahSim.star['pos'] = starList[0] noahSim.star['vel'] = starList[1] noahSim.star['eps'] = .075
def snapshot_gen(ICobj): """ Generates a tipsy snapshot from the initial conditions object ICobj. Returns snapshot, param snapshot: tipsy snapshot param: dictionary containing info for a .param file Note: Code has been edited (dflemin3) such that now it returns a snapshot for a circumbinary disk where initial conditions generated assuming star at origin of mass M. After gas initialized, replaced star at origin with binary system who's center of mass lies at the origin and who's mass m1 +m2 = M """ print 'Generating snapshot...' # Constants G = SimArray(1.0, 'G') # ------------------------------------ # Load in things from ICobj # ------------------------------------ print 'Accessing data from ICs' settings = ICobj.settings # snapshot file name snapshotName = settings.filenames.snapshotName paramName = settings.filenames.paramName #Load user supplied snapshot (assumed to be in cwd) path = "/astro/store/scratch/tmp/dflemin3/nbodyshare/9au-Q1.05-129K/" snapshot = pynbody.load(path + snapshotName) # particle positions r = snapshot.gas['r'] xyz = snapshot.gas['pos'] # Number of particles nParticles = len(snapshot.gas) # molecular mass m = settings.physical.m #Pull star mass from user-supplied snapshot ICobj.settings.physical.M = snapshot.star[ 'mass'] #Total stellar mass in solar masses m_star = ICobj.settings.physical.M # disk mass m_disk = np.sum(snapshot.gas['mass']) m_disk = isaac.match_units(m_disk, m_star)[0] # mass of the gas particles m_particles = m_disk / float(nParticles) # re-scale the particles (allows making of low-mass disk) m_particles *= settings.snapshot.mScale # ------------------------------------------------- # Assign output # ------------------------------------------------- print 'Assigning data to snapshot' # Get units all set up m_unit = m_star.units pos_unit = r.units if xyz.units != r.units: xyz.convert_units(pos_unit) # time units are sqrt(L^3/GM) t_unit = np.sqrt((pos_unit**3) * np.power((G * m_unit), -1)).units # velocity units are L/t v_unit = (pos_unit / t_unit).ratio('km s**-1') # Make it a unit, save value for future conversion v_unit_vel = v_unit #Ensure v_unit_vel is the same as what I assume it is. assert (np.fabs(AddBinary.VEL_UNIT - v_unit_vel) < AddBinary.SMALL), "VEL_UNIT not equal to ChaNGa unit! Why??" v_unit = pynbody.units.Unit('{0} km s**-1'.format(v_unit)) # Other settings metals = settings.snapshot.metals star_metals = metals # Estimate the star's softening length as the closest particle distance eps = r.min() # Make param file param = isaac.make_param(snapshot, snapshotName) param['dMeanMolWeight'] = m gc.collect() # CALCULATE VELOCITY USING calc_velocity.py. This also estimates the # gravitational softening length eps preset = settings.changa_run.preset # ------------------------------------------------- # Estimate time step for changa to use # ------------------------------------------------- # Save param file isaac.configsave(param, paramName, 'param') # Save snapshot snapshot.write(filename=snapshotName, fmt=pynbody.tipsy.TipsySnap) # est dDelta dDelta = ICgen_utils.est_time_step(paramName, preset) param['dDelta'] = dDelta # ------------------------------------------------- # Create director file # ------------------------------------------------- # largest radius to plot r_director = float(0.9 * r.max()) # Maximum surface density sigma_min = float(ICobj.sigma(r_director)) # surface density at largest radius sigma_max = float(ICobj.sigma.input_dict['sigma'].max()) # Create director dict director = isaac.make_director(sigma_min, sigma_max, r_director, filename=param['achOutName']) ## Save .director file #isaac.configsave(director, directorName, 'director') """ Now that the gas disk is initializes around the primary (M=m1), add in the second star as specified by the user. """ #Now that velocities and everything are all initialized for gas particles, create new snapshot to return in which #single star particle is replaced by 2, same units as above snapshotBinary = pynbody.new(star=2, gas=nParticles) snapshotBinary['eps'] = 0.01 * SimArray( np.ones(nParticles + 2, dtype=np.float32), pos_unit) snapshotBinary['metals'] = SimArray( np.zeros(nParticles + 2, dtype=np.float32)) snapshotBinary['vel'].units = v_unit snapshotBinary['pos'].units = pos_unit snapshotBinary['mass'].units = snapshot['mass'].units snapshotBinary['rho'] = SimArray(np.zeros(nParticles + 2, dtype=np.float32)) #Assign gas particles with calculated/given values from above snapshotBinary.gas['pos'] = snapshot.gas['pos'] snapshotBinary.gas['vel'] = snapshot.gas['vel'] snapshotBinary.gas['temp'] = snapshot.gas['temp'] snapshotBinary.gas['rho'] = snapshot.gas['rho'] snapshotBinary.gas['eps'] = snapshot.gas['eps'] snapshotBinary.gas['mass'] = snapshot.gas['mass'] snapshotBinary.gas['metals'] = snapshot.gas['metals'] #Load Binary system obj to initialize system binsys = ICobj.settings.physical.binsys m_disk = isaac.strip_units(np.sum(snapshotBinary.gas['mass'])) binsys.m1 = isaac.strip_units(m_star) binsys.m1 = binsys.m1 + m_disk #Recompute cartesian coords considering primary as m1+m_disk binsys.computeCartesian() x1, x2, v1, v2 = binsys.generateICs() #Assign position, velocity assuming CCW orbit snapshotBinary.star[0]['pos'] = SimArray(x1, pos_unit) snapshotBinary.star[0]['vel'] = SimArray(v1, v_unit) snapshotBinary.star[1]['pos'] = SimArray(x2, pos_unit) snapshotBinary.star[1]['vel'] = SimArray(v2, v_unit) """ We have the binary positions about their center of mass, (0,0,0), so shift the position, velocity of the gas disk to be around the primary. """ snapshotBinary.gas['pos'] += snapshotBinary.star[0]['pos'] snapshotBinary.gas['vel'] += snapshotBinary.star[0]['vel'] #Set stellar masses: Create simArray for mass, convert units to simulation mass units snapshotBinary.star[0]['mass'] = SimArray(binsys.m1 - m_disk, m_unit) snapshotBinary.star[1]['mass'] = SimArray(binsys.m2, m_unit) snapshotBinary.star['metals'] = SimArray(star_metals) print 'Wrapping up' # Now set the star particle's tform to a negative number. This allows # UW ChaNGa treat it as a sink particle. snapshotBinary.star['tform'] = -1.0 #Set sink radius, stellar smoothing length as fraction of distance #from primary to inner edge of the disk r_sink = eps snapshotBinary.star[0]['eps'] = SimArray(r_sink / 2.0, pos_unit) snapshotBinary.star[1]['eps'] = SimArray(r_sink / 2.0, pos_unit) param['dSinkBoundOrbitRadius'] = r_sink param['dSinkRadius'] = r_sink param['dSinkMassMin'] = 0.9 * binsys.m2 param['bDoSinks'] = 1 return snapshotBinary, param, director
def test_kd_issue_88(): # number of particles less than number of smoothing neighbours f = pynbody.new(gas=16) f['pos'] = np.random.uniform(size=(16, 3)) with pytest.raises(ValueError): f["smooth"]
def __init__(self, **kwargs): self.__kwargs = kwargs self.__profile = kwargs.get('profile', density_profiles.alphabetagamma) self.__drhodr = kwargs.get('drhodr', density_profiles.dalphabetagammadr) self.__d2rhodr2 = kwargs.get('d2rhodr2', density_profiles.d2alphabetagammadr2) self.__pars = kwargs.get('pars', { 'alpha': 1., 'beta': 3., 'gamma': 1., 'c': 10., 'factor': 0.1 }) if self.__profile == density_profiles.alphabetagamma and self.__pars[ 'beta'] <= 3.: if 'factor' not in self.__pars.keys(): self.__pars['factor'] = 0.1 self.__m_vir = kwargs.get('m_vir', '1e12 Msol') self.__m_vir = units.Unit(self.__m_vir) self.__h = kwargs.get('h', 0.7) self.__overden = kwargs.get('overden', 200.) self.__r_vir = tools.calc_r_vir(self.__m_vir, self.__h, self.__overden) self.__r_s = self.__r_vir / self.__pars['c'] self.__n_particles = int(kwargs.get('n_particles', 1e5)) self.__logxmax_rho = np.log10(self.__pars['c']) + 2. # Make sure to sample well inside the gravitational softening self.__logxmin_rho = self.__logxmax_rho - .5 * np.log10( self.__n_particles) - 3. self.__logxmin_dist_func = kwargs.get('logxmin_dist_func', -3.) self.__logxmax_dist_func = kwargs.get('logxmax_dist_func', 14.) self.__n_sample_rho = int(kwargs.get('n_sample_rho', 1e4)) self.__n_sample_dist_func = int(kwargs.get('n_sample_dist_func', 1e2)) self.__n_sample_dist_func_rho = int( kwargs.get('n_sample_dist_func_rho', 1e4)) self.__random_seed = kwargs.get('random_seed', 4) if 'prng' in kwargs.keys(): self.__prng = kwargs['prng'] else: self.__prng = np.random.RandomState(self.__random_seed) self.__spline_order = kwargs.get('spline_order', 3) self.__progress_bar = kwargs.get('progress_bar', False) self.__no_bulk_vel = kwargs.get('no_bulk_vel', True) self.__x_rho = np.logspace(self.__logxmin_rho, self.__logxmax_rho, self.__n_sample_rho) self.__f_bary = kwargs.get('f_bary', 0.1) self.__mu = kwargs.get('mu', 1.3) self.__spin_parameter = kwargs.get('spin_parameter', 0.04) self.__rot_balanced = kwargs.get('rot_balanced', False) # Different gas profiles are not yet implemented or successfully tested self.__gas_profile = self.__profile self.__gas_pars = self.__pars #self.__gas_profile = kwargs.get('gas_profile', density_profiles.alphabetagamma) #self.__gas_pars = kwargs.get('gas_pars', {'alpha': 1., 'beta': 3., 'gamma': 1., # 'c': 10., 'factor': 0.1}) self.__r_s_gas = self.__r_vir / self.__gas_pars['c'] #self.__vel_prof = kwargs.get('vel_prof', None) self.__vel_pars = kwargs.get( 'vel_pars', { 'rs_v': array.SimArray(1., 'kpc'), 'c': self.__pars['c'], 'prefac': 1., 'factor': 1. }) self.__n_gas_particles = int( kwargs.get('n_gas_particles', self.__n_particles)) self.__ang_mom_prof = kwargs.get('ang_mom_prof', am_profiles.bullock_prof) self.__ang_mom_pars = kwargs.get('ang_mom_pars', {'mu': self.__mu}) self.__fname = kwargs.get('fname', 'halo.out') # Careful here: as of now, only the output as tipsy files has been successfully tested self.__type = { 'gadget': gadget.GadgetSnap, 'grafic': grafic.GrafICSnap, 'nchilada': nchilada.NchiladaSnap, 'ramses': ramses.RamsesSnap, 'tipsy': tipsy.TipsySnap }[kwargs.get('type', 'tipsy')] self.sim = new(dm=self.__n_particles, gas=self.__n_gas_particles) self.sim.physical_units()
def makeICs(simdir='difftest', cs=1., boxSize=1., criticalRadius=0.25, dustFrac0=0.1, tStop=0.1, rho=1., nSmooth=32, dustFracMin=0., inputSnap=None, dDeltaFactor=1, boxRes=[50, 58, 60]): r""" Generates ICs for the dustydiffusion test of Price & Laibe 2015. The ICs are in a periodic cube, centered on the origin, with uniform density and a dust fraction decaying from the origin. The dust fraction profile is set as: .. math:: \epsilon(r, 0) = \epsilon_0 (1 - (r/r_c)^2) ICs will be saved to simdir Parameters ---------- simdir : str Directory to save ICs in cs : float Sound speed (code units) boxSize : float Size of the periodic cube (code units) criticalRadius : float :math:`r_c` in the equation above dustFrac0 : float :math:`\epsilon_0` in the equation above tStop : float Dust stopping time (code units) rho : float total density (code units) nSmooth : int Number of neighbors for smoothing operations dustFracMin : float Minimum dust fraction inputSnap : SimSnap (optional) The positions for the simulation can be taken from another simulation if one is supplied. dDeltaFactor : float Factor by which to scale time step. This will keep outputs at the same simulation time (ie will scale iOutInterval, etc...). This can be useful e.g. to test multistepping boxRes : array-like Resolution of the box (number of grid points) along each axis Returns ------- ICs : SimSnap Generated ICs param : dict params used simdir : str Directory the ICs are saved in paramname : str Path to the saved .param file """ runParams = locals() # ----------------------------------------------- # Load stuff # ----------------------------------------------- if inputSnap is not None: # Load inputSnap file if isinstance(inputSnap, str): inputSnap = pynbody.load(inputSnap) else: inputSnap = inputSnap ngas = len(inputSnap) else: # Create grid ICs boxRes = np.asarray(boxRes).astype(int) ngas = np.product(boxRes) # Parse param file param = testdust.utils.loadDefaultParam(defaultParam, userDefaults) # Get units units = diskpy.pychanga.units_from_param(param) grainSize = param['dDustSize'] # filenames fname = param['achInFile'] outparam = param['achOutName'] + '.param' molecularWeight = param['dMeanMolWeight'] # ----------------------------------------------- # set up simulation directory # ----------------------------------------------- if not os.path.exists(simdir): os.mkdir(simdir) fRunParams = os.path.join(simdir, runParamsName) fname = os.path.join(simdir, fname) # ----------------------------------------------- snap = pynbody.new(gas=ngas) # Give everything units cs = SimArray(cs, units['v_unit']) rho = SimArray(rho, units['rho_unit']) boxSize = SimArray(boxSize, units['l_unit']) criticalRadius = SimArray(criticalRadius, units['l_unit']) tStop = SimArray(tStop, units['t_unit']) molecularWeight = SimArray(molecularWeight, 'm_p') grainSize = SimArray(grainSize, units['l_unit']) # Save/update run parameters runParams['criticalRadius'] = criticalRadius runParams['cs'] = cs runParams['tStop'] = tStop pickle.dump(runParams, open(fRunParams, 'w')) print "Run parameters saved to:", fRunParams # Isothermal temperature T = (cs**2) * molecularWeight / kB T.convert_units('K') snap['temp'] = T * np.ones(ngas) # Mass m = (rho * boxSize**3) / ngas m.convert_units(units['m_unit']) snap['mass'] = m # Grain density grainDensity = rho * cs * tStop * np.sqrt(8 / np.pi) / grainSize grainDensity.convert_units(units['rho_unit']) param['dDustGrainDensity'] = float(grainDensity) # Setup positions if inputSnap is not None: pos = inputSnap['pos'].view(float, np.ndarray) snap['pos'] = boxSize * pos Lfloat = float(boxSize) param['dPeriod'] = Lfloat else: boxShape = boxSize * np.ones(3) pos = periodicGrid(boxRes, boxShape) snap['pos'] = pos Lfloat = float(boxSize) param['dPeriod'] = Lfloat # Define dust fraction snap['dustFrac'] = dustFrac0 * (1 - (snap['r'] / criticalRadius)**2) snap['dustFrac'][snap['dustFrac'] < dustFracMin] = dustFracMin # Estimate a useable softening length. Make it big so that it does not # constrain the timestepping. Gravitational forces should be off, so this # is okay snap['rho'] snap['eps'] = 100 * snap['smooth'].mean() # Save out snap.write(fmt=pynbody.tipsy.TipsySnap, filename=fname) # Set up the param file param['nSmooth'] = nSmooth scaleTimeStep(param, dDeltaFactor) outparamfull = os.path.join(simdir, outparam) diskpy.utils.configsave(param, outparamfull, 'param') print 'ICs saved to ' + fname return snap, param, simdir, outparam
def load_gadget(infile, plot_thing, centredens=False): f = h5py.File(infile, "r") header = f["/Header"] time = header.attrs.get("Time") time *= 0.9778e9 # to yr time /= 1.e6 # to Myr xyz = np.array(f["/PartType0/Coordinates"]) # kpc n = xyz.shape[0] data = pynbody.new(gas=n) data["xyz"] = xyz try: BH_data = f["/BH_binary"] Binary_pos_1 = BH_data.attrs.get("Binary_pos_1") Binary_pos_2 = BH_data.attrs.get("Binary_pos_2") if isinstance(Binary_pos_1, np.ndarray) & isinstance( Binary_pos_2, np.ndarray): data.binary_positions = [Binary_pos_1 * 1.e3, Binary_pos_2 * 1.e3] else: data.binary_positions = None # verboseprint("Binary BH data loaded") except KeyError as e: data.binary_positions = None # verboseprint("No Binary BH data found, skipping") data["m_p"] = np.array(f["/PartType0/Masses"]) # 10^10 msun data["m_p"] *= 1e+10 # 10^10 solar masses to solar masses data["h_p"] = np.array(f["/PartType0/SmoothingLength"]) # kpc need_to_load = set(plot_thing) if centredens: need_to_load.add("nH") need_to_load = preqs_config.process_preqs(need_to_load) if "id" in need_to_load: data["id_p"] = np.array(f["/PartType0/ParticleIDs"]).astype(int) if "age" in need_to_load: infile_split = infile.split("/") run_id = infile_split[-3] run_name = infile_split[-2] run_snapfile = infile_split[-1] run_isnap = int(run_snapfile[-8:-5]) age_file = "../../data/age_{}_{}_{}.dat".format( run_id, run_name, run_isnap) data["age"] = time - np.loadtxt(age_file) if "pres" in need_to_load: data["pres"] = np.array(f["/PartType0/Pressure"]) # data.pres*=1.989e+33 # from internal units to dyne/cm*8*2 if "arads" in need_to_load: data["arads"] = np.array(f["/PartType0/RadiativeAcceleration"]) data["arads"] *= 3.24086617e-12 # to cm/s/s if "arad" in need_to_load: data["arad"] = np.sqrt(np.sum(data["arads"]**2, axis=1)) if "accel" in need_to_load: data["accels"] = np.array(f["/PartType0/Acceleration"]) data["accels"] *= 3.24086617e-12 # to cm/s/s data["accel"] = np.sqrt(np.sum(data["accels"]**2, axis=1)) if "depth" in need_to_load: data["depth"] = np.array( f["/PartType0/AGNOpticalDepth"]) # Msun/kpc**2 if "list" in need_to_load: data["list"] = np.arange(n) if "rand" in need_to_load: data["rand"] = np.random.random(n) if "nneigh" in need_to_load: data["nneigh"] = np.array(f["/PartType0/TrueNumberOfNeighbours"]) if "temp" in need_to_load: data["u_p"] = np.array(f["/PartType0/InternalEnergy"]) # 1e10 erg/g data["u_p"] *= 1.e10 # to erg/g data["TK_p"] = (gamma_minus_one / boltzmann_cgs * (molecular_mass * proton_mass_cgs) * data["u_p"]) if "vels" in need_to_load: data["vels"] = np.array(f["/PartType0/Velocities"]) # in km/s # doesn't work well if "dt" in need_to_load: data["dt_p"] = np.array(f["/PartType0/TimeStep"]) data["dt_p"] *= 0.9778e9 # to yr # doesn't work well if "heat" in need_to_load: data["heat"] = np.array(f["/PartType0/AGNHeat"]) data["heat"] *= 1e10 / 3.08568e+16 # to erg/s/g if "nH" in need_to_load: data["rho_p"] = np.array(f["/PartType0/Density"]) data["rho_p"] *= 6.77e-22 # to g/cm**3 data["nH_p"] = data["rho_p"] / (molecular_mass * proton_mass_cgs) if "tau" in need_to_load: data["tau"] = np.array(f["/PartType0/AGNDepth"]) if "tau_2" in need_to_load: data["tau_2"] = np.array(f["/PartType0/AGNDepth_2"]) if "tau_eff" in need_to_load: data["tau_eff"] = np.array(f["/PartType0/AGNDepth_Effective"]) if "AGNI" in need_to_load: data["AGNI"] = np.array(f["/PartType0/AGNIntensity"]) data["AGNI"] *= ( 1.989e53 / (0.9778e9 * 3.154e7) / 3.086e21**2 ) # convert from internal units (energy/Gyr-ish/kpc**2) to erg/s/cm**2 if "AGNI2" in need_to_load: data["AGNI2"] = np.array(f["/PartType0/AGNIntensity_2"]) data["AGNI2"] *= ( 1.989e53 / (0.9778e9 * 3.154e7) / 3.086e21**2 ) # convert from internal units (energy/Gyr-ish/kpc**2) to erg/s/cm**2 if "AGNIeff" in need_to_load: data["AGNIeff"] = np.array(f["/PartType0/AGNIntensity_Effective"]) data["AGNIeff"] *= ( 1.989e53 / (0.9778e9 * 3.154e7) / 3.086e21**2 ) # convert from internal units (energy/Gyr-ish/kpc**2) to erg/s/cm**2 if "table" in need_to_load: verboseprint("Load dust tables") # table_date="060319" # used in paper - not all intensities are there table_date = "130720" # table_res = "0.1" table_res = "0.0001" coolheat_dir = os.path.join(this_dir, "../coolheat_tab/") cloudy_table = gizmo_tools.cloudy_table(table_date, table_res, coolheat_dir) data["flux_p"] = np.array( f["/PartType0/AGNIntensity"]) # energy per surface area per time data["flux_p"] *= 1.989e+53 / 3.086e21**2 / 3.08568e+16 table_particles = pd.DataFrame() table_particles["nH"] = data["nH_p"] table_particles["temp"] = data["TK_p"] table_particles["AGNIntensity"] = data["flux_p"] table_particles["AGNDepth"] = data["tau"] # TODO: correct optical depths etc for binary # if "tau_eff" in data: # table_particles["AGNDepth"] = data["tau_eff"] # else: # table_particles["AGNDepth"] = data["tau"] verboseprint("Calculating dust/cooling/heating properties from table") cloudy_table.interp(table_particles) if "col" in need_to_load: if "/PartType0/AGNColDens" in f: data["coldens"] = np.array( f["/PartType0/AGNColDens"]) # Msun/kpc**2 data["coldens"] *= (1.989e+43 / 3.086e+21**2) # to g/cm**2 data["coldens"] /= (molecular_mass * proton_mass_cgs ) # N in cm**(-2) else: data["coldens"] = table_particles["column_out"] if "tdust" in need_to_load: data["dustTemp"] = table_particles["dustT"] for line in lines[1:]: if line in need_to_load: data[line] = table_particles["line_" + line] if line in [ "12mic", "8mic", "850mic" ]: # these are given in erg/cm**3/s, need to convert to erg/g/s data[line] /= data["nH_p"] if line + "m" in need_to_load: data[line + "m"] = table_particles[ "line_" + line] * data["m_p"] * 1.9891e33 / 9.52140614e36 / ( 4. * np.pi ) # erg/s/g to erg/s, extra factor for pc**2 to ster cm**2, output is erg/s/cm**2/ster if "dg" in need_to_load: data["dg"] = table_particles["dg"] if "dust" in need_to_load: data["dust"] = data["dg"] * data["m_p"] if "emit" in need_to_load: data["emissivity"] = 5.67e-5 * data["dustTemp"]**4. * data[ "dg"] / np.nanmax(data["dg"]) # erg/s/cm^2 if "opac" in need_to_load: data["opac"] = np.array(f["/PartType0/AGNOpacity"] ) # internal units: kpc**2/1e10 solar mass data["opac"] *= 0.478679108 # to cm**2/g if ("view" in need_to_load or "vlos" in need_to_load or any(x in need_to_load for x in ["view" + line for line in lines]) or "dusttau" in need_to_load): if "view" in need_to_load: data["brightness"] = 5.67e-5 * data["dustTemp"]**4. * data[ "dg"] / np.nanmax(data["dg"]) # erg/s/cm^2 verboseprint("faking opacity") opacity = 65.2 # cm^2/g, somewhat arbitrary verboseprint("Broad IR opacity is now ", opacity, " cm^2/g") opacity *= 0.000208908219 # convert to pc**2/solar mass for consistency data["opac"] = np.full(n, opacity) data["opac"] *= data["dg"] / np.nanmax( data["dg"]) # take into account dust fraction if "dusttau" in need_to_load: data["dusttau"] = data["opac"] * data["m_p"] for line in lines[1:]: if not "view" + line in need_to_load: continue data[line + "opac"] = np.full(n, line_opacities[line]) data[line + "brightness"] = data[line + "m"] / data[ line + "opac"] # erg/s/cm^2 - multiply by opacity to get actual emission # data.__dict__[line+"brightness"]=data.__dict__[line+"m"] # erg/s, gets SPH smoothed to get erg/s/cm**2 if "view" in need_to_load: # sputtered = (data.dustTemp>2.5e3) # or something, super arbitrary sputtered = (data["dustTemp"] > 1.e5 ) # or something, super arbitrary data["brightness"][sputtered] = 0. data["opac"][sputtered] = 0. if any(x in need_to_load for x in ("IRdustm", "IRdust", "IRdustopac", "IRdustbrightness", "viewIRdust")): # data["dustTemp"] = table_particles["dustT"] data["IRdustbrightness"] = 5.67e-5 * data["dustTemp"]**4. * data[ "dg"] / np.nanmax(data["dg"]) data["IRdustopac"] = np.full(n, line_opacities["IRdust"]) data["IRdustm"] = data["IRdustbrightness"] * data["IRdustopac"] data["IRdust"] = data["IRdustm"] / (data["m_p"] * 1.9891e33 / 9.52140614e36 / (4. * np.pi)) if "rad0" in need_to_load: data["rad0"] = np.load("rad0.npy") data["rad0"] = data["rad0"][data["id_p"] - 1] return time, data
def make_binary(IC, snapshot): """ Turns a snapshot for a single star into a snapshot of a binary system Parameters ---------- IC : IC object snapshot : SimSnap Single star system to turn into a binary Returns ------- snapshotBinary : SimSnap A binary version of the simulation snapshot """ # Initialize snapshot snapshotBinary = pynbody.new(star=2, gas=len(snapshot.g)) # Copy gas particles over for key in snapshot.gas.keys(): snapshotBinary.gas[key] = snapshot.gas[key] # Load Binary system obj to initialize system starMode = IC.settings.physical.starMode.lower() binsys = IC.settings.physical.binsys if starMode == 'stype': # Treate the primary as a star of mass mStar + mDisk m_disk = strip_units(np.sum(snapshotBinary.gas['mass'])) binsys.m1 += m_disk binsys.computeCartesian() x1,x2,v1,v2 = binsys.generateICs() #Assign star parameters assuming CCW orbit snapshotBinary.star[0]['pos'] = x1 snapshotBinary.star[0]['vel'] = v1 snapshotBinary.star[1]['pos'] = x2 snapshotBinary.star[1]['vel'] = v2 #Set stellar masses priMass = binsys.m1 secMass = binsys.m2 snapshotBinary.star[0]['mass'] = priMass snapshotBinary.star[1]['mass'] = secMass snapshotBinary.star['metals'] = snapshot.s['metals'] if starMode == 'stype': # We have the binary positions about their center of mass, (0,0,0), so # shift the position, velocity of the gas disk to be around the primary. snapshotBinary.gas['pos'] += snapshotBinary.star[0]['pos'] snapshotBinary.gas['vel'] += snapshotBinary.star[0]['vel'] # Remove disk mass from the effective star mass snapshotBinary[0]['mass'] -= m_disk binsys.m1 -= m_disk # Star smoothing snapshotBinary.star['eps'] = snapshot.star['eps'] elif starMode == 'binary': # Estimate stars' softening length as fraction of distance to COM d = np.sqrt(AddBinary.dotProduct(x1-x2,x1-x2)) pos_unit = snapshotBinary['pos'].units snapshotBinary.star['eps'] = SimArray(abs(d)/4.0,pos_unit) return snapshotBinary
def test_kd_issue_88(): # number of particles less than number of smoothing neighbours f = pynbody.new(gas=16) f['pos'] = np.random.uniform(size=(16, 3)) trigger_fn = lambda: f['smooth'] nose.tools.assert_raises(ValueError, trigger_fn)
def combine(self): """ Combines the two galaxies into a new TipsySnap. Returns ---------- """ # these x y z refer to initial condit to be added print("Getting initial conditions") x1, y1, vx1, vy1 = self._initial_conds(which_gal=self.Gal1) x2, y2, vx2, vy2 = self._initial_conds(which_gal=self.Gal2) # Mass ratio is unitless so it doesn't matter that they are in kg # Units specified and value taken only because later we use in_units # Only using simulation units to avoid namespace clutter x1 = (x1).to(self.dKpcUnit).value * (self.Mass1_scaled / self.m_tot_scaled) y1 = (y1).to(self.dKpcUnit).value * (self.Mass1_scaled / self.m_tot_scaled) x2 = (x2).to(self.dKpcUnit).value * (self.Mass2_scaled / self.m_tot_scaled) y2 = (y2).to(self.dKpcUnit).value * (self.Mass2_scaled / self.m_tot_scaled) vx1 = (vx1).to(self.velUnit).value * (self.Mass1_scaled / self.m_tot_scaled) vy1 = (vy1).to(self.velUnit).value * (self.Mass1_scaled / self.m_tot_scaled) vx2 = (vx2).to(self.velUnit).value * (self.Mass2_scaled / self.m_tot_scaled) vy2 = (vy2).to(self.velUnit).value * (self.Mass2_scaled / self.m_tot_scaled) print("Done") print("") lengths = {} for fam in self.Gal1.families(): lengths[fam.name] = len(self.Gal1[fam]) gal1_shifted = pynbody.new(**lengths) def transform(row, rmat): row = (rmat * np.matrix(row).transpose()) return(row) for fam in self.Gal1.families(): s1 = self.Gal1[fam] if self.transform is True: print("Tranforming " + str(fam)) s1["pos"] = np.apply_along_axis(transform, 1, s1["pos"], (self._rmat(a=self.W1, b=self.i1, g=self.w1))) s1["vel"] = np.apply_along_axis(transform, 1, s1["vel"], (self._rmat(a=self.W1, b=self.i1, g=self.w1))) print("Done") print("") else: pass print("Shifting family " + str(fam)) # in_units here IS needed to ensure units match when added to IC gal1_shifted[fam][:len(s1)]["pos"] = s1["pos"].in_units(str(self.dKpcUnit.value) + " kpc") + [x1, y1, 0] gal1_shifted[fam][:len(s1)]["vel"] = s1["vel"].in_units(str(self.velUnit.value) + " km s**-1") * np.sqrt(self.massScale) + [vx1, vy1, 0] gal1_shifted[fam][:len(s1)]["mass"] = s1["mass"].in_units(str(self.dMsolUnit.value) + " Msol") * self.massScale gal1_shifted[fam][:len(s1)]["rho"] = s1["rho"].in_units(str((self.dMsolUnit / (self.dKpcUnit**3)).value) + " Msol kpc**-3") * self.massScale gal1_shifted[fam][:len(s1)]["eps"] = s1["eps"].in_units("kpc") if str(fam) == 'gas': gal1_shifted[fam][:len(s1)]["temp"] = s1["temp"] * self.massScale else: pass print("Done") print("") lengths = {} for fam in self.Gal2.families(): lengths[fam.name] = len(self.Gal2[fam]) gal2_shifted = pynbody.new(**lengths) for fam in self.Gal2.families(): s2 = self.Gal2[fam] if self.transform is True: print("Tranforming " + str(fam)) s2["pos"] = np.apply_along_axis(transform, 1, s2["pos"], (self._rmat(a=self.W2, b=self.i2, g=self.w2))) s2["vel"] = np.apply_along_axis(transform, 1, s2["vel"], (self._rmat(a=self.W2, b=self.i2, g=self.w2))) print("Done") print("") else: pass print("Shifting family " + str(fam)) gal2_shifted[fam][:len(s2)]["pos"] = s2["pos"].in_units(str(self.dKpcUnit.value) + " kpc") + [x2, y2, 0] gal2_shifted[fam][:len(s2)]["vel"] = s2["vel"].in_units(str(self.velUnit.value) + " km s**-1") * np.sqrt(self.massScale) + [vx2, vy2, 0] gal2_shifted[fam][:len(s2)]["mass"] = s2["mass"].in_units(str(self.dMsolUnit.value) + " Msol") * self.massScale gal2_shifted[fam][:len(s2)]["rho"] = s2["rho"].in_units(str((self.dMsolUnit / (self.dKpcUnit**3)).value) + " Msol kpc**-3") * self.massScale gal2_shifted[fam][:len(s2)]["eps"] = s2["eps"].in_units("kpc") if str(fam) == 'g': gal2_shifted[fam][:len(s2)]["temp"] = s2["temp"] * self.massScale else: pass print("Done") print("") print("Combining galaxies") for fam in gal1_shifted.families(): lengths[fam.name] = len(gal1_shifted[fam]) + len(gal2_shifted[fam]) combined = pynbody.new(**lengths) for fam in self.Gal1.families(): s1 = gal1_shifted[fam] s2 = gal2_shifted[fam] for arname in "pos", "vel", "mass", "rho", "eps": combined[fam][:len(s1)][arname] = s1[arname] combined[fam][len(s1):][arname] = s2[arname] if str(fam) == "gas": # temp starts out uniform combined[fam][:len(s1)]["temp"] = s1["temp"][:] combined[fam][len(s1):]["temp"] = s1["temp"][:] print(combined[fam]["temp"]) else: pass print("Done") print("") return combined
def shock1d(nParticles=2 * 569, L=2., P=(1, 1. / 8), rhog=(1, 1. / 8), dustFrac=0.5, gamma=5. / 3, inputParamName=None): """ Creates SPH ICs for a 1D dusty-shock tube a la Price & Laibe 2015 (see their dustyshock, section 4.2). Particles are in a line along the z-axis. Note that since ChaNGa uses periodic boundaries (rather than particles in a tube) the shock tube should be twice as long and will actually produce 2 shocks. Parameters ---------- nParticles: int Approximate number of particles to use. nParticles will be set in the end to best approximate the gas density in each region. L: float Length of the shock tube. (in code units) P: array-like Pressure in the two regions (left and right) rhog: array-like Gas density in the two regions dustFrac: float Dust fraction (between 0 and 1) gamma: float Adiabatic index inputParamName: str (optional) Override the default ChaNGa params. This can also be done by changing the appropriate user default param in this directory. Returns ------- ICs: SimSnap Pynbody snapshot of the ICs param: dict dict of the runtime params arguments: dict Arguments used when calling this function, including defaults. paramsavename: str Path the param file is saved to """ # Keep track of arguments (and save at the end) arguments = locals() P = np.asarray(P) rhog = np.asarray(P) L = float(L) gamma = float(gamma) # -------------------------------------------- # Initialize # -------------------------------------------- # Load stuff if inputParamName is not None: param = diskpy.utils.configparser(inputParamName) else: param = testdust.utils.loadDefaultParam(defaultParam1d, userDefault1d) # param = diskpy.utils.configparser(inputParamName, 'param') fprefix = param['achOutName'] savename = param['achInFile'] molecularWeight = SimArray(param['dMeanMolWeight'], 'm_p') units = diskpy.pychanga.units_from_param(param) # Initialize quantities L = SimArray(L, units['l_unit']) P = SimArray(P, units['pres_unit']) rhog = SimArray(rhog, units['rho_unit']) rho = rhog / (1. - dustFrac) # Set-up number of particles to left/right of boundary N = np.array(np.round(nParticles * rho / rho.sum()).astype(int)) nParticles = N.sum() # Initialize snapshot f = pynbody.new(gas=nParticles) # Initialize arrays for key in ('temp', 'rho', 'dustFrac'): f[key] = 0. # Set up left/right slices. These select the left/right regions slices = [slice(0, N[0]), slice(N[0], N[0] + N[1])] # -------------------------------------------- # Setup values # -------------------------------------------- # Mass totMass = float((rho * (L / 2.)).sum()) f['mass'] = totMass / nParticles # Position z = [0.5 * L * testdust.utils.periodicLine(n) for n in N] f['z'][slices[0]] = z[0] - 0.25 * L f['z'][slices[1]] = z[1] + 0.25 * L # Temperature T = molecularWeight * P / (rhog * kB) T.convert_units('K') # Assign arrays, looping over both sides for i, s in enumerate(slices): f['temp'][s] = T[i] f['rho'][s] = rho[i] f['dustFrac'][s] = dustFrac # Other f['eps'] = 10 * L / nParticles # Setup params testdust.utils.setupParamBounds(param, [float(L)]) param['dConstGamma'] = gamma # Save f.write(filename=savename, fmt=pynbody.tipsy.TipsySnap) print 'snapshot saved to:', savename paramsavename = fprefix + '.param' diskpy.utils.configsave(param, paramsavename) print '.param file saved to:', paramsavename pickle.dump(arguments, open(argsavename, 'w'), 2) print 'arguments dict pickled to:', argsavename return f, param, arguments, paramsavename
v[nanind] = 0.0 print 'Setting {0} particle velocities to 0 (to avoid nans)'.format( nanind.sum()) # ------------------------------------------------- # Assign output # ------------------------------------------------- vel = SimArray(np.zeros([nParticles, 3]), '2.98e+01 km s**-1') vel[:, 0] = -np.sin(pos['theta']) * v vel[:, 1] = np.cos(pos['theta']) * v # Generate positions xyz = SimArray(np.zeros([nParticles, 3]), 'au') xyz[:, 0] = pos['x'] xyz[:, 1] = pos['y'] xyz[:, 2] = pos['z'] # Generate snapshot snapshot = pynbody.new(star=1, gas=nParticles) snapshot.gas['vel'] = vel snapshot.gas['pos'] = xyz snapshot.gas['temp'] = T snapshot.gas['mass'] = mGas snapshot.gas['metals'] = metals snapshot.gas['eps'] = eps snapshot.star['pos'] = SimArray([[0., 0., 0.]], 'au') snapshot.star['vel'] = SimArray([[0., 0., 0.]], '2.98e+01 km s**-1') snapshot.star['mass'] = mStar snapshot.star['metals'] = SimArray([1.]) snapshot.star['eps'] = SimArray([0.01], 'au') # ------------------------------------------------- # Save Output # -------------------------------------------------