Random numbers in litebird_sim
¶
The LiteBIRD Simulation Framework can be used to generate random numbers, used for example for producing noise timelines. In order to do so, a seed and a Random Number Generator (RNG) are used.
Seed¶
The random_seed
is used to control the behaviour of the RNG. The seed
can be None
or an integer number.
If you are not interested in the reproducibility of your results, you can
set random_seed
to None
. However, this is not recommended.
In fact, this means that if you run multiple times a function or method where
a RNG is used, e.g. for producing noise timelines, then
the outputs will be different and you will not be able to re-obtain these
results again.
If instead you are interested in the reproducibility of your results, you can
set random_seed
to an integer number.
With this choice, if you run multiple times a function or method where
a RNG is used, then the outputs will be the same and
you will re-obtain these results by re-running your script, as the random
numbers produced by the generator will be exactly the same.
How should you set the random_seed
? This parameter must be passed to
the constructor of a Simulation
class.
If a Simulation
instance is created without passing the seed, an
error will be raised and your script will fail. This feature has been
introduced on purpose in order to avoid automatic settings of the seed and
unclear behaviour of the generation of random numbers.
If you are running a parallel script using MPI, you do not have to
worry about setting a different seed for different MPI ranks: by passing
the same seed, the random numbers generated by the different ranks will be
different. This is ensured by the random number generator. We want this
behaviour as we do not want repetitions of, e.g., the same noise TOD if
we split their computation on different MPI ranks. For example, in this
way, if you split the TOD matrix of an Observation
class by the
time, you will not encounter the same noise after the samples generated
by a certain rank; if you split the TOD matrix of an Observation
class by the detectors, each one will have a different noise timestream.
Regarding the reproducibility of the results in a parallel code, there is an important thing to bear in mind: if you set the seed to an integer number but run your script with a different number of MPI ranks, the outputs will be different! Think about a noise time stream of 4 samples. If you use 2 MPI ranks, then the first 2 samples will be generated by one RNG (the one of rank 0), while the last 2 samples will be generated by a different RNG (the one of rank 1). If you then run the same script with the same seed but with 4 MPI ranks, each of the samples will be generated by a different RNG and only the first sample will be the same for the two runs, as it is always the first one generated by rank 0’s RNG.
The setting of the random_seed
is as simple as this:
sim = lbs.Simulation(
base_path="/storage/output",
start_time=astropy.time.Time("2020-02-01T10:30:00"),
duration_s=3600.0,
name="My noise simulation",
description="I want to generate some noise and be able to reproduce my results",
random_seed=12345, # Here the seed for the random number generator is set
)
During the execution of the Simulation
constructor, the
Simulation.init_random()
method is run. There, the RNG is
built and seeded with random_seed
. You can then use this RNG
by calling sim.random
. There is also the possibility to
change the random seed after creatinga Simulation
instance.
This is achieved by calling Simulation.init_random()
:
sim = lbs.Simulation(random_seed=12345)
[...]
sim.init_random(random_seed=42)
Random number generators¶
The random number generator used by the Simulation.init_random()
method of the Simulation
class is
PCG64.
After creating this RNG by calling Simulation.init_random()
(directly or from the Simulation
constructor), you can use it
via sim.random:
sim = lbs.Simulation(random_seed=12345)
[...]
sim.add_noise(noise_type='white', random=sim.random)
You can also use your own RNG with the functions and methods of
litebird_sim
:
sim = lbs.Simulation(random_seed=12345)
[...]
my_rng = ... # New RNG definition
sim.add_noise(noise_type='white', random=my_rng)
You should just make sure that your custom RNG implements the
normal
method, so it can be used for white noise generation.