diff options
Diffstat (limited to 'fg21sim')
| -rw-r--r-- | fg21sim/configs/20-extragalactic.conf.spec | 28 | ||||
| -rw-r--r-- | fg21sim/extragalactic/clusters/main.py | 82 | 
2 files changed, 95 insertions, 15 deletions
| diff --git a/fg21sim/configs/20-extragalactic.conf.spec b/fg21sim/configs/20-extragalactic.conf.spec index 377bd27..0f797a8 100644 --- a/fg21sim/configs/20-extragalactic.conf.spec +++ b/fg21sim/configs/20-extragalactic.conf.spec @@ -16,13 +16,31 @@  [extragalactic] -  # Emissions from the clusters of galaxies +  # Extended emissions from the clusters of galaxies +  # The configurations in this ``[[clusters]]`` section may also be +  # used by the following ``[[halos]]`` section.    [[clusters]]    # The clusters catalog derived from the Hubble Volume Project (CSV file)    catalog = string(default=None)    # Output the effective/inuse clusters catalog data (CSV file)    catalog_outfile = string(default=None) +  # Minimum mass change of the main cluster to be regarded as a merger +  # event instead of an accretion event. +  # Unit: [Msun] +  merger_mass_min = float(default=1e12, min=1e10, max=1e14) + +  # Mass ratio of the main and sub clusters, below which is regarded as +  # a major merger event. +  ratio_major = float(default=3.0, min=1.0, max=10.0) + +  # The merger timescale, which roughly describes the duration of the +  # merger-induced disturbance (~2-3 Gyr).  This timescale is much longer +  # the merger crossing time (~1 Gyr), and is also longer than the lifetime +  # of radio halos. +  # Unit: [Gyr] +  tau_merger = float(default=3.0, min=1.0, max=5.0) +    # The fraction that a cluster hosts a radio halo    halo_fraction = float(default=None, min=0.0, max=1.0) @@ -51,14 +69,6 @@    # merger. (unit: Msun)    merger_mass_th = float(default=1e13, min=1e12) -  # Minimum mass change of the main-cluster to be regarded as a merger -  # event rather than accretion. (unit: Msun) -  merger_mass_min = float(default=1e12, min=1e10) - -  # Mass ratio of the main and sub clusters, below which is regarded as -  # a major merger event. -  ratio_major = float(default=3.0, min=1.0, max=10.0) -    # Radius of the giant radio halo in clusters (unit: kpc)    # XXX: currently only support a constant radius of halos    radius = float(default=500.0, min=100.0) diff --git a/fg21sim/extragalactic/clusters/main.py b/fg21sim/extragalactic/clusters/main.py index 501dc6a..c3a89d0 100644 --- a/fg21sim/extragalactic/clusters/main.py +++ b/fg21sim/extragalactic/clusters/main.py @@ -54,15 +54,15 @@ class GalaxyClusters:          self.prefix = self.configs.getn(comp+"/prefix")          self.save = self.configs.getn(comp+"/save")          self.output_dir = self.configs.get_path(comp+"/output_dir") -        if self.sky.type_ == "patch": -            self.resolution = self.sky.pixelsize -        else: -            raise NotImplementedError("TODO: full-sky simulations") -        # +        self.merger_mass_min = self.configs.getn(comp+"/merger_mass_min") +        self.ratio_major = self.configs.getn(comp+"/ratio_major") +        self.tau_merger = self.configs.getn(comp+"/tau_merger") +          self.filename_pattern = self.configs.getn("output/filename_pattern")          self.use_float = self.configs.getn("output/use_float")          self.checksum = self.configs.getn("output/checksum")          self.clobber = self.configs.getn("output/clobber") +          # Cosmology model          self.H0 = self.configs.getn("cosmology/H0")          self.OmegaM0 = self.configs.getn("cosmology/OmegaM0") @@ -70,7 +70,13 @@ class GalaxyClusters:          self.sigma8 = self.configs.getn("cosmology/sigma8")          self.cosmo = Cosmology(H0=self.H0, Om0=self.OmegaM0,                                 Ob0=self.Omegab0, sigma8=self.sigma8) -        # + +        # Sky and resolution +        if self.sky.type_ == "patch": +            self.resolution = self.sky.pixelsize  # [arcsec] +        else: +            raise NotImplementedError("TODO: full-sky simulations") +          logger.info("Loaded and set up configurations")      def _load_catalog(self): @@ -143,6 +149,70 @@ class GalaxyClusters:              "rotation : ellipse rotation angle [deg]")          logger.info("Added catalog column: rotation.") +    def _simulate_merger(self): +        """ +        Simulate the *last/recent major merger* event for each cluster. + +        First simulate the cluster formation history by tracing the +        merger and accretion events of the main cluster, then identify +        the last (i.e., most recent) major merger event according +        to the mass ratio of two merging clusters.  And the properties +        of the found merger event are appended to the catalog. + +        NOTE +        ---- +        There may be no such recent major merger event satisfying the +        criteria, since we only tracing ``tau_merger`` (~3 Gyr) back. +        On the other hand, the cluster may only experience minor merger +        or accretion events. + +        Catalog columns +        --------------- +        * ``lmm_mass1``, ``lmm_mass2`` : masses of the main and sub +          clusters upon the last major merger event; unit: [Msun] +        * ``lmm_z``, ``lmm_age`` : redshift and cosmic age (unit: [Gyr]) +          of the last major merger event. +        """ +        logger.info("Simulating the galaxy formation to identify " + +                    "the last/recent major merger event ...") +        num = len(self.catalog) +        mdata = np.zeros(shape=(num, 4)) +        num_major = 0  # number of clusters with recent major merger + +        for i, row in zip(range(num), self.catalog.itertuples()): +            ii = i + 1 +            if ii % 50 == 0: +                logger.info("[%d/%d] %.1f%% ..." % (ii, num, 100*ii/num)) +            z0, M0 = row.z, row.mass +            age0 = self.cosmo.age(z0) +            zmax = self.cosmo.redshift(age0 - self.tau_merger) +            clform = ClusterFormation(M0=M0, z0=z0, zmax=zmax, +                                      ratio_major=self.ratio_major, +                                      cosmo=self.cosmo, +                                      merger_mass_min=self.merger_mass_min) +            clform.simulate_mergertree(main_only=True) +            mmev = clform.last_major_merger +            if mmev: +                num_major += 1 +                mdata[i, :] = [mmev["M_main"], mmev["M_sub"], +                               mmev["z"], mmev["age"]] +            else: +                mdata[i, :] = [np.nan, np.nan, np.nan, np.nan] + +        mdf = pd.DataFrame(data=mdata, +                           columns=["lmm_mass1", "lmm_mass2", +                                    "lmm_z", "lmm_age"]) +        self.catalog = self.catalog.join(mdf, how="outer") +        self.catalog_comment += [ +            "lmm_mass1 : main cluster mass at last major merger; [Msun]", +            "lmm_mass2 : sub cluster mass at last major merger; [Msun]", +            "lmm_z : redshift of the last major merger", +            "lmm_age : cosmic age of the last major merger; [Gyr]", +        ] +        logger.info("Simulated and identified last major merger events.") +        logger.info("%d (%.1f%%) clusters have recent major mergers." % +                    (num_major, 100*num_major/num)) +      def postprocess(self):          """          Do some necessary post-simulation operations. | 
