Environmental properties (#20)

* rm get_positions

* Add comment

* add halfwidth func

* Update docs

* Add imprt

* Evaluate multiple fields simulatenously

* add halfwidth selection

* Change order of grav field and tensor field

* Add gravitational field norm

* Add eigenvalue calculation

* Sorted eigenvalues

* add init script

* add progress

* Add surveys

* Add more survey flexibility

* Minor changes

* add survey names

* rm name

* Fix list bug

* Fig bugs when running the script

* add phi to dtype

* fix dump bug

* Add comment

* Add smoothing options

* Add further comment

* Update TODO
This commit is contained in:
Richard Stiskalek 2022-12-31 17:46:05 +00:00 committed by GitHub
parent 65059f3798
commit 2e99b901ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 302 additions and 109 deletions

View file

@ -18,7 +18,7 @@
### TODO ### TODO
- [ ] Add gradient and Hessian of the overdensity field. - [ ] Add gradient and Hessian of the overdensity field.
- [ ] Write a script to smoothen an overdensity field, calculate the derived fields and evaluate them at the galaxy positions. - [x] Write a script to smoothen an overdensity field, calculate the derived fields and evaluate them at the galaxy positions.
### Questions ### Questions

View file

@ -139,7 +139,7 @@ class DensityField:
x = x.astype(numpy.float32) x = x.astype(numpy.float32)
return x return x
def density_field(self, grid, verbose=True): def density_field(self, grid, smooth_scale=None, verbose=True):
""" """
Calculate the density field using a Pylians routine [1, 2]. Enforces Calculate the density field using a Pylians routine [1, 2]. Enforces
float32 precision. float32 precision.
@ -148,6 +148,9 @@ class DensityField:
---------- ----------
grid : int grid : int
The grid size. The grid size.
smooth_scale : float, optional
Scale to smoothen the density field, in units matching
`self.boxsize`. By default `None`, i.e. no smoothing is applied.
verbose : float, optional verbose : float, optional
A verbosity flag. By default `True`. A verbosity flag. By default `True`.
@ -170,9 +173,11 @@ class DensityField:
# Pre-allocate and do calculations # Pre-allocate and do calculations
rho = numpy.zeros((grid, grid, grid), dtype=numpy.float32) rho = numpy.zeros((grid, grid, grid), dtype=numpy.float32)
MASL.MA(pos, rho, self.boxsize, self.MAS, W=weights, verbose=verbose) MASL.MA(pos, rho, self.boxsize, self.MAS, W=weights, verbose=verbose)
if smooth_scale is not None:
rho = self.smooth_field(rho, smooth_scale)
return rho return rho
def overdensity_field(self, grid, verbose=True): def overdensity_field(self, grid, smooth_scale=None, verbose=True):
r""" r"""
Calculate the overdensity field using Pylians routines. Calculate the overdensity field using Pylians routines.
Defined as :math:`\rho/ <\rho> - 1`. Defined as :math:`\rho/ <\rho> - 1`.
@ -181,6 +186,9 @@ class DensityField:
---------- ----------
grid : int grid : int
The grid size. The grid size.
smooth_scale : float, optional
Scale to smoothen the density field, in units matching
`self.boxsize`. By default `None`, i.e. no smoothing is applied.
verbose : float, optional verbose : float, optional
A verbosity flag. By default `True`. A verbosity flag. By default `True`.
@ -190,12 +198,12 @@ class DensityField:
Overdensity field. Overdensity field.
""" """
# Get the overdensity # Get the overdensity
delta = self.density_field(grid, verbose) delta = self.density_field(grid, smooth_scale, verbose)
delta /= delta.mean() delta /= delta.mean()
delta -= 1 delta -= 1
return delta return delta
def potential_field(self, grid, verbose=True): def potential_field(self, grid, smooth_scale=None, verbose=True):
""" """
Calculate the potential field using Pylians routines. Calculate the potential field using Pylians routines.
@ -203,6 +211,9 @@ class DensityField:
---------- ----------
grid : int grid : int
The grid size. The grid size.
smooth_scale : float, optional
Scale to smoothen the original density field, in units matching
`self.boxsize`. By default `None`, i.e. no smoothing is applied.
verbose : float, optional verbose : float, optional
A verbosity flag. By default `True`. A verbosity flag. By default `True`.
@ -211,42 +222,24 @@ class DensityField:
potential : 3-dimensional array of shape `(grid, grid, grid)`. potential : 3-dimensional array of shape `(grid, grid, grid)`.
Potential field. Potential field.
""" """
delta = self.overdensity_field(grid, verbose) delta = self.overdensity_field(grid, smooth_scale, verbose)
if verbose: if verbose:
print("Calculating potential from the overdensity..") print("Calculating potential from the overdensity..")
return MASL.potential( return MASL.potential(
delta, self.box._omega_m, self.box._aexp, self.MAS) delta, self.box._omega_m, self.box._aexp, self.MAS)
def tensor_field(self, grid, verbose=True): def gravitational_field(self, grid, smooth_scale=None, verbose=True):
""" """
Calculate the tidal tensor field. Calculate the gravitational vector field. Note that this method is
only defined in a fork of `Pylians`.
Parameters
----------
grid : int
The grid size.
verbose : float, optional
A verbosity flag. By default `True`.
Returns
-------
tidal_tensor : :py:class:`MAS_library.tidal_tensor`
Tidal tensor object, whose attributes `tidal_tensor.Tij` contain
the relevant tensor components.
"""
delta = self.overdensity_field(grid, verbose)
return MASL.tidal_tensor(
delta, self.box._omega_m, self.box._aexp, self.MAS)
def gravitational_field(self, grid, verbose=True):
"""
Calculate the gravitational tensor field. Note that this method is
only defined in fork of `Pylians`.
Parameters Parameters
---------- ----------
grid : int grid : int
The grid size. The grid size.
smooth_scale : float, optional
Scale to smoothen the original density field, in units matching
`self.boxsize`. By default `None`, i.e. no smoothing is applied.
verbose : float, optional verbose : float, optional
A verbosity flag. By default `True`. A verbosity flag. By default `True`.
@ -256,11 +249,35 @@ class DensityField:
Tidal tensor object, whose attributes `grav_field_tensor.gi` Tidal tensor object, whose attributes `grav_field_tensor.gi`
contain the relevant tensor components. contain the relevant tensor components.
""" """
delta = self.overdensity_field(grid, verbose) delta = self.overdensity_field(grid, smooth_scale, verbose)
return MASL.grav_field_tensor( return MASL.grav_field_tensor(
delta, self.box._omega_m, self.box._aexp, self.MAS) delta, self.box._omega_m, self.box._aexp, self.MAS)
def auto_powerspectrum(self, grid, verbose=True): def tensor_field(self, grid, smooth_scale=None, verbose=True):
"""
Calculate the tidal tensor field.
Parameters
----------
grid : int
The grid size.
smooth_scale : float, optional
Scale to smoothen the original density field, in units matching
`self.boxsize`. By default `None`, i.e. no smoothing is applied.
verbose : float, optional
A verbosity flag. By default `True`.
Returns
-------
tidal_tensor : :py:class:`MAS_library.tidal_tensor`
Tidal tensor object, whose attributes `tidal_tensor.Tij` contain
the relevant tensor components.
"""
delta = self.overdensity_field(grid, smooth_scale, verbose)
return MASL.tidal_tensor(
delta, self.box._omega_m, self.box._aexp, self.MAS)
def auto_powerspectrum(self, grid, smooth_scale, verbose=True):
""" """
Calculate the auto 1-dimensional power spectrum. Calculate the auto 1-dimensional power spectrum.
@ -268,6 +285,9 @@ class DensityField:
---------- ----------
grid : int grid : int
The grid size. The grid size.
smooth_scale : float, optional
Scale to smoothen the original density field, in units matching
`self.boxsize`. By default `None`, i.e. no smoothing is applied.
verbose : float, optional verbose : float, optional
A verbosity flag. By default `True`. A verbosity flag. By default `True`.
@ -276,7 +296,7 @@ class DensityField:
pk : py:class`Pk_library.Pk` pk : py:class`Pk_library.Pk`
Power spectrum object. Power spectrum object.
""" """
delta = self.overdensity_field(grid, verbose) delta = self.overdensity_field(grid, smooth_scale, verbose)
return PKL.Pk( return PKL.Pk(
delta, self.boxsize, axis=1, MAS=self.MAS, threads=1, delta, self.boxsize, axis=1, MAS=self.MAS, threads=1,
verbose=verbose) verbose=verbose)
@ -305,48 +325,51 @@ class DensityField:
W_k = SL.FT_filter(self.boxsize, scale, grid, Filter, threads) W_k = SL.FT_filter(self.boxsize, scale, grid, Filter, threads)
return SL.field_smoothing(field, W_k, threads) return SL.field_smoothing(field, W_k, threads)
def evaluate_field(self, pos, field): def evaluate_field(self, *field, pos):
""" """
Evaluate the field at Cartesian coordinates. Evaluate the field at Cartesian coordinates.
Parameters Parameters
---------- ----------
field : (list of) 3-dimensional array of shape `(grid, grid, grid)`
The density field that is to be interpolated.
pos : 2-dimensional array of shape `(n_samples, 3)` pos : 2-dimensional array of shape `(n_samples, 3)`
Positions to evaluate the density field. The coordinates span range Positions to evaluate the density field. The coordinates span range
of [0, boxsize]. of [0, boxsize].
field : 3-dimensional array of shape `(grid, grid, grid)`
The density field that is to be interpolated.
Returns Returns
------- -------
interp_field : 1-dimensional array of shape `(n_samples,). interp_field : (list of) 1-dimensional array of shape `(n_samples,).
Interpolated field at `pos`. Interpolated fields at `pos`.
""" """
self._force_f32(pos, "pos") self._force_f32(pos, "pos")
density_interpolated = numpy.zeros(pos.shape[0], dtype=numpy.float32)
MASL.CIC_interp(field, self.boxsize, pos, density_interpolated)
return density_interpolated
def evaluate_sky(self, pos, field, isdeg=True): interp_field = [numpy.zeros(pos.shape[0], dtype=numpy.float32)
for __ in range(len(field))]
for i, f in enumerate(field):
MASL.CIC_interp(f, self.boxsize, pos, interp_field[i])
return interp_field
def evaluate_sky(self, *field, pos, isdeg=True):
""" """
Evaluate the field at given distance, right ascension and declination. Evaluate the field at given distance, right ascension and declination.
Assumes that the observed is in the centre of the box. Assumes that the observed is in the centre of the box.
Parameters Parameters
---------- ----------
field : (list of) 3-dimensional array of shape `(grid, grid, grid)`
The density field that is to be interpolated. Assumed to be defined
on a Cartesian grid.
pos : 2-dimensional array of shape `(n_samples, 3)` pos : 2-dimensional array of shape `(n_samples, 3)`
Spherical coordinates to evaluate the field. Should be distance, Spherical coordinates to evaluate the field. Should be distance,
right ascension, declination, respectively. right ascension, declination, respectively.
field : 3-dimensional array of shape `(grid, grid, grid)`
The density field that is to be interpolated. Assumed to be defined
on a Cartesian grid.
isdeg : bool, optional isdeg : bool, optional
Whether `ra` and `dec` are in degres. By default `True`. Whether `ra` and `dec` are in degres. By default `True`.
Returns Returns
------- -------
interp_field : 1-dimensional array of shape `(n_samples,). interp_field : (list of) 1-dimensional array of shape `(n_samples,).
Interpolated field at `pos`. Interpolated fields at `pos`.
""" """
self._force_f32(pos, "pos") self._force_f32(pos, "pos")
X = numpy.vstack( X = numpy.vstack(
@ -354,7 +377,58 @@ class DensityField:
X = X.astype(numpy.float32) X = X.astype(numpy.float32)
# Place the observer at the center of the box # Place the observer at the center of the box
X += 0.5 * self.boxsize X += 0.5 * self.boxsize
return self.evaluate_field(X, field) return self.evaluate_field(*field, pos=X)
@staticmethod
def gravitational_field_norm(gx, gy, gz):
"""
Calculate the norm (magnitude) of a gravitational field.
Parameters
----------
gx, gy, gz : 1-dimensional arrays of shape `(n_samples,)`
Gravitational field components.
Returns
-------
g : 1-dimensional array of shape `(n_samples,)`
Gravitational field norm.
"""
return numpy.sqrt(gx * gx + gy * gy + gz * gz)
@staticmethod
def tensor_field_eigvals(T00, T01, T02, T11, T12, T22):
"""
Calculate the eigenvalues of a symmetric tensor field. Eigenvalues are
sorted in increasing order.
Parameters
----------
T00, T01, T02, T11, T12, T22 : 1-dim arrays of shape `(n_samples,)`
Tensor field upper components evaluated for each sample.
Returns
-------
eigvals : 2-dimensional array of shape `(n_samples, 3)`
Eigenvalues of each sample.
"""
n_samples = T00.size
# Fill array of shape `(n_samples, 3, 3)` to calculate eigvals
Teval = numpy.full((n_samples, 3, 3), numpy.nan, dtype=numpy.float32)
Teval[:, 0, 0] = T00
Teval[:, 0, 1] = T01
Teval[:, 0, 2] = T02
Teval[:, 1, 1] = T11
Teval[:, 1, 2] = T12
Teval[:, 2, 2] = T22
# Calculate the eigenvalues
eigvals = numpy.full((n_samples, 3), numpy.nan, dtype=numpy.float32)
for i in range(n_samples):
eigvals[i, :] = numpy.linalg.eigvalsh(Teval[i, ...], 'U')
eigvals[i, :] = numpy.sort(eigvals[i, :])
return eigvals
def make_sky_map(self, ra, dec, field, dist_marg, isdeg=True, def make_sky_map(self, ra, dec, field, dist_marg, isdeg=True,
verbose=True): verbose=True):
@ -364,6 +438,8 @@ class DensityField:
position evaluates the field at distances `dist_marg` and sums these position evaluates the field at distances `dist_marg` and sums these
interpolated values of the field. interpolated values of the field.
NOTE: Supports only scalar fields.
Parameters Parameters
---------- ----------
ra, dec : 1-dimensional arrays of shape `(n_pos, )` ra, dec : 1-dimensional arrays of shape `(n_pos, )`
@ -400,6 +476,6 @@ class DensityField:
dec_loop[:] = pos[i, 1] dec_loop[:] = pos[i, 1]
pos_loop[:] = numpy.vstack([dist_marg, ra_loop, dec_loop]).T pos_loop[:] = numpy.vstack([dist_marg, ra_loop, dec_loop]).T
# Evaluate and sum it up # Evaluate and sum it up
out[i] = numpy.sum(self.evaluate_sky(pos_loop, field, isdeg)) out[i] = numpy.sum(self.evaluate_sky(field, pos_loop, isdeg)[0, :])
return out return out

View file

@ -13,7 +13,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from .readsim import (CSiBORGPaths, ParticleReader, read_mmain, read_initcm, get_positions) # noqa from .readsim import (CSiBORGPaths, ParticleReader, read_mmain, read_initcm, halfwidth_select) # noqa
from .make_cat import (HaloCatalogue, CombinedHaloCatalogue) # noqa from .make_cat import (HaloCatalogue, CombinedHaloCatalogue) # noqa
from .readobs import (PlanckClusters, MCXCClusters, TwoMPPGalaxies, # noqa from .readobs import (PlanckClusters, MCXCClusters, TwoMPPGalaxies, # noqa
TwoMPPGroups, SDSS) # noqa TwoMPPGroups, SDSS) # noqa

View file

@ -95,6 +95,7 @@ class TwoMPPGalaxies(TextSurvey):
[3] Improving NASA/IPAC Extragalactic Database Redshift Calculations [3] Improving NASA/IPAC Extragalactic Database Redshift Calculations
(2021); Anthony Carr and Tamara Davis (2021); Anthony Carr and Tamara Davis
""" """
name = "2M++_galaxies"
def __init__(self, fpath=None): def __init__(self, fpath=None):
if fpath is None: if fpath is None:
@ -143,6 +144,7 @@ class TwoMPPGroups(TextSurvey):
[3] Improving NASA/IPAC Extragalactic Database Redshift Calculations [3] Improving NASA/IPAC Extragalactic Database Redshift Calculations
(2021); Anthony Carr and Tamara Davis (2021); Anthony Carr and Tamara Davis
""" """
name = "2M++_groups"
def __init__(self, fpath): def __init__(self, fpath):
if fpath is None: if fpath is None:
@ -411,6 +413,7 @@ class PlanckClusters(FitsSurvey):
---------- ----------
[1] https://heasarc.gsfc.nasa.gov/W3Browse/all/plancksz2.html [1] https://heasarc.gsfc.nasa.gov/W3Browse/all/plancksz2.html
""" """
name = "Planck_clusters"
_hdata = 0.7 # little h value of the data _hdata = 0.7 # little h value of the data
def __init__(self, fpath=None, h=0.7, sel_steps=None): def __init__(self, fpath=None, h=0.7, sel_steps=None):
@ -514,6 +517,7 @@ class MCXCClusters(FitsSurvey):
[2] https://heasarc.gsfc.nasa.gov/W3Browse/rosat/mcxc.html [2] https://heasarc.gsfc.nasa.gov/W3Browse/rosat/mcxc.html
[3] https://cdsarc.cds.unistra.fr/viz-bin/cat/J/A+A/534/A109#/article [3] https://cdsarc.cds.unistra.fr/viz-bin/cat/J/A+A/534/A109#/article
""" """
name = "MCXC"
_hdata = 0.7 # Little h of the catalogue _hdata = 0.7 # Little h of the catalogue
def __init__(self, fpath=None, h=0.7, sel_steps=None): def __init__(self, fpath=None, h=0.7, sel_steps=None):
@ -571,6 +575,7 @@ class SDSS(FitsSurvey):
---------- ----------
[1] https://www.sdss.org/dr13/manga/manga-target-selection/nsa/ [1] https://www.sdss.org/dr13/manga/manga-target-selection/nsa/
""" """
name = "SDSS"
def __init__(self, fpath=None, h=1, sel_steps=None): def __init__(self, fpath=None, h=1, sel_steps=None):
if fpath is None: if fpath is None:

View file

@ -18,12 +18,11 @@ Functions to read in the particle and clump files.
import numpy import numpy
from scipy.io import FortranFile from scipy.io import FortranFile
import gc
from os.path import (join, isfile, isdir) from os.path import (join, isfile, isdir)
from glob import glob from glob import glob
from tqdm import tqdm from tqdm import tqdm
from warnings import warn from warnings import warn
from ..utils import (cols_to_structured, extract_from_structured) from ..utils import (cols_to_structured)
F16 = numpy.float16 F16 = numpy.float16
@ -883,49 +882,31 @@ def read_initcm(n, srcdir, fname="clump_{}_cm.npy"):
return None return None
def get_positions(paths, get_clumpid, verbose=True): def halfwidth_select(hw, particles):
""" """
Shortcut to get particle IDs, positions, masses and optionally clump Select particles that in a cube of size `2 hw`, centered at the origin.
indices. Note that this directly modifies the original array and throws away
particles outside the central region.
Parameters Parameters
---------- ----------
paths : py:class`csiborgtools.read.CSiBORGPaths` hw : float
CSiBORG paths-handling object with set `n_sim` and `n_snap`. Central region halfwidth.
get_clumpid : bool particles : structured array
Whether to also return the clump indices. Particle array with keys `x`, `y`, `z`.
verbose : bool, optional
Verbosity flag. By default `True`.
Returns Returns
------- -------
particle_ids : 1-dimensional array particles : structured array
Particle IDs of shape `(n_particles, )`. The modified particle array.
particle_pos : 2-dimensional array
Particle box coordinates of shape `(n_particles, 3)`.
particle_mass : 1-dimensional array
Particle mass of shape `(n_particles, )`.
clump_ids : 1-dimensional array, optional
Particles' clump IDs of shape `(n_particles, )`. Returned only if
`get_clumpid` is `True`.
""" """
# Extract particles assert 0 < hw < 0.5
reader = ParticleReader(paths) mask = ((0.5 - hw < particles['x']) & (particles['x'] < 0.5 + hw)
pars_extract = ["ID", "x", "y", "z", "M"] & (0.5 - hw < particles['y']) & (particles['y'] < 0.5 + hw)
& (0.5 - hw < particles['z']) & (particles['z'] < 0.5 + hw))
# Read particles and unpack # Subselect the particles
particles = reader.read_particle(pars_extract, verbose) particles = particles[mask]
pids = extract_from_structured(particles, "ID") # Rescale to range [0, 1]
ppos = extract_from_structured(particles, ["x", "y", "z"]) for p in ('x', 'y', 'z'):
pmass = extract_from_structured(particles, "M") particles[p] = (particles[p] - 0.5 + hw) / (2 * hw)
return particles
# Force early memory release
del particles
gc.collect()
out = (pids, ppos, pmass)
if get_clumpid:
out += (reader.read_clumpid(verbose),)
return out

View file

@ -70,27 +70,18 @@ for n in jobs:
particles = reader.read_particle(["x", "y", "z", "M"], verbose=False) particles = reader.read_particle(["x", "y", "z", "M"], verbose=False)
# Halfwidth -- particle selection # Halfwidth -- particle selection
if args.halfwidth < 0.5: if args.halfwidth < 0.5:
hw = args.halfwidth particles = csiborgtools.read.halfwidth_select(
mask = ((0.5 - hw < particles['x']) & (particles['x'] < 0.5 + hw) args.halfwidth, particles)
& (0.5 - hw < particles['y']) & (particles['y'] < 0.5 + hw) length = box.box2mpc(2 * args.halfwidth) * box.h # Mpc/h
& (0.5 - hw < particles['z']) & (particles['z'] < 0.5 + hw))
# Subselect the particles
particles = particles[mask]
# Rescale to range [0, 1]
for p in ('x', 'y', 'z'):
particles[p] = (particles[p] - 0.5 + hw) / (2 * hw)
length = box.box2mpc(2 * hw) * box.h
else: else:
mask = None length = box.box2mpc(1) * box.h # Mpc/h
length = box.box2mpc(1) * box.h
# Calculate the overdensity field # Calculate the overdensity field
field = csiborgtools.field.DensityField(particles, length, box, MAS) field = csiborgtools.field.DensityField(particles, length, box, MAS)
delta = field.overdensity_field(args.grid, verbose=False) delta = field.overdensity_field(args.grid, verbose=False)
aexp = box._aexp aexp = box._aexp
# Try to clean up memory # Try to clean up memory
del field, particles, box, reader, mask del field, particles, box, reader
collect() collect()
# Dump the results # Dump the results

120
scripts/run_fieldprop.py Normal file
View file

@ -0,0 +1,120 @@
# Copyright (C) 2022 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.
"""
MPI script to evaluate field properties at the galaxy positions.
NOTE:
- Calculate for the entire box or just for a smaller region?
- Add argparser for different options.
- In the argparser add options to smoothen the field.
"""
import numpy
from datetime import datetime
from mpi4py import MPI
from os.path import join
from os import remove
try:
import csiborgtools
except ModuleNotFoundError:
import sys
sys.path.append("../")
import csiborgtools
import utils
halfwidth = 0.5
MAS = "CIC"
grid = 256
# Get MPI things
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
nproc = comm.Get_size()
# Galaxy positions
survey = "SDSS"
survey = utils.surveys[survey]()()
pos = numpy.vstack([survey[p] for p in ("DIST", "RA", "DEC")]).T
pos = pos.astype(numpy.float32)
# File paths
ftemp = join(utils.dumpdir, "temp_fields", "out_" + survey.name + "_{}.npy")
fperm = join(utils.dumpdir, "fields", "out_{}.npy".format(survey.name))
# Edit depending on what is calculated
dtype = {"names": ["delta", "phi"], "formats": [numpy.float32] * 2}
# CSiBORG simulation paths
paths = csiborgtools.read.CSiBORGPaths()
ics = paths.ic_ids[:10]
n_sims = len(ics)
for n in csiborgtools.fits.split_jobs(n_sims, nproc)[rank]:
print("Rank {}@{}: working on {}th IC.".format(rank, datetime.now(), n),
flush=True)
# Set the paths
n_sim = ics[n]
paths.set_info(n_sim, paths.get_maximum_snapshot(n_sim))
# Set reader and the box
reader = csiborgtools.read.ParticleReader(paths)
box = csiborgtools.units.BoxUnits(paths)
# Read particles and select a subset of them
particles = reader.read_particle(["x", "y", "z", "M"], verbose=False)
if halfwidth < 0.5:
particles = csiborgtools.read.halfwidth_select(halfwidth, particles)
length = box.box2mpc(2 * halfwidth) * box.h # Mpc/h
else:
length = box.box2mpc(1) * box.h # Mpc/h
# Initialise the field object and output array
field = csiborgtools.field.DensityField(particles, length, box, MAS)
out = numpy.full(pos.shape[0], numpy.nan, dtype=dtype)
# Calculate the overdensity field and interpolate at galaxy positions
feval = field.overdensity_field(grid, verbose=False)
out["delta"] = field.evaluate_sky(feval, pos=pos, isdeg=True)[0]
# Potential
feval = field.potential_field(grid, verbose=False)
out["phi"] = field.evaluate_sky(feval, pos=pos, isdeg=True)[0]
# Calculate the remaining fields
# ...
# ...
# Dump the results
with open(ftemp.format(n_sim), "wb") as f:
numpy.save(f, out)
# Wait for all ranks to finish
comm.Barrier()
if rank == 0:
print("Collecting files...", flush=True)
out = numpy.full((n_sims, pos.shape[0]), numpy.nan, dtype=dtype)
for n in range(n_sims):
n_sim = ics[n]
with open(ftemp.format(n_sim), "rb") as f:
fin = numpy.load(f, allow_pickle=True)
for name in dtype["names"]:
out[name][n, ...] = fin[name]
# Remove the temporary file
remove(ftemp.format(n_sim))
print("Saving results to `{}`.".format(fperm), flush=True)
with open(fperm, "wb") as f:
numpy.save(f, out)

View file

@ -18,11 +18,11 @@ Notebook utility functions.
# from os.path import join # from os.path import join
# try: try:
# import csiborgtools import csiborgtools
# except ModuleNotFoundError: except ModuleNotFoundError:
# import sys import sys
# sys.path.append("../") sys.path.append("../")
Nsplits = 200 Nsplits = 200
@ -39,3 +39,23 @@ _virgo = {"RA": (12 + 27 / 60) * 15,
"COMDIST": 16.5} "COMDIST": 16.5}
specific_clusters = {"Coma": _coma, "Virgo": _virgo} specific_clusters = {"Coma": _coma, "Virgo": _virgo}
###############################################################################
# Surveys #
###############################################################################
class SDSS:
@staticmethod
def steps(cls):
return [(lambda x: cls[x], ("IN_DR7_LSS",)),
(lambda x: cls[x] < 17.6, ("ELPETRO_APPMAG_r", )),
(lambda x: cls[x] < 155, ("DIST", ))
]
def __call__(self):
return csiborgtools.read.SDSS(h=1, sel_steps=self.steps)
surveys = {"SDSS": SDSS}