subhaloscript 1.0.3__tar.gz → 1.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/PKG-INFO +3 -2
  2. subhaloscript-1.0.5/README.md +11 -0
  3. subhaloscript-1.0.5/example-notebooks/basic-usage.ipynb +339 -0
  4. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/meta.yaml +1 -1
  5. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/pyproject.toml +1 -1
  6. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/subscript/scripts/nfilters.py +1 -1
  7. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/subscript/wrappers.py +5 -4
  8. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/tests/test_wrappers.py +36 -4
  9. subhaloscript-1.0.3/README.md +0 -10
  10. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/.github/workflows/main.yml +0 -0
  11. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/.gitignore +0 -0
  12. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/LICENSE +0 -0
  13. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/subscript/defaults.py +0 -0
  14. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/subscript/macros.py +0 -0
  15. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/subscript/scripts/histograms.py +0 -0
  16. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/subscript/scripts/nodes.py +0 -0
  17. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/subscript/scripts/spatial.py +0 -0
  18. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/subscript/tabulatehdf5.py +0 -0
  19. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/subscript/util.py +0 -0
  20. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/tests/test_histograms.py +0 -0
  21. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/tests/test_macros.py +0 -0
  22. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/tests/test_nfilters.py +0 -0
  23. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/tests/test_nfilters_legacy.py +0 -0
  24. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/tests/test_nodes.py +0 -0
  25. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/tests/test_spatial.py +0 -0
  26. {subhaloscript-1.0.3 → subhaloscript-1.0.5}/tests/test_tabulatehdf5.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: subhaloscript
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: Utility functions for analyzing subhalo distributions.
5
5
  Author-email: Charles Gannon <cgannon@ucmerced.edu>
6
6
  License-File: LICENSE
@@ -15,7 +15,7 @@ Requires-Dist: scipy
15
15
  Description-Content-Type: text/markdown
16
16
 
17
17
  # SubScript
