Python reference

Generated from the type stubs otswap/__init__.pyi and otswap/io.pyi, whose docstrings are the ones an IDE shows.

otswap

Errors

exception otswap.Error

Raised by every otswap function on invalid input or failure.

exception otswap.ExtrapolationWarning

Issued, once per call, when b(z) is extrapolated beyond the redshift range of its table.

Distances

class otswap.DistanceTable

Sampled relation between redshift, comoving distance and, optionally, the linear growth rate, interpolated in both directions. Immutable.

Build it with DistanceTable.flat or DistanceTable.from_table.

distance_at(z: numpy.typing.ArrayLike) → numpy.typing.NDArray[numpy.float64]

Comoving distance at each redshift. Raises outside the table.

static flat(omega_m: float, h: float, w0: float = -1.0, wa: float = 0.0, z_min: float = 0.0, z_max: float = 10.0, n_samples: int = 50000) → DistanceTable

Tabulate a flat cosmology with dark energy w(a) = w0 + wa (1 - a).

Comoving distances are in Mpc/h. The growth rate f = dlnD/dlna comes from integrating the linear growth equation. The range must cover every redshift to be converted, including reconstructed positions, which can fall slightly outside the range of the data.

static from_table(redshift: numpy.typing.ArrayLike, distance: numpy.typing.ArrayLike, growth_rate: numpy.typing.ArrayLike | None = None) → DistanceTable

Use a table computed by the caller. Redshift and distance must be strictly increasing, with at least two entries; distance in Mpc/h. Without growth_rate, growth_rate_at raises.

growth_rate_at(z: numpy.typing.ArrayLike) → numpy.typing.NDArray[numpy.float64]

Linear growth rate at each redshift. Raises outside the table, or if the table has no growth rate.

property has_growth_rate: bool
property max_redshift: float
property min_redshift: float
redshift_at(distance: numpy.typing.ArrayLike) → numpy.typing.NDArray[numpy.float64]

Redshift at each comoving distance. Raises outside the table.

otswap.to_cartesian(sky: numpy.typing.ArrayLike, distances: DistanceTable, *, angle_unit: AngleUnit) → numpy.typing.NDArray[numpy.float64]

Convert sky coordinates, shape (N, 3), to Cartesian ones in Mpc/h, using the same convention as reconstruct_lightcone. Raises if a declination lies outside [-90, 90] degrees ([-pi/2, pi/2] radians); the message gives it in angle_unit.

otswap.to_sky(cartesian: numpy.typing.ArrayLike, distances: DistanceTable, *, angle_unit: AngleUnit) → numpy.typing.NDArray[numpy.float64]

Convert Cartesian coordinates, shape (N, 3), in Mpc/h, to sky coordinates, shape (N, 3): right ascension in [0, 360) degrees ([0, 2 pi) radians), declination, redshift. The inverse of to_cartesian, with the same observer; a position at the origin gets right ascension and declination 0. A row holding a NaN gives a NaN row; an infinite entry, or a distance outside the table, raises.

Mask

class otswap.Mask(fits_file: str)

HEALPix mask, read from a FITS file or built from a full-sky map in memory with Mask.from_array. Immutable.

A pixel is observed when its value is greater than 0, whatever its magnitude: fractional values, the smallest positive ones and +inf included. 0, negative values, -inf, NaN and UNSEEN mark an unobserved pixel. Each value is tested once, in float64, when the mask is built; no value is kept or used as a weight. The rule is the same for both sources.

NSIDE may be any integer from 1 to 2**29, HEALPix’s limit, and must be a power of 2 in the NESTED scheme. The mask holds one byte per pixel, 12 NSIDE**2 bytes: 12.6 MB at NSIDE 1024, 805 MB at NSIDE 8192, 3.2 GB at NSIDE 16384.

allows(ra: numpy.typing.ArrayLike, dec: numpy.typing.ArrayLike, *, angle_unit: AngleUnit) → numpy.typing.NDArray[numpy.bool_]

Whether each direction falls in an observed pixel. Raises if a right ascension is not finite, or a declination is not in [-90, 90] degrees ([-pi/2, pi/2] radians); the message gives it in angle_unit.

static from_array(values: numpy.typing.ArrayLike, nest: bool = False) → Mask

A full-sky HEALPix map given in memory, as healpy holds one.

Parameters:
  • values (array_like, shape (12 NSIDE**2,)) – One value per pixel, of any real dtype: integer, unsigned, floating, or bool as 0 and 1. It is read once and not kept. A C-contiguous float64 array is read in place; any other input is first converted to one, which takes 8 bytes per pixel while the mask is built.

  • nest (bool, optional) – True for NESTED, False for RING, as healpy’s nest.

Raises:

Error – For another length, NSIDE above 2**29, NESTED with an NSIDE that is not a power of 2, an array that is not 1-D, values that are not real numbers, or a nest that is not a bool.

