otswap¶
otswap reconstructs the Lagrangian displacement field of a catalogue of large-scale structure tracers, such as galaxies, quasars or dark matter haloes, by discrete optimal transport. Each tracer is paired one to one with a point drawn from a random catalogue that samples the same volume uniformly, standing for the homogeneous initial conditions, so that the sum of squared comoving distances between paired points is minimal. The pairing starts from a local first guess, which matches each tracer to a nearby free random, and is then refined by sweeps of local swaps: for four neighbouring tracers, all 24 permutations of their partners are tried and the cheapest is kept, until the fraction of successful swaps in a sweep no longer exceeds a chosen threshold.
The reconstruction is repeated on independent sets of N points extracted from the random catalogue. A tracer’s displacement is the mean, over these realizations, of the vector from the tracer to its partner. As the number of realizations grows, the mean Lagrangian position tends to the centroid of the equal-volume Laguerre cell that optimal transport assigns to the tracer: the Lagrangian volume from which the observed object has evolved.
otswap is built for survey data as much as for simulations. It handles boxes and lightcones; in a lightcone the footprint enters through a HEALPix mask and through a random catalogue reproducing the selection function, with an optional redshift cut, and displacements crossing unobserved regions are rejected. From the reconstructed displacements it corrects the catalogue for redshift-space distortions, given a fiducial cosmology and a bias b(z), and it writes its results as ASCII or FITS tables. Results are identical bit for bit on every supported platform and compiler, whatever the number of threads (see Reproducibility). C++17, with a Python package on the same code.
The two APIs are one library: the C++ library and the Python package run the same code and give the same results, bit for bit. Names side by side maps one to the other, and the guide covers what applies to both.
Install¶
pip install otswap
For the C++ library, build and install it with CMake; it needs a C++17 compiler and cfitsio, uses OpenMP when found, and fetches meshsearch when it is not installed:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
cmake --install build --prefix /path/to/prefix
and use it from your own CMake project:
find_package(otswap 0.1 CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE otswap::otswap)
In a few lines¶
A box reconstruction of tracers given as an array, its mean displacement, and a file with one row per tracer:
import otswap
result = otswap.reconstruct_box(tracers, n_realizations=8, seed=12345)
print(result.mean_displacement[0])
otswap.io.write_displacements("displacements.dat", result)
#include "otswap/OT.h"
otswap::Config config;
config.nRealizations = 8;
config.seed = 12345;
otswap::Result result = otswap::reconstructBox(tracers, {}, config);
std::cout << result.meanDisplacement[0] << '\n';
otswap::io::writeDisplacements("displacements.dat", result);
tracers is an array of shape (N, 3) in Python, a std::vector<double> of
3 * N entries in C++, in Mpc/h. Without randoms, otswap draws them in the
tracers’ bounding box. The examples read real catalogues and
show every step.