Пример #1
0
    def QCD_transition(self,
                       hadrons=None,
                       quarkic_interactions=None,
                       hadronic_interactions=None,
                       secondary_interactions=None):
        self.data.truncate()

        dof_before_qcd = Params.entropic_dof_eq(self)

        self.particles = utils.particle_filter([
            'Up quark', 'Down quark', 'Charm quark', 'Strange quark',
            'Top quark', 'Bottom quark', 'Gluon'
        ], self.particles)
        self.add_particles(hadrons)

        dof_after_qcd = Params.entropic_dof_eq(self)

        self.params.aT = self.data['aT'][-1] * (dof_before_qcd /
                                                dof_after_qcd)**(1 / 3)
        #        self.params.x = self.data['x'][-1] * (dof_before_qcd/dof_after_qcd)**(1/3)
        #        self.params.a = self.data['a'][-1] * (dof_before_qcd/dof_after_qcd)**(1/3)
        self.params.update(self.total_energy_density(),
                           self.total_entropy())  # T will be updated here...
        #        self.params.T = CONST.lambda_QCD # That's why we change it here again
        self.update_particles()

        if quarkic_interactions and self.interactions:
            for inter in quarkic_interactions:
                self.interactions.remove(inter)
        if hadronic_interactions:
            self.interactions += (hadronic_interactions)
        if secondary_interactions:
            self.interactions += (secondary_interactions)
Пример #2
0
    def __init__(self, folder='logs', plotting=True, params=None, grid=None):
        """
        :param particles: Set of `particle.Particle` to model
        :param interactions: Set of `interaction.Interaction` - quantum interactions \
                             between particle species
        :param folder: Log file path (current `datetime` by default)
        """

        self.particles = []
        self.interactions = []

        self.clock_start = time.time()

        self.params = Params() if not params else params

        # self.graphics = None
        # if utils.getboolenv("PLOT", plotting):
        #     from plotting import Plotting
        #     self.graphics = Plotting()

        self.init_log(folder=folder)

        # Controls parallelization of the collision integrals calculations
        self.PARALLELIZE = utils.getboolenv("PARALLELIZE", True)
        if self.PARALLELIZE:
            parallelization.init_pool()

        self.fraction = 0

        self.step = 1
def main():
    from sys import argv
    dir_path = os.path.dirname(os.path.realpath(__file__))
    if not os.path.exists(dir_path + "/output"):
        print "No output detected. Exiting."
        return

    config = Params(argv[1])

    writeDecision(config, dir_path, "output/decision.file")
    print "Tuning file written to output/decision.file"
Пример #4
0
def decoupling_test():

    params = Params(T=SMP.leptons.neutrino_e['decoupling_temperature'] * 2,
                    dy=0.025)
    neutrino = Particle(params=params, **SMP.leptons.neutrino_e)

    assert neutrino.in_equilibrium
    eq_distribution = neutrino._distribution

    params.T /= 2
    params.a = params.m / params.T
    params.infer()

    assert neutrino.in_equilibrium, "Neutrino should not depend on global temperature change"
    neutrino.update()

    assert not neutrino.in_equilibrium, "Neutrino should have decoupled"
    noneq_distribution = neutrino._distribution

    assert all(eq_distribution == noneq_distribution), \
        "Free massless particle distribution should be conserved in conformal coordinates"
Пример #5
0
def decoupling_test():

    params = Params(T=SMP.leptons.neutrino_e['decoupling_temperature'] * 2,
                    dy=0.025)
    neutrino = Particle(params=params, **SMP.leptons.neutrino_e)

    assert neutrino.in_equilibrium
    eq_distribution = neutrino._distribution

    params.T /= 2
    params.a = params.m / params.T
    params.infer()

    assert neutrino.in_equilibrium, "Neutrino should not depend on global temperature change"
    neutrino.update()

    assert not neutrino.in_equilibrium, "Neutrino should have decoupled"
    noneq_distribution = neutrino._distribution

    assert all(eq_distribution == noneq_distribution), \
        "Free massless particle distribution should be conserved in conformal coordinates"
Пример #6
0
    def __init__(self, folder=None, params=None, max_log_rate=2):
        """
        :param folder: Log file path (current `datetime` by default)
        """

        self.particles = []
        self.interactions = []

        self.clock_start = time.time()
        self.log_throttler = utils.Throttler(max_log_rate)

        self.params = params
        if not self.params:
            self.params = Params()

        self.folder = folder
        if self.folder:
            if os.path.exists(folder):
                shutil.rmtree(folder)
            self.init_log(folder=folder)

        self.fraction = 0

        self.step = 1
Пример #7
0
    def __init__(self, folder=None, params=None, max_log_rate=2):
        """
        :param folder: Log file path (current `datetime` by default)
        """

        self.particles = []
        self.interactions = []

        self.clock_start = time.time()
        self.log_throttler = utils.Throttler(max_log_rate)

        self.params = params
        if not self.params:
            self.params = Params()

        self.folder = folder
        if self.folder:
            if os.path.exists(folder):
                shutil.rmtree(folder)
            self.init_log(folder=folder)

        self.fraction = 0

        self.step = 1