property nside: int

NSIDE of the map, from 1 to 2**29.

property sky_area_deg2: float

their count times the pixel area, whatever their values.

Type:

Area covered by the observed pixels, in square degrees

Reconstruction

otswap.reconstruct_box(tracers: numpy.typing.ArrayLike, randoms: numpy.typing.ArrayLike | None = None, *, mps: float | None = None, n_realizations: int = 1, convergence: float = 0.001, seed: int = 0, cell_size: float = 4.0, verbosity: Verbosity = 'normal') → Result

Reconstruct in box geometry, with a constant mean particle separation.

Parameters:
  • tracers (array_like, shape (N, 3)) – Cartesian coordinates.

  • randoms (array_like, shape (M, 3), optional) – Cartesian coordinates, M >= n_realizations * N; each realization uses a disjoint subset. If omitted, n_realizations * N randoms are drawn uniformly in the bounding box of the tracers.

  • mps (float, optional) – Mean particle separation, in the units of the coordinates. If omitted, (V / N)^(1/3), with V the volume of the tracers’ bounding box, the box drawn randoms fill; it is Result.mps. Raises if the tracers span no volume.

  • n_realizations (int, optional) – Independent reconstructions to run.

  • convergence (float, optional) – The sweeps stop once the fraction of successful swaps in a sweep, swaps per tracer visited, no longer exceeds this threshold.

  • seed (int, optional) – Seed of the random streams; 0 draws one at random. With a fixed seed the result does not depend on the number of threads.

  • cell_size (float, optional) – Grid cell size in units of the mps. Affects speed only.

  • verbosity (Verbosity, optional) – What the call prints; see Verbosity. "normal" prints one line, "detailed" the mps and its source before it.

Notes

The box is not periodic: nothing flows through its faces, so modes on the scale of the box itself cannot be reconstructed.

otswap.reconstruct_lightcone(tracers_sky: numpy.typing.ArrayLike, randoms_sky: numpy.typing.ArrayLike, *, sky_area_deg2: float | None = None, mask: Mask | None = None, n_bins: int, distances: DistanceTable, angle_unit: AngleUnit, tracers: numpy.typing.ArrayLike | None = None, randoms: numpy.typing.ArrayLike | None = None, n_realizations: int = 1, convergence: float = 0.001, seed: int = 0, cell_size: float = 4.0, redshift_cut: tuple[float, float] | None = None, reject_crossings: bool = True, max_unobserved_pixels_crossed: int = 0, verbosity: Verbosity = 'normal') → Result

Reconstruct in lightcone geometry.

The mean particle separation is measured from the tracers: n_bins uniform redshift bins over the observed range, mps = (N / V)^(-1/3) in each, with V the shell volume implied by the sky area. The bin values are joined by linear interpolation and extrapolated linearly beyond the outermost bins. Raises if a bin holds too few tracers for a 2% accuracy on its mps.

Randoms are required: they carry the survey geometry, the selection function and the completeness.

Parameters:
  • tracers_sky (array_like, shape (N, 3)) – Sky coordinates of the tracers.

  • randoms_sky (array_like, shape (M, 3)) – Sky coordinates of the randoms, M >= n_realizations * N.

  • sky_area_deg2 (float, optional) – Effective survey area, when no mask is given: the published value. Give exactly one of sky_area_deg2 and mask.

  • mask (Mask, optional) – The survey’s mask. The sky area is then mask.sky_area_deg2, and the mask is applied twice. Before the reconstruction, tracers and randoms on unobserved pixels are left out, as Mask.allows decides: the randoms are dropped, and the tracers keep their row, flagged in Result.outside_mask. After it, with reject_crossings, reject_mask_crossings is applied with max_unobserved_pixels_crossed. The mask and the redshift cut are both evaluated on every object; the objects kept pass both.

  • n_bins (int) – Redshift bins used to measure mps(z).

  • distances (DistanceTable) – Table used for the conversion to Cartesian coordinates.

  • angle_unit (AngleUnit) – Unit of right ascension and declination. A declination outside [-90, 90] degrees ([-pi/2, pi/2] radians) raises, the message giving it in this unit.

  • tracers (array_like, optional) – Cartesian coordinates already computed, shape (N, 3) and (M, 3). Give both or neither; when given, the conversion is skipped, and their agreement with the sky coordinates is not checked.

  • randoms (array_like, optional) – Cartesian coordinates already computed, shape (N, 3) and (M, 3). Give both or neither; when given, the conversion is skipped, and their agreement with the sky coordinates is not checked.

  • redshift_cut (tuple of two floats, optional) – (min, max). Tracers and randoms whose redshift lies outside this closed range are left out of the reconstruction, before anything else: the randoms are dropped, and the tracers keep their row, flagged in Result.outside_redshift_cut. mps(z) is measured on the tracers kept, and only their redshifts need lie in the distance table. None, the default, cuts nothing.

  • reject_crossings (bool, optional) – With a mask, filter the result with reject_mask_crossings. Ignored without a mask.

  • max_unobserved_pixels_crossed (int, optional) – The threshold of that filter. To filter with another threshold, set it here: a second filter with the same mask and a higher threshold changes nothing, since the filter only marks displacements invalid.

  • verbosity (Verbosity, optional) –

    What the call prints; see Verbosity. With "normal", when a mask or a cut with a finite bound is applied, what was left out: one line for the tracers, one for the randoms, one for the rejected crossings, as Result.selection records them; then the line of the call. In the form:

    otswap: kept <n> of <N> tracers: <a> outside the redshift cut [<zmin>, <zmax>], <b> outside the mask (<c> outside both)
    otswap: kept <m> of <M> randoms: <a> outside the redshift cut [<zmin>, <zmax>], <b> outside the mask (<c> outside both)
    otswap: rejected <r> of <D> displacements crossing more than <L> unobserved pixels
    otswap: reconstructLightcone: <R> realizations of <N> tracers in <T> s; <K> without a valid displacement
    

    "detailed" adds the mps(z) profile before the last line.

  • n_realizations – As in reconstruct_box.

  • convergence – As in reconstruct_box.

  • seed – As in reconstruct_box.

  • cell_size – As in reconstruct_box.

