mirror of
https://github.com/Richard-Sti/csiborgtools_public.git
synced 2025-05-13 14:11:11 +00:00
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:
parent
3b46f17ead
commit
d578c71b83
36 changed files with 365 additions and 231 deletions
127
scripts/field_prop/field_projected.py
Normal file
127
scripts/field_prop/field_projected.py
Normal 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)
|
26
scripts/field_prop/field_projected.sh
Executable file
26
scripts/field_prop/field_projected.sh
Executable 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
|
|
@ -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)
|
Loading…
Add table
Add a link
Reference in a new issue