Particle init CM separation (#17)

* Rename

* rename module

* add new_ic_ids

* Add to_new support

* rm unnecessary comment

* Remove JUlia!

* add new package attempt

* add dump script

* simplify positions getter

* Remove unused code

* change dumpdirs

* update project

* Add sorting

* fix indexing bug

* add comment

* Add particle dumping

* Delete blank line

* Delete Julia things

* Update README

* add working script

* fix assignment bug

* fix bug

* save temp to temp folder

* fix indexing bug & path

* do not always crreate folder

* Rename file

* add initcm reader

* add x0, y0, z0 transforms

* add initcm to halo cat

* docs update

* add initial KNN

* add attempt at init match

* add initial fiducial radius

* rm blank space

* Add further KNN Init pos support

* Add init radius support

* Remove message about the bug

* Get rid of an error msg

* purge mention of knn_init

* Add init CM distance calc
This commit is contained in:
Richard Stiskalek 2022-12-16 10:18:16 +00:00 committed by GitHub
parent c3c686fa60
commit 13a9d11afe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 409 additions and 525 deletions

View file

@ -1,344 +0,0 @@
# This file is machine-generated - editing it directly is not advised
julia_version = "1.8.3"
manifest_format = "2.0"
project_hash = "8ac89492dc497a2481ecf3e1e7f2cc6ba12b4702"
[[deps.ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
version = "1.1.1"
[[deps.Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
[[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
[[deps.BenchmarkTools]]
deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"]
git-tree-sha1 = "d9a9701b899b30332bbcb3e1679c41cce81fb0e8"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "1.3.2"
[[deps.CSTParser]]
deps = ["Tokenize"]
git-tree-sha1 = "3ddd48d200eb8ddf9cb3e0189fc059fd49b97c1f"
uuid = "00ebfdb7-1f24-5e51-bd34-a7502290713f"
version = "3.3.6"
[[deps.CodeTracking]]
deps = ["InteractiveUtils", "UUIDs"]
git-tree-sha1 = "cc4bd91eba9cdbbb4df4746124c22c0832a460d6"
uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2"
version = "1.1.1"
[[deps.CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
version = "0.5.2+0"
[[deps.Conda]]
deps = ["Downloads", "JSON", "VersionParsing"]
git-tree-sha1 = "6e47d11ea2776bc5627421d59cdcc1296c058071"
uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d"
version = "1.7.0"
[[deps.Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
[[deps.Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"
[[deps.Downloads]]
deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
version = "1.6.0"
[[deps.FileIO]]
deps = ["Pkg", "Requires", "UUIDs"]
git-tree-sha1 = "7be5f99f7d15578798f338f5433b6c432ea8037b"
uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
version = "1.16.0"
[[deps.FileWatching]]
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
[[deps.IJulia]]
deps = ["Base64", "Conda", "Dates", "InteractiveUtils", "JSON", "Libdl", "Markdown", "MbedTLS", "Pkg", "Printf", "REPL", "Random", "SoftGlobalScope", "Test", "UUIDs", "ZMQ"]
git-tree-sha1 = "98ab633acb0fe071b671f6c1785c46cd70bb86bd"
uuid = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
version = "1.23.3"
[[deps.InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
[[deps.JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.4.1"
[[deps.JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "3c837543ddb02250ef42f4738347454f95079d4e"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.3"
[[deps.JuliaInterpreter]]
deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"]
git-tree-sha1 = "a79c4cf60cc7ddcdcc70acbb7216a5f9b4f8d188"
uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a"
version = "0.9.16"
[[deps.LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
version = "0.6.3"
[[deps.LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
version = "7.84.0+0"
[[deps.LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
[[deps.LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
version = "1.10.2+0"
[[deps.Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
[[deps.LinearAlgebra]]
deps = ["Libdl", "libblastrampoline_jll"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
[[deps.Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
[[deps.LoweredCodeUtils]]
deps = ["JuliaInterpreter"]
git-tree-sha1 = "dedbebe234e06e1ddad435f5c6f4b85cd8ce55f7"
uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b"
version = "2.2.2"
[[deps.MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "42324d08725e200c23d4dfb549e0d5d89dede2d2"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.10"
[[deps.Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
[[deps.MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "Random", "Sockets"]
git-tree-sha1 = "03a9b9718f5682ecb107ac9f7308991db4ce395b"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.1.7"
[[deps.MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
version = "2.28.0+0"
[[deps.Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"
[[deps.MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
version = "2022.2.1"
[[deps.NPZ]]
deps = ["FileIO", "ZipFile"]
git-tree-sha1 = "60a8e272fe0c5079363b28b0953831e2dd7b7e6f"
uuid = "15e1cf62-19b3-5cfa-8e77-841668bca605"
version = "0.4.3"
[[deps.NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
version = "1.2.0"
[[deps.OpenBLAS_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
version = "0.3.20+0"
[[deps.OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"
[[deps.Parsers]]
deps = ["Dates", "SnoopPrecompile"]
git-tree-sha1 = "b64719e8b4504983c7fca6cc9db3ebc8acc2a4d6"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.5.1"
[[deps.Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
version = "1.8.0"
[[deps.Preferences]]
deps = ["TOML"]
git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.3.0"
[[deps.Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
[[deps.Profile]]
deps = ["Printf"]
uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"
[[deps.PyCall]]
deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"]
git-tree-sha1 = "53b8b07b721b77144a0fbbbc2675222ebf40a02d"
uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
version = "1.94.1"
[[deps.REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
[[deps.Random]]
deps = ["SHA", "Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
[[deps.Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.3.0"
[[deps.Revise]]
deps = ["CodeTracking", "Distributed", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "Pkg", "REPL", "Requires", "UUIDs", "Unicode"]
git-tree-sha1 = "dad726963ecea2d8a81e26286f625aee09a91b7c"
uuid = "295af30f-e4ad-537b-8983-00126c2a3abe"
version = "3.4.0"
[[deps.SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
version = "0.7.0"
[[deps.Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
[[deps.SnoopPrecompile]]
git-tree-sha1 = "f604441450a3c0569830946e5b33b78c928e1a85"
uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c"
version = "1.0.1"
[[deps.Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
[[deps.SoftGlobalScope]]
deps = ["REPL"]
git-tree-sha1 = "986ec2b6162ccb95de5892ed17832f95badf770c"
uuid = "b85f4697-e234-5449-a836-ec8e2f98b302"
version = "1.1.0"
[[deps.SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
[[deps.StaticLint]]
deps = ["CSTParser", "Serialization", "SymbolServer"]
git-tree-sha1 = "1152934b19a8a296db95ef6e1d454d4acc2aa79d"
uuid = "b3cc710f-9c33-5bdb-a03d-a94903873e97"
version = "8.1.0"
[[deps.Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
[[deps.SymbolServer]]
deps = ["InteractiveUtils", "LibGit2", "Markdown", "Pkg", "REPL", "SHA", "Serialization", "Sockets", "UUIDs"]
git-tree-sha1 = "d675e3a860523660421b1ca33543c06db2783a9b"
uuid = "cf896787-08d5-524d-9de7-132aaa0cb996"
version = "7.2.1"
[[deps.TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
version = "1.0.0"
[[deps.Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
version = "1.10.1"
[[deps.Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
[[deps.Tokenize]]
git-tree-sha1 = "2b3af135d85d7e70b863540160208fa612e736b9"
uuid = "0796e94c-ce3b-5d07-9a54-7f471281c624"
version = "0.5.24"
[[deps.UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[[deps.Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
[[deps.VersionParsing]]
git-tree-sha1 = "58d6e80b4ee071f5efd07fda82cb9fbe17200868"
uuid = "81def892-9a0e-5fdd-b105-ffc91e053289"
version = "1.3.0"
[[deps.ZMQ]]
deps = ["FileWatching", "Sockets", "ZeroMQ_jll"]
git-tree-sha1 = "356d2bdcc0bce90aabee1d1c0f6d6f301eda8f77"
uuid = "c2297ded-f4af-51ae-bb23-16f91089e4e1"
version = "1.2.2"
[[deps.ZeroMQ_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "libsodium_jll"]
git-tree-sha1 = "fe5c65a526f066fb3000da137d5785d9649a8a47"
uuid = "8f1865be-045e-5c20-9c9f-bfbfb0764568"
version = "4.3.4+0"
[[deps.ZipFile]]
deps = ["Libdl", "Printf", "Zlib_jll"]
git-tree-sha1 = "ef4f23ffde3ee95114b461dc667ea4e6906874b2"
uuid = "a5390f91-8eb1-5f08-bee0-b1d1ffed6cea"
version = "0.10.0"
[[deps.Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
version = "1.2.12+3"
[[deps.libblastrampoline_jll]]
deps = ["Artifacts", "Libdl", "OpenBLAS_jll"]
uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
version = "5.1.1+0"
[[deps.libsodium_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "848ab3d00fe39d6fbc2a8641048f8f272af1c51e"
uuid = "a9144af2-ca23-56d9-984f-0d03f7b5ccf8"
version = "1.0.20+0"
[[deps.nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
version = "1.48.0+0"
[[deps.p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
version = "17.4.0+0"

View file

@ -1,12 +0,0 @@
name = "JuliaCSiBORGTools"
uuid = "6ceada58-95f6-416f-bef9-d16b3bb7d5db"
authors = ["rstiskalek <richard.stiskalek@protonmail.com>"]
version = "0.1.0"
[deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
NPZ = "15e1cf62-19b3-5cfa-8e77-841668bca605"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
StaticLint = "b3cc710f-9c33-5bdb-a03d-a94903873e97"

View file

@ -1,22 +0,0 @@
# 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.
module JuliaCSiBORGTools
include("./particles_match.jl")
export halo_parts
end # module JuliaCSiBORGTools

View file

@ -1,29 +0,0 @@
# 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.
"""
halo_parts(clumpid::Int, partids::Vector{<:Int}, clumpids::Vector{<:Int})
Return particle IDs belonging to a given clump.
# Arguments
- `clumpid::Integer`: the ID of the clump.
- `partids::Vector{<:Integer}`: vector of shape `(n_particles,)` with the particle IDs.
- `clumpids::Vector{<:Integer}`: vector of shape `(n_particles, )` with the particles' clump IDs.
"""
function halo_parts(clumpid::Integer, partids::Vector{<:Integer}, clumpids::Vector{<:Integer})
return partids[clumpids .== clumpid]
end

View file

@ -20,8 +20,4 @@
## Open questions ## Open questions
- What scaling of the search region? No reason for it to be a multiple of $R_{200c}$. - What scaling of the search region? No reason for it to be a multiple of $R_{200c}$.
- Begin extracting the DM environmental properties at galaxy positions? - Begin extracting the DM environmental properties at galaxy positions?
## Notes
- New sims with part files in initial snapshot: `/mnt/extraspace/hdesmond/ramses_out_7468_new`. Also numbers 7588, 8020, 8452, 8836.

View file

@ -14,7 +14,7 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import numpy import numpy
from tqdm import tqdm from tqdm import (tqdm, trange)
from astropy.coordinates import SkyCoord from astropy.coordinates import SkyCoord
from ..read import CombinedHaloCatalogue from ..read import CombinedHaloCatalogue
@ -125,7 +125,7 @@ class RealisationsMatcher:
def cosine_similarity(self, x, y): def cosine_similarity(self, x, y):
r""" r"""
Calculate the cosine similarity between two Cartesian vectors. Defined Calculate the cosine similarity between two Cartesian vectors. Defined
as :math:`\Sum_{i} x_i y_{i} / (|x| |y|)`. as :math:`\Sum_{i} x_i y_{i} / (|x| * |y|)`.
Parameters Parameters
---------- ----------
@ -152,8 +152,8 @@ class RealisationsMatcher:
return out[0] return out[0]
return out return out
def cross_knn_position_single(self, n_sim, nmult=5, dlogmass=2, def cross_knn_position_single(self, n_sim, nmult=5, dlogmass=None,
verbose=True): init_dist=False, verbose=True):
r""" r"""
Find all neighbours within :math:`n_{\rm mult} R_{200c}` of halos in Find all neighbours within :math:`n_{\rm mult} R_{200c}` of halos in
the `nsim`th simulation. Also enforces that the neighbours' the `nsim`th simulation. Also enforces that the neighbours'
@ -168,21 +168,28 @@ class RealisationsMatcher:
Multiple of :math:`R_{200c}` within which to return neighbours. By Multiple of :math:`R_{200c}` within which to return neighbours. By
default 5. default 5.
dlogmass : float, optional dlogmass : float, optional
Tolerance on mass logarithmic mass difference. By default 2 dex. Tolerance on mass logarithmic mass difference. By default `None`.
init_dist : bool, optional
Whether to calculate separation of the initial CMs. By default
`False`.
verbose : bool, optional
Iterator verbosity flag. By default `True`.
Returns Returns
------- -------
matches : composite array matches : composite array
Array, indices are `(n_sims - 1, 2, n_halos, n_matches)`. The Array, indices are `(n_sims - 1, 3, n_halos, n_matches)`. The
2nd axis is `index` of the neighbouring halo in its catalogue and 2nd axis is `index` of the neighbouring halo in its catalogue,
`dist`, which is the 3D distance to the halo whose neighbours are `dist`, which is the 3D distance to the halo whose neighbours are
searched. searched, and `dist0` which is the separation of the initial CMs.
The latter is calculated only if `init_dist` is `True`.
""" """
# R200c, M200c and positions of halos in `n_sim` IC realisation # Radius, M200c and positions of halos in `n_sim` IC realisation
r200 = self.cats[n_sim]["r200"]
logm200 = numpy.log10(self.cats[n_sim]["m200"]) logm200 = numpy.log10(self.cats[n_sim]["m200"])
R = self.cats[n_sim]["r200"]
pos = self.cats[n_sim].positions pos = self.cats[n_sim].positions
if init_dist:
pos0 = self.cats[n_sim].positions0 # These are CM positions
matches = [None] * (self.cats.N - 1) matches = [None] * (self.cats.N - 1)
# Verbose iterator # Verbose iterator
if verbose: if verbose:
@ -191,19 +198,30 @@ class RealisationsMatcher:
iters = enumerate(self.search_sim_indices(n_sim)) iters = enumerate(self.search_sim_indices(n_sim))
# Search for neighbours in the other simulations # Search for neighbours in the other simulations
for count, i in iters: for count, i in iters:
dist, indxs = self.cats[i].radius_neigbours(pos, r200 * nmult) dist, indxs = self.cats[i].radius_neigbours(pos, R * nmult)
# Get rid of neighbors whose mass is too off # Get rid of neighbors whose mass is too off
for j, indx in enumerate(indxs): if dlogmass is not None:
match_logm200 = numpy.log10(self.cats[i][indx]["m200"]) for j, indx in enumerate(indxs):
mask = numpy.abs(match_logm200 - logm200[j]) < dlogmass match_logm200 = numpy.log10(self.cats[i]["m200"][indx])
dist[j] = dist[j][mask] mask = numpy.abs(match_logm200 - logm200[j]) < dlogmass
indxs[j] = indx[mask] dist[j] = dist[j][mask]
indxs[j] = indx[mask]
# Find distance to the between the initial CM
dist0 = [numpy.asanyarray([], dtype=numpy.float64)] * dist.size
if init_dist:
with_neigbours = numpy.where([ii.size > 0 for ii in indxs])[0]
# Fill the pre-allocated array on positions with neighbours
for k in with_neigbours:
dist0[k] = numpy.linalg.norm(
pos0[k] - self.cats[i].positions0[indxs[k]], axis=1)
# Append as a composite array # Append as a composite array
matches[count] = numpy.asarray([indxs, dist], dtype=object) matches[count] = numpy.asarray([indxs, dist, dist0], dtype=object)
return numpy.asarray(matches, dtype=object) return numpy.asarray(matches, dtype=object)
def cross_knn_position_all(self, nmult=5, dlogmass=2): def cross_knn_position_all(self, nmult=5, dlogmass=None,
init_dist=False, verbose=True):
r""" r"""
Find all neighbours within :math:`n_{\rm mult} R_{200c}` of halos in Find all neighbours within :math:`n_{\rm mult} R_{200c}` of halos in
all simulations listed in `self.cats`. Also enforces that the all simulations listed in `self.cats`. Also enforces that the
@ -215,7 +233,12 @@ class RealisationsMatcher:
Multiple of :math:`R_{200c}` within which to return neighbours. By Multiple of :math:`R_{200c}` within which to return neighbours. By
default 5. default 5.
dlogmass : float, optional dlogmass : float, optional
Tolerance on mass logarithmic mass difference. By default 2 dex. Tolerance on mass logarithmic mass difference. By default `None`.
init_dist : bool, optional
Whether to calculate separation of the initial CMs. By default
`False`.
verbose : bool, optional
Iterator verbosity flag. By default `True`.
Returns Returns
------- -------
@ -226,6 +249,7 @@ class RealisationsMatcher:
N = self.cats.N # Number of catalogues N = self.cats.N # Number of catalogues
matches = [None] * N matches = [None] * N
# Loop over each catalogue # Loop over each catalogue
for i in range(N): for i in trange(N) if verbose else range(N):
matches[i] = self.cross_knn_position_single(i, nmult, dlogmass) matches[i] = self.cross_knn_position_single(
i, nmult, dlogmass, init_dist)
return matches return matches

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, get_positions) # noqa from .readsim import (CSiBORGPaths, ParticleReader, read_mmain, read_initcm, get_positions) # 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

@ -15,13 +15,12 @@
""" """
Functions to read in the particle and clump files. Functions to read in the particle and clump files.
""" """
import numpy import numpy
from os.path import join from os.path import join
from tqdm import trange from tqdm import trange
from copy import deepcopy from copy import deepcopy
from sklearn.neighbors import NearestNeighbors from sklearn.neighbors import NearestNeighbors
from .readsim import read_mmain from .readsim import (read_mmain, read_initcm)
from ..utils import (flip_cols, add_columns) from ..utils import (flip_cols, add_columns)
from ..units import (BoxUnits, cartesian_to_radec) from ..units import (BoxUnits, cartesian_to_radec)
@ -45,6 +44,7 @@ class HaloCatalogue:
_data = None _data = None
_knn = None _knn = None
_positions = None _positions = None
_positions0 = None
def __init__(self, paths, min_m500=None, max_dist=None): def __init__(self, paths, min_m500=None, max_dist=None):
self._box = BoxUnits(paths) self._box = BoxUnits(paths)
@ -117,7 +117,7 @@ class HaloCatalogue:
@property @property
def n_sim(self): def n_sim(self):
""" """
The initiali condition (IC) realisation ID. The initial condition (IC) realisation ID.
Returns Returns
------- -------
@ -142,6 +142,12 @@ class HaloCatalogue:
# Cut on number of particles and finite m200 # Cut on number of particles and finite m200
data = data[(data["npart"] > 100) & numpy.isfinite(data["m200"])] data = data[(data["npart"] > 100) & numpy.isfinite(data["m200"])]
# Now also load the initial positions
initcm = read_initcm(self.n_sim, self.paths.initmatch_path)
if initcm is not None:
data = self.merge_initmatch_to_clumps(data, initcm)
flip_cols(data, "x0", "z0")
# Calculate redshift # Calculate redshift
pos = [data["peak_{}".format(p)] - 0.5 for p in ("x", "y", "z")] pos = [data["peak_{}".format(p)] - 0.5 for p in ("x", "y", "z")]
vel = [data["v{}".format(p)] for p in ("x", "y", "z")] vel = [data["v{}".format(p)] for p in ("x", "y", "z")]
@ -171,9 +177,14 @@ class HaloCatalogue:
# Cut on separation # Cut on separation
data = data[data["dist"] < max_dist] data = data[data["dist"] < max_dist]
# Pre-allocate the positions array # Pre-allocate the positions arrays
self._positions = numpy.vstack( self._positions = numpy.vstack(
[data["peak_{}".format(p)] for p in ("x", "y", "z")]).T [data["peak_{}".format(p)] for p in ("x", "y", "z")]).T
# And do the unit transform
if initcm is not None:
data = self.box.convert_from_boxunits(data, ["x0", "y0", "z0"])
self._positions0 = numpy.vstack(
[data["{}0".format(p)] for p in ("x", "y", "z")]).T
self._data = data self._data = data
@ -203,10 +214,39 @@ class HaloCatalogue:
X[mask, 1] = mmain["sub_frac"] X[mask, 1] = mmain["sub_frac"]
return add_columns(clumps, X, ["mass_mmain", "sub_frac"]) return add_columns(clumps, X, ["mass_mmain", "sub_frac"])
def merge_initmatch_to_clumps(self, clumps, initcat):
"""
Merge columns from the `init_cm` files to the `clump` file.
Parameters
----------
clumps : structured array
Clumps structured array.
initcat : structured array
Catalog with the clumps initial centre of mass at z = 70.
Returns
-------
out : structured array
"""
# There are more initcat clumps, so check which ones have z = 0
# and then downsample
mask = numpy.isin(initcat["ID"], clumps["index"])
initcat = initcat[mask]
# Now the index ordering should match
if not numpy.alltrue(initcat["ID"] == clumps["index"]):
raise ValueError(
"Ordering of `initcat` and `clumps` is inconsistent.")
X = numpy.full((clumps.size, 3), numpy.nan)
for i, p in enumerate(['x', 'y', 'z']):
X[:, i] = initcat[p]
return add_columns(clumps, X, ["x0", "y0", "z0"])
@property @property
def positions(self): def positions(self):
""" """
3D positions of halos. 3D positions of halos in comoving units of Mpc.
Returns Returns
------- -------
@ -216,6 +256,21 @@ class HaloCatalogue:
""" """
return self._positions return self._positions
@property
def positions0(self):
r"""
3D positions of halos in the initial snapshot in comoving units of Mpc.
Returns
-------
X : 2-dimensional array
Array of shape `(n_halos, 3)`, where the latter axis represents
`x`, `y` and `z`.
"""
if self._positions0 is None:
raise RuntimeError("Initial positions are not set!")
return self._positions0
@property @property
def velocities(self): def velocities(self):
""" """
@ -240,6 +295,26 @@ class HaloCatalogue:
""" """
return numpy.vstack([self["L{}".format(p)] for p in ("x", "y", "z")]).T return numpy.vstack([self["L{}".format(p)] for p in ("x", "y", "z")]).T
@property
def init_radius(self):
r"""
A fiducial initial radius of particles that are identified as a single
halo in the final snapshot. Estimated to be
..math:
R = (3 N / 4 \pi)^{1 / 3} * \Delta
where :math:`N` is the number of particles and `Delta` is the initial
inter-particular distance :math:`Delta = 1 / 2^{11}` in box units. The
output fiducial radius is in comoving units of Mpc.
Returns
-------
R : float
"""
delta = self.box.box2mpc(1 / 2**11)
return (3 * self["npart"] / (4 * numpy.pi))**(1/3) * delta
def radius_neigbours(self, X, radius): def radius_neigbours(self, X, radius):
""" """
Return sorted nearest neigbours within `radius` or `X`. Return sorted nearest neigbours within `radius` or `X`.
@ -272,6 +347,9 @@ class HaloCatalogue:
return self.data.dtype.names return self.data.dtype.names
def __getitem__(self, key): def __getitem__(self, key):
initpars = ["x0", "y0", "z0"]
if key in initpars and key not in self.keys:
raise RuntimeError("Initial positions are not set!")
return self._data[key] return self._data[key]
@ -299,8 +377,9 @@ class CombinedHaloCatalogue:
def __init__(self, paths, min_m500=None, max_dist=None, verbose=True): def __init__(self, paths, min_m500=None, max_dist=None, verbose=True):
# Read simulations and their maximum snapshots # Read simulations and their maximum snapshots
# NOTE remove this later and take all cats # NOTE later change this back to all simulations
self._n_sims = paths.ic_ids[:10] self._n_sims = [7468, 7588, 8020, 8452, 8836]
# self._n_sims = paths.ic_ids
n_snaps = [paths.get_maximum_snapshot(i) for i in self._n_sims] n_snaps = [paths.get_maximum_snapshot(i) for i in self._n_sims]
self._n_snaps = numpy.asanyarray(n_snaps) self._n_snaps = numpy.asanyarray(n_snaps)

View file

@ -18,10 +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
from os import listdir 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 ..utils import (cols_to_structured, extract_from_structured) from ..utils import (cols_to_structured, extract_from_structured)
@ -56,22 +57,40 @@ class CSiBORGPaths:
mmain_path : str, optional mmain_path : str, optional
Path to where mmain files are stored. By default Path to where mmain files are stored. By default
`/mnt/zfsusers/hdesmond/Mmain`. `/mnt/zfsusers/hdesmond/Mmain`.
initmatch_path : str, optional
Path to where match between the first and final snapshot is stored. By
default `/mnt/extraspace/rstiskalek/csiborg/initmatch/`.
to_new : bool, optional
Whether the paths should point to `new` files, for example
`ramses_out_8452_new`.
""" """
_srcdir = None _srcdir = None
_n_sim = None _n_sim = None
_n_snap = None _n_snap = None
_dumpdir = None _dumpdir = None
_mmain_path = None _mmain_path = None
_initmatch_path = None
_to_new = None
def __init__(self, n_sim=None, n_snap=None, # NOTE deuglify this stuff
srcdir="/mnt/extraspace/hdesmond/", def __init__(self, n_sim=None, n_snap=None, srcdir=None, dumpdir=None,
dumpdir="/mnt/extraspace/rstiskalek/csiborg/", mmain_path=None, initmatch_path=None, to_new=False):
mmain_path="/mnt/zfsusers/hdesmond/Mmain"): if srcdir is None:
srcdir = "/mnt/extraspace/hdesmond/"
self.srcdir = srcdir self.srcdir = srcdir
if dumpdir is None:
dumpdir = "/mnt/extraspace/rstiskalek/csiborg/"
self.dumpdir = dumpdir self.dumpdir = dumpdir
if mmain_path is None:
mmain_path = "/mnt/zfsusers/hdesmond/Mmain"
self.mmain_path = mmain_path self.mmain_path = mmain_path
if initmatch_path is None:
initmatch_path = "/mnt/extraspace/rstiskalek/csiborg/initmatch/"
self.initmatch_path = initmatch_path
self.to_new = to_new
if n_sim is not None and n_snap is not None: if n_sim is not None and n_snap is not None:
self.set_info(n_sim, n_snap) self.set_info(n_sim, n_snap)
# "/mnt/extraspace/rstiskalek/csiborg/initmatch/clump_cm_7468.npy"
@property @property
def srcdir(self): def srcdir(self):
@ -147,6 +166,45 @@ class CSiBORGPaths:
raise IOError("Invalid directory `{}`!".format(mmain_path)) raise IOError("Invalid directory `{}`!".format(mmain_path))
self._mmain_path = mmain_path self._mmain_path = mmain_path
@property
def initmatch_path(self):
"""
Path to where match between the first and final snapshot is stored.
Returns
-------
initmach_path : str
"""
return self._initmatch_path
@initmatch_path.setter
def initmatch_path(self, initmatch_path):
"""
Set `initmatch_path`, check that the directory exists.
"""
if not isdir(initmatch_path):
raise IOError("Invalid directory `{}`!".format(initmatch_path))
self._initmatch_path = initmatch_path
@property
def to_new(self):
"""
Flag whether paths should point to `new` files, for example
`ramses_out_8452_new`.
Returns
-------
to_new : bool
"""
return self._to_new
@to_new.setter
def to_new(self, to_new):
"""Set `to_new`."""
if not isinstance(to_new, bool):
raise TypeError("`to_new` must be be a bool")
self._to_new = to_new
@property @property
def n_sim(self): def n_sim(self):
""" """
@ -236,14 +294,26 @@ class CSiBORGPaths:
def ic_ids(self): def ic_ids(self):
""" """
CSiBORG initial condition (IC) simulation IDs from the list of folders CSiBORG initial condition (IC) simulation IDs from the list of folders
in `self.srcdir`. Assumes that the folders look like `ramses_out_X` in `self.srcdir`.
and extracts the `X` integer. Removes `5511` from the list of IDs.
Returns Returns
------- -------
ids : 1-dimensional array ids : 1-dimensional array
Array of CSiBORG simulation IDs. Array of CSiBORG simulation IDs.
""" """
if self.to_new:
return self._ic_ids_new
return self._ic_ids
@property
def _ic_ids(self):
"""
IC simulation IDs.
Returns
-------
ids : 1-dimensional array
"""
files = glob(join(self.srcdir, "ramses_out*")) files = glob(join(self.srcdir, "ramses_out*"))
# Select only file names # Select only file names
files = [f.split("/")[-1] for f in files] files = [f.split("/")[-1] for f in files]
@ -260,6 +330,25 @@ class CSiBORGPaths:
pass pass
return numpy.sort(ids) return numpy.sort(ids)
@property
def _ic_ids_new(self):
"""
ICs simulation IDs denoted as `new` with recoved :math:`z = 70`
particle information.
Returns
-------
ids : 1-dimensional array
"""
files = glob(join(self.srcdir, "ramses_out*"))
# Select only file names
files = [f.split("/")[-1] for f in files]
# Only _new files
files = [f for f in files if "_new" in f]
# Take the ICs
ids = [int(f.split("_")[2]) for f in files]
return numpy.sort(ids)
def ic_path(self, n_sim=None): def ic_path(self, n_sim=None):
""" """
Path to `n_sim`th CSiBORG IC realisation. Path to `n_sim`th CSiBORG IC realisation.
@ -276,6 +365,8 @@ class CSiBORGPaths:
""" """
n_sim = self.get_n_sim(n_sim) n_sim = self.get_n_sim(n_sim)
fname = "ramses_out_{}" fname = "ramses_out_{}"
if self.to_new:
fname += "_new"
return join(self.srcdir, fname.format(n_sim)) return join(self.srcdir, fname.format(n_sim))
def get_snapshots(self, n_sim=None): def get_snapshots(self, n_sim=None):
@ -291,7 +382,6 @@ class CSiBORGPaths:
Returns Returns
------- -------
snapshots : 1-dimensional array snapshots : 1-dimensional array
Array of snapshot IDs.
""" """
n_sim = self.get_n_sim(n_sim) n_sim = self.get_n_sim(n_sim)
simpath = self.ic_path(n_sim) simpath = self.ic_path(n_sim)
@ -314,7 +404,6 @@ class CSiBORGPaths:
Returns Returns
------- -------
maxsnap : float maxsnap : float
Maximum snapshot.
""" """
n_sim = self.get_n_sim(n_sim) n_sim = self.get_n_sim(n_sim)
return max(self.get_snapshots(n_sim)) return max(self.get_snapshots(n_sim))
@ -332,7 +421,6 @@ class CSiBORGPaths:
Returns Returns
------- -------
minsnap : float minsnap : float
Minimum snapshot.
""" """
n_sim = self.get_n_sim(n_sim) n_sim = self.get_n_sim(n_sim)
return min(self.get_snapshots(n_sim)) return min(self.get_snapshots(n_sim))
@ -353,7 +441,6 @@ class CSiBORGPaths:
Returns Returns
------- -------
snappath : str snappath : str
Path to the CSiBORG IC realisation snapshot.
""" """
n_snap = self.get_n_snap(n_snap) n_snap = self.get_n_snap(n_snap)
n_sim = self.get_n_sim(n_sim) n_sim = self.get_n_sim(n_sim)
@ -455,15 +542,6 @@ class ParticleReader:
print("Reading in output `{}` with ncpu = `{}`." print("Reading in output `{}` with ncpu = `{}`."
.format(nout, ncpu)) .format(nout, ncpu))
# Check whether the unbinding file exists.
snapdirlist = listdir(snappath)
unbinding_file = "unbinding_{}.out00001".format(nout)
if unbinding_file not in snapdirlist:
raise FileNotFoundError(
"Couldn't find `{}` in `{}`. Use mergertreeplot.py -h or "
"--help to print help message."
.format(unbinding_file, snappath))
# First read the headers. Reallocate arrays and fill them. # First read the headers. Reallocate arrays and fill them.
nparts = numpy.zeros(ncpu, dtype=int) nparts = numpy.zeros(ncpu, dtype=int)
partfiles = [None] * ncpu partfiles = [None] * ncpu
@ -761,25 +839,46 @@ def read_mmain(n, srcdir, fname="Mmain_{}.npy"):
return out return out
def get_positions(n_sim, n_snap, get_clumpid, verbose=True, def read_initcm(n, srcdir, fname="clump_cm_{}.npy"):
srcdir="/mnt/extraspace/hdesmond/"): """
Read `clump_cm`, i.e. the center of mass of a clump at redshift z = 70.
If the file does not exist returns `None`.
Parameters
----------
n : int
The index of the initial conditions (IC) realisation.
srcdir : str
The path to the folder containing the files.
fname : str, optional
The file name convention. By default `clump_cm_{}.npy`, where the
substituted value is `n`.
Returns
-------
out : structured array
"""
fpath = join(srcdir, fname.format(n))
try:
return numpy.load(fpath)
except FileNotFoundError:
warn("File {} does not exist.".format(fpath))
return None
def get_positions(paths, get_clumpid, verbose=True):
""" """
Shortcut to get particle IDs, positions, masses and optionally clump Shortcut to get particle IDs, positions, masses and optionally clump
indices. indices.
Parameters Parameters
---------- ----------
n_sim : int paths : py:class`csiborgtools.read.CSiBORGPaths`
CSiBORG IC realisation index. CSiBORG paths-handling object with set `n_sim` and `n_snap`.
n_snap : int
Snapshot index.
get_clumpid : bool get_clumpid : bool
Whether to also return the clump indices. Whether to also return the clump indices.
verbose : bool, optional verbose : bool, optional
Verbosity flag. By default `True`. Verbosity flag. By default `True`.
srcdir : str, optional
The file path to the folder where realisations of the ICs are stored.
By default `/mnt/extraspace/hdesmond/`.
Returns Returns
------- -------
@ -793,9 +892,6 @@ def get_positions(n_sim, n_snap, get_clumpid, verbose=True,
Particles' clump IDs of shape `(n_particles, )`. Returned only if Particles' clump IDs of shape `(n_particles, )`. Returned only if
`get_clumpid` is `True`. `get_clumpid` is `True`.
""" """
# Setup the paths
paths = CSiBORGPaths(srcdir)
paths.set_info(n_sim, n_snap)
# Extract particles # Extract particles
reader = ParticleReader(paths) reader = ParticleReader(paths)
pars_extract = ["ID", "x", "y", "z", "M"] pars_extract = ["ID", "x", "y", "z", "M"]
@ -805,8 +901,10 @@ def get_positions(n_sim, n_snap, get_clumpid, verbose=True,
pids = extract_from_structured(particles, "ID") pids = extract_from_structured(particles, "ID")
ppos = extract_from_structured(particles, ["x", "y", "z"]) ppos = extract_from_structured(particles, ["x", "y", "z"])
pmass = extract_from_structured(particles, "M") pmass = extract_from_structured(particles, "M")
# Force early memory release # Force early memory release
del particles del particles
gc.collect()
out = (pids, ppos, pmass) out = (pids, ppos, pmass)

View file

@ -26,7 +26,7 @@ from ..read import ParticleReader
# Map of unit conversions # Map of unit conversions
CONV_NAME = { CONV_NAME = {
"length": ["peak_x", "peak_y", "peak_z", "Rs", "rmin", "rmax", "r200", "length": ["peak_x", "peak_y", "peak_z", "Rs", "rmin", "rmax", "r200",
"r500"], "r500", "x0", "y0", "z0"],
"mass": ["mass_cl", "totpartmass", "m200", "m500", "mass_mmain"], "mass": ["mass_cl", "totpartmass", "m200", "m500", "mass_mmain"],
"density": ["rho0"] "density": ["rho0"]
} }
@ -414,7 +414,7 @@ class BoxUnits:
"Conversion of `{}` is not defined.".format(name)) "Conversion of `{}` is not defined.".format(name))
# Center at the observer # Center at the observer
if name in ["peak_x", "peak_y", "peak_z"]: if name in ["peak_x", "peak_y", "peak_z", "x0", "y0", "z0"]:
data[name] -= transforms["length"](0.5) data[name] -= transforms["length"](0.5)
return data return data

View file

@ -1,49 +0,0 @@
# 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.
using Pkg: activate, build
activate("../JuliaCSiBORGTools/")
using JuliaCSiBORGTools
using NPZ: npzread
using PyCall: pyimport
csiborgtools = pyimport("csiborgtools")
verbose = true
paths = csiborgtools.read.CSiBORGPaths()
nsims = paths.ic_ids[:1]
for nsim in nsims
nsnap_min = convert(Int64, paths.get_minimum_snapshot(nsim))
nsnap_max = convert(Int64, paths.get_maximum_snapshot(nsim))
# Get the maximum snapshot properties
verbose ? println("Loading snapshot $nsnap_max from simulation $nsim") : nothing
pids, ppos, pmass, clumpids = csiborgtools.read.get_positions(nsim, nsnap_max, get_clumpid=true, verbose=false)
println("Sizes are: ")
println(size(pids))
println(size(ppos))
println(size(pmass))
# # Get the minimum snapshot properties
# verbose ? println("Loading snapshot $nsnap_min from simulation $nsim") : nothing
# pids, ppos, pmass = csiborgtools.read.get_positions(nsim, nsnap_max, get_clumpid=false, verbose=false)
JuliaCSiBORGTools.halo_parts(0, partids, clumpids)
end

143
scripts/run_initmatch.py Normal file
View file

@ -0,0 +1,143 @@
# 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.
"""
A script to calculate the centre of mass of particles at redshift 70 that
are grouped in a clump at present redshift.
Optionally also dumps the clumps information, however watch out as this will
eat up a lot of memory.
"""
from argparse import ArgumentParser
import numpy
from datetime import datetime
from mpi4py import MPI
from distutils.util import strtobool
from os.path import join, isdir
from os import mkdir
from os import remove
from sys import stdout
from gc import collect
try:
import csiborgtools
except ModuleNotFoundError:
import sys
sys.path.append("../")
import csiborgtools
parser = ArgumentParser()
parser.add_argument("--dump_clumps", default=False,
type=lambda x: bool(strtobool(x)))
args = parser.parse_args()
# Get MPI things
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
nproc = comm.Get_size()
init_paths = csiborgtools.read.CSiBORGPaths(to_new=True)
fin_paths = csiborgtools.read.CSiBORGPaths(to_new=False)
nsims = init_paths.ic_ids
# Output files
dumpdir = "/mnt/extraspace/rstiskalek/csiborg/initmatch"
ftemp = join(dumpdir, "temp", "temp_{}_{}.npy")
fperm = join(dumpdir, "clump_cm_{}.npy")
for nsim in nsims:
if rank == 0:
print("{}: reading simulation {}.".format(datetime.now(), nsim))
stdout.flush()
# Check that the output folder for this sim exists
clumpdumpdir = join(dumpdir, "out_{}".format(nsim))
if args.dump_clumps and rank == 0 and not isdir(clumpdumpdir):
mkdir(clumpdumpdir)
# Barrier to make sure we created the directory with the rank 0
comm.Barrier()
# Set the snapshot numbers
init_paths.set_info(nsim, init_paths.get_minimum_snapshot(nsim))
fin_paths.set_info(nsim, fin_paths.get_maximum_snapshot(nsim))
# Set the readers
init_reader = csiborgtools.read.ParticleReader(init_paths)
fin_reader = csiborgtools.read.ParticleReader(fin_paths)
# Read and sort the initial particle files by their particle IDs
part0 = init_reader.read_particle(["x", "y", "z", "M", "ID"],
verbose=False)
part0 = part0[numpy.argsort(part0["ID"])]
# Order the final snapshot clump IDs by the particle IDs
pid = fin_reader.read_particle(["ID"], verbose=False)["ID"]
clump_ids = fin_reader.read_clumpid(verbose=False)
clump_ids = clump_ids[numpy.argsort(pid)]
del pid
collect()
# Get rid of the clumps whose index is 0 -- those are unassigned
mask = clump_ids > 0
clump_ids = clump_ids[mask]
part0 = part0[mask]
del mask
collect()
if rank == 0:
print("{}: dumping clumps for simulation.".format(datetime.now()))
stdout.flush()
# Grab unique clump IDs and loop over them
unique_clumpids = numpy.unique(clump_ids)
njobs = unique_clumpids.size
jobs = csiborgtools.fits.split_jobs(njobs, nproc)[rank]
for i in jobs:
n = unique_clumpids[i]
x0 = part0[clump_ids == n]
# Center of mass
cm = numpy.asanyarray(
[numpy.average(x0[p], weights=x0["M"]) for p in ('x', 'y', 'z')])
# Dump the center of mass
with open(ftemp.format(nsim, n), 'wb') as f:
numpy.save(f, cm)
# Optionally dump the entire clump
if args.dump_clumps:
fout = join(clumpdumpdir, "clump_{}.npy".format(n))
stdout.flush()
with open(fout, "wb") as f:
numpy.save(f, x0)
comm.Barrier()
if rank == 0:
print("Collecting CM files...")
stdout.flush()
# Collect the centre of masses and dump them
dtype = {"names": ['x', 'y', 'z', "ID"],
"formats": [numpy.float32] * 3 + [numpy.int32]}
out = numpy.full(njobs, numpy.nan, dtype=dtype)
for i, n in enumerate(unique_clumpids):
with open(ftemp.format(nsim, n), 'rb') as f:
fin = numpy.load(f)
out['x'][i] = fin[0]
out['y'][i] = fin[1]
out['z'][i] = fin[2]
out["ID"][i] = n
remove(ftemp.format(nsim, n))
print("Dumping CM files to .. `{}`.".format(fperm.format(nsim)))
with open(fperm.format(nsim), 'wb') as f:
numpy.save(f, out)