otswap.reject_mask_crossings(result: Result, mask: Mask, max_unobserved_pixels_crossed: int = 0) → None

Mark as invalid the displacements whose path crosses more than max_unobserved_pixels_crossed distinct unobserved pixels of the mask; 0 rejects at the first one.

The path is the great-circle arc between the directions of the tracer and of its matched random. The pixels containing the two endpoints are not tested. The count depends on NSIDE. Updates result in place; it only ever marks displacements invalid, and raises if result was already filtered against a mask of a different NSIDE. Tracers flagged in outside_redshift_cut or outside_mask are left as they are. valid_realizations, mean_displacement, lagrangian and lagrangian_sky are recomputed, and result.selection records the filter.

otswap.recompute_means(result: Result) → None

Recompute valid_realizations, mean_displacement, lagrangian and lagrangian_sky from displacement and valid, as the reconstruction computes them: the sum over the valid realizations in realization order, divided by their count. Updates result in place.

Results

class otswap.Result

Displacement field produced by a reconstruction.

Displacements point from the observed (Eulerian) position of a tracer to its reconstructed (Lagrangian) position, which is the position of the random it is matched to.

Every array attribute is read-only. The sky arrays (tracers_sky, lagrangian_sky) are in the angle_unit of the call that made the result; in degrees they are converted once, on first access, and kept. Every other array is a view on memory owned by this object, and keeps it alive. Use .copy() to obtain a writable array. Filtering with reject_mask_crossings updates valid, valid_realizations, mean_displacement and lagrangian in place, so views taken earlier reflect it; lagrangian_sky is recomputed, and an array taken from it in degrees before the filter is not updated.

property angle_unit: AngleUnit | None

the angle_unit of the call that made the result. None for a box.

Type:

The unit of tracers_sky and lagrangian_sky

property displacement: numpy.typing.NDArray[numpy.float64]

Displacements, shape (n_realizations, n_objects, 3).

property elapsed_seconds: float

Wall time of the call that made the result, in seconds. Two runs with the same seed give the same result but for this value.

property filtered_nside: int

NSIDE of the mask the result was filtered against, 0 if none.

static from_arrays(displacement: numpy.typing.ArrayLike, matched_random: numpy.typing.ArrayLike, valid: numpy.typing.ArrayLike, tracers: numpy.typing.ArrayLike, *, tracers_sky: numpy.typing.ArrayLike | None = None, angle_unit: AngleUnit | None = None, distances: DistanceTable | None = None, outside_redshift_cut: numpy.typing.ArrayLike | None = None, outside_mask: numpy.typing.ArrayLike | None = None, seed: int = 0) → Result

Build a result from its arrays, as read back from a file.

Parameters:
  • displacement (array_like, shape (n_realizations, n_objects, 3))

  • matched_random (array_like, shape (n_realizations, n_objects, 3))

  • valid (array_like, shape (n_realizations, n_objects)) – Each entry 0 or 1 (or bool).

  • tracers (array_like, shape (n_objects, 3)) – Cartesian.

  • tracers_sky (array_like, shape (n_objects, 3), optional) – For a lightcone result, with its angle_unit and the distances table of the reconstruction, from which lagrangian_sky is computed. Without it the result is a box result, and neither may be given.

  • outside_redshift_cut (array_like, shape (n_objects,), optional) – 0 or 1; all 0 when omitted.

  • outside_mask (array_like, shape (n_objects,), optional) – 0 or 1; all 0 when omitted.

  • seed (int, optional) – The seed to record.

