LSS projected basics (#140)

* Move files

* Move files

* Add galactic to RA/dec

* Update sky maps

* Add projected fields

* Remove old import

* Quick update

* Add IO

* Add imports

* Update imports

* Add basic file
This commit is contained in:
Richard Stiskalek 2024-08-14 13:02:38 +02:00 committed by GitHub
parent 3b46f17ead
commit d578c71b83
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 365 additions and 231 deletions

View file

@ -0,0 +1,127 @@
# Copyright (C) 2023 Richard Stiskalek
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
A script to calculate the projected density field for a given simulation as a
sky map. The script is not parallelized in any way. The generated fields are
converted to galactic coordinates to match the CMB maps.
"""
from argparse import ArgumentParser
from os import remove
from os.path import exists, join
import csiborgtools
import numpy as np
from h5py import File
def get_field(simname, nsim, field_kind, MAS, grid):
"""Get the appropriate field reader for the simulation."""
if simname == "csiborg1":
reader = csiborgtools.read.CSiBORG1Field(nsim)
elif "csiborg2" in simname:
kind = simname.split("_")[-1]
reader = csiborgtools.read.CSiBORG2Field(nsim, kind)
elif simname == "csiborg2X":
reader = csiborgtools.read.CSiBORG2XField(nsim)
elif "quijote" in simname:
reader = csiborgtools.read.QuijoteField(nsim)
else:
raise ValueError(f"Unknown simname: `{simname}`.")
if field_kind == "density":
return reader.density_field(MAS, grid)
else:
raise ValueError(f"Unknown field kind: `{field_kind}`.")
def main(simname, nsims, field_kind, nside, dist_ranges, MAS, grid,
volume_weight, folder, normalize_to_overdensity=True):
boxsize = csiborgtools.simname2boxsize(simname)
Om0 = csiborgtools.simname2Omega_m(simname)
matter_density = Om0 * 277.53662724583074 # Msun / kpc^3
fname = join(folder, f"{simname}_{field_kind}.hdf5")
if volume_weight:
fname = fname.replace(".hdf5", "_volume_weighted.hdf5")
print(f"Writing to `{fname}`...")
if exists(fname):
remove(fname)
with File(fname, "w") as f:
f.create_dataset("dist_ranges", data=np.asarray(dist_ranges))
f.create_dataset("nsims", data=nsims)
# These are at first generated in RA/dec but we can assume it is galactic
# and convert it to RA/dec.
pixel_angpos = csiborgtools.field.nside2radec(nside)
RA, dec = csiborgtools.galactic_to_radec(*pixel_angpos.T)
pixel_angpos = np.vstack([RA, dec]).T
npix = len(pixel_angpos)
Rmax = np.asanyarray(dist_ranges).reshape(-1).max()
dr = 0.5 * boxsize / grid
print(f"{'R_max:':<20} {Rmax} Mpc / h", flush=True)
print(f"{'dr:':<20} {dr} Mpc / h", flush=True)
for nsim in nsims:
print(f"Interpolating at {npix} pixel for simulation {nsim}...",
flush=True)
field = get_field(simname, nsim, field_kind, MAS, grid)
rdist, finterp = csiborgtools.field.make_sky(
field, pixel_angpos, Rmax, dr, boxsize, return_full=True,
interpolation_method="linear")
with File(fname, "a") as f:
grp = f.create_group(f"nsim_{nsim}")
for n in range(len(dist_ranges)):
dmin, dmax = dist_ranges[n]
k_start = np.searchsorted(rdist, dmin)
k_end = np.searchsorted(rdist, dmax)
r = rdist[k_start:k_end + 1]
y = r**2 * finterp[:, k_start:k_end + 1]
skymap = np.trapz(y, r, axis=-1) / np.trapz(r**2, r)
if normalize_to_overdensity:
skymap /= matter_density
skymap -= 1
grp.create_dataset(f"dist_range_{n}", data=skymap)
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("--simname", type=str, help="Simulation name.")
args = parser.parse_args()
fdir = "/mnt/extraspace/rstiskalek/csiborg_postprocessing/field_projected"
dx = 25
dist_ranges = [[0, n * dx] for n in range(1, 5)]
dist_ranges += [[n * dx, (n + 1) * dx] for n in range(0, 5)]
paths = csiborgtools.read.Paths(**csiborgtools.paths_glamdring)
nsims = paths.get_ics(args.simname)
print(f"{'Num. sims:':<20} {len(nsims)}", flush=True)
MAS = "SPH"
grid = 1024
nside = 128
field_kind = "density"
volume_weight = True
main(args.simname, nsims, field_kind, nside, dist_ranges, MAS, grid,
volume_weight, fdir)

View file

@ -0,0 +1,26 @@
nthreads=1
memory=64
on_login=${1}
simname=${2}
queue="berg"
env="/mnt/users/rstiskalek/csiborgtools/venv_csiborg/bin/python"
file="field_projected.py"
if [ "$on_login" != "1" ] && [ "$on_login" != "0" ]
then
echo "'on_login' (1) must be either 0 or 1."
exit 1
fi
pythoncm="$env $file --simname $simname"
if [ $on_login -eq 1 ]; then
echo $pythoncm
$pythoncm
else
cm="addqueue -q $queue -n $nthreads -m $memory $pythoncm"
echo "Submitting:"
echo $cm
echo
eval $cm
fi

View file

@ -1,158 +0,0 @@
# Copyright (C) 2024 Richard Stiskalek
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
NOTE: The script is far from finished or written well.
"""
from os.path import join
import numpy as np
import csiborgtools
from h5py import File
from sklearn.neighbors import NearestNeighbors
from numba import jit
from scipy.stats import binned_statistic
###
def find_indxs(rtree, r, radius):
"""
Find the indices of points that are within a given radius of a given
point `r`.
"""
if isinstance(r, (int, float)):
r = np.array(r)
return rtree.radius_neighbors(
r.reshape(-1, 1), radius=radius, return_distance=False, )[0]
@jit(nopython=True)
def dot_product_norm(x1_norm, x2_norm):
"""Dot product of two normalised 1D vectors."""
return x1_norm[0] * x2_norm[0] + x1_norm[1] * x2_norm[1] + x1_norm[2] * x2_norm[2] # noqa
@jit(nopython=True)
def get_angdist_vrad_product(i_comb, j_comb, pos_norm, vrad, r, rbin_i, rbin_j):
# TODO: Add itself?
len_i = len(i_comb)
len_j = len(j_comb)
cos_angdist_values = np.full(len_i * len_j, np.nan)
vrad_product = np.full(len_i * len_j, np.nan)
weights = np.full(len_i * len_j, np.nan)
k = 0
for i in range(len_i):
pos_norm_i = pos_norm[i_comb[i]]
vrad_i = vrad[i_comb[i]]
w_i = (rbin_i / r[i_comb[i]])**2
for j in range(len_j):
cos_angdist_values[k] = dot_product_norm(pos_norm_i, pos_norm[j_comb[j]])
# Product of the peculiar velocities
vrad_product[k] = vrad_i * vrad[j_comb[j]]
# Weight the product
w = w_i * (rbin_j / r[j_comb[j]])**2
vrad_product[k] *= w
weights[k] = w
k += 1
return cos_angdist_values, vrad_product, weights
def main(out_summed_product, out_weights, ri, rj, angular_bins, pos, vel, observer, rmax):
# Centre the positions at the observer
pos = np.copy(pos) - observer
r = np.linalg.norm(pos, axis=1)
mask = r < rmax
# Select only the haloes within the radial range
pos = pos[mask]
vel = vel[mask]
r = r[mask]
# Create a KDTree for the radial positions
rtree = NearestNeighbors().fit(r.reshape(-1, 1))
# Calculate the radial velocity and the normalised position vector
pos_norm = pos / r[:, None]
vrad = np.sum(vel * pos_norm, axis=1)
# TODO: eventually here loop over the radii
# for ....
dr = 2.5
i_indxs = find_indxs(rtree, ri, radius=dr)
j_indxs = find_indxs(rtree, rj, radius=dr)
# Calculate the cosine of the angular distance and the product of the
# radial velocities for each pair of points.
cos_angdist, vrad_product, weights = get_angdist_vrad_product(
i_indxs, j_indxs, pos_norm, vrad, r, ri, rj)
out_summed_product += binned_statistic(
cos_angdist, vrad_product, bins=angular_bins, statistic="sum")[0]
out_weights += binned_statistic(
cos_angdist, weights, bins=angular_bins, statistic="sum")[0]
return out_summed_product, out_weights
if __name__ == "__main__":
fdir = "/mnt/extraspace/rstiskalek/BBF/Quijote_C_ij"
rmax = 150
nradial = 20
nangular = 40
ncatalogue = 1
# NOTE check this
radial_bins = np.linspace(0, rmax, nradial + 1)
angular_bins = np.linspace(-1, 1, nangular + 1)
summed_product = np.zeros(nangular)
weights = np.zeros(nangular)
fiducial_observers = csiborgtools.read.fiducial_observers(1000, rmax)
ri = 100
rj = 120
# for i in trange(ncatalogue, desc="Catalogues"):
for i in [30]:
cat = csiborgtools.read.QuijoteCatalogue(i)
for j in range(len(fiducial_observers)):
# Loop over all the fiducial observers in this simulation
observer = fiducial_observers[j]
summed_product, weights = main(
summed_product, weights, ri, rj, angular_bins,
cat["cartesian_pos"], cat["cartesian_vel"], observer, rmax)
# TODO: Save
fname = join(fdir, "test.h5")
print(f"Saving to `{fname}`.")
with File(fname, 'w') as f:
f.create_dataset("summed_product", data=summed_product)
f.create_dataset("weights", data=weights)
f.create_dataset("angular_bins", data=angular_bins)