aboutsummaryrefslogtreecommitdiffstats
path: root/fg21sim/extragalactic/pointsources/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'fg21sim/extragalactic/pointsources/base.py')
-rw-r--r--fg21sim/extragalactic/pointsources/base.py203
1 files changed, 203 insertions, 0 deletions
diff --git a/fg21sim/extragalactic/pointsources/base.py b/fg21sim/extragalactic/pointsources/base.py
new file mode 100644
index 0000000..1544f5b
--- /dev/null
+++ b/fg21sim/extragalactic/pointsources/base.py
@@ -0,0 +1,203 @@
+# Copyright (c) 2016 Zhixian MA <zxma_sjtu@qq.com>
+# MIT license
+
+"""
+Simulation of point sources for 21cm signal detection
+
+Point sources types
+-------------------
+1. Star forming (SF) galaxies
+2. Star bursting (SB) galaxies
+3. Radio quiet AGN (RQ_AGN)
+4. Faranoff-Riley I (FRI)
+5. Faranoff-Riley II (FRII)
+
+References
+----------
+[1] Wilman et al.,
+ "A semi-empirical simulation of the extragalactic radio continuum
+ sky for next generation radio telescopes",
+ 2008, MNRAS, 388, 1335-1348.
+ http://adsabs.harvard.edu/abs/2008MNRAS.388.1335W
+[2] Jelic et al.,
+ "Foreground simulations for the LOFAR-Epoch of Reionization
+ Experiment",
+ 2008, MNRAS, 389, 1319-1335.
+ http://adsabs.harvard.edu/abs/2008MNRAS.389.1319W
+[3] Spherical uniform distribution
+ https://www.jasondavies.com/maps/random-points/
+"""
+import os
+import numpy as np
+import pandas as pd
+import healpy as hp
+
+from .psparams import PixelParams
+
+
+class BasePointSource:
+ """
+ The basic class of point sources
+
+ Parameters
+ ----------
+ z: float;
+ Redshift, z ~ U(0,20)
+ dA: au.Mpc;
+ Angular diameter distance, which is calculated according to the
+ cosmology constants. In this work, it is calculated by module
+ basic_params
+ lumo: au.Jy;
+ Luminosity at the reference frequency.
+ lat: au.deg;
+ The colatitude angle in the spherical coordinate system
+ lon: au.deg;
+ The longtitude angle in the spherical coordinate system
+ area: au.sr;
+ Area of the point sources, sr = rad^2
+
+ """
+ # Init
+
+ def __init__(self, configs):
+ # configures
+ self.configs = configs
+ # PS_list information
+ self.columns = ['z', 'dA (Mpc)', 'luminosity (Jy)', 'Lat (deg)',
+ 'Lon (deg)', 'Area (sr)']
+ self.nCols = len(self.columns)
+ self._set_configs()
+
+ def _set_configs(self):
+ """
+ Load the configs and set the corresponding class attributes.
+ """
+ comp = "extragalactic/pointsources/"
+ # common
+ self.nside = self.configs.getn("common/nside")
+ # resolution
+ self.resolution = self.configs.getn(comp+"resolution")
+ # save flag
+ self.save = self.configs.getn(comp+"save")
+ # Output_dir
+ self.output_dir = self.configs.get_path(comp+"output_dir")
+
+ def calc_number_density(self):
+ pass
+
+ def calc_cdf(self):
+ """
+ Calculate cumulative distribution functions for simulating of
+ samples with corresponding reshift and luminosity.
+
+ Parameter
+ -----------
+ rho_mat: np.ndarray rho(lumo,z)
+ The number density matrix (joint-distribution of z and flux)
+ of this type of PS.
+
+ Returns
+ -------
+ cdf_z, cdf_lumo: np.ndarray
+ Cumulative distribution functions of redshift and flux.
+ """
+ # Normalization
+ rho_mat = self.rho_mat
+ rho_sum = np.sum(rho_mat)
+ rho_norm = rho_mat / rho_sum
+ # probability distribution of redshift
+ pdf_z = np.sum(rho_norm, axis=0)
+ pdf_lumo = np.sum(rho_norm, axis=1)
+ # Cumulative function
+ cdf_z = np.zeros(pdf_z.shape)
+ cdf_lumo = np.zeros(pdf_lumo.shape)
+ for i in range(len(pdf_z)):
+ cdf_z[i] = np.sum(pdf_z[:i])
+ for i in range(len(pdf_lumo)):
+ cdf_lumo[i] = np.sum(pdf_lumo[:i])
+
+ return cdf_z, cdf_lumo
+
+ def get_lumo_redshift(self):
+ """
+ Randomly generate redshif and luminosity at ref frequency using
+ the CDF functions.
+
+ Paramaters
+ ----------
+ df_z, cdf_lumo: np.ndarray
+ Cumulative distribution functions of redshift and flux.
+ zbin,lumobin: np.ndarray
+ Bins of redshif and luminosity.
+
+ Returns
+ -------
+ z: float
+ Redshift.
+ lumo: au.W/Hz/sr
+ Luminosity.
+ """
+ # Uniformlly generate random number in interval [0,1]
+ rnd_z = np.random.uniform(0, 1)
+ rnd_lumo = np.random.uniform(0, 1)
+ # Get redshift
+ dist_z = np.abs(self.cdf_z - rnd_z)
+ idx_z = np.where(dist_z == dist_z.min())
+ z = self.zbin[idx_z[0]]
+ # Get luminosity
+ dist_lumo = np.abs(self.cdf_lumo - rnd_lumo)
+ idx_lumo = np.where(dist_lumo == dist_lumo.min())
+ lumo = 10 ** self.lumobin[idx_lumo[0]]
+
+ return float(z), float(lumo)
+
+ def gen_single_ps(self):
+ """
+ Generate single point source, and return its data as a list.
+ """
+ # Redshift and luminosity
+ self.z, self.lumo = self.get_lumo_redshift()
+ # angular diameter distance
+ self.param = PixelParams(self.z)
+ self.dA = self.param.dA
+ # W/Hz/Sr to Jy
+ dA = self.dA * 3.0856775814671917E+22 # Mpc to meter
+ self.lumo = self.lumo / dA**2 / (10.0**-24) # [Jy]
+ # Position
+ x = np.random.uniform(0, 1)
+ self.lat = (np.arccos(2 * x - 1) / np.pi * 180 - 90) # [deg]
+ self.lon = np.random.uniform(0, np.pi * 2) / np.pi * 180 # [deg]
+ # Area
+ npix = hp.nside2npix(self.nside)
+ self.area = 4 * np.pi / npix # [sr]
+
+ ps_list = [self.z, self.dA, self.lumo, self.lat, self.lon, self.area]
+ return ps_list
+
+ def gen_catalog(self):
+ """
+ Generate num_ps of point sources and save them into a csv file.
+ """
+ # Init
+ ps_table = np.zeros((self.num_ps, self.nCols))
+ for x in range(self.num_ps):
+ ps_table[x, :] = self.gen_single_ps()
+
+ # Transform into Dataframe
+ self.ps_catalog = pd.DataFrame(ps_table, columns=self.columns,
+ index=list(range(self.num_ps)))
+
+ def save_as_csv(self):
+ """Save the catalog"""
+ if not os.path.exists(self.output_dir):
+ os.mkdir(self.output_dir)
+
+ pattern = "{prefix}.csv"
+ filename = pattern.format(prefix=self.prefix)
+
+ # save to csv
+ if self.save:
+ file_name = os.path.join(self.output_dir, filename)
+ self.ps_catalog.to_csv(file_name)
+
+ return file_name