Notes

valid_realizations, mean_displacement, lagrangian and lagrangian_sky are computed as recompute_means computes them, so arrays read back exactly give the reconstruction’s values, bit for bit. The profile, the mps and the selection counts are not reconstructed: mps and mps_profile are None.

property geometry: Literal['box', 'lightcone']
property lagrangian: numpy.typing.NDArray[numpy.float64]

Mean Lagrangian position of each tracer, tracers + mean_displacement, shape (n_objects, 3). NaN rows where the mean displacement is NaN.

property lagrangian_sky: numpy.typing.NDArray[numpy.float64] | None

Sky coordinates of each tracer’s mean Lagrangian position, lagrangian, shape (n_objects, 3), in angle_unit: right ascension in [0, 360) degrees ([0, 2 pi) radians), declination, redshift, as to_sky computes them with the reconstruction’s distance table. NaN rows where lagrangian is NaN: the tracers left out by a selection and those with no valid realization; a position whose distance falls outside the table has a NaN redshift. None for a box. Recomputed by reject_mask_crossings.

property matched_random: numpy.typing.NDArray[numpy.float64]

Cartesian position of the random matched to each tracer, shape (n_realizations, n_objects, 3).

property mean_displacement: numpy.typing.NDArray[numpy.float64]

Displacement averaged over the valid realizations, shape (n_objects, 3). NaN for a tracer with no valid realization.

property mps: float | None

the mean particle separation used, given or computed, in Mpc/h. None for a lightcone, whose separation is mps_profile.

Type:

Box

property mps_profile: MpsProfile | None

the mean particle separation as a function of redshift, measured on the tracers kept. None for a box. Keeps this result alive.

Type:

Lightcone

property n_objects: int
property n_realizations: int
property outside_mask: numpy.typing.NDArray[numpy.bool_]

Whether each tracer fell on an unobserved pixel of the mask of reconstruct_lightcone and took no part in the reconstruction, shape (n_objects,). All false without a mask. Independent of outside_redshift_cut: a tracer may carry both flags. A flagged tracer’s rows are as for a cut one.

property outside_redshift_cut: numpy.typing.NDArray[numpy.bool_]

Whether each tracer lay outside the redshift_cut of reconstruct_lightcone and took no part in the reconstruction, shape (n_objects,). All false without a cut. A cut tracer has NaN displacements and matched randoms, no valid realization and a NaN mean displacement.

property seed: int

the one drawn when seed=0 was given, so that the result can be reproduced.

Type:

The seed used

property selection: SelectionCounts

What reconstruct_lightcone left out, and why. Keeps this result alive.

property tracers: numpy.typing.NDArray[numpy.float64]

Cartesian position of each tracer, the start of its displacements, shape (n_objects, 3): the array given, or the conversion of tracers_sky. A tracer left out by the redshift cut or the mask has its conversion when its redshift lies in the distance table, NaN otherwise.

property tracers_sky: numpy.typing.NDArray[numpy.float64] | None

Sky coordinates of each tracer, shape (n_objects, 3), in angle_unit; None for a box. In degrees, the angles come back as x * (pi/180) * (180/pi), which can differ from the input in the last bit.

property valid: numpy.typing.NDArray[numpy.bool_]

Whether each displacement is valid, shape (n_realizations, n_objects). All true unless a filter was applied.

property valid_realizations: numpy.typing.NDArray[numpy.uint32]

Number of valid realizations per tracer, shape (n_objects,).

class otswap.MpsProfile

The mean particle separation of a lightcone as a function of redshift, measured by reconstruct_lightcone: the tracers kept in n_bins uniform redshift bins over [redshift_min, redshift_max], mps = (N / V)^(-1/3) in each, joined linearly and extrapolated linearly beyond the outermost bins. Read-only.

at(z: numpy.typing.ArrayLike) → numpy.typing.NDArray[numpy.float64]

The mps at each redshift, Mpc/h, the shape of z kept: the value the reconstruction used at a tracer of that redshift. Raises where the extrapolation is not positive.

property count: numpy.typing.NDArray[numpy.uint64]

Tracers in each bin, shape (n_bins,).

property mps: numpy.typing.NDArray[numpy.float64]

Mean particle separation at each centre, Mpc/h, shape (n_bins,).

property redshift: numpy.typing.NDArray[numpy.float64]

Bin centres, shape (n_bins,).

property redshift_max: float
property redshift_min: float
property representative: float

The count-weighted median of mps, which sizes the grids of the reconstruction.

class otswap.SelectionCounts

What a lightcone reconstruction left out, and why. Read-only.

The tracers removed are tracers_outside_redshift_cut + tracers_outside_mask - tracers_outside_both, and the same for the randoms. All counts are 0, and nothing is applied, for reconstruct_box. repr gives the report reconstruct_lightcone prints.

