diff options
Diffstat (limited to 'fg21sim/extragalactic/clusters')
| -rw-r--r-- | fg21sim/extragalactic/clusters/formation.py | 87 | 
1 files changed, 77 insertions, 10 deletions
| diff --git a/fg21sim/extragalactic/clusters/formation.py b/fg21sim/extragalactic/clusters/formation.py index 6dbf58e..59c8cbe 100644 --- a/fg21sim/extragalactic/clusters/formation.py +++ b/fg21sim/extragalactic/clusters/formation.py @@ -169,23 +169,92 @@ class ClusterFormation:          dS = self.cdf_K_inv(r, dw)          return dS -    def simulate_mergertree(self): +    def simulate_mergertree(self, main_only=True):          """          Simulate the merger tree of this cluster by tracing its formation          using the PS formalism. +        Parameters +        ---------- +        main_only : bool, optional +            Whether to only trace the forming history of the main +            halo/cluster. +            (default: True) +          References: Ref.[1],Sec.(3.1)          """          logger.info("Simulating cluster formation: " + -                    "M0={:.3g}[Msun] from z={:.2f} ...".format( -                        self.M0, self.z0)) -        self.mtree = self._trace_formation(self.M0, -                                           dMc=self.merger_mass_min, -                                           _z=self.z0) +                    "M0={:.3g}[Msun] from z={:.2f} to z={zmax} ...".format( +                        self.M0, self.z0, zmax=self.zmax)) +        self.main_only = main_only +        if main_only: +            logger.info("Only trace the formation of the *main* cluster ...") +            self.mtree = self._trace_main() +        else: +            logger.info("Trace formations of both main and sub cluster ...") +            self.mtree = self._trace_formation(self.M0, _z=self.z0)          logger.info("Simulated cluster formation with merger tree")          return self.mtree -    def _trace_formation(self, M, dMc, _z=None): +    def _trace_main(self): +        """ +        Iteratively trace the merger and accretion events of the +        main cluster/halo. +        """ +        # Initial properties +        zc = self.z0 +        Mc = self.M0 +        mtree = MergerTree(data={"mass": Mc, +                                 "z": zc, +                                 "age": self.cosmo.age(zc)}) + +        while True: +            # Whether to stop the trace +            if self.zmax is not None and zc > self.zmax: +                break +            if Mc <= self.merger_mass_min: +                break + +            # Trace the formation by simulate a merger/accretion event +            # Notation: progenitor (*1) -> current (*2) + +            # Current properties +            w2 = self.f_delta_c(z=zc) +            S2 = self.f_sigma(Mc) ** 2 +            dw = 0.5 * self.f_dw_max(Mc) +            dS = self.gen_dS(dw) +            # Progenitor properties +            z1 = self.calc_z(w2 + dw) +            age1 = self.cosmo.age(z1) +            S1 = S2 + dS +            M1 = self.calc_mass(S1) +            dM = Mc - M1 + +            M_min = min(M1, dM) +            if M_min <= self.merger_mass_min: +                # Accretion +                M_main = Mc - M_min +                # NOTE: no sub node +            else: +                # Merger event +                M_main = max(M1, dM) +                M_sub = M_min +                mtree.sub = MergerTree(data={"mass": M_sub, +                                             "z": z1, +                                             "age": age1}) + +            # Update main cluster +            mtree.main = MergerTree(data={"mass": M_main, +                                          "z": z1, +                                          "age": age1}) + +            # Update for next iteration +            Mc = M_main +            zc = z1 +            mtree = mtree.main + +        return mtree +      def _trace_formation(self, M, _z=None, zmax=None):          """          Recursively trace the cluster formation and thus simulate its @@ -194,12 +263,10 @@ class ClusterFormation:          z = 0.0 if _z is None else _z          node_data = {"mass": M, "z": z, "age": self.cosmo.age(z)} +        # Whether to stop the trace          if self.zmax is not None and z > self.zmax: -            # Stop the trace              return MergerTree(data=node_data) -          if M <= self.merger_mass_min: -            # Stop the trace              return MergerTree(data=node_data)          # Trace the formation by simulate a merger/accretion event | 
