def isotropic_w0(N=100): # positions d = np.random.lognormal(mean=np.log(25), sigma=0.5, size=N) phi = np.random.uniform(0, 2 * np.pi, size=N) theta = np.arccos(np.random.uniform(size=N) - 0.5) vr = np.random.normal(150., 40., size=N) * u.km / u.s vt = np.random.normal(100., 40., size=N) vt = np.vstack((vt, np.zeros_like(vt))).T # rotate to be random position angle pa = np.random.uniform(0, 2 * np.pi, size=N) M = np.array([[np.cos(pa), -np.sin(pa)], [np.sin(pa), np.cos(pa)]]).T vt = np.array([vv.dot(MM) for (vv, MM) in zip(vt, M)]) * u.km / u.s vphi, vtheta = vt.T rep = coord.PhysicsSphericalRepresentation(r=d * u.dimensionless_unscaled, phi=phi * u.radian, theta=theta * u.radian) x = rep.represent_as(coord.CartesianRepresentation).xyz.T.value vr = vr.decompose(galactic).value * u.one vphi = vphi.decompose(galactic).value * u.one vtheta = vtheta.decompose(galactic).value * u.one vsph = coord.PhysicsSphericalDifferential(d_phi=vphi / (d * np.sin(theta)), d_theta=vtheta / d, d_r=vr) with u.set_enabled_equivalencies(u.dimensionless_angles()): v = vsph.represent_as(coord.CartesianDifferential, base=rep).d_xyz.value.T return np.hstack((x, v)).T
def read_pop_fromhdf5(self, filename): """ Read from an hdf5 file the cloud population. the :class:`Cloud_Population` is thus initialized by :func:`initialize_cloud_population_from_output` """ f = h5.File(filename, 'r') g = f["Cloud_Population"] self.r = g["R"][...] self.phi = g["Phi"][...] self.L = g["Sizes"][...] self.W = g["Emissivity"][...] coord_array = np.zeros(self.n) if self.models[self.model] == 1: self.theta = g["Theta"][...] coord_array = coord.PhysicsSphericalRepresentation( self.phi * u.rad, self.theta * u.rad, self.r * u.kpc) elif self.models[self.model] >= 2: self.zeta = g["Z"][...] coord_array = coord.CylindricalRepresentation( self.r * u.kpc, self.phi * u.rad, self.zeta * u.kpc) self.d_sun = g["D_sun"][...] self.long = g["Gal_longitude"][...] self.lat = g["Gal_Latitude"][...] self.healpix_vecs = g["Healpix_Vec"][...] self.cartesian_galactocentric = self.cartesianize_coordinates( coord_array) from utilities.utilities_functions import bash_colors cols = bash_colors() f.close() print(cols.bold("////// \t read from " + filename + "\t ////////")) pass
def isotropic_w0(N=100): # positions d = np.random.lognormal(mean=np.log(25), sigma=0.5, size=N) phi = np.random.uniform(0, 2*np.pi, size=N) theta = np.arccos(np.random.uniform(size=N) - 0.5) vr = np.random.normal(150., 40., size=N)*u.km/u.s vt = np.random.normal(100., 40., size=N) vt = np.vstack((vt,np.zeros_like(vt))).T # rotate to be random position angle pa = np.random.uniform(0, 2*np.pi, size=N) M = np.array([[np.cos(pa), -np.sin(pa)],[np.sin(pa), np.cos(pa)]]).T vt = np.array([vv.dot(MM) for (vv,MM) in zip(vt,M)])*u.km/u.s vphi,vtheta = vt.T rep = coord.PhysicsSphericalRepresentation(r=d*u.dimensionless_unscaled, phi=phi*u.radian, theta=theta*u.radian) x = rep.represent_as(coord.CartesianRepresentation).xyz.T.value vr = vr.decompose(galactic).value vphi = vphi.decompose(galactic).value vtheta = vtheta.decompose(galactic).value v = physicsspherical_to_cartesian(rep, [vr,vphi,vtheta]*u.dimensionless_unscaled).T.value return np.hstack((x,v)).T
def rv_to_3d_isotropic(r, v): """Given radii and velocity magnitudes, generate a set of 6D initial conditions by assuming isotropy. Parameters ---------- r : quantity_like [length] Radii. v : quantity_like [speed] Velocity magnidues. """ phi = np.random.uniform(0, 2*np.pi, size=r.size) * u.radian theta = np.arccos(2*np.random.uniform(size=r.size) - 1) * u.radian sph = coord.PhysicsSphericalRepresentation(phi=phi, theta=theta, r=r) xyz = sph.represent_as(coord.CartesianRepresentation).xyz phi = np.random.uniform(0, 2*np.pi, size=r.size) * u.radian theta = np.arccos(2*np.random.uniform(size=r.size) - 1) * u.radian v_sph = coord.PhysicsSphericalRepresentation(phi=phi, theta=theta, r=np.ones_like(v.value)*u.one) v_xyz = v * v_sph.represent_as(coord.CartesianRepresentation).xyz return gd.PhaseSpacePosition(pos=xyz, vel=v_xyz)
def test_represent_as(self) -> None: """Test method ``represent_as``. Astropy tests the underlying method. Only need to test that it is interpolated. """ # super().test_represent_as() rep = self.inst.represent_as( coord.PhysicsSphericalDifferential, base=coord.PhysicsSphericalRepresentation( 0 * u.rad, 0 * u.rad, 0 * u.km, ), ) assert isinstance(rep, coord.PhysicsSphericalDifferential) assert isinstance(rep, icoord.InterpolatedDifferential) assert isinstance(rep, self.klass)
def __call__(self): self.clouds = [] np.random.seed(11 + self.random_seed) a = np.random.uniform(low=0., high=1., size=self.n) self.phi = 2. * np.pi * a if self.model == 'Spherical': self.r = norm.rvs(loc=self.R_params[0], scale=self.R_params[1], size=self.n) v = np.random.uniform(low=0., high=1., size=self.n) self.theta = np.arccos(2. * v - 1.) coord_array = coord.PhysicsSphericalRepresentation( self.phi * u.rad, self.theta * u.rad, self.r * u.kpc) self.cartesian_galactocentric = self.cartesianize_coordinates( coord_array) self.heliocentric_coordinates() for i, x, p, t, d, latit, longit in zip(np.arange(self.n), self.r, self.phi, self.theta, self.d_sun, self.lat, self.long): if x <= 0.: self.r[i] = np.random.uniform(low=0., high=1., size=1) x = self.r[i] c = Cloud(i, x, p, t, size=None, em=None) c.assign_sun_coord(d, latit, longit) self.clouds.append(c) else: self.r = self.phi * 0. rbar = self.R_params[2] if self.model == 'Axisymmetric': np.random.seed(self.random_seed + 29) self.r = norm.rvs(loc=self.R_params[0], scale=self.R_params[1], size=self.n) negs = np.ma.masked_less(self.r, 0.) #central molecular zone self.r[negs.mask] = 0. elif self.model == 'LogSpiral': #the bar is assumed axisymmetric and with an inclination angle phi0~25 deg as #it has been measured by F*x et al. 1999 phi_0 = np.deg2rad(25.) self.phi += phi_0 subsize = np.int(self.n / 10) self.r[0:subsize] = norm.rvs(loc=self.R_params[0], scale=self.R_params[1], size=subsize) #np.random.uniform(low=0.,high=8.,size=self.n/4) rscale = rbar / 1.5 self.r[subsize:self.n],self.phi[subsize:self.n]=log_spiral_radial_distribution2(\ rbar,phi_0,self.n-subsize,self.R_params[0],self.R_params[1]) #self.r[subsize:self.n]=log_spiral_radial_distribution(self.phi[subsize:self.n],rbar,phi_0) #simulate the bar arr = np.ma.masked_less(self.r, rbar) self.r[arr.mask] = abs( np.random.normal(loc=0., scale=rscale, size=len(self.r[arr.mask]))) negs = np.ma.masked_less(self.r, 0.) #central molecular zone self.r[negs.mask] = 0. #the thickness of the Galactic plane is function of the Galactic Radius roughly as ~ 100 pc *cosh((x/R0) ), with R0~10kpc # for reference see fig.6 of Heyer and Dame, 2015 sigma_z0 = self.z_distr[0] R_z0 = self.z_distr[1] sigma_z = lambda R: sigma_z0 * np.cosh((R / R_z0)) self.zeta = self.phi * 0. np.random.seed(self.random_seed + 19) for i, x, p in zip(np.arange(self.n), self.r, self.phi): self.zeta[i] = np.random.normal(loc=0., scale=sigma_z(x)) self.clouds.append( Cloud(i, x, p, self.zeta[i], size=None, em=None)) coord_array = coord.CylindricalRepresentation( self.r * u.kpc, self.phi * u.rad, self.zeta * u.kpc) self.cartesian_galactocentric = self.cartesianize_coordinates( coord_array) self.heliocentric_coordinates() for c, d, latit, longit in zip(self.clouds, self.d_sun, self.lat, self.long): c.assign_sun_coord(d, latit, longit) self.L = np.array(self.sizes) self.healpix_vecs = self.compute_healpix_vec() self.W = self.get_pop_emissivities_sizes()[0]
def isochrone_to_xv(actions, angles, potential): """ Transform the input actions and angles to ordinary phase space (position and velocity) in cartesian coordinates. See Section 3.5.2 in Binney & Tremaine (2008), and be aware of the errata entry for Eq. 3.225. .. note:: This function is included as a method of the :class:`~gala.potential.IsochronePotential` and it is recommended to call :meth:`~gala.potential.IsochronePotential.action_angle()` instead. Parameters ---------- actions : array_like Action variables. Must have shape ``(3,N)`` or ``(3,)``. angles : array_like Angle variables. Must have shape ``(3,N)`` or ``(3,)``. Should be in radians. potential : :class:`gala.potential.IsochronePotential` An instance of the potential to use for computing the transformation to angle-action coordinates. Returns ------- x : :class:`numpy.ndarray` An array of cartesian positions computed from the input angles and actions. v : :class:`numpy.ndarray` An array of cartesian velocities computed from the input angles and actions. """ raise NotImplementedError( "Implementation not supported until working with " "angle-action variables has a better API.") actions = atleast_2d(actions, insert_axis=1).copy() angles = atleast_2d(angles, insert_axis=1).copy() usys = potential.units GM = (G * potential.parameters['m']).decompose(usys).value b = potential.parameters['b'].decompose(usys).value # actions Jr = actions[0] Lz = actions[1] L = actions[2] + np.abs(Lz) # angles theta_r, theta_phi, theta_theta = angles # get longitude of ascending node theta_1 = theta_phi - np.sign(Lz) * theta_theta Omega = theta_1 # Ly = -np.cos(Omega) * np.sqrt(L**2 - Lz**2) # Lx = np.sqrt(L**2 - Ly**2 - Lz**2) cosi = Lz / L sini = np.sqrt(1 - cosi**2) # Hamiltonian (energy) H = -2. * GM**2 / (2. * Jr + L + np.sqrt(4. * b * GM + L**2))**2 if np.any(H > 0.): raise ValueError("Unbound particle. (E = {})".format(H)) # Eq. 3.240 c = -GM / (2. * H) - b e = np.sqrt(1 - L * L * (1 + b / c) / GM / c) # solve for eta theta_3 = theta_r eta_func = lambda x: x - e * c / (b + c) * np.sin(x) - theta_3 eta_func_prime = lambda x: 1 - e * c / (b + c) * np.cos(x) # use newton's method to find roots niter = 100 eta = np.ones_like(theta_3) * np.pi / 2. for i in range(niter): eta -= eta_func(eta) / eta_func_prime(eta) # TODO: when to do this??? eta -= 2 * np.pi r = c * np.sqrt((1 - e * np.cos(eta)) * (1 - e * np.cos(eta) + 2 * b / c)) vr = np.sqrt(GM / (b + c)) * (c * e * np.sin(eta)) / r theta_2 = theta_theta Omega_23 = 0.5 * (1 + L / np.sqrt(L**2 + 4 * GM * b)) a = np.sqrt((1 + e) / (1 - e)) ap = np.sqrt((1 + e + 2 * b / c) / (1 - e + 2 * b / c)) def F(x, y): z = np.zeros_like(x) ix = y > np.pi / 2. z[ix] = np.pi / 2. - np.arctan( np.tan(np.pi / 2. - 0.5 * y[ix]) / x[ix]) ix = y < -np.pi / 2. z[ix] = -np.pi / 2. + np.arctan( np.tan(np.pi / 2. + 0.5 * y[ix]) / x[ix]) ix = (y <= np.pi / 2) & (y >= -np.pi / 2) z[ix] = np.arctan(x[ix] * np.tan(0.5 * y[ix])) return z theta_2[Lz < 0] -= 2 * np.pi theta_3 -= 2 * np.pi A = Omega_23 * theta_3 - F( a, eta) - F(ap, eta) / np.sqrt(1 + 4 * GM * b / L / L) psi = theta_2 - A # theta theta = np.arccos(np.sin(psi) * sini) vtheta = L * sini * np.cos(psi) / np.cos(theta) vtheta = -L * sini * np.cos(psi) / np.sin(theta) / r vphi = Lz / (r * np.sin(theta)) # phi sinu = np.sin(psi) * cosi / np.sin(theta) uu = np.arcsin(sinu) uu[sinu > 1.] = np.pi / 2. uu[sinu < -1.] = -np.pi / 2. uu[vtheta > 0.] = np.pi - uu[vtheta > 0.] sinu = cosi / sini * np.cos(theta) / np.sin(theta) phi = (uu + Omega) % (2 * np.pi) # We now need to convert from spherical polar coord to cart. coord. pos = coord.PhysicsSphericalRepresentation(r=r * u.dimensionless_unscaled, phi=phi * u.rad, theta=theta * u.rad) x = pos.represent_as(coord.CartesianRepresentation).xyz.value v = physicsspherical_to_cartesian(pos, [vr, vphi, vtheta] * u.dimensionless_unscaled).value return x, v
def test__fix_branch_cuts(self): """Test method ``_fix_branch_cuts``. .. todo:: graphical proof via mpl_test that the point hasn't moved. """ # ------------------------------- # no angular units rep = coord.CartesianRepresentation( x=[1, 2] * u.kpc, y=[3, 4] * u.kpc, z=[5, 6] * u.kpc, ) array = rep._values.view(dtype=np.float64).reshape(rep.shape[0], -1).T got = self.inst._fix_branch_cuts(array, rep.__class__, rep._units) assert got is array # ------------------------------- # UnitSphericalRepresentation # 1) all good rep = coord.UnitSphericalRepresentation( lon=[1, 2] * u.deg, lat=[3, 4] * u.deg, ) array = rep._values.view(dtype=np.float64).reshape(rep.shape[0], -1).T got = self.inst._fix_branch_cuts( array.copy(), rep.__class__, rep._units, ) assert np.allclose(got, array) # 2) needs correction array = np.array([[-360, 0, 360], [-91, 0, 91]]) got = self.inst._fix_branch_cuts( array.copy(), rep.__class__, rep._units, ) assert np.allclose(got, np.array([[-180, 0, 540], [-89, 0, 89]])) # ------------------------------- # SphericalRepresentation # 1) all good rep = coord.SphericalRepresentation( lon=[1, 2] * u.deg, lat=[3, 4] * u.deg, distance=[5, 6] * u.kpc, ) array = rep._values.view(dtype=np.float64).reshape(rep.shape[0], -1).T got = self.inst._fix_branch_cuts( array.copy(), rep.__class__, rep._units, ) assert np.allclose(got, array) # 2) needs correction array = np.array([[-360, 0, 360], [-91, 0, 91], [5, 6, 7]]) got = self.inst._fix_branch_cuts( array.copy(), rep.__class__, rep._units, ) assert np.allclose( got, np.array([[-180, 0, 540], [-89, 0, 89], [5, 6, 7]]), ) # 3) needs correction array = np.array([[-360, 0, 360], [-91, 0, 91], [-5, 6, -7]]) got = self.inst._fix_branch_cuts( array.copy(), rep.__class__, rep._units, ) assert np.allclose( got, np.array([[0, 0, 720], [89, 0, -89], [5, 6, 7]]), ) # ------------------------------- # CylindricalRepresentation # 1) all good rep = coord.CylindricalRepresentation( rho=[5, 6] * u.kpc, phi=[1, 2] * u.deg, z=[3, 4] * u.parsec, ) array = rep._values.view(dtype=np.float64).reshape(rep.shape[0], -1).T got = self.inst._fix_branch_cuts( array.copy(), rep.__class__, rep._units, ) assert np.allclose(got, array) # 2) needs correction array = np.array([[-5, 6, -7], [-180, 0, 180], [-4, 4, 4]]) got = self.inst._fix_branch_cuts( array.copy(), rep.__class__, rep._units, ) assert np.allclose(got, np.array([[5, 6, 7], [0, 0, 360], [-4, 4, 4]])) # ------------------------------- # NotImplementedError with pytest.raises(NotImplementedError): rep = coord.PhysicsSphericalRepresentation( phi=[1, 2] * u.deg, theta=[3, 4] * u.deg, r=[5, 6] * u.kpc, ) array = (rep._values.view(dtype=np.float64).reshape( rep.shape[0], -1).T) self.inst._fix_branch_cuts( array.copy(), coord.PhysicsSphericalRepresentation, rep._units, )