property displacements: int

Valid displacements before the first mask filter.

property displacements_crossing_mask: int

Of them, those rejected by every mask filter so far.

property mask_applied: bool

Whether a mask was given.

property max_unobserved_pixels_crossed: int | None

The threshold of the latest mask filter applied to the result, by reconstruct_lightcone (reject_crossings) or by reject_mask_crossings afterwards; None when none was.

property randoms: int

Randoms given.

property randoms_outside_both: int

Randoms counted in both of the two above.

property randoms_outside_mask: int
property randoms_outside_redshift_cut: int
property redshift_cut: tuple[float, float] | None

The (min, max) of the redshift cut; None when no cut was applied.

property tracers: int

Tracers given.

property tracers_outside_both: int

Tracers counted in both of the two above.

property tracers_outside_mask: int
property tracers_outside_redshift_cut: int

Redshift-space correction

otswap.real_space_lightcone(result: Result, *, distances: DistanceTable, bias: BiasTable, sigma: float, weight_by_realizations: bool = False, verbosity: Verbosity = 'normal') → RealSpaceCatalog

Move a lightcone catalogue, the tracers of result, from redshift space to real space.

For each tracer: the projection of result.mean_displacement on its line of sight, at result.tracers, the gaussian average of width sigma over the tracers with a valid realization, times f / (b + 3 f / 5) at its observed redshift; the tracer keeps its right ascension and declination and moves to the redshift of comoving distance d(z) + shift. A tracer without a valid realization still moves with the average of its neighbours; only one with no valid tracer within 3 sigma is not moved.

Parameters:
  • result (Result) – A lightcone result, which carries its tracers; sky comes back in its angle_unit.

  • distances (DistanceTable) – Must carry the growth rate, and cover the corrected distances as well as the observed ones.

  • bias (BiasTable) – The b(z) table, as in rsd_factor; warns ExtrapolationWarning once if b(z) is extrapolated.

  • sigma (float) – Width of the average, in Mpc/h; 0 for none. 10 Mpc/h is a reasonable starting value; the best value depends on the sample, and should be checked in each analysis.

  • weight_by_realizations (bool, optional) – Weight each neighbour by its number of valid realizations as well.

  • verbosity (Verbosity, optional) – What the call prints; see Verbosity. "normal" prints the line of the call; "detailed" before it how many of the corrected moved with their neighbours’ average, having no valid realization, and how many of the uncorrected were left out of the reconstruction or had no valid tracer within 3 sigma.

Raises:

Error – For a box result, or if a corrected comoving distance is not positive or lies outside the distance table; the message names the tracer.

Notes

Tracers outside the reconstruction’s redshift cut or mask are not corrected, take no part in any average, and have status 3.

otswap.real_space_box(result: Result, *, axis: int, redshift: float, distances: DistanceTable, bias: float, sigma: float, weight_by_realizations: bool = False, verbosity: Verbosity = 'normal') → RealSpaceCatalog

Move a box catalogue, the tracers of result, from redshift space to real space, with the line of sight along axis: the chain of real_space_lightcone with the projection on the axis, a single factor at redshift with the constant bias, and the shift along the axis, without periodic wrapping. Raises for a lightcone result.

The box is not periodic: nothing flows through its faces, so modes on the scale of the box itself cannot be reconstructed.

class otswap.RealSpaceCatalog

A catalogue moved to real space; row i describes input tracer i.

Every array attribute is read-only; sky is in the angle_unit of the result corrected, converted once and kept, and every other array is a view on memory owned by this object, as for Result.

property angle_unit: AngleUnit | None

The unit of sky, that of the result corrected; None for a box.

property axis: int | None

the line-of-sight axis; None for a lightcone.

Type:

Box

property box_bias: float | None

the bias of the tracers; None for a lightcone.

Type:

Box

property box_redshift: float | None

the redshift of the box; None for a lightcone.

Type:

Box

property cartesian: numpy.typing.NDArray[numpy.float64]

the tracer with its axis coordinate moved. Lightcone: r (1 + shift / |r|), the tracer moved along its line of sight. NaN rows for the tracers not moved.

Type:

Corrected Cartesian position, Mpc/h, shape (n_objects, 3). Box

property elapsed_seconds: float

Wall time of the call that made the catalogue, in seconds.

property factor: numpy.typing.NDArray[numpy.float64]

f / (b + 3 f / 5) at each tracer’s observed redshift, shape (n_objects,); in a box the single factor, repeated. NaN for the tracers left out of the reconstruction.

property geometry: Literal['box', 'lightcone']
property n_extrapolated: int

Tracers at whose redshift b(z) was extrapolated beyond its table; 0 for a box.

property n_neighbours: numpy.typing.NDArray[numpy.uint32]