18
- Utility functions for analyzing subhalo distributions, focusing on the Galacticus (https://github.com/galacticusorg/galacticus) output format. The goal of this package is to facilitate quick statistical analysis of subhalo distributions across multiple trees.
18
+ The ```subscript``` python package provides a library of ergonomic utility functions for analyzing Galacticus (https://github.com/galacticusorg/galacticus) subhalo data.
19
19
 
20
20
  ## Installation
21
21
 
@@ -24,3 +24,4 @@ Utility functions for analyzing subhalo distributions, focusing on the Galacticu
24
24
 
25
25
  ### Install via conda
26
26
  ```conda install cgannonucm::subhaloscript```
27
+
@@ -0,0 +1,11 @@
1
+ # SubScript
2
+ The ```subscript``` python package provides a library of ergonomic utility functions for analyzing Galacticus (https://github.com/galacticusorg/galacticus) subhalo data.
3
+
4
+ ## Installation
5
+
6
+ ### Install via pip
7
+ ```pip install subhaloscript```
8
+
9
+ ### Install via conda
10
+ ```conda install cgannonucm::subhaloscript```
11
+
@@ -0,0 +1,339 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "410260d7",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Example Notebook\n",
9
+ "Author: Charles Gannon\n",
10
+ "\n",
11
+ "Contact: cgannon@ucmerced.edu\n",
12
+ "\n",
13
+ "## Introduction\n",
14
+ "The ```subscript``` python package provides a library of ergonomic utility functions for analyzing Galacticus (https://github.com/galacticusorg/galacticus) subhalo data. This notebook provides an introduction to the functionality provided in this package. More examples are provided in the test folder. \n",
15
+ "\n",
16
+ "# Installation \n",
17
+ "\n",
18
+ "### Install via pip\n",
19
+ "```pip install subhaloscript```\n",
20
+ "\n",
21
+ "### Install via conda\n",
22
+ "```conda install cgannonucm::subhaloscript```"
23
+ ]
24
+ },
25
+ {
26
+ "cell_type": "markdown",
27
+ "id": "cd324615",
28
+ "metadata": {},
29
+ "source": [
30
+ "## Data From File\n",
31
+ "```subscript``` integrates with h5py"
32
+ ]
33
+ },
34
+ {
35
+ "cell_type": "code",
36
+ "execution_count": 1,
37
+ "id": "2caf02a4",
38
+ "metadata": {},
39
+ "outputs": [],
40
+ "source": [
41
+ "import h5py\n",
42
+ "gout = h5py.File('data/test.hdf5')"
43
+ ]
44
+ },
45
+ {
46
+ "cell_type": "markdown",
47
+ "id": "57c0468a",
48
+ "metadata": {},
49
+ "source": [
50
+ "## Node Data\n",
51
+ "In Galacticus each subhalo is represented as a node on the primary halo's merger tree. To access properties of each node, use the ```nodedata``` function. Galacticus can contain multiple trees in a single output file, subscript automatically seperates the output nodes into their respective trees."
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "code",
56
+ "execution_count": 2,
57
+ "id": "fd9fdbe4",
58
+ "metadata": {},
59
+ "outputs": [
60
+ {
61
+ "name": "stdout",
62
+ "output_type": "stream",
63
+ "text": [
64
+ "[7.21810428e+09 1.49945391e+09 3.45035586e+09 3.10940712e+09\n",
65
+ " 2.28942716e+10]\n",
66
+ "[2.51769675e+09 6.33693813e+09 1.88133845e+09 1.02403051e+09\n",
67
+ " 1.48554503e+09]\n"
68
+ ]
69
+ }
70
+ ],
71
+ "source": [
72
+ "from subscript.scripts.nodes import nodedata\n",
73
+ "\n",
74
+ "mass = nodedata(gout, key='basicMass')\n",
75
+ "\n",
76
+ "# The infall mass of the first 5 subhalos in the 1st galacticus output tree\n",
77
+ "print(mass[0][:5])\n",
78
+ "\n",
79
+ "# The infall mass of the first 5 subhalos in the 2nd galacticus output tree\n",
80
+ "print(mass[1][:5])"
81
+ ]
82
+ },
83
+ {
84
+ "cell_type": "markdown",
85
+ "id": "018f16ee",
86
+ "metadata": {},
87
+ "source": [
88
+ "Multiple keys can be passed at once"
89
+ ]
90
+ },
91
+ {
92
+ "cell_type": "code",
93
+ "execution_count": 3,
94
+ "id": "e53ac8e2",
95
+ "metadata": {},
96
+ "outputs": [
97
+ {
98
+ "name": "stdout",
99
+ "output_type": "stream",
100
+ "text": [
101
+ "0.5666598142807098\n"
102
+ ]
103
+ }
104
+ ],
105
+ "source": [
106
+ "import numpy as np\n",
107
+ "mass_basic, mass_bound = nodedata(gout, key=['basicMass', 'massBound'])[0]\n",
108
+ "mass_ratio = np.mean(mass_bound/mass_basic)\n",
109
+ "\n",
110
+ "# The average mass at infall to bound masss for the first tree\n",
111
+ "print(mass_ratio)"
112
+ ]
113
+ },
114
+ {
115
+ "cell_type": "markdown",
116
+ "id": "06d4750c",
117
+ "metadata": {},
118
+ "source": [
119
+ "Count number of nodes"
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "code",
124
+ "execution_count": 4,
125
+ "id": "5812266f",
126
+ "metadata": {},
127
+ "outputs": [
128
+ {
129
+ "name": "stdout",
130
+ "output_type": "stream",
131
+ "text": [
132
+ "246.05357142857142\n"
133
+ ]
134
+ }
135
+ ],
136
+ "source": [
137
+ "from subscript.scripts.nodes import nodecount\n",
138
+ "\n",
139
+ "# Average number of nodes per tree\n",
140
+ "print(np.mean(nodecount(gout)))"
141
+ ]
142
+ },
143
+ {
144
+ "cell_type": "markdown",
145
+ "id": "7279057e",
146
+ "metadata": {},
147
+ "source": [
148
+ "## Filters\n",
149
+ "```subscript``` supports filtering nodes by passing a ```nfilter``` function or numpy array of booleans."
150
+ ]
151
+ },
152
+ {
153
+ "cell_type": "code",
154
+ "execution_count": 5,
155
+ "id": "f88029f9",
156
+ "metadata": {},
157
+ "outputs": [
158
+ {
159
+ "name": "stdout",
160
+ "output_type": "stream",
161
+ "text": [
162
+ "13.0\n"
163
+ ]
164
+ }
165
+ ],
166
+ "source": [
167
+ "# Get the average host halo mass\n",
168
+ "import subscript.scripts.nfilters as nf\n",
169
+ "# Only include host halo nodes\n",
170
+ "host_halo_mass = nodedata(gout, key='basicMass', nfilter=nf.hosthalos)\n",
171
+ "\n",
172
+ "# Log 10 of average host halo mass\n",
173
+ "print(np.log10(np.mean(host_halo_mass)))"
174
+ ]
175
+ },
176
+ {
177
+ "cell_type": "markdown",
178
+ "id": "44f816e1",
179
+ "metadata": {},
180
+ "source": [
181
+ "### Combining filters"
182
+ ]
183
+ },
184
+ {
185
+ "cell_type": "markdown",
186
+ "id": "caa435ed",
187
+ "metadata": {},
188
+ "source": [
189
+ "Filters can be combined or modified using boolean logic. We can use the ```logical_and``` or ```logical_not``` function to combine two filters or the ```logical_not``` function to invert the filter."
190
+ ]
191
+ },
192
+ {
193
+ "cell_type": "code",
194
+ "execution_count": 6,
195
+ "id": "1368ab7d",
196
+ "metadata": {},
197
+ "outputs": [
198
+ {
199
+ "name": "stdout",
200
+ "output_type": "stream",
201
+ "text": [
202
+ "0.04988945595354875\n"
203
+ ]
204
+ }
205
+ ],
206
+ "source": [
207
+ "from subscript.scripts.spatial import project3d\n",
208
+ "# Only get subhalos within 50 kpc of the host \n",
209
+ "# Note ```subscript``` uses default units of galacticus which is MPC\n",
210
+ "filter_combined = nf.logical_and(\n",
211
+ " nf.subhalos,\n",
212
+ " nf.r3d(None, 0, 5E-2) # Passing 'None' as a first argument 'freezes' the filter, saving the key word arguments\n",
213
+ " )\n",
214
+ "\n",
215
+ "# Now we have no subhalos outside of 0.05 MPC from the center of the host\n",
216
+ "print(np.max(project3d(gout, nfilter=filter_combined)[0])) "
217
+ ]
218
+ },
219
+ {
220
+ "cell_type": "markdown",
221
+ "id": "00dce686",
222
+ "metadata": {},
223
+ "source": [
224
+ "## Statistical Analysis\n",
225
+ "\n",
226
+ "Perform statistical analysis over multiple trees by passing the argument ```summarize=true``` and optionally pass a list of functions, for statistical analysis passing the ```statfuncs``` argument. The default option is ```statfuncs=[np.mean]```, but if the standard deviation is required, you can pass ```statfuncts=[np.mean, np.std]```"
227
+ ]
228
+ },
229
+ {
230
+ "cell_type": "code",
231
+ "execution_count": 7,
232
+ "id": "72a2eb62",
233
+ "metadata": {},
234
+ "outputs": [
235
+ {
236
+ "data": {
237
+ "text/plain": [
238
+ "[]"
239
+ ]
240
+ },
241
+ "execution_count": 7,
242
+ "metadata": {},
243
+ "output_type": "execute_result"
244
+ },
245
+ {
246
+ "data": {
247
+ "image/png": "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",
248
+ "text/plain": [
249
+ "<Figure size 640x480 with 1 Axes>"
250
+ ]
251
+ },
252
+ "metadata": {},
253
+ "output_type": "display_data"
254
+ }
255
+ ],
256
+ "source": [
257
+ "# Subhalo massfunction\n",
258
+ "from subscript.scripts.histograms import massfunction\n",
259
+ "# Provides galacticus default parameter keys\n",
260
+ "from subscript.defaults import ParamKeys\n",
261
+ "import matplotlib.pyplot as plt\n",
262
+ "\n",
263
+ "\n",
264
+ "out = massfunction(\n",
265
+ " gout,\n",
266
+ " bins=np.logspace(9, 13, 30), \n",
267
+ " key_mass = ParamKeys.mass_bound, # The default key for bound mass of the subhalo\n",
268
+ " nfilter=nf.subhalos, # Only consider subhalos \n",
269
+ " summarize=True, # Take statistics over multiple trees\n",
270
+ " statfuncs=[np.mean, np.std] # Get the mean and std\n",
271
+ " )\n",
272
+ "\n",
273
+ "dndm_mean, mbine = out[0]\n",
274
+ "dndm_std , _ = out[1]\n",
275
+ "\n",
276
+ "# Plot the mean mass function over all trees, show the standard deviation at each point\n",
277
+ "plt.errorbar(mbine[:-1], dndm_mean, dndm_std)\n",
278
+ "plt.loglog()"
279
+ ]
280
+ },
281
+ {
282
+ "cell_type": "markdown",
283
+ "id": "a5a8888c",
284
+ "metadata": {},
285
+ "source": [
286
+ "### Custom Analysis Functions\n",
287
+ "\n",
288
+ "Use the ```gscript``` decerator to create analysis functions"
289
+ ]
290
+ },
291
+ {
292
+ "cell_type": "code",
293
+ "execution_count": 8,
294
+ "id": "ba018c49",
295
+ "metadata": {},
296
+ "outputs": [
297
+ {
298
+ "name": "stdout",
299
+ "output_type": "stream",
300
+ "text": [
301
+ "0.5539299558467177\n"
302
+ ]
303
+ }
304
+ ],
305
+ "source": [
306
+ "from subscript.wrappers import gscript\n",
307
+ "\n",
308
+ "# Custom analysis function to take the ratio between bound and infall mass\n",
309
+ "@gscript\n",
310
+ "def massratio_avg(gout, **kwargs):\n",
311
+ " return np.mean(gout[ParamKeys.mass_bound] / gout[ParamKeys.mass_basic])\n",
312
+ "\n",
313
+ "# Average bound to infall mass ratio\n",
314
+ "print(massratio_avg(gout, nfilter=nf.subhalos, summarize=True))"
315
+ ]
316
+ }
317
+ ],
318
+ "metadata": {
319
+ "kernelspec": {
320
+ "display_name": ".venv",
321
+ "language": "python",
322
+ "name": "python3"
323
+ },
324
+ "language_info": {
325
+ "codemirror_mode": {
326
+ "name": "ipython",
327
+ "version": 3
328
+ },
329
+ "file_extension": ".py",
330
+ "mimetype": "text/x-python",
331
+ "name": "python",
332
+ "nbconvert_exporter": "python",
333
+ "pygments_lexer": "ipython3",
334
+ "version": "3.13.3"
335
+ }
336
+ },
337
+ "nbformat": 4,
338
+ "nbformat_minor": 5
339
+ }
@@ -1,6 +1,6 @@
1
1
  package:
2
2
  name: subhaloscript
3
- version: "1.0.3"
3
+ version: "1.0.5"
4
4
 
5
5
  source:
6
6
  path: . # Or use `git_url`/`url` if not building from local files
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
  [project]
6
6
  dependencies = ["numpy","pandas","scipy","h5py", "scikit-learn"]
7
7
  name = "subhaloscript"
8
- version = "1.0.3"
8
+ version = "1.0.5"
9
9
  authors = [
10
10
  { name="Charles Gannon", email="cgannon@ucmerced.edu" },
11
11
  ]
@@ -278,7 +278,7 @@ def nfilter_virialized(*args, **kwargs):
278
278
  return withinrv(*args, **kwargs)
279
279
 
280
280
  @gscript
281
- def subhalos_valid(gout, mass_min, mass_max, key_mass=ParamKeys.mass,
281
+ def subhalos_valid(gout, mass_min=-np.inf, mass_max=np.inf, key_mass=ParamKeys.mass,
282
282
  kwargs_nfilter_subhalos=None, kwargs_nfilter_virialized=None, kwargs_nfilter_range=None, **kwargs):
283
283
  """
284
284
  Select subhalos within the virial radius and a given mass range.
@@ -230,14 +230,15 @@ def gscript_proj(func):
230
230
 
231
231
  ## This wrapped as well so we can call with None
232
232
  def wrap_inner(gout, **kwargs2):
233
- _gout = format_nodedata(gout)[0].unfilter()
233
+ _gout = format_nodedata(gout)
234
234
 
235
235
  _input = []
236
236
  for n, _ in enumerate(normvector):
237
237
  _in = copy(_gout)
238
- _in.data = copy(_in.data)
239
- _in.data['__custom_proj_iter__'] = n * np.ones(_in.data[next(_in.data.__iter__())].shape[0], dtype=int)
240
- _input.append(_in)
238
+ for i in _in:
239
+ _i = copy(i)
240
+ _i.data['__custom_proj_iter__'] = n * np.ones(i.data[next(i.data.__iter__())].shape[0], dtype=int)
241
+ _input.append(_i)
241
242
 
242
243
  return wrap_inner_main(_input, **(kwargs | kwargs2))
243
244
 
@@ -53,12 +53,10 @@ def test_multi_proj():
53
53
  out_expected_yz = np.asarray((4, 3, 0), dtype=int)
54
54
 
55
55
  out_expected = np.mean(np.asarray((out_expected_xy, out_expected_xz, out_expected_yz)), axis=0)
56
- print(out_expected)
57
56
 
58
57
  out = spatial2d_dn(mockdata, bins=bins, normvector=norm, summarize=True)
59
- print(out)
60
- out_actual, dn_r = out
61
58
 
59
+ out_actual, dn_r = out
62
60
 
63
61
  testing.assert_allclose(dn_r, bins)
64
62
  testing.assert_allclose(out_actual, out_expected)
@@ -170,11 +168,45 @@ def test_multiproj():
170
168
 
171
169
 
172
170
  def test_multiproj_file():
171
+ # Test that combining multiple projections is the same as
172
+ # passing multiple projection vectors
173
+ path_dmo = "tests/data/test.hdf5"
174
+ gout = h5py.File(path_dmo)
175
+
176
+ nfproj = freeze(r2d, rmin=1E-1, rmax=2E-2)
177
+
178
+ nv = np.identity(3)
179
+ n_actual = multiproj(nodecount, nfilter=nfproj)(gout, summarize=True, normvector=nv)
180
+
181
+ ncomb = []
182
+ ncomb += nodecount(gout, nfilter=nfproj, normvector=nv[0])
183
+ ncomb = nodecount(gout, nfilter=nfproj, normvector=nv[0])
184
+ ncomb = nodecount(gout, nfilter=nfproj, normvector=nv[0])
185
+
186
+ n_expected = np.mean(ncomb)
187
+
188
+ testing.assert_allclose(n_actual, n_expected)
189
+
190
+
191
+ def test_multiproj_file():
192
+ # Test that projections are treated as trees in output shape
173
193
  path_dmo = "tests/data/test.hdf5"
174
194
  gout = h5py.File(path_dmo)
175
195
 
176
196
  nfproj = freeze(r2d, rmin=1E-1, rmax=2E-2)
177
- n_actual = multiproj(nodecount, nfilter=nfproj)(gout, summarize=True, normvector=np.identity(3))
197
+
198
+ nprojv = 6
199
+
200
+ nv = np.random.random(18).reshape(nprojv,3)
201
+ nproj = multiproj(nodecount, nfilter=nfproj)(gout, normvector=nv)
202
+
203
+ ntrees = len(nodecount(gout))
204
+
205
+ testing.assert_equal(len(nproj), ntrees * nprojv)
206
+
207
+
208
+
209
+
178
210
 
179
211
  def test_gscript_unfilter():
180
212
  # Ensure the expected behaviour occours when calling a script within a script
@@ -1,10 +0,0 @@
1
- # SubScript
2
- Utility functions for analyzing subhalo distributions, focusing on the Galacticus (https://github.com/galacticusorg/galacticus) output format. The goal of this package is to facilitate quick statistical analysis of subhalo distributions across multiple trees.
3
-
4
- ## Installation
5
-
6
- ### Install via pip
7
- ```pip install subhaloscript```
8
-
9
- ### Install via conda
10
- ```conda install cgannonucm::subhaloscript```
File without changes
File without changes