Пример #8
0
"""

import os

from particles import Particle
from library.SM import particles as SMP, interactions as SMI
from evolution import Universe
from common import UNITS, Params

folder = os.path.join(os.path.split(__file__)[0], 'output')

T_kawano = 10 * UNITS.MeV
T_simple = 0.05 * UNITS.MeV
T_final = 0.0008 * UNITS.MeV
params = Params(T=T_kawano, dy=0.0125)

universe = Universe(params=params, folder=folder)

photon = Particle(**SMP.photon)
electron = Particle(**SMP.leptons.electron)
neutrino_e = Particle(**SMP.leptons.neutrino_e)
neutrino_mu_tau = Particle(**SMP.leptons.neutrino_mu)
neutrino_mu_tau.dof = 4

neutron = Particle(**SMP.hadrons.neutron)
proton = Particle(**SMP.hadrons.proton)

universe.add_particles(
    [photon, electron, neutrino_e, neutrino_mu_tau, neutron, proton])
Пример #9
0
def setup():
    params = Params(T=SMP.leptons.neutrino_e['decoupling_temperature'],
                    dy=0.025)
    return [params], {}
def main():
    from os import system
    from sys import argv
    from common import Params
    import sys

    dir_path = os.path.dirname(os.path.realpath(__file__))
    config = Params(argv[1])
    scheduler = argv[2]
    collective_list = config.getStrlst("collectives")
    omb_path = config.getStr("omb_collective_directory")
    imb_bin = config.getStr("imb_binary")
    num_rank_list = config.getIntlst("number_of_ranks")
    max_num_node = config.getInt("max_num_node")
    num_core_per_node = config.getInt("number_of_cores_per_node")
    num_run = config.getInt("number_of_runs_per_test")

    job_directory = dir_path + "/collective_jobs"
    for collective in collective_list:
        params = Params(job_directory + "/" + collective + ".job")

        if not os.path.exists(dir_path + "/output"):
            os.makedirs(dir_path + "/output")
        if not os.path.exists(dir_path + "/output/" + collective):
            os.makedirs(dir_path + "/output/" + collective)

        num_alg = params.getInt("number_of_algorithms")
        exclude_alg = params.getIntlst("exclude_algorithms")
        two_proc_alg = -1
        try:
            two_proc_alg = params.getInt("two_proc_alg")
        except Exception as e:
            print "No two proc algorithm for " + collective

        f = open(
            dir_path + "/output/" + collective + "/" + collective +
            "_coltune.sh", "w")
        print >> f, "#!/bin/sh"
        print >> f, "#"
        if scheduler == "slurm":
            print >> f, "#SBATCH --job-name=" + collective
            print >> f, "#SBATCH --output=res.txt"
            print >> f, "#"
            print >> f, "#SBATCH --ntasks-per-node=" + str(num_core_per_node)
            print >> f, "#SBATCH --time=1000:00:00"
            print >> f, "#SBATCH --nodes=" + str(max_num_node)
        elif scheduler == "sge":
            print >> f, "#$ -j y"
            print >> f, "#$ -pe mpi %d" % (max_num_node * num_core_per_node)
            print >> f, "#"
            print >> f, "#$ -cwd"
            print >> f, "#"
            print >> f, "echo Got $NSOLTS processors."
        else:
            print "Unknown scheduler. Aborting.."
            sys.exit()

        print >> f, ""

        for num_rank in num_rank_list:
            for alg in range(num_alg + 1):
                if alg in exclude_alg or (alg == two_proc_alg
                                          and num_rank > 2):
                    continue
                print >> f, "# ", alg, num_rank, "ranks"
                for run_id in xrange(num_run):
                    if collective in imb_collectives:
                        prg_name = imb_bin + " -npmin %d %s " % (num_rank,
                                                                 collective)
                    else:
                        prg_name = omb_path + "/osu_" + collective
                    cmd = "mpirun --np %d " % (num_rank)
                    cmd += "--mca coll_tuned_use_dynamic_rules 1 --mca coll_tuned_" + collective + "_algorithm " + str(
                        alg)
                    cmd += " " + prg_name
                    cmd += " >& " + dir_path + "/output/" + collective + "/" + str(
                        alg) + "_" + str(num_rank) + "ranks" + "_run" + str(
                            run_id) + ".out"
                    print >> f, cmd
                print >> f, ""

        f.close()
        print "SGE script wrote to " + collective + "_coltune.sh successfully!"
Пример #11
0
class Universe(object):

    """ ## Universe
        The master object that governs the calculation. """

    # System state is rendered to the log file each `log_freq` steps
    log_freq = 1
    clock_start = None

    particles = None
    interactions = None

    kawano = None
    kawano_log = None

    oscillations = None

    step_monitor = None

    data = pandas.DataFrame(columns=('aT', 'T', 'a', 'x', 't', 'rho', 'fraction'))

    def __init__(self, folder='logs', plotting=True, params=None, grid=None):
        """
        :param particles: Set of `particle.Particle` to model
        :param interactions: Set of `interaction.Interaction` - quantum interactions \
                             between particle species
        :param folder: Log file path (current `datetime` by default)
        """

        self.particles = []
        self.interactions = []

        self.clock_start = time.time()

        self.params = Params() if not params else params

        # self.graphics = None
        # if utils.getboolenv("PLOT", plotting):
        #     from plotting import Plotting
        #     self.graphics = Plotting()

        self.init_log(folder=folder)

        # Controls parallelization of the collision integrals calculations
        self.PARALLELIZE = utils.getboolenv("PARALLELIZE", True)
        if self.PARALLELIZE:
            parallelization.init_pool()

        self.fraction = 0

        self.step = 1

    def init_kawano(self, datafile='s4.dat', **kwargs):
        kawano.init_kawano(**kwargs)
        self.kawano_log = open(os.path.join(self.folder, datafile), 'w')
        self.kawano_log.write("\t".join(kawano.heading) + "\n")
        self.kawano = kawano
        self.kawano_data = pandas.DataFrame(columns=self.kawano.heading)

    def init_oscillations(self, pattern, particles):
        self.oscillations = (pattern, particles)

    def evolve(self, T_final, export=True):
        """
        ## Main computing routine

        Modeling is carried in steps of scale factor, starting from the initial conditions defined\
        by a single parameter: the initial temperature.

        Initial temperature (e.g. 10 MeV) corresponds to a point in the history of the Universe \
        long before then BBN. Then most particle species are in the thermodynamical equilibrium.

        """

        for particle in self.particles:
            print particle

        for interaction in self.interactions:
            print interaction

        if self.params.rho is None:
            self.update_particles()
            self.params.update(self.total_energy_density())
        self.save_params()

        while self.params.T > T_final:
            try:
                self.log()
                self.make_step()
                self.save()
                self.step += 1
                self.data.to_pickle(os.path.join(self.folder, "evolution.pickle"))
            except KeyboardInterrupt:
                print "Keyboard interrupt!"
                break

        self.log()
        if export:
            self.export()

        return self.data

    def export(self):
        for particle in self.particles:
            print particle

        # if self.graphics:
        #     self.graphics.save(self.logfile)

        if self.kawano:
            # if self.graphics:
            #     self.kawano.plot(self.kawano_data, save=self.kawano_log.name)

            self.kawano_log.close()
            print kawano.run(self.folder)

            self.kawano_data.to_pickle(os.path.join(self.folder, "kawano.pickle"))

        print "Data saved to file {}".format(self.logfile)

        self.data.to_pickle(os.path.join(self.folder, "evolution.pickle"))

    def make_step(self):
        self.integrand(self.params.x, self.params.aT)

        order = min(self.step + 1, 5)
        fs = self.data['fraction'].tail(order-1).values.tolist()
        fs.append(self.fraction)

        self.params.aT +=\
            integrators.adams_bashforth_correction(fs=fs, h=self.params.dy, order=order)
        self.params.x += self.params.dx

        self.params.update(self.total_energy_density())
        if self.step_monitor:
            self.step_monitor(self)

    def add_particles(self, particles):
        for particle in particles:
            particle.set_params(self.params)

        self.particles += particles

    def update_particles(self):
        """ ### 1. Update particles state
            Update particle species distribution functions, check for regime switching,\
            update precalculated variables like energy density and pressure. """
        for particle in self.particles:
            particle.update()

    def init_interactions(self):
        """ ### 2. Initialize non-equilibrium interactions
            Non-equilibrium interactions of different particle species are treated by a\
            numerical integration of the Boltzmann equation for distribution functions in\
            the expanding space-time.

            Depending on the regime of the particle species involved and cosmological parameters, \
            each `Interaction` object populates `Particle.collision_integrals` array with \
            currently active `Integral` objects.
        """
        for interaction in self.interactions:
            interaction.initialize()

    def calculate_collisions(self):
        """ ### 3. Calculate collision integrals """

        particles = [particle for particle in self.particles if particle.collision_integrals]

        with utils.printoptions(precision=2):
            if self.PARALLELIZE:
                for particle in particles:
                    parallelization.orders = [
                        (particle,
                         parallelization.poolmap(particle, 'calculate_collision_integral',
                                                 particle.grid.TEMPLATE))
                    ]
                    for particle, result in parallelization.orders:
                        with utils.benchmark(lambda: "I(" + particle.symbol + ") = "
                                             + repr(particle.collision_integral)):
                            particle.collision_integral = numpy.array(result.get(1000))
            else:
                for particle in particles:
                    with utils.benchmark(lambda: "I(" + particle.symbol + ") = "
                                         + repr(particle.collision_integral)):
                        particle.collision_integral = particle.integrate_collisions()

    def update_distributions(self):
        """ ### 4. Update particles distributions """

        if self.oscillations:
            pattern, particles = self.oscillations

            integrals = {A.flavour: A.collision_integral for A in particles}

            for A in particles:
                A.collision_integral = sum(pattern[(A.flavour, B.flavour)] * integrals[B.flavour]
                                           for B in particles)

        for particle in self.particles:
            particle.update_distribution()

    def calculate_temperature_terms(self):
        """ ### 5. Calculate temperature equation terms """

        numerator = 0
        denominator = 0

        for particle in self.particles:
            numerator += particle.numerator
            denominator += particle.denominator

        return numerator, denominator

    def integrand(self, t, y):
        """ ## Temperature equation integrand

            Master equation for the temperature looks like

            \begin{equation}
                \frac{d (aT)}{dx} = \frac{\sum_i{N_i}}{\sum_i{D_i}}
            \end{equation}

            Where $N_i$ and $D_i$ represent contributions from different particle species.

            See definitions for different regimes:
              * [[Radiation|particles/RadiationParticle.py#master-equation-terms]]
              * [[Intermediate|particles/IntermediateParticle.py#master-equation-terms]]
              * [[Dust|particles/DustParticle.py#master-equation-terms]]
              * [[Non-equilibrium|particles/NonEqParticle.py#master-equation-terms]]
        """

        # 1\. Update particles states
        self.update_particles()
        # 2\. Initialize non-equilibrium interactions
        self.init_interactions()
        # 3\. Calculate collision integrals
        self.calculate_collisions()
        # 4\. Update particles distributions
        self.update_distributions()
        # 5\. Calculate temperature equation terms
        numerator, denominator = self.calculate_temperature_terms()
        self.fraction = self.params.x * numerator / denominator

        return self.fraction

    def save_params(self):
        self.data = self.data.append({
            'aT': self.params.aT,
            'T': self.params.T,
            'a': self.params.a,
            'x': self.params.x,
            'rho': self.params.rho,
            'N_eff': self.params.N_eff,
            't': self.params.t,
            'fraction': self.fraction
        }, ignore_index=True)

    def save(self):
        """ Save current Universe parameters into the data arrays or output files """
        self.save_params()

        if self.kawano and self.params.T <= self.kawano.T_kawano:

            #     t[s]         x    Tg[10^9K]   dTg/dt[10^9K/s] rho_tot[g cm^-3]     H[s^-1]
            # n nue->p e  p e->n nue  n->p e nue  p e nue->n  n e->p nue  p nue->n e

            rates = self.kawano.baryonic_rates(self.params.a)

            row = {
                self.kawano.heading[0]: self.params.t / UNITS.s,
                self.kawano.heading[1]: self.params.x / UNITS.MeV,
                self.kawano.heading[2]: self.params.T / UNITS.K9,
                self.kawano.heading[3]: (self.params.T - self.data['T'].iloc[-2])
                / (self.params.t - self.data['t'].iloc[-2]) * UNITS.s / UNITS.K9,
                self.kawano.heading[4]: self.params.rho / UNITS.g_cm3,
                self.kawano.heading[5]: self.params.H * UNITS.s
            }

            row.update({self.kawano.heading[i]: rate / UNITS.MeV**5
                        for i, rate in enumerate(rates, 6)})

            self.kawano_data = self.kawano_data.append(row, ignore_index=True)
            log_entry = "\t".join("{:e}".format(item) for item in self.kawano_data.iloc[-1])

            print "KAWANO", log_entry
            self.kawano_log.write(log_entry + "\n")

    def init_log(self, folder=''):
        self.folder = folder
        self.logfile = utils.ensure_path(os.path.join(self.folder, 'log.txt'))
        sys.stdout = utils.Logger(self.logfile)

    def log(self):
        """ Runtime log output """

        # Print parameters every now and then
        if self.step % self.log_freq == 0:
            print ('[{clock}] #{step}\tt = {t:e}\taT = {aT:e}\tT = {T:e}\ta = {a:e}\tdx = {dx:e}'
                   .format(clock=str(timedelta(seconds=int(time.time() - self.clock_start))),
                           step=self.step,
                           t=self.params.t / UNITS.s,
                           aT=self.params.aT / UNITS.MeV,
                           T=self.params.T / UNITS.MeV,
                           a=self.params.a,
                           dx=self.params.dx / UNITS.MeV))

            # if self.graphics:
            #     self.graphics.plot(self.data)

    def total_energy_density(self):
        return sum(particle.energy_density for particle in self.particles)