Tracers with a valid realization averaged for each tracer, itself included if valid, shape (n_objects,); 0 for a tracer left out.

property n_objects: int
property n_realizations_averaged: numpy.typing.NDArray[numpy.uint32]

Sum of the valid realizations of those tracers, shape (n_objects,).

property shift: numpy.typing.NDArray[numpy.float64]

Shift applied along the line of sight, Mpc/h, shape (n_objects,): the factor times the averaged projection. NaN where nothing moved.

property sigma: float

The width of the average, Mpc/h, as given.

property sky: numpy.typing.NDArray[numpy.float64] | None

right ascension, in [0, 360) degrees ([0, 2 pi) radians), and declination of each tracer, and its corrected redshift, shape (n_objects, 3). The angles are those of Result.tracers_sky; in degrees they come back as x * (pi/180) * (180/pi), which can differ from the input in the last bit. NaN rows for the tracers not moved. None for a box.

Type:

Lightcone

property status: numpy.typing.NDArray[numpy.uint8]

0 corrected, 1 moved with the average of its neighbours (it had no valid realization), 2 not moved, with no valid tracer within 3 sigma (with sigma = 0: no valid realization), 3 not moved, left out of the reconstruction by its redshift cut or mask (Result.outside_* say which). See CorrectionStatus.

Type:

What the correction did with each tracer, shape (n_objects,)

property valid_realizations: numpy.typing.NDArray[numpy.uint32]

Valid realizations of each tracer, as in the result corrected, shape (n_objects,).

property weight_by_realizations: bool
class otswap.CorrectionStatus

The values of RealSpaceCatalog.status.

CORRECTED = 0

Had a valid realization; moved.

LEFT_OUT = 3

Outside the reconstruction’s redshift cut or mask; not moved.

MOVED_BY_NEIGHBOURS = 1

Had no valid realization; moved with its neighbours’ average.

NO_VALID_NEIGHBOUR = 2

no valid realization); not moved.

Type:

No valid tracer within 3 sigma (with sigma = 0

otswap.radial_projection(displacement: numpy.typing.ArrayLike, positions: numpy.typing.ArrayLike) → numpy.typing.NDArray[numpy.float64]

Component of each displacement, shape (N, 3), along the line of sight of its position, shape (N, 3), Cartesian, finite and away from the origin (for example Result.tracers): r . d / |r|, shape (N,), positive when the displacement points away from the observer. NaN displacements give NaN; infinite ones raise.

otswap.axis_projection(displacement: numpy.typing.ArrayLike, axis: int) → numpy.typing.NDArray[numpy.float64]

Component of each displacement, shape (N, 3), along the Cartesian axis 0, 1 or 2, the line of sight of a box; shape (N,).

otswap.neighbour_average(positions: numpy.typing.ArrayLike, values: numpy.typing.ArrayLike, valid_realizations: numpy.typing.ArrayLike, *, sigma: float, weight_by_realizations: bool = False) → NeighbourAverage

Gaussian average of values over the neighbours of each object.

An object is valid when its entry of valid_realizations is greater than zero. Each object, valid or not, receives the mean of the values of the valid objects within 3 sigma of its position, itself included when valid, weighted by exp(-d^2 / (2 sigma^2)) and, with weight_by_realizations, by their valid realizations; the weights are normalised, so a constant value comes back unchanged. NaN when no valid object lies within 3 sigma. With sigma = 0, values is returned unchanged.

Parameters:
  • positions (array_like, shape (N, 3)) – Cartesian coordinates, finite.

  • values (array_like, shape (N,)) – Finite wherever the object is valid.

  • valid_realizations (array_like, shape (N,)) – Non-negative integers, such as Result.valid_realizations.

  • sigma (float) – Width of the gaussian, in the unit of the positions; finite and non-negative. 10 Mpc/h is a reasonable starting value; the best value depends on the sample, and should be checked in each analysis.

Returns:

The averages and, per object, the number of valid objects averaged and the sum of their valid realizations.

Return type:

NeighbourAverage

Notes

The result does not depend on the internal neighbour grid within rounding, and is the same bit for bit for the same inputs, whatever the number of threads. With sigma > 0, positions that span no volume (a single object, or all in one plane or on one line) raise RuntimeError from the neighbour search, not otswap.Error.

class otswap.NeighbourAverage

What neighbour_average returns, shape (N,) each.

n_neighbours: numpy.typing.NDArray[numpy.uint32]

Valid objects averaged, the object itself included when it is valid.

n_realizations_averaged: numpy.typing.NDArray[numpy.uint32]

Sum of the valid realizations of those objects.

values: numpy.typing.NDArray[numpy.float64]

The average at each object; NaN with no valid object within 3 sigma.

otswap.rsd_factor(redshift: numpy.typing.ArrayLike, distances: DistanceTable, *, bias: BiasTable) → numpy.typing.NDArray[numpy.float64]

The factor f / (b + 3 f / 5) at each redshift, shape (N,).

f is distances.growth_rate_at(z), b(z) the bias table at z. Beyond the table’s nodes b(z) is extrapolated linearly from the end segments, and one ExtrapolationWarning is issued for the call. Raises if the extrapolated bias is not positive, if a redshift lies outside the distance table, or if the table has no growth rate.

otswap.rsd_factor_box(redshift: float, distances: DistanceTable, *, bias: float) → float

The factor f / (b + 3 f / 5) of a box at a single redshift, with a constant, positive bias.

class otswap.BiasTable(redshift: numpy.typing.ArrayLike, bias: numpy.typing.ArrayLike)

A b(z) table: the linear bias of the tracers at redshift nodes, interpolated linearly between them and extrapolated linearly beyond them from the first or last segment. Immutable.

Read one from a file with otswap.io.read_bias_table.

property bias: numpy.typing.NDArray[numpy.float64]

Bias at each node, shape (n,).

property redshift: numpy.typing.NDArray[numpy.float64]

Redshifts of the nodes, shape (n,).

otswap.shift_radially(positions: numpy.typing.ArrayLike, shift: numpy.typing.ArrayLike) → numpy.typing.NDArray[numpy.float64]

Move each position, shape (N, 3), by its shift, shape (N,), along its own line of sight: r (1 + shift / |r|). A positive shift moves away from the observer. A NaN shift gives a NaN row; infinite ones raise.

otswap.shift_along_axis(positions: numpy.typing.ArrayLike, shift: numpy.typing.ArrayLike, axis: int) → numpy.typing.NDArray[numpy.float64]

Move each position, shape (N, 3), by its shift, shape (N,), along the Cartesian axis 0, 1 or 2, without periodic wrapping. A NaN shift gives NaN along the axis; infinite ones raise.

Aliases

otswap.AngleUnit: TypeAlias = Literal['deg', 'rad']
otswap.Verbosity: TypeAlias = Literal['silent', 'normal', 'detailed']

What a reconstruction or a correction prints, to sys.stdout, each line starting with otswap::

  • "silent": nothing;

  • "normal": the selection report of a lightcone, when a selection applied, then one line per call with its time and what was lost:

    otswap: reconstructLightcone: <R> realizations of <N> tracers in <T> s; <K> without a valid displacement
    otswap: realSpaceLightcone: corrected <C> of <N> tracers in <T> s; <U> left uncorrected
    
  • "detailed": as "normal", with the lines that explain it: the mean particle separation of a box and its source, the mps(z) profile of a lightcone, and the breakdown of the corrected and of the uncorrected.

The counts behind every line are in the object returned. The extrapolation of b(z) is an ExtrapolationWarning, whatever the verbosity.

otswap.io

Tables

class otswap.io.Column(name: str, data: numpy.typing.ArrayLike, *, type: Literal['D', 'J', 'K'] = 'D', description: str = '', unit: str = '')

One column of a table to write. Read-only.

property data: numpy.typing.NDArray[numpy.float64] | numpy.typing.NDArray[numpy.int64]

int64 for a "K" column, float64 otherwise.

Type:

The values

property description: str
property name: str
property type: Literal['D', 'J', 'K']
property unit: str
class otswap.io.Table

A table read from file. Read-only; its arrays are views that keep it alive.

property integers: numpy.typing.NDArray[numpy.int64]

The integer_columns of read, shape (n_rows, n_integer_columns).

property n_columns: int

Columns read as float64.

property n_integer_columns: int

Columns read as int64.

property n_rows: int
property values: numpy.typing.NDArray[numpy.float64]

The columns of read, shape (n_rows, n_columns).

otswap.io.read(file: Path, columns: Sequence[str | int], *, integer_columns: Sequence[str | int] = (), delimiter: str = ' ', comment: str = '#') → Table

Read selected columns of a table: columns as float64, integer_columns exactly as int64, each in the order given.

In FITS the columns are named, case insensitively, and must be scalar; an integer column must have an integer type. In ASCII an int, or a str of digits, is a 0-based index; any other str is a name, looked up in the last line starting with ### before the first data row, where write puts the names. Lines that are empty or start with comment are skipped; fields are separated by delimiter, blanks or tabs. An ASCII integer field is an optional - followed by digits.

NaN and infinities are returned as stored, in both formats. Raises if a column is absent (the message lists the names found) or requested twice, a row is too short, an integer field is not an integer or lies outside the 64-bit range, or a FITS integer column holds a null value.

otswap.io.write(file: Path, columns: Sequence[Column], *, precision: int = 9, keywords: Sequence[tuple[str, str, str]] | None = None) → None

Write a table. An existing file is overwritten.

Parameters:
  • precision (int, optional) – Significant digits of a "D" value in ASCII, from 1 to 17; 17 reads back as the same float64. FITS stores the values themselves.

  • keywords (sequence of (str, str, str), optional) – (name, value, comment) tuples, written in this order; a name is 1 to 8 characters of A-Z, 0-9, - and _, a value at most 68 characters. In FITS a value that reads entirely as an integer or a finite number is written as one, anything else as a string.

Raises:

Error – If the columns differ in length, or a "J" value is not an integer in [-2**31, 2**31); the message names the column and the row.

otswap.io.read_bias_table(file: Path, *, delimiter: str = ' ', comment: str = '#') → otswap.BiasTable

Read a b(z) table: FITS from the columns named REDSHIFT and BIAS, ASCII from columns 0 and 1. Checked as BiasTable checks its arrays; the message names the file and the row.

Writers

otswap.io.write_displacements(file: Path, result: otswap.Result, *, groups: Sequence[DisplacementGroup] | None = None) → None

Write the mean displacement field of a result, one row per tracer.

The groups and their columns:

  • "index": index (64-bit integer), the row of the tracer in the input;

  • "tracer_sky": tracRA, tracDec (degrees), tracRed, the observed tracer; lightcone only;

  • "lagrangian_sky": lagrRA, lagrDec, lagrRed, Result.lagrangian_sky; lightcone only;

  • "tracer": tracX, tracY, tracZ (Mpc/h), Result.tracers;

  • "lagrangian": lagrX, lagrY, lagrZ, Result.lagrangian;

  • "displacement": displX, displY, displZ, Result.mean_displacement;

  • "valid_realizations": nValidRec;

  • "selection": outsideRedshiftCut, outsideMask (0 or 1); lightcone only.

Parameters:

groups (sequence of DisplacementGroup, optional) – In output order; None for the default, CosmoBolognaLib’s columns first: box tracer, lagrangian, displacement, valid_realizations; lightcone tracer_sky, lagrangian_sky, tracer, lagrangian, displacement, valid_realizations, selection.

Notes

Floating values are written with 9 significant digits in ASCII. Keywords: NREC, SEED (the seed used), CONVERG; MPS for a box; ZCUTMIN and ZCUTMAX for the finite bounds of a redshift cut, MASK = 1 when a mask selected the objects, FILTNSID and MAXPIXCR when a mask filter was applied. Raises for a repeated group, or one that does not apply to the geometry.

otswap.io.DisplacementGroup: TypeAlias = Literal['index', 'tracer_sky', 'lagrangian_sky', 'tracer', 'lagrangian', 'displacement', 'valid_realizations', 'selection']
otswap.io.write_displacement_field(file: Path, result: otswap.Result) → None

Write every realization of a result, losslessly: one row per realization and tracer, ordered [realization][object].

Columns: realization, index, tracX..tracZ (Result.tracers, repeated), lagrX..lagrZ (Result.matched_random), displX..displZ (Result.displacement), valid, outsideRedshiftCut, outsideMask. Keywords as write_displacements.

Floating values are written with 17 significant digits in ASCII, and as they are in FITS, so every value reads back identical, NaN included, in both formats; Result.from_arrays on the arrays read back gives the reconstruction’s means bit for bit. displX..displZ equal lagr - trac bit for bit.

otswap.io.write_real_space_catalog(file: Path, catalog: otswap.RealSpaceCatalog, *, groups: Sequence[CatalogGroup] | None = None) → None

Write a catalogue moved to real space, one row per tracer.

The groups and their columns:

  • "index": index (64-bit integer);

  • "sky": tracRA, tracDec (degrees), tracRed, RealSpaceCatalog.sky; lightcone only;

  • "cartesian": tracX, tracY, tracZ (Mpc/h), RealSpaceCatalog.cartesian;

  • "valid_realizations": nValidRec;

  • "neighbours": nNeighbours, nRealizationsAveraged;

  • "shift": shift (Mpc/h), rsdFactor;

  • "status": status, as RealSpaceCatalog.status.

Parameters:

groups (sequence of CatalogGroup, optional) – In output order; None for the default, CosmoBolognaLib’s columns first: lightcone sky, cartesian, valid_realizations, neighbours, status; box the same without sky.

Notes

Floating values are written with 9 significant digits in ASCII. Keywords: SIGMA, WEIGHTED; NEXTRAP for a lightcone; AXIS, ZBOX and BIAS for a box.

otswap.io.CatalogGroup: TypeAlias = Literal['index', 'sky', 'cartesian', 'valid_realizations', 'neighbours', 'shift', 'status']
otswap.io.write_mps_profile(file: Path, profile: otswap.MpsProfile) → None

Write a mean particle separation profile: redshift (the bin centre), MPS (Mpc/h), nTracers, one row per bin. Keywords: ZMIN, ZMAX, MPSREPR (the representative value). MpsProfile.at gives the profile anywhere.