Getting started¶
The mojito package provides tools to download, read, and write Mojito L1 files (also known as “bricks”). This guide will walk you through the basic steps to get started with Mojito L1 files.
Installation¶
To install the mojito package, follow the instructions provided in the Installation section of the documentation.
Pour yourself a drink¶
Use the mojito.download module to download Mojito L1 files and source
parameter catalogs from the Mojito brick market. Convenience functions are
provided to handle authentication, caching (to reduce disk and network usage),
integrity checks and versioning.
Note
Downloading Mojito L1 files and source catalogs from the Mojito brick market requires authentication using a Nextcloud username and token. For more information on how to obtain your credentials and use them with Mojito, see the Authentication section.
Download brick files¶
You can use the mojito.download.download_brick() function to download a
Mojito L1 brick file. Simply provide the source type (e.g., “mbhb”, “gb”,
“noise”, “combined”, etc.) and an optional source identifier.
from mojito.download import download_brick
# Download Mojito L1 brick file for a massive black hole binary source
brick_file = download_brick("mbhb", 12)
# Download Mojito L1 brick file for noise (no source id needed)
noise_file = download_brick("noise", version=1)
# Subsequent calls will use the cached file if available (no re-download)
brick_file_cached = download_brick("mbhb", 12)
# Provide authentication explicitly if needed
brick_file = download_brick("mbhb", 12, username="myuser", token="mytoken")
# Download reduced (downsampled and stripped off) brick
# Warning: reduced bricks are not official L1 files and may be missing some
# quantities; use only for testing and development!
reduced_brick_file = download_brick("mbhb", 12, reduced=True)
If the file is not already cached, it will be downloaded from the Mojito brick market and the path to the downloaded file will be returned. If the file is already cached, the path to the cached file will be returned without re-downloading.
Note
Authentication is required to download files. You can provide credentials
via function arguments (username and token), environment variables
(MOJITO_USERNAME and MOJITO_TOKEN), or you will be prompted
interactively if credentials are not available.
Fetch source parameters¶
You can also use mojito.download.get_source_params() to download the
relevant source catalog and fetch the source parameters for a specified source.
You can also download an entire catalog of source parameters using
mojito.download.download_catalog().
from mojito.download import download_catalog, get_source_params
# Fetch source parameters for a specified source
source_params = get_source_params("mbhb", 12)
# Download the entire catalog of galactic binaries
galactic_catalog_file = download_catalog("gb")
More details on the downloading functions and their options can be found in Download data.
Caching¶
By default, downloaded files are cached in a directory following the XDG Base
Directory Specification (typically
~/.cache/mojito). You can change this location by setting the environment
variable MOJITO_CACHE_DIR, or by passing the cache_dir keyword argument
to the download functions.
Note
Make sure that the cache directory has enough disk space to store the downloaded files.
You can clear the cache by using the mojito.download.clear_cache()
function.
from mojito.download import get_cache_dir, clear_cache
# Get the current cache directory
cache_dir = get_cache_dir()
print(f"Current cache directory: {cache_dir}")
# Clear the cache directory
clear_cache()
Warning
Use with caution as this will delete all cached files. All files will need to be re-downloaded if needed again.
Versioning¶
By default, the latest version of each brick or parameter catalog is downloaded.
You can specify a different version by providing the version keyword
argument.
Command-line interface¶
The mojito package also provides a command-line interface (CLI) to download Mojito L1 files and source catalogs. You can use
$ mojito download-brick mbhb 12
$ mojito source-params mbhb 12
$ mojito download-catalog gb
$ mojito clear-cache
More details on the CLI and its commands can be found in Command-line interface.
Have a drink¶
The mojito.reader module provides the mojito.reader.MojitoL1File
class to read Mojito L1 brick files. This class provides access to the various
datasets stored in the file, including TDI observables, light travel times,
spacecraft orbits, and noise estimates.
Reading datasets¶
Dataset access is done via attributes of the mojito.reader.MojitoL1File
object. Convenience properties are provided to stack and rescale datasets (unit
conversion) as needed.
Note
Always use the context manager (with statement) to open Mojito L1 files.
This ensures that the file is properly closed after use, preventing resource
leaks.
from mojito import MojitoL1File
with MojitoL1File("path/to/file.h5") as f:
# TDI observables
x2 = f.tdis.x2[:] # TDI X2 observable in Hz
y2 = f.tdis.y2[:] # TDI Y2 observable in Hz
z2 = f.tdis.z2[:] # TDI Z2 observable in Hz
# Complete set of TDI observables in Doppler units
xyz = f.tdis.xyz_doppler[:] # TDI XYZ in Doppler units
aet = f.tdis.aet_doppler[:] # TDI AET in Doppler units
# Associated time sampling
tdi_time_sampling = f.tdis.time_sampling
tdi_dt = tdi_time_sampling.dt # time step in seconds
tdi_times = tdi_time_sampling.t() # array of times in seconds
# Light travel times and spacecraft orbits for response function
ltts = f.ltts.ltts[:] # Stacked light travel times
ltt_times = f.ltts.time_sampling.t()
orbits = f.orbits.positions[:] # Stacked spacecraft positions
orbits_times = f.orbits.time_sampling.t()
# Noise estimates for TDI AET
noise_aet = f.noise_estimates.aet[:] # in Hz^2/Hz
noise_times = f.noise_estimates.time_sampling.t() # array of times
noise_freqs = f.noise_estimates.freq_sampling.f() # array of freqs
Multiple bricks can be read together by providing a list of file paths to the constructor. The datasets will be automatically combined across bricks.
with MojitoL1File(["file1.h5", "file2.h5"]) as f:
# Access the first 1000 samples of XYZ TDI observables (Doppler units)
# Datasets are automatically combined across bricks
xyz = f.tdis.xyz_doppler[:1000] # shape (1000, 3)
Note that some datasets will be summed (typically, TDI observables), while others will be OR-ed (typically, quality flags) and some will be returned from one of the bricks (typically, orbits and light travel times). This is transparent to the user.
More information on each dataset and its methods can be found in
mojito.reader.MojitoL1File and its attributes.
Time and frequency grids¶
The time and frequency grids (sampling) associated with each dataset can be
accessed via the time_sampling and freq_sampling attributes.
These are instances of mojito.sampling.UniformTimeSampling and
mojito.sampling.UniformFreqSampling, and provide methods to reconstruct
the time and frequency arrays, as well as properties like the time step dt.
with MojitoL1File("path/to/file.h5") as f:
tdi_time_sampling = f.tdis.time_sampling
# Print time sampling information
print(tdi_time_sampling)
tdi_t0 = tdi_time_sampling.t0 # Start time in seconds
tdi_dt = tdi_time_sampling.dt # Time step in seconds
tdi_size = tdi_time_sampling.size # Number of samples
tdi_duration = tdi_time_sampling.duration # Duration in seconds
tdi_fs = tdi_time_sampling.fs # Sampling frequency in Hz
# Generate time array in seconds
tdi_times = tdi_time_sampling.t()
# You can also start at zero (ignore t0)
tdi_times_zero = tdi_time_sampling.t(elapsed=True)
Initial times t0 are expressed in seconds since the LISA epoch, as defined
in lisaconstants.LISA_EPOCH_TCB.
You can also generate sliced time arrays by providing a slice object to the
t() method. This allows for better memory management when working with large
datasets.
# Generate time array for samples 1000 to 2000
tdi_times = tdi_time_sampling.t(slice(1000, 2000))
# Generate time array for every other sample
tdi_times = tdi_time_sampling.t(slice(None, None, 2))
More details on the time and frequency sampling classes can be found in Time and frequency grids.
Memory usage and slicing¶
All datasets in mojito.reader.MojitoL1File support lazy loading to
minimize memory usage; therefore, only the requested data (sliced arrays) are
loaded into memory.
Warning
You must slice the datasets to read the data into memory. Accessing a
non-sliced dataset returns a lazy-loading object that cannot be used outside
of the context manager (that is, outside of the with block).
For example, to read only the first 1000 samples of the TDI X2 observable, you can do:
with MojitoL1File("path/to/file.h5") as f:
x2_first_1000 = f.tdis.x2[:1000]
times_first_1000 = f.tdis.time_sampling.t(slice(0, 1000))
Note that some attributes, such as mojito.reader.TDI.xyz_doppler and
mojito.reader.TDI.aet_doppler, perform stacking and rescaling of the
underlying datasets. They have been designed to provide lazy loading and
transparent slicing as well (including along the stacking dimension).
For example, to read only the first 1000 samples of the TDI XY observables in Doppler units, you can do:
with MojitoL1File("path/to/file.h5") as f:
xy_doppler_first_1000 = f.tdis.xyz_doppler[:1000, :2]
Behind the scenes, Mojito uses h5py to read HDF5
files, and properties return h5py.Dataset objects that support slicing and
lazy loading. Stacked datasets are handled by the
mojito.lazy.ScaledStackedDataset class, which also supports slicing and
lazy loading.
Stir the drink¶
Writing Mojito files¶
Mojito provides a writer to create Mojito L1 files from simulation outputs or by combining existing Mojito L1 files. The writer ensures that the created files are compliant with the Mojito L1 file specification.
To combine existing Mojito L1 files, you can use the
mojito.writer.combine_bricks() function. This function can also check for
consistency across the input files and raise an error if inconsistencies are
found.
from mojito.writer import combine_bricks
combine_bricks(
["file1.h5", "file2.h5"],
"combined_file.h5",
check_consistent=True,
)
The module mojito.writer also provides functions to create empty Mojito
L1 files and various groups, and write attributes. The class
mojito.reader.MojitoL1File can also be used to write data to an
existing Mojito L1 file.
from mojito import MojitoL1File
from mojito.sampling import UniformTimeSampling
from mojito.writer import write_attrs, create_tdis
# Create an empty Mojito L1 file
with MojitoL1File("path/to/new_file.h5", mode="a") as f:
# Write attributes
write_attrs(
f,
pipeline_name="my_pipeline",
lolipops_version="1.0.0",
laser_frequency=2.82e14,
)
# Create TDI group with time sampling
tdi_time_sampling = UniformTimeSampling(t0=0.0, dt=2.0, size=10000)
create_tdis(f, time_sampling=tdi_time_sampling)
# Write TDI observables
f.tdis.x2[:] = my_x2_data # in Hz
f.tdis.y2[:] = my_y2_data # in Hz
f.tdis.z2[:] = my_z2_data # in Hz
# etc.
You can copy entire groups from an existing Mojito L1 file to a new one by
providign the data keyword argument to the group creation functions. For
example, to copy the orbits and LTT groups from an existing file:
from mojito import MojitoL1File
from mojito.writer import create_orbits, create_ltts
with MojitoL1File("path/to/existing_file.h5", mode="r") as f_existing:
with MojitoL1File("path/to/new_file.h5", mode="a") as f_new:
# Copy orbits group
create_orbits(
f_new,
time_sampling=f_existing.orbits.time_sampling,
data=f_existing.orbits,
)
# Copy LTT group
create_ltts(
f_new,
time_sampling=f_existing.ltts.time_sampling,
data=f_existing.ltts,
)
If datasets are missing from the existing file, they will be created as empty datasets in the new file.
More details on the writer and its functions can be found in stirring/writer.