Пример #12
0
[Log file](log.txt)


"""

import os
from particles import Particle
from evolution import Universe
from common import Params, UNITS
from semianalytic import step_monitor
from library.SM import particles as SMP


folder = os.path.split(__file__)[0]

params = Params(T=10 * UNITS.MeV,
                dy=0.025)
T_final = 0.0008 * UNITS.MeV


Particles = []
photon = Particle(**SMP.photon)
neutron = Particle(**SMP.hadrons.neutron)
proton = Particle(**SMP.hadrons.proton)
neutrino_e = Particle(**SMP.leptons.neutrino_e)
neutrino_mu = Particle(**SMP.leptons.neutrino_mu)
neutrino_tau = Particle(**SMP.leptons.neutrino_tau)
electron = Particle(**SMP.leptons.electron)
muon = Particle(**SMP.leptons.muon)
tau = Particle(**SMP.leptons.tau)

Particles += [
Пример #13
0
[Log file](log.txt)

"""

import os
import numpy

from particles import Particle
from evolution import Universe
from library.SM import particles as SMP
from common import Params, UNITS

folder = os.path.join(os.path.split(__file__)[0], 'output')

T_final = 100 * UNITS.keV
params = Params(T=100 * UNITS.MeV, dy=0.05)

universe = Universe(params=params, folder=folder)

photon = Particle(**SMP.photon)
electron = Particle(**SMP.leptons.electron)

universe.add_particles([photon, electron])
universe.evolve(T_final)

initial_aT = universe.data['aT'][0]
print("a * T is not conserved: {}".format(
    any([initial_aT != value for value in universe.data['aT']])))
initial_a = universe.data['a'][int(len(universe.data) / 2)]
initial_t = universe.data['t'][int(len(universe.data) / 2)] / UNITS.s
last_a = universe.data['a'][-1]
def writeDecision(config, dir_path, outfil):
    collective_list = config.getStrlst("collectives")
    num_rank_list = config.getIntlst("number_of_ranks")
    num_run = config.getInt("number_of_runs_per_test")

    num_coll = len(collective_list)
    output_dir = dir_path + "/output"
    job_dir = dir_path + "/collective_jobs"
    f = open(outfil, "w")
    print >> f, "%-10s" % num_coll, "# Number of collectives"
    for collective in collective_list:
        if not os.path.exists(dir_path + "/output/" + collective):
            print "Collective " + collective + " output not detected. Exiting."
            return

        params = Params(job_dir + "/" + collective + ".job")
        num_alg = params.getInt("number_of_algorithms")
        exclude_alg = params.getIntlst("exclude_algorithms")
        two_proc_alg = -1
        try:
            two_proc_alg = params.getInt("two_proc_alg")
        except Exception as e:
            print "No two proc algorithm for " + collective
        raw_dir = dir_path + "/output/" + collective

        coll_result = {}
        for num_rank in num_rank_list:
            coll_result[num_rank] = NumRankResult(config, num_alg, exclude_alg,
                                                  two_proc_alg, raw_dir,
                                                  num_rank, collective)

        writeResult(num_rank_list, coll_result, raw_dir + "/best.out")
        print "Result wrote for " + collective + " to " + collective + "/best.out"

        print >> f, "%-10s" % coll_id_from_name(
            collective), "# Collective ID for", collective

        com_sizes = len(num_rank_list)
        print >> f, "%-10s" % com_sizes, "# Number of com sizes"
        for num_rank in num_rank_list:
            nod_result = coll_result[num_rank]
            print >> f, "%-10s" % num_rank, "# Com size"
            best = Params(output_dir + "/" + collective + "/best.out")
            best_alg = 0
            # Open MPI requires that all data should start from msg size 0.
            # The default one is `0 0 0 0\n`
            # For collective data starts from msg size 0 (barrier or
            # collectives benchmarked by IMB) this line could be updated.
            if nod_result.msgsizlst()[0] == 0:
                num_sizes = 0
                size_output = ""
            else:
                num_sizes = 1
                size_output = "0 0 0 0\n"
            for i, msg_siz in enumerate(nod_result.msgsizlst()):
                new_alg = nod_result.selectAlg()[i]
                if new_alg == best_alg:
                    continue
                best_alg = new_alg
                num_sizes += 1
                size_output += str(msg_siz)
                size_output += " " + str(best_alg)
                size_output += " 0"
                size_output += " 0\n"
            print >> f, "%-10s" % num_sizes, "# Number of msg sizes"
            print >> f, size_output,
        writeDetail(params, coll_result, raw_dir + "/detail.out", num_alg,
                    exclude_alg, two_proc_alg, num_run, num_rank_list)
Пример #15
0
    description='Run simulation for given mass and mixing angle')
parser.add_argument('--mass', default=300)
parser.add_argument('--theta', default=0.001)
parser.add_argument('--comment', default='')
args = parser.parse_args()

mass = float(args.mass) * UNITS.MeV
theta = float(args.theta)

folder = utils.ensure_dir(
    os.path.split(__file__)[0], 'output',
    "mass={:e}_theta={:e}".format(mass / UNITS.MeV, theta) + args.comment)

T_initial = 50. * UNITS.MeV
T_final = 0.0008 * UNITS.MeV
params = Params(T=T_initial, dy=0.0003125)

universe = Universe(params=params, folder=folder)

linear_grid_s = LinearSpacedGrid(MOMENTUM_SAMPLES=51,
                                 MAX_MOMENTUM=20 * UNITS.MeV)
linear_grid = LinearSpacedGrid(MOMENTUM_SAMPLES=51,
                               MAX_MOMENTUM=50 * UNITS.MeV)
photon = Particle(**SMP.photon)

#electron = Particle(**SMP.leptons.electron)
#muon = Particle(**SMP.leptons.muon)
#tau = Particle(**SMP.leptons.tau)

neutrino_e = Particle(**SMP.leptons.neutrino_e, **{'grid': linear_grid})
#neutrino_mu = Particle(**SMP.leptons.neutrino_mu)
Пример #16
0
import os

from collections import defaultdict

from particles import Particle
from library.SM import particles as SMP, interactions as SMI
from library.NuMSM import particles as NuP, interactions as NuI
from evolution import Universe
from common import UNITS, Params


folder = os.path.join(os.path.split(__file__)[0], 'output')

T_initial = 200 * UNITS.MeV
T_final = 50 * UNITS.MeV
params = Params(T=T_initial,
                dy=0.025)

universe = Universe(params=params, logfile=os.path.join(folder, 'log.txt'))

photon = Particle(**SMP.photon)

electron = Particle(**SMP.leptons.electron)

neutrino_e = Particle(**SMP.leptons.neutrino_e)

neutral_pion = Particle(**SMP.hadrons.neutral_pion)

sterile = Particle(**NuP.sterile_neutrino(300 * UNITS.MeV))
sterile.decoupling_temperature = T_initial

universe.add_particles([
Пример #17
0
class Universe(object):

    """ ## Universe
        The master object that governs the calculation. """

    # System state is rendered to the evolution.txt file each `export_freq` steps
    export_freq = 100
    log_throttler = None
    clock_start = None

    particles = None
    interactions = None

    kawano = None
    kawano_log = None

    oscillations = None

    step_monitor = None

    data = utils.DynamicRecArray([
        ['aT', 'MeV', UNITS.MeV],
        ['T', 'MeV', UNITS.MeV],
        ['a', None, 1],
        ['x', 'MeV', UNITS.MeV],
        ['t', 's', UNITS.s],
        ['rho', 'MeV^4', UNITS.MeV**4],
        ['N_eff', None, 1],
        ['fraction', None, 1],
        ['S', 'MeV^3', UNITS.MeV**3]
    ])

    def __init__(self, folder=None, params=None, max_log_rate=2):
        """
        :param folder: Log file path (current `datetime` by default)
        """

        self.particles = []
        self.interactions = []

        self.clock_start = time.time()
        self.log_throttler = utils.Throttler(max_log_rate)

        self.params = params
        if not self.params:
            self.params = Params()

        self.folder = folder
        if self.folder:
            if os.path.exists(folder):
                shutil.rmtree(folder)
            self.init_log(folder=folder)

        self.fraction = 0

        self.step = 1

    def init_kawano(self, datafile='s4.dat', **kwargs):
        kawano.init_kawano(**kwargs)
        if self.folder:
            self.kawano_log = open(os.path.join(self.folder, datafile), 'w')
            self.kawano_log.write("\t".join([col[0] for col in kawano.heading]) + "\n")
        self.kawano = kawano
        self.kawano_data = utils.DynamicRecArray(self.kawano.heading)

    def init_oscillations(self, pattern, particles):
        self.oscillations = (pattern, particles)

    def evolve(self, T_final, export=True, init_time=True):
        """
        ## Main computing routine

        Modeling is carried in steps of scale factor, starting from the initial conditions defined\
        by a single parameter: the initial temperature.

        Initial temperature (e.g. 10 MeV) corresponds to a point in the history of the Universe \
        long before then BBN. Then most particle species are in the thermodynamical equilibrium.

        """
        T_initial = self.params.T

        print("\n\n" + "#"*32 + " Initial states " + "#"*32 + "\n")
        for particle in self.particles:
            print(particle)
        print("\n\n" + "#"*34 + " Log output " + "#"*34 + "\n")

        for interaction in self.interactions:
            print(interaction)
        print("\n")


        # TODO: test if changing updating particles beforehand changes the computed time
        if init_time:
            self.params.init_time(self.total_energy_density())

        if self.params.rho is None:
#            self.update_particles()
            self.params.update(self.total_energy_density(), self.total_entropy())
        self.save_params()

        while self.params.T > T_final:
            try:
                self.log()
                self.make_step()
                self.save()
                self.step += 1
                if self.folder and self.step % self.export_freq == 0:
                    with open(os.path.join(self.folder, "evolution.txt"), "wb") as f:
                        self.data.savetxt(f)
            except KeyboardInterrupt:
                print("\nKeyboard interrupt!")
                sys.exit(1)
                break

        if not (T_initial > self.params.T > 0):
            print("\n(T < 0) or (T > T_initial): suspect numerical instability")
            sys.exit(1)

        self.log()
        if export:
            self.export()

        return self.data

    def export(self):
        print("\n\n" + "#"*33 + " Final states " + "#"*33 + "\n")
        for particle in self.particles:
            print(particle)
        print("\n")

        if self.folder:
            if self.kawano:

                self.kawano_log.close()
                print(kawano.run(self.folder))

                with open(os.path.join(self.folder, "kawano.txt"), "wb") as f:
                    self.kawano_data.savetxt(f)

            print("Execution log saved to file {}".format(self.logfile))

            with open(os.path.join(self.folder, "evolution.txt"), "wb") as f:
                self.data.savetxt(f)

    def make_step(self):
        self.integrand(self.params.x, self.params.aT)

        if self.step_monitor:
            self.step_monitor(self)

        if environment.get('ADAMS_BASHFORTH_TEMPERATURE_CORRECTION'):
            fs = (list(self.data['fraction'][-MAX_ADAMS_BASHFORTH_ORDER:]) + [self.fraction])

            self.params.aT += adams_bashforth_correction(fs=fs, h=self.params.h)
        else:
            self.params.aT += self.fraction * self.params.h

        self.params.x += self.params.dx
        self.params.update(self.total_energy_density(), self.total_entropy())

        self.log_throttler.update()

    def add_particles(self, particles):
        for particle in particles:
            particle.set_params(self.params)

        self.particles += particles

    def update_particles(self):
        """ ### 1. Update particles state
            Update particle species distribution functions, check for regime switching,\
            update precalculated variables like energy density and pressure. """

        for particle in self.particles:
            particle.update()

    def init_interactions(self):
        """ ### 2. Initialize non-equilibrium interactions
            Non-equilibrium interactions of different particle species are treated by a\
            numerical integration of the Boltzmann equation for distribution functions in\
            the expanding space-time.

            Depending on the regime of the particle species involved and cosmological parameters, \
            each `Interaction` object populates `Particle.collision_integrals` array with \
            currently active `Integral` objects.
        """
        for interaction in self.interactions:
            interaction.initialize()

    def calculate_collisions(self):
        """ ### 3. Calculate collision integrals """

        particles = [particle for particle in self.particles if particle.collision_integrals]

        with utils.printoptions(precision=3, linewidth=100):
            for particle in particles:
                with (utils.benchmark(lambda: "δf/f ({}) = {}".format(particle.symbol, particle.collision_integral / particle._distribution * self.params.h),
                      self.log_throttler.output)):
                    particle.collision_integral = particle.integrate_collisions()

    def update_distributions(self):
        """ ### 4. Update particles distributions """

        if self.oscillations:
            pattern, particles = self.oscillations

            integrals = {A.flavour: A.collision_integral for A in particles}

            for A in particles:
                A.collision_integral = sum(pattern[(A.flavour, B.flavour)] * integrals[B.flavour]
                                           for B in particles)

        for particle in self.particles:
            particle.update_distribution()

    def calculate_temperature_terms(self):
        """ ### 5. Calculate temperature equation terms """

        numerator = 0
        denominator = 0

        for particle in self.particles:
            numerator += particle.numerator()
            denominator += particle.denominator()

        return numerator, denominator

    def integrand(self, t, y):
        """ ## Temperature equation integrand

            Master equation for the temperature looks like

            \begin{equation}
                \frac{d (aT)}{dx} = \frac{\sum_i{N_i}}{\sum_i{D_i}}
            \end{equation}

            Where $N_i$ and $D_i$ represent contributions from different particle species.

            See definitions for different regimes:
              * [[Radiation|particles/RadiationParticle.py#master-equation-terms]]
              * [[Intermediate|particles/IntermediateParticle.py#master-equation-terms]]
              * [[Dust|particles/DustParticle.py#master-equation-terms]]
              * [[Non-equilibrium|particles/NonEqParticle.py#master-equation-terms]]
        """

        # 1\. Update particles states
        self.update_particles()
        # 2\. Initialize non-equilibrium interactions
        self.init_interactions()
        # 3\. Calculate collision integrals
        self.calculate_collisions()
        # 4\. Update particles distributions
        self.update_distributions()
        # 5\. Calculate temperature equation terms
        numerator, denominator = self.calculate_temperature_terms()

        if environment.get('LOGARITHMIC_TIMESTEP'):
            self.fraction = self.params.x * numerator / denominator
        else:
            self.fraction = numerator / denominator

        return self.fraction

    def save_params(self):
        self.data.append({
            'aT': self.params.aT,
            'T': self.params.T,
            'a': self.params.a,
            'x': self.params.x,
            'rho': self.params.rho,
            'N_eff': self.params.N_eff,
            't': self.params.t,
            'fraction': self.fraction,
            'S': self.params.S
        })

    def save(self):
        """ Save current Universe parameters into the data arrays or output files """
        self.save_params()

        if self.kawano and self.params.T <= self.kawano.T_kawano:

            #     t[s]         x    Tg[10^9K]   dTg/dt[10^9K/s] rho_tot[g cm^-3]     H[s^-1]
            # n nue->p e  p e->n nue  n->p e nue  p e nue->n  n e->p nue  p nue->n e

            rates = self.kawano.baryonic_rates(self.params.a)

            row = {
                self.kawano_data.columns[0]: self.params.t,
                self.kawano_data.columns[1]: self.params.x,
                self.kawano_data.columns[2]: self.params.T,
                self.kawano_data.columns[3]:
                    (self.data['T'][-1] - self.data['T'][-2])
                    / (self.data['t'][-1] - self.data['t'][-2]),
                self.kawano_data.columns[4]: self.params.rho,
                self.kawano_data.columns[5]: self.params.H
            }

            row.update({self.kawano_data.columns[i]: rate
                        for i, rate in enumerate(rates, 6)})

            self.kawano_data.append(row)

            if self.log_throttler.output:
                print("KAWANO", self.kawano_data.row_repr(-1, names=True))
            self.kawano_log.write(self.kawano_data.row_repr(-1) + "\n")

    def init_log(self, folder=''):
        self.logfile = utils.ensure_path(os.path.join(self.folder, 'log.txt'))
        sys.stdout = utils.Logger(self.logfile)

    def log(self):
        """ Runtime log output """

        # Print parameters every now and then
        if self.log_throttler.output:
            print('[{clock}] #{step}\tt = {t:e} s\taT = {aT:e} MeV\tT = {T:e} MeV'
                  '\tδaT/aT = {daT:e}\tS = {S:e} MeV^3'
                  .format(clock=timedelta(seconds=int(time.time() - self.clock_start)),
                          step=self.step,
                          t=self.params.t / UNITS.s,
                          aT=self.params.aT / UNITS.MeV,
                          T=self.params.T / UNITS.MeV,
                          daT=self.fraction * self.params.h / self.params.aT,
                          S=self.params.S / UNITS.MeV**3))

    def total_entropy(self):
        return sum(particle.entropy for particle in self.particles) * self.params.a**3

    def total_energy_density(self):
        return sum(particle.energy_density for particle in self.particles)
Пример #18
0
from library.SM import particles as SMP
from interactions import CrossGeneratingInteraction
from interactions.four_particle import FourParticleM, FourParticleIntegral
from particles import Particle
from evolution import Universe
from common import CONST, UNITS, Params

params = Params(T=2 * UNITS.MeV, dy=0.025)

photon = Particle(**SMP.photon)
neutrino = Particle(**SMP.leptons.neutrino_e)

neutrino_scattering = CrossGeneratingInteraction(
    particles=((neutrino, neutrino), (neutrino, neutrino)),
    antiparticles=((False, True), (False, True)),
    Ms=(FourParticleM(K1=64 * CONST.G_F**2, order=(0, 1, 2, 3)), ),
    integral_type=FourParticleIntegral)

universe = Universe(params=params)
universe.PARALLELIZE = False
universe.add_particles([photon, neutrino])
universe.interactions += [neutrino_scattering]

import numpy
addition = numpy.vectorize(lambda x: 0.1 * numpy.exp(-(x / UNITS.MeV - 3)**2),
                           otypes=[numpy.float_])
neutrino._distribution += addition(neutrino.grid.TEMPLATE)

# def check(p=[]):
#     return neutrino_scattering.F_B(in_p=p[:2], out_p=p[2:]) * (1 - neutrino.distribution(p[0])) \
#         - neutrino_scattering.F_A(in_p=p[:2], out_p=p[2:]) * neutrino.distribution(p[0])
Пример #19
0
[Log file](log.txt)


"""

import os
from particles import Particle
from evolution import Universe
from common import Params, UNITS
from library.SM import particles as SMP


folder = os.path.join(os.path.split(__file__)[0], 'output')

params = Params(T=10 * UNITS.MeV,
                dy=0.003125)
T_final = 0.008 * UNITS.MeV


Particles = []
photon = Particle(**SMP.photon)
neutrino_e = Particle(**SMP.leptons.neutrino_e)
neutrino_mu = Particle(**SMP.leptons.neutrino_mu)
neutrino_tau = Particle(**SMP.leptons.neutrino_tau)
electron = Particle(**SMP.leptons.electron)

Particles += [
    photon,
    neutrino_e,
    neutrino_mu,
    neutrino_tau,
Пример #20
0
class Universe(object):
    """ ## Universe
        The master object that governs the calculation. """

    # System state is rendered to the evolution.txt file each `export_freq` steps
    export_freq = 100
    log_throttler = None
    clock_start = None

    particles = None
    interactions = None

    kawano = None
    kawano_log = None

    oscillations = None

    step_monitor = None

    data = utils.DynamicRecArray([['aT', 'MeV', UNITS.MeV],
                                  ['T', 'MeV', UNITS.MeV], ['a', None, 1],
                                  ['x', 'MeV', UNITS.MeV], ['t', 's', UNITS.s],
                                  ['rho', 'MeV^4', UNITS.MeV**4],
                                  ['N_eff', None, 1], ['fraction', None, 1],
                                  ['S', 'MeV^3', UNITS.MeV**3]])

    def __init__(self, folder=None, params=None, max_log_rate=2):
        """
        :param folder: Log file path (current `datetime` by default)
        """

        self.particles = []
        self.interactions = []

        self.clock_start = time.time()
        self.log_throttler = utils.Throttler(max_log_rate)

        self.params = params
        if not self.params:
            self.params = Params()

        self.folder = folder
        if self.folder:
            if os.path.exists(folder):
                shutil.rmtree(folder)
            self.init_log(folder=folder)

        self.fraction = 0

        self.step = 1

    def init_kawano(self, datafile='s4.dat', **kwargs):
        kawano.init_kawano(**kwargs)
        if self.folder:
            self.kawano_log = open(os.path.join(self.folder, datafile), 'w')
            self.kawano_log.write("\t".join([col[0]
                                             for col in kawano.heading]) +
                                  "\n")
        self.kawano = kawano
        self.kawano_data = utils.DynamicRecArray(self.kawano.heading)

    def oscillation_parameters(self):

        if self.oscillation_matter:
            MSW_12 = CONST.MSW_constant * self.oscillation_particles[
                0].grid.TEMPLATE**2 * self.params.T**4 / CONST.delta_m12_sq / self.params.a**2
            MSW_13 = CONST.MSW_constant * self.oscillation_particles[
                0].grid.TEMPLATE**2 * self.params.T**4 / CONST.delta_m13_sq / self.params.a**2
            if not environment.get("NORMAL_HIERARCHY_NEUTRINOS"):
                MSW_13 *= -1

        else:
            MSW_12 = 0.
            MSW_13 = 0.

        pattern = self.pattern_function(MSW_12, MSW_13,
                                        self.oscillation_matter)
        self.oscillations = (pattern, self.oscillation_particles)

    def init_oscillations(self,
                          pattern_function,
                          particles,
                          matter_effects=True):
        self.pattern_function = pattern_function
        self.oscillation_particles = particles
        self.oscillation_matter = matter_effects
        self.oscillation_parameters()

    def evolve(self, T_final, export=True, init_time=True):
        """
        ## Main computing routine

        Modeling is carried in steps of scale factor, starting from the initial conditions defined\
        by a single parameter: the initial temperature.

        Initial temperature (e.g. 10 MeV) corresponds to a point in the history of the Universe \
        long before then BBN. Then most particle species are in the thermodynamical equilibrium.

        """
        T_initial = self.params.T

        print("\n\n" + "#" * 32 + " Initial states " + "#" * 32 + "\n")
        for particle in self.particles:
            print(particle)
        print("\n\n" + "#" * 34 + " Log output " + "#" * 34 + "\n")

        for interaction in self.interactions:
            if interaction.integrals:
                print(interaction)
        print("\n")

        # TODO: test if changing updating particles beforehand changes the computed time
        if init_time:
            self.params.init_time(self.total_energy_density())

        if self.params.rho is None:
            #            self.update_particles()
            self.params.update(self.total_energy_density(),
                               self.total_entropy())
        self.save_params()

        while self.params.T > T_final:
            try:
                self.log()
                self.make_step()
                self.save()
                self.step += 1
                if self.folder and self.step % self.export_freq == 0:
                    with open(os.path.join(self.folder, "evolution.txt"),
                              "wb") as f:
                        self.data.savetxt(f)
                    if self.kawano:
                        with open(os.path.join(self.folder, "kawano.txt"),
                                  "wb") as f:
                            self.kawano_data.savetxt(f)
            except KeyboardInterrupt:
                print("\nKeyboard interrupt!")
                sys.exit(1)
                break

        if not (self.params.T > 0):
            print("\n(T < 0): suspect numerical instability")
            sys.exit(1)

        self.log()
        if export:
            self.export()

        return self.data

    def export(self):
        print("\n\n" + "#" * 33 + " Final states " + "#" * 33 + "\n")
        for particle in self.particles:
            print(particle)
        print("\n")

        if self.folder:
            if self.kawano:

                self.kawano_log.close()
                print(kawano.run(self.folder))

                with open(os.path.join(self.folder, "kawano.txt"), "wb") as f:
                    self.kawano_data.savetxt(f)

            print("Execution log saved to file {}".format(self.logfile))

            with open(os.path.join(self.folder, "evolution.txt"), "wb") as f:
                self.data.savetxt(f)

    def make_step(self):
        self.integrand(self.params.x, self.params.aT)

        if self.step_monitor:
            self.step_monitor(self)

        if environment.get('ADAMS_BASHFORTH_TEMPERATURE_CORRECTION'):
            fs = (list(self.data['fraction'][-MAX_ADAMS_BASHFORTH_ORDER:]) +
                  [self.fraction])

            self.params.aT += adams_bashforth_correction(fs=fs,
                                                         h=self.params.h)
        else:
            self.params.aT += self.fraction * self.params.h

        self.params.x += self.params.dx
        self.params.update(self.total_energy_density(), self.total_entropy())

        self.log_throttler.update()

    def add_particles(self, particles):
        for particle in particles:
            particle.set_params(self.params)

        self.particles += particles

        self.particles = utils.particle_orderer(self.particles)

    def update_particles(self):
        """ ### 1. Update particles state
            Update particle species distribution functions, check for regime switching,\
            update precalculated variables like energy density and pressure. """

        for particle in self.particles:
            particle.update()

    def init_interactions(self):
        """ ### 2. Initialize non-equilibrium interactions
            Non-equilibrium interactions of different particle species are treated by a\
            numerical integration of the Boltzmann equation for distribution functions in\
            the expanding space-time.

            Depending on the regime of the particle species involved and cosmological parameters, \
            each `Interaction` object populates `Particle.collision_integrals` array with \
            currently active `Integral` objects.
        """
        for interaction in self.interactions:
            interaction.initialize()

    def calculate_collisions(self):
        """ ### 3. Calculate collision integrals """

        particles = [
            particle for particle in self.particles
            if particle.collision_integrals
        ]

        with utils.printoptions(precision=3, linewidth=100):
            for particle in particles:
                # with (utils.benchmark(lambda: "δf/f ({}) = {}".format(particle.symbol, particle.collision_integral / particle._distribution * self.params.h),
                #       self.log_throttler.output)):
                particle.collision_integral = particle.integrate_collisions()

    def update_distributions(self):
        """ ### 4. Update particles distributions """

        if self.oscillations:
            self.oscillation_parameters()
            pattern, particles = self.oscillations

            if any(self.params.T < A.decoupling_temperature
                   for A in particles):

                integrals = {
                    A.flavour: A.collision_integral
                    for A in particles
                }

                for A in particles:
                    A.collision_integral = sum(
                        pattern[(A.flavour, B.flavour)] * integrals[B.flavour]
                        for B in particles)

        for particle in self.particles:
            particle.update_distribution()

    def calculate_temperature_terms(self):
        """ ### 5. Calculate temperature equation terms """

        numerator = 0
        denominator = 0

        for particle in self.particles:
            numerator += particle.numerator()
            denominator += particle.denominator()

        return numerator, denominator

    def integrand(self, t, y):
        """ ## Temperature equation integrand

            Master equation for the temperature looks like

            \begin{equation}
                \frac{d (aT)}{dx} = \frac{\sum_i{N_i}}{\sum_i{D_i}}
            \end{equation}

            Where $N_i$ and $D_i$ represent contributions from different particle species.

            See definitions for different regimes:
              * [[Radiation|particles/RadiationParticle.py#master-equation-terms]]
              * [[Intermediate|particles/IntermediateParticle.py#master-equation-terms]]
              * [[Dust|particles/DustParticle.py#master-equation-terms]]
              * [[Non-equilibrium|particles/NonEqParticle.py#master-equation-terms]]
        """

        # 1\. Update particles states
        self.update_particles()
        # 2\. Initialize non-equilibrium interactions
        self.init_interactions()
        # 3\. Calculate collision integrals
        self.calculate_collisions()
        # 4\. Update particles distributions
        self.update_distributions()
        # 5\. Calculate temperature equation terms
        numerator, denominator = self.calculate_temperature_terms()

        if environment.get('LOGARITHMIC_TIMESTEP'):
            self.fraction = self.params.x * numerator / denominator
        else:
            self.fraction = numerator / denominator

        return self.fraction

    def save_params(self):
        self.data.append({
            'aT': self.params.aT,
            'T': self.params.T,
            'a': self.params.a,
            'x': self.params.x,
            'rho': self.params.rho,
            'N_eff': self.params.N_eff,
            't': self.params.t,
            'fraction': self.fraction,
            'S': self.params.S
        })

    def save(self):
        """ Save current Universe parameters into the data arrays or output files """
        self.save_params()

        if self.kawano and self.params.T <= self.kawano.T_kawano:

            #     t[s]         x    Tg[10^9K]   dTg/dt[10^9K/s] rho_tot[g cm^-3]     H[s^-1]
            # n nue->p e  p e->n nue  n->p e nue  p e nue->n  n e->p nue  p nue->n e

            rates = self.kawano.baryonic_rates(self.params.a)

            if environment.get('LOGARITHMIC_TIMESTEP'):
                dTdt = (self.fraction -
                        self.params.aT) * self.params.H / self.params.a
            else:
                dTdt = (self.fraction - self.params.T /
                        self.params.m) * self.params.H * self.params.m

            row = {
                self.kawano_data.columns[0]: self.params.t,
                self.kawano_data.columns[1]: self.params.x,
                self.kawano_data.columns[2]: self.params.T,
                self.kawano_data.columns[3]: dTdt,
                self.kawano_data.columns[4]: self.params.rho,
                self.kawano_data.columns[5]: self.params.H
            }

            row.update({
                self.kawano_data.columns[i]: rate
                for i, rate in enumerate(rates, 6)
            })

            self.kawano_data.append(row)

            if self.log_throttler.output:
                print("KAWANO", self.kawano_data.row_repr(-1, names=True))
            self.kawano_log.write(self.kawano_data.row_repr(-1) + "\n")

    def init_log(self, folder=''):
        self.logfile = utils.ensure_path(os.path.join(self.folder, 'log.txt'))
        sys.stdout = utils.Logger(self.logfile)

    def log(self):
        """ Runtime log output """

        # Print parameters every now and then
        if self.log_throttler.output:
            print(
                '[{clock}] #{step}\tt = {t:e} s\taT = {aT:e} MeV\tT = {T:e} MeV'
                '\tδaT/aT = {daT:e}\tS = {S:e} MeV^3'.format(
                    clock=timedelta(seconds=int(time.time() -
                                                self.clock_start)),
                    step=self.step,
                    t=self.params.t / UNITS.s,
                    aT=self.params.aT / UNITS.MeV,
                    T=self.params.T / UNITS.MeV,
                    daT=self.fraction * self.params.h / self.params.aT,
                    S=self.params.S / UNITS.MeV**3))

    def total_entropy(self):
        return sum(particle.entropy for particle in
                   self.particles)  #* (self.params.a_ini/self.params.a)**3

    def total_energy_density(self):
        return sum(particle.energy_density for particle in self.particles)

    def QCD_transition(self,
                       hadrons=None,
                       quarkic_interactions=None,
                       hadronic_interactions=None,
                       secondary_interactions=None):
        self.data.truncate()

        dof_before_qcd = Params.entropic_dof_eq(self)

        self.particles = utils.particle_filter([
            'Up quark', 'Down quark', 'Charm quark', 'Strange quark',
            'Top quark', 'Bottom quark', 'Gluon'
        ], self.particles)
        self.add_particles(hadrons)

        dof_after_qcd = Params.entropic_dof_eq(self)

        self.params.aT = self.data['aT'][-1] * (dof_before_qcd /
                                                dof_after_qcd)**(1 / 3)
        #        self.params.x = self.data['x'][-1] * (dof_before_qcd/dof_after_qcd)**(1/3)
        #        self.params.a = self.data['a'][-1] * (dof_before_qcd/dof_after_qcd)**(1/3)
        self.params.update(self.total_energy_density(),
                           self.total_entropy())  # T will be updated here...
        #        self.params.T = CONST.lambda_QCD # That's why we change it here again
        self.update_particles()

        if quarkic_interactions and self.interactions:
            for inter in quarkic_interactions:
                self.interactions.remove(inter)
        if hadronic_interactions:
            self.interactions += (hadronic_interactions)
        if secondary_interactions:
            self.interactions += (secondary_interactions)