mirror of
https://github.com/Richard-Sti/csiborgtools.git
synced 2025-01-05 07:14:14 +00:00
159 lines
4.8 KiB
Python
159 lines
4.8 KiB
Python
|
# 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)
|