subhaloscript 1.0.4__tar.gz → 1.0.6__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 (28) hide show
  1. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/PKG-INFO +3 -2
  2. subhaloscript-1.0.6/README.md +11 -0
  3. subhaloscript-1.0.6/example-notebooks/basic-usage.ipynb +339 -0
  4. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/meta.yaml +1 -1
  5. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/pyproject.toml +1 -1
  6. subhaloscript-1.0.6/subscript/external.py +87 -0
  7. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/subscript/scripts/nfilters.py +1 -1
  8. subhaloscript-1.0.6/tests/test_symphony.py +167 -0
  9. subhaloscript-1.0.4/README.md +0 -10
  10. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/.github/workflows/main.yml +0 -0
  11. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/.gitignore +0 -0
  12. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/LICENSE +0 -0
  13. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/subscript/defaults.py +0 -0
  14. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/subscript/macros.py +0 -0
  15. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/subscript/scripts/histograms.py +0 -0
  16. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/subscript/scripts/nodes.py +0 -0
  17. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/subscript/scripts/spatial.py +0 -0
  18. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/subscript/tabulatehdf5.py +0 -0
  19. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/subscript/util.py +0 -0
  20. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/subscript/wrappers.py +0 -0
  21. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/tests/test_histograms.py +0 -0
  22. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/tests/test_macros.py +0 -0
  23. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/tests/test_nfilters.py +0 -0
  24. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/tests/test_nfilters_legacy.py +0 -0
  25. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/tests/test_nodes.py +0 -0
  26. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/tests/test_spatial.py +0 -0
  27. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/tests/test_tabulatehdf5.py +0 -0
  28. {subhaloscript-1.0.4 → subhaloscript-1.0.6}/tests/test_wrappers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: subhaloscript
3
- Version: 1.0.4
3
+ Version: 1.0.6
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": "iVBORw0KGgoAAAANSUhEUgAAAj4AAAGhCAYAAABh6r6nAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAARg5JREFUeJzt3XlcVPX+P/DXmYFhExBEQRbFcukisoRsLoVFcc1c02zRkMrKcCludfF7v1fz/uraN80sndL0mlsWWUmlZSZlpKIgOG6gZqEiyCgqAwyyzczvj3LMCygDw5yZM6/n4zGPmM85c84bPyEvz/mcz0cwGAwGEBEREdkBmdgFEBEREVkKgw8RERHZDQYfIiIishsMPkRERGQ3GHyIiIjIbjD4EBERkd1g8CEiIiK74SB2AZai1+tRVlYGd3d3CIIgdjlERETUBgaDAdXV1fD394dM1vHrNXYTfMrKyhAUFCR2GURERNQOJSUlCAwM7PBx7Cb4uLu7A/j9D87Dw0PkaoiIiKgtqqqqEBQUZPw93lGSDz5KpRJKpRI6nQ4A4OHhweBDRERkY8w1TEWwl7W6qqqq4OnpCY1Gw+BDRERkI8z9+5tPdREREZHdYPAhIiIiu8HgQ0RERHaDwYeIiIjshuSDj1KpREhICKKjo8UuhYiIiETGp7qIiIjIavGpLiIiIqJ2YvAhIiIiu8HgQ0RERHaDwYeIiIjsBoMPERER2Q0GHyIiIrIbkg8+nMeHiIiIruE8Ph1U29CEkHnfAQAK/5UEV4WD2Y5NRERk7ziPDxEREVE7Mfh0UM6vl4xfL/vhFPR6u7iARkREZJMYfDooqreX8ev3d/2Kp9blQVPbKGJFRERE1BoGnw5SOFz/I3RykOHHExcxevluFJ2vErEqIiIiagmDjxl9ND0WgV4uOHu5FhPe24svVaVil0RERER/wqe6zOyKtgFzMlTIPnkRAPDUsD5IH3kHHOXMmERERKbiU11WzstNgQ+nRWPmiL4AgP/sLsaU1ftxsbpe5MqIiIjIZoLPiRMnEBERYXy5uLggMzNT7LJaJJcJeClpAFZMiUIXJwfsL76M0ct2o+DsFbFLIyIisms2eaurpqYGwcHBOHPmDNzc3Nr0GUvd6vpvpy7U4NkNB/DrRS0c5QJeHTMQj8X0giAIFquBiIjIVvFWF4CvvvoK9957b5tDj5j69uiCL2cOw8hQPzTqDPjHlqNI//wI6hp1YpdGRERkd8wWfLKzszF69Gj4+/tDEIQWb0MplUoEBwfD2dkZsbGxyM3Nbde5Pv30U0yePLmDFVtOFycHvPf4nfj7X++ATAAyDpTg4ZU5KK28KnZpREREdsVswUer1SI8PBxKpbLF7RkZGUhLS8P8+fNRUFCA8PBwJCUl4cKFC8Z9IiIiEBoa2uxVVlZm3Keqqgp79+7FAw88cNN66uvrUVVVdcNLTIIgYEbC7Vj3ZAy8XB1x+JwGo5ftxg/H1QhO34bg9G2obWgStUYiIiKp65QxPoIgYMuWLRg3bpyxLTY2FtHR0Vi+fDkAQK/XIygoCLNmzUJ6enqbj71hwwZ899132Lhx4033e/XVV7FgwYJm7ZYe49OSksu1mPFRPo6WVkEmANdWueAip0RERDeyyTE+DQ0NyM/PR2Ji4vUTy2RITExETk6OScdq622uuXPnQqPRGF8lJSUm191Zgrxd8dlzQ/DQnYH489JeNXW84kNERNSZLBJ8KioqoNPp4Ovre0O7r68vysvL23wcjUaD3NxcJCUl3XJfJycneHh4YMOGDYiLi8O9995rct2dydlRjsWTwjDvwb8Y2yatzOFSF0RERJ3Ipp7q8vT0hFqthkKhaPNnUlNTUVhYiLy8vE6srH0EQcAjMb2M789cqsU45R58mmc9V6eIiIikxCLBx8fHB3K5HGq1+oZ2tVoNPz8/S5RgE4b380F9kx6vfH4Yf/v0EAc7ExERmZlFgo9CoUBUVBSysrKMbXq9HllZWYiPj+/UcyuVSoSEhCA6OrpTz2MO7z9+J15OGgCZAHxecA7jlHtw6kKN2GURERFJhtme6qqpqcGpU6cAAJGRkViyZAlGjBgBb29v9OrVCxkZGUhOTsbKlSsRExODpUuX4tNPP8Xx48ebjf3pDGLN3NweOb9ewuxPDuJidT1cFXIsnDAIYyMCxC6LiIjI4sz9+9tswWfXrl0YMWJEs/bk5GSsXbsWALB8+XIsWrQI5eXliIiIwLvvvovY2FhznL5VSqUSSqUSOp0OJ0+etIngAwAXq+sx55OD2PvrJQDA47G98M8HQ+DsKBe5MiIiIsux2uBj7Wzpis81Or0B7+w8iWU/noLBAIQGeOC9x6LQq5ur2KURERFZhE3O40PtI5cJSLt/ANamxMDbTYGjpVUYtexnbD/a9ikAiIiI6DrJBx9bGtzcmrv7d8e22cMQ1dsL1XVNeG5jPl7bWohGnV7s0oiIiGwKb3XZkEadHm9uP45VPxcDAO7s1RWLJoXh3reyAXDJCyIikh7e6rJjjnIZ/jEqBB9MjYKHswMKzlbiofdNW/KDiIjInjH42KD7B/ph2+zhGBTgicraRmO7Tm8XF++IiIjaTfLBRwpjfFoS5O2Kz2bE47GYIGPb8x8VQHO18SafIiIism8c42PjahuaEDLvO+P7Pj5uWPVEFPr2cBexKiIiIvPgGB9qVU9PZxRXaDFOuRffF6pv/QEiIiI7w+AjIZufi0dsH2/U1Ddh+voDeDfrF+g57oeIiMiIwUdCvN0U2Ph0LJLjewMAlnx/Es9/VABtPVd5JyIiAuxgjI+trtXVURl5Z/HPzGNo0OkxwNcdq54YzKUuiIjI5nCtrnaS6uDmm8k/cwXPbczHxep6eLo4QvnYnRjWz0fssoiIiNqMg5upzaJ6e+HrmcMQHtQVmquNeGLNfqz++TfYSdYlIiJqhsFH4vw8nZHxTBwmRgVCbwBe21aEv316CHWNOrFLIyIisjgGHzvg7CjHoolhmD86BHKZgC8OluLhlTk4r7kqdmlEREQWJfngI9WZm00lCAJShvbBhidj4OXqiMPnNBi9bA92/3IRwenbEJy+DbUNfPqLiIikjYOb7VDJ5VpMX38Ax8ur4SAX0KT7/X8Bru5ORETWhoObqcOCvF3xxfNDMGpQT2PoAYCGJr2IVREREXU+Bh875apwwPLHIvFCYj9j2xNrclFayXE/REQkXQw+dkwQBDxz123G94fPaTDq3Z+x68QFEasiIiLqPAw+ZBTq74HK2kakrM3DWztOQMd1voiISGIYfMho49OxmBrXGwYDsOyHU3hizX5U1NSLXRYREZHZ8KkuauZLVSnSPz+Cq406+Ho4YfljdyI62FvssoiIyA7xqS7qdGMjAvDVzKHo26ML1FX1eOSDfViVzaUuiIjI9kk++HACw/bp5+uOL1OHYmyEP3R6A17/pgjPbsiH5mqj2KURERG1G2910U0ZDAZs3H8W/+/rQjTo9OjdzRXvPX4nBvp7il0aERHZAd7qIosSBAFT43rjsxnxCOjqgjOXajH+vb3IyDsLg8GA2oYmLnlBREQ2g8GH2iQssCu2zR6Ge+7ogYYmPf7++RG8tPkwrjZwlXciIrIdDD7UZl1dFVj9xGC88tcBkAnA5wXn8OiqfWKXRURE1GYMPmQSmUzA8wl98dHTcfDp4oST6hqxSyIiImozBh9ql/jbu+Gb2cMwuLeXse2fmUdRXcenvoiIyHox+FC79fBwxpppg43vPy8oxV+X/ow9pypErIqIiKh1DD7UIQ7y6/8LBXq5oLTyKh5fvR/zvjzKp7yIiMjq2FTwefvttzFw4ECEhIRg9uzZnEnYymx5fgimxPUCAKzPOYOR7/yMA6cvi1wVERHRdTYTfC5evIjly5cjPz8fR44cQX5+Pvbt4xNF1sTNyQGvjRuEDU/FoKenM85cqsWklTn49zdFqGvkY+9ERCQ+mwk+ANDU1IS6ujo0NjaisbERPXr0ELskasHwft3x3Yt3YVJUIAwG4IPs3/Dgst04VFIpdmlERGTnzBZ8srOzMXr0aPj7+0MQBGRmZjbbR6lUIjg4GM7OzoiNjUVubm6bj9+9e3e89NJL6NWrF/z9/ZGYmIjbb7/dXOWTmXk4O2LRpHCsfmIwfLo44dSFGkx4fy+W7DiBhia92OUREZGdMlvw0Wq1CA8Ph1KpbHF7RkYG0tLSMH/+fBQUFCA8PBxJSUm4cOGCcZ+IiAiEhoY2e5WVleHKlSvYunUrTp8+jdLSUuzduxfZ2dmt1lNfX4+qqqobXmR+rgoHnH5jFE6/MQquCodm2xNDfPH9i3dhdPjvi52++8MpjFPuQdF59gcREVlepyxSKggCtmzZgnHjxhnbYmNjER0djeXLlwMA9Ho9goKCMGvWLKSnp9/ymJs3b8auXbuMwWrRokUwGAx45ZVXWtz/1VdfxYIFC5q1c5FS8Ww7fB7/m3kEV2ob4SgX8EJif0yN64WwBd8DAAr/ldRieCIiIvtlk4uUNjQ0ID8/H4mJiddPLJMhMTEROTk5bTpGUFAQ9u7di7q6Ouh0OuzatQsDBgxodf+5c+dCo9EYXyUlJR3+PqhjRoX1xI4X78b9Ib5o1Bmw6LsTeHx12293EhERdZRFgk9FRQV0Oh18fX1vaPf19UV5eXmbjhEXF4cHHngAkZGRCAsLw+23344xY8a0ur+TkxM8PDywYcMGxMXF4d577+3Q90Dm0d3dCSunRmHJw+Fwd3bAkVKNcZtez+kJiIioc9nUU12vv/46ioqKcOzYMbz77rsQBOGWn0lNTUVhYSHy8vIsUCG1hSAImHBnIHa8eBeG9e1mbJ/9iYqTHhIRUaeySPDx8fGBXC6HWq2+oV2tVsPPz69Tz61UKhESEoLo6OhOPQ+ZrqenC1ZOjTK+/+H4BTzywT5cqK4TsSoiIpIyiwQfhUKBqKgoZGVlGdv0ej2ysrIQHx/fqefmFR/r9uerdl1dHXH4nAbjlXtxUl0tYlVERCRVZgs+NTU1UKlUUKlUAIDi4mKoVCqcPXsWAJCWloZVq1Zh3bp1KCoqwowZM6DVapGSkmKuEsjGfTw9Fn183FBaeRUPvbcXu3/hYqdERGReZgs+Bw4cQGRkJCIjIwH8HnQiIyMxb948AMDkyZOxePFizJs3DxEREVCpVNi+fXuzAc/mxltdtqN3Nzd8MWMIYoK9UV3fhGkf5uLTPD6NR0RE5tMp8/hYI3PPA0DmUdvQhJB53wG4Po9PfZMOr3x2GF+qygAAzyfcjpfuHwCZ7NaD2YmISFrM/fubwYesksFgwNvfn8S7P5wCADwY1hOLJ4XD2VEucmVERGRJNjmBoZh4q8s2CYKAtPsHYNHEMDjIBGw9fB5TVu/HZW2D2KUREZEN4xUfsnp7T1Xg2Y35qK5rQnA3V3yYEoM+Pm5il0VERBbAKz5kd4b09cEXM4Yg0MsFpy/VYvx7e5BbfNm4vbahCcHp2xCcvo0TIBIR0U0x+JBN6Ofrji3PD0V4UFdU1jZiyur9+FJVKnZZRERkYyQffDjGRzq6uzvhk+lx+OtAPzTo9JjziQrLsn6BndytJSIiM+AYH7I5er0Bb2w/jg+yfwMAjIv0R+bB3x99v/ZIPBERSQPH+JDdk8kE/M8Df8H/GxcKmQBj6CEiIroVBh+yWVPjeuM/06Lhqrg+t8+3R87z1hcREbVK8sGHY3ykbcSAHtj4dIzx/d82H0bK2jyUXK4VsSoiIrJWHONDNu/Py144ygU06gxwcZQj7b7+SBkaDAe55PM9EZFkcYwP0U1kpg5FbB9vXG3U4fVvijBWuQeHz1WKXRYREVkJBh+SlD4+bvjkmTi8+VAYPF0ccaysCuOUe7Dg62OoqefkhkRE9o7BhyRHEAQ8HB2ErL/djXER/tAbgA/3nMb9S37C94XqZvtz5mciIvvB4EOS5dPFCUsficS6J2MQ5O2CMk0dpq8/gOc25KNcUyd2eUREJALJBx8+1UV39++OHS/cjefuvh1ymYDtx8qRuOQnbMg5Db3eLsb2ExHRH/hUF9mVwrIqzN1yBIdKKgEAkb26Yv7oEIxT7v19O2d+JiKyKnyqi6gDQvw98MWMIVgwZiC6ODng4NlKTHw/R+yyiIjIQhh8yO7IZQKShwTj+7S7kDTQF01/ut11oYpjf4iIpIzBh+xWT08XrJw6GMsejTS2PfLBfhSWVYlYFRERdSYGH7J79/6lh/Hr8qo6TFqxFz8evyBiRURE1FkYfIj+JLaPN7QNOjy1Lg8bck6LXQ4REZkZgw/Rn6ycGoVJUYHQG4B/fnkM/29rIXR85J2ISDIkH3w4jw+ZQuEgw5sTw/By0gAAwH92F+PZDfmc0ZmISCIkH3xSU1NRWFiIvLw8sUshGyEIAlJH9MWyRyOhcJBhZ5EaD6/MgZpPfBER2TzJBx+i9hod7o+Pp8fC202Bo6VVGK/cg6LzzZ/44lpfRES2g8GH7J6rwgGn3xiF02+MajZrc1Rvb2x5fghu6+6GMk0dJq3Iwa4TfOKLiMhWMfgQ3ULvbm7YMmMo4m7zRk19E55adwAb9p0RuywiImoHBh+iNvB0dcT6J2MxMSoQOr0B/8w8itf4xBcRkc1h8CFqI4WDDIsmhuGl+/sDAFbvLsaMjXzii4jIlnAZaiITCIKAmff0Q5C3K17+7DB2FKpRWnlV7LKIiKiNeMWHqB3GRgRg09Ox8HJ1xDGu7UVEZDNsKvgsXrwYAwcORGhoKDZu3Ch2OWTnBgd7Y8vzQxHczdXYlpFXAoOB436IiKyVzQSfI0eOYNOmTcjPz0deXh6WL1+OyspKscsiOxfs44ZN02ON7xd8XYgZGwtQWdsgYlVERNQamwk+RUVFiI+Ph7OzM1xcXBAeHo7t27eLXRYRuroqjF87yAVsP1aOB975GbnFl0WsioiIWmK24JOdnY3Ro0fD398fgiAgMzOz2T5KpRLBwcFwdnZGbGwscnNz23z80NBQ7Nq1C5WVlbhy5Qp27dqF0tJSc5VPZBabno5FcDdXlGnq8MgHOVi68ySadHqxyyIioj+YLfhotVqEh4dDqVS2uD0jIwNpaWmYP38+CgoKEB4ejqSkJFy4cH0W3IiICISGhjZ7lZWVISQkBLNnz8Y999yDCRMmIC4uDnK53FzlE5lFaIAnts4ejgl3BkBvAJbu/AWPrdp/0ye/uOQFEZHlCIZOGIkpCAK2bNmCcePGGdtiY2MRHR2N5cuXAwD0ej2CgoIwa9YspKenm3yOp59+GuPHj8eoUaNa3F5fX4/6+nrj+6qqKgQFBUGj0cDDw8Pk8xG1prahCSHzvgMAFP4rybjsRebBUvxjyxFoG3TwdHHE/z00CH8N7dnmzxMR0e+/vz09Pc32+9siY3waGhqQn5+PxMTE6yeWyZCYmIicnJw2H+fa1aETJ04gNzcXSUlJre67cOFCeHp6Gl9BQUHt/waI2mFcZAC+mTMc4YGe0FxtxHMbC/A/W47gaoNO7NKIiOyWRYJPRUUFdDodfH19b2j39fVFeXl5m48zduxYhISEYMqUKfjwww/h4ND6v4znzp0LjUZjfJWUlLS7fqL26t3NDZufG4Ln7r4dALBp/1mMVe7GifJqkSsjIrJPNnVN3ZSrQ05OTnBycoJSqYRSqYROx39lkzgUDjKkj7wDQ/t2Q9qnh3BSXYMxy3fjf0f9BVPieotdHhGRXbHIFR8fHx/I5XKo1eob2tVqNfz8/Dr13KmpqSgsLEReXl6nnofoVob3645v5wxHwoDuqG/S459fHsMzG/I55w8RkQVZJPgoFApERUUhKyvL2KbX65GVlYX4+PhOPbdSqURISAiio6M79TxEbeHTxQlrkqPxzwdD4CgX8H2hGuPf2yt2WUREdsNst7pqampw6tQp4/vi4mKoVCp4e3ujV69eSEtLQ3JyMgYPHoyYmBgsXboUWq0WKSkp5iqhRampqUhNTTWOCicSm0wm4KlhfRDbxxuzPz6I3yq0xm1c7oKIqHOZ7YrPgQMHEBkZicjISABAWloaIiMjMW/ePADA5MmTsXjxYsybNw8RERFQqVTYvn17swHPRPYiNMATX88ahvGRAca21785Dr2e4YeIqLN0yjw+1uTPg5tPnjzJeXzI6vx5Hh8AmHBnAN58KAwOcptZUYaIqNOYex4fyQefa8z9B0dkLn8OPnKZAJ3egKSBvnj30Ug4OXB2ciKybzY5gSERtc07j0RA4SDDd8fUeHrdAS5hQURkZpIPPnyqi2zJPXf0wIfTouGqkOPnXyow9T+50FxtFLssIiLJkHzw4Tw+ZGuG9vXBxqdj4eHsgPwzV/DoB/tQUVN/6w8SEdEtST74ENmiO3t5IePZePh0cULh+So8vCIHZa2s8M7V3YmI2o7Bh8hK/aWnBzY/F4+Ari74rUKLSStyUPynOX+IiMh0kg8+HONDtqyPjxs+fS4et/m4obTyKiatyEHR+SqxyyIislmSDz4c40O2LqCrCz59Lh4hPT1QUVOPyStzUHD2ithlERHZJMkHHyIp8OnihI+fiUNUby9U1TVhyur92HuqQuyyiIhsDoMPkY3wdHHEhqdiMLyfD2obdJi2Ng/fF6o7fFwOjiYieyL54MMxPiQlrgoHrE4ejKSBvmho0uO5jfn4+lCZ2GUREdkMyQcfjvEhqXFykEP52J2YEBkAnd6A9C+OiF0SEZHNcBC7ACJ756pwwOk3Rpn0GQe5DIsnhaOLswPW55wxtmvrm+Cq4I81EVFrJH/Fh0iqZDIBC8YMxLN33WZsG7H4J/z7myKUtjLZIRGRvWPwIbJhgiBgTmI/4/ua+iZ8kP0b7nrzR8z6+CAOlVSKVxwRkRVi8CGSkPcfvxPxt3WDTm/A14fKMFa5B5NW7MV3x8qh0xvELo+ISHSSHwygVCqhVCqh0+nELoWo0909oDtGDuqJo6UarNldjK8OlSHv9BXknc5H726ueHJoH0yMCoSbk+R/9ImIWiT5Kz58qovsUWiAJ5ZMjsDuv9+D5xNuh6eLI85cqsX8r44hfmEW3vj2OM5rOA6IiOwP/9lHJGF+ns545a93YOY9ffF5/jn8Z3cxTl+qxYqffsXqn3/Dg2E9MSWut9hlEhFZDIMPkR1wVThganwwHo/tjazjF7D659+wv/gyMlVlyFRxAkQish+Sv9VFRNfJZALuC/FFxrPx+HrmMIyN8IeDTDBuf/v7k9BzEDQRSRiDD5GdGhToiXceicR3Lw43tq36uRgzPsrnml1EJFkMPkR2rqeni/FrR7mA746pMfH9HJRxEkQikiAGHyIy+nBaNLq5KVB4vgpjlXugasMEiFzdnYhsieSDD1dnJ2q7O3t7ITN1KAb4uuNidT0mr8zh6u9EJCmSDz6cx4fINEHervj8+SG4944eqG/SY9bHB/H29ydhMHDQMxHZPskHHyIyXRcnB3zwxGA888cCqO9k/YKZHx9EXSNnQCci28bgQ0QtkssE/M8Df8GbD4XBUS5g2+HzmLwyB+qqOrFLIyJqNwYfIrqph6ODsOGpWHi5OuLQOQ3GLt+Do6UascsiImoXBh8iuqW427ohM3Uo+vbogvKqOkxcsRffHjkvdllERCZj8CGiNundzQ1fPD8Ed/XvjrpGPWZ8VIDlP/zCQc9EZFMYfIiozTycHbEmeTBShgYDABbvOIm/f35E3KKIiEzA4ENEJnGQyzB/9EC8Pj4UDjIBWw/zlhcR2Q6rDD7jx4+Hl5cXJk6c2Gzb1q1bMWDAAPTr1w+rV68WoToiAoDHY3tj/ZMx8HBxMLaduaQVsSIioluzyuAzZ84crF+/vll7U1MT0tLS8MMPP+DgwYNYtGgRLl26JEKFRNbDVeGA02+Mwuk3RsFV4XDrD5jRkL4++GR6nPF9ytoDKLlca9EaiIhMYZXBJyEhAe7u7s3ac3NzMXDgQAQEBKBLly4YOXIkduzYIUKFRHRNsI+b8etyTR0e+WAfzl1h+CEi62Ry8MnOzsbo0aPh7+8PQRCQmZnZbB+lUong4GA4OzsjNjYWubm55qgVZWVlCAgIML4PCAhAaWmpWY5NRB3Xu5srSiuv4rFV+3Few9Xdicj6mBx8tFotwsPDoVQqW9yekZGBtLQ0zJ8/HwUFBQgPD0dSUhIuXLhg3CciIgKhoaHNXmVl5lsMsb6+HlVVVTe8iKhzrU2JRu9urjh7uRaPfrCPszwTkdUxOfiMHDkSr732GsaPH9/i9iVLlmD69OlISUlBSEgIVqxYAVdXV6xZs8a4j0qlwtGjR5u9/P39b3puf3//G67wlJaWtvqZhQsXwtPT0/gKCgoy9VslIhP5ejhj0/Q4BHq54PSlWjy6ah8uVN88/NQ2NCE4fRuC07ehtqHJQpUSkb0y6xifhoYG5OfnIzEx8foJZDIkJiYiJyenw8ePiYnB0aNHUVpaipqaGnz77bdISkpqcd+5c+dCo9EYXyUlJR0+PxHdWkBXF3w8PQ4BXV3w20UtHlu1HxU19WKXRUQEwMzBp6KiAjqdDr6+vje0+/r6ory8vM3HSUxMxKRJk/DNN98gMDDQGJocHBzw1ltvYcSIEYiIiMDf/vY3dOvWrcVjODk5wcPDAxs2bEBcXBzuvffe9n9jRGSSIG9XbJoeCz8PZ5y6UIMpq/fjsrZB7LKIiGDZZ1/baOfOna1uGzNmDMaMGdPmY6WmpiI1NRVVVVXw9PQ0R3lE1Aa9u7nh42fiMHllDo6XV2PK6v3YND0WXV0VYpdGRHbMrFd8fHx8IJfLoVarb2hXq9Xw8/Mz56mIyAb08XHDpulx8OnihMLzVZjyn/3Q1DaKXRYR2TGzBh+FQoGoqChkZWUZ2/R6PbKyshAfH2/OU7WZUqlESEgIoqOjRTk/kb3r26MLNk2PRTc3BY6WVuGJNftRVcfwQ0TiMDn41NTUQKVSQaVSAQCKi4uhUqlw9uxZAEBaWhpWrVqFdevWoaioCDNmzIBWq0VKSopZC2+r1NRUFBYWIi8vT5TzExHQ39cdH02PhZerIw6d02DamlzU1PMJLiKyPJODz4EDBxAZGYnIyEgAvwedyMhIzJs3DwAwefJkLF68GPPmzUNERARUKhW2b9/ebMAzEdmXO/w8sPHpWHi6OKLgbCVSPsyFluGHiCzM5OCTkJAAg8HQ7LV27VrjPjNnzsSZM2dQX1+P/fv3IzY21pw1m4S3uoisx0B/T2x8Khbuzg7IO30FT63Lw9UGXYeOyXmAiMgUVrlWlznxVheRdRkU6In1T8agi5MD9v12GambCsQuiYjsiOSDDxFZn8heXlj3ZDTcFHLs++2y2OUQkR2RfPDhrS6im3NVOOD0G6Nw+o1RcFVYbmqvqN7e+DAlBi6OcmNbZS0nOSSiziX54MNbXUTWK6aPN96fcqfx/X1vZ+Pt70/ycXci6jSSDz5EZN1i+ngbv9bW6/BO1i8Y/n8/QvnjKT71RURmJ/ngw1tdRLbj7cnh6NejCzRXG7HouxMY/uaP+CD71w4/+UVEdI3kgw9vdRHZjqSBftj+wl1455EI9PFxw2VtA/79zXEMf/NHrNldjLpGBiAi6hjJBx8isi1ymYCxEQH4/sW7sGhiGIK8XVBRU49/bS1EwqJd2LjvDBqa9GKXSUQ2isGHiKySg1yGSYODkJWWgH+PH4Sens4or6rD/2YexT1v7cKneSVo0jEAEZFpGHyIyKopHGR4LLYXdr2cgAVjBqKHuxPOXbmKVz4/jMQlP+GrQ2Vil0hENkTywYeDm4mkwclBjuQhwch+ZQT+d9Rf0M1NgdOXapH++RHjPgaDoV3H5rIXRPZD8sGHg5uJpMXZUY6nh9+G7FdG4JW/DoCHy/VJF1/+7DAHQBPRTUk++BCRNLk5OeD5hL7Y+eLdxrZvjpRj8socXKiqE7EyIrJmDD5EZNO6OF+/4uPp4ohD5zQYs3wPjpZqRKyKiKwVgw8RScYnz8Ti9u5uKK+qw6QVOdh+9LzYJRGRlWHwIaIOEWuR05b07uaGL54fiuH9fHC1UYfnNhZA+eOpdg96JiLpkXzw4VNdRPbF08URH06LxrQhwQCARd+dwIsZKg56JiIAdhB8+FQXkf1xkMvw6piBeG1cKOQyAZmqMjy2ah8uVteLXRoRiUzywYeI7NeUuN5Y/2QMPJwdUHC2EuOUe1B0vkrssohIRAw+RCRpQ/v6IDN1KPr4uKG08ioeen8vvi9Ui10WEYmEwYeIJO+27l2Q+fxQDO3bDbUNOjyz4QBW/vQrBz0T2SEGHyKyC56ujlibEoMpcb1gMAALvz2Olz87jPomDnomsicMPkRkNxzlMrw2bhAWjBkImQB8ln8OU1bvx2VtQ4eOy7W+iGwHgw8R2Z3kIcFYmxIDd2cH5J2+gskr94ldEhFZiOSDD+fxIaKW3NW/O7Y8PxS9u7mitPKq2OUQkYVIPvhwHh8iak3fHr8Peo4J9jK2vZv1C3R6DnomkirJBx8iopvxclNgVfJg4/sVP/2GaR/m4koHx/0QkXVi8CEiu+cov/5XoYujHD//UoEHl+3G4XOV4hVFRJ2CwYeI6E8+fiYWwX+M+5m4IgcZeWfFLomIzIjBh4joT/r7uuOrWcNwX4gvGpr0+PvnR5D++WEuckokEQw+RET/xcPZESunROHlpAGQCcAneSWYtCIH567Uil0aEXUQgw8RUQtkMgGpI/pi3ZMx8HJ1xJFSDR5cthvZJy+a/VycAJHIchh8iIhuYni/7tg6ezjCAj1RWduI5A9zsfyHX6DnI+9ENskqg8/48ePh5eWFiRMnmrSNiKgzBHR1wafPxuPRmN/X+Vq84ySe2XAAmquNYpdGRCayyuAzZ84crF+/3uRtRESdxdlRjoUTBuHNh8KgcJBhZ9EFjFm+G0Xnq8QujYhMYJXBJyEhAe7u7iZvIyLqbA9HB+GLGUMQ0NUFZy7VYvx7e/DVoTKxyyKiNjI5+GRnZ2P06NHw9/eHIAjIzMxsto9SqURwcDCcnZ0RGxuL3Nxcc9RKRGQVQgM8sXXWMNzVvzvqGvVI//yI2CURURuZHHy0Wi3Cw8OhVCpb3J6RkYG0tDTMnz8fBQUFCA8PR1JSEi5cuGDcJyIiAqGhoc1eZWXm+1dTfX09qqqqbngREZmLl5sCH06Lxux7+t7Qzkfeiaybg6kfGDlyJEaOHNnq9iVLlmD69OlISUkBAKxYsQLbtm3DmjVrkJ6eDgBQqVTtq9YECxcuxIIFCzr9PERkv+QyAWn3D8AdPd3x/EcHAQAPvZ+D/3soDA8M6ilydUTUErOO8WloaEB+fj4SExOvn0AmQ2JiInJycsx5qluaO3cuNBqN8VVSUmLR8xOR/UgY0MP4dXVdE57/qAD/2HKEsz0TWSGzBp+KigrodDr4+vre0O7r64vy8vI2HycxMRGTJk3CN998g8DAwBtC0822/ZmTkxM8PDywYcMGxMXF4d57723fN0VEZILpw/tAEICP9p/FOOUenLpQLXZJRPQnJt/qsoSdO3e2a1tLUlNTkZqaiqqqKnh6ena0NCKim3rxvv64q393vJihwvHyaoxetgf/GjsQE6MCIQiC2OUR2T2zXvHx8fGBXC6HWq2+oV2tVsPPz8+cpyIislrD+3XHN3OGY2jfbrjaqMPLnx1G2qeHUFPfOctRcMkLorYza/BRKBSIiopCVlaWsU2v1yMrKwvx8fHmPFWbKZVKhISEIDo6WpTzE5F96uHujPVPxuLlpAGQywRsOViK0ct242ipRuzSiOyaybe6ampqcOrUKeP74uJiqFQqeHt7o1evXkhLS0NycjIGDx6MmJgYLF26FFqt1viUl6XxVheRdXNVOOD0G6PELqNTyP9Y6DSmjzfmfHwQxRVaTHhvL/7ngTuQPCSYt76IRGBy8Dlw4ABGjBhhfJ+WlgYASE5Oxtq1azF58mRcvHgR8+bNQ3l5OSIiIrB9+/ZmA54tRalUQqlUQqfj0xVEJI7oYG98M2c4Xtp8GDuL1Hj160Ls/fUSFk0Mh6ero9jlEdkVk291JSQkwGAwNHutXbvWuM/MmTNx5swZ1NfXY//+/YiNjTVnzSZJTU1FYWEh8vLyRKuBiKirqwKrnojCvAdD4CgXsKNQjQfe/Rn5Zy6LXRqRXbHKtbqIiKRIEAQ8OawPvpgxFMHdXFFaeRUPr9yHVdm/iV0akd2QfPDh4GYisjaDAj3x9axhGBvhD53egLd3/iJ2SUR2Q/LBh7e6iMgauTs7YunkCLz5UBicHa//VfxJ7lno9AYRKyOSNskHHyIiayUIAh6ODsKnz16f7uNfW4sw4b09OHKOj70TdQYGHyIikfXt0cX4dRcnBxw6p8FY5W7M//IoNFcbRayMSHokH3w4xoeIbMm22b+P/dEbgHU5Z3DvWz8h82ApDAbe/iIyB8kHH47xISJb0t3dCe88EomPno7Fbd3dUFFTjxcyVHh89X6culAjdnlENk/ywYeIyBYN7euDb+cMx0v394eTgwx7f72Eke9kY9F3x3G1gROyErUXgw8RkZVycpBj5j39sDPtbtxzRw806gxQ/vgr7nv7J2QVqW99ACJqhsGHiMjKBXm74j/Jg7FyahT8PZ1x7spVPLXuAJ5ZfwCllVfFLo/Ippi8Vpet4VpdRCQFgiAgaaAfhvfzwTtZv+A/PxdjR6EaP/9SgRkJt4ldHpHNkPwVHw5uJiIpcVU4YO7Iv+CbOcMR08cbVxt1WPI9Z34maivJX/EhImlzVTjg9BujxC7D4vr7uiPjmThsOViK17YV4bK2AQBwsboevbvxr3ai1kj+ig8RkVQJgoAJdwZi2+xhxrbXtxWZfJzahiYEp29DcPo21DY0mbNEIqvD4ENEZOM8XRyNX+8oVOObI+dFrIbIukk++HDmZiKyN/O+PIorf9z6IqIbST74cHAzEdmTvj26oKKmAf/aWih2KURWSfLBh4jInrw2biBkArDlYCl+OG6ZSQ45RohsCYMPEZGEhAV2xdPDf5/X53++OIqqOq7uTvRnDD5ERBKTdl9/9PFxQ3lVHRZ+Y/pTXkRSxuBDRCQxzo5yvDFhEADg49wS7DlVIXJFRNaDwYeISIJib+uGJ+J7AwDSvzgMbT3H3hABDD5ERJL1yl/vQEBXF5RcvopF350Quxwiq8DgQ0QkUV2cHLDwj1te63JO48DpyyJXRCQ+yQcfTmBIRPbsrv7d8fDgQBgMwCufHUZdo07skohEJfngwwkMicje/WNUCHq4O+G3Ci2W7uRK7mTfJB98iIjsnaeLI14f//strw+yf8Xhc5XiFkQkIgYfIiI7cF+IL8aE+0P/xy2vhia92CUZceZnsiQGHyIiO/HqmIHo5qbA8fJqvLfrlNjlEImCwYeIyE54uynw6piBAIDlP5zC8fIqkSsisjwGHyIiO/JgWE/cH+KLJr0Br3x2GE0667nlRWQJDD5ERHZEEAS8Ni4UHs4OOHxOg9W7i8UuiciirDL4jB8/Hl5eXpg4ceIN7SUlJUhISEBISAjCwsKwefNmkSokIrJdPTyc8c8HQwAAS74/ieIKrcgVEVmOVQafOXPmYP369c3aHRwcsHTpUhQWFmLHjh144YUXoNXyB5aIyFQTowJxV//uaGjS45+ZR8Uuh8hirDL4JCQkwN3dvVl7z549ERERAQDw8/ODj48PLl/mFOxERKYSBAELJwyCm0KOgrOVYpdDZDEmB5/s7GyMHj0a/v7+EAQBmZmZzfZRKpUIDg6Gs7MzYmNjkZuba45ab5Cfnw+dToegoCCzH5uIyB4EdHVB+gN/EbsMIotyMPUDWq0W4eHhePLJJzFhwoRm2zMyMpCWloYVK1YgNjYWS5cuRVJSEk6cOIEePXoAACIiItDU1HySqh07dsDf3/+WNVy+fBlPPPEEVq1aZWr5RET0J4/H9MJXqlLknb4CAHjhExX69uiCYB833Objhj4+bvB2U0AQBJErJTIPk4PPyJEjMXLkyFa3L1myBNOnT0dKSgoAYMWKFdi2bRvWrFmD9PR0AIBKpWpftQDq6+sxbtw4pKenY8iQITfdr76+3vi+qorzVRAR/TeZTMC/xg7EyHd2AwB2FKqxo1B9wz4ezg7o80cI6uPTBX26u6FPNzcE+7jC3dlRjLKJ2s3k4HMzDQ0NyM/Px9y5c41tMpkMiYmJyMnJ6fDxDQYDpk2bhnvuuQdTp0696b4LFy7EggULOnxOIiKp693Nzfj13JF34NyVqyiu0KK4QosyzVVU1TXh0DkNDp3TNPtsd3cn9PJ2Nb43GAwWqZmovcwafCoqKqDT6eDr63tDu6+vL44fP97m4yQmJuLQoUPQarUIDAzE5s2bER8fjz179iAjIwNhYWHGsUUbNmzAoEGDmh1j7ty5SEtLM76vqqrieCAioluYGt8brorrvxrqGnU4c6kWxRU1KK649l8tiitqUVFTj4vVv7+u+ceWo3jjoTA4O8rFKJ/olswafMxl586dLbYPGzYMen3bZhl1cnKCk5MTlEollEoldDqdOUskIrILzo5yDPBzxwC/5k/aVtU14nSFFsfLq/DKZ0cAAJmqMvxWocWKKVHw7+pi6XKJbsmsj7P7+PhALpdDrb7x/rBarYafn585T9VmqampKCwsRF5enijnJyKSKg9nR4QFdsWDYdcfSunq6ojD5zQYvWw39v92ScTqiFpm1uCjUCgQFRWFrKwsY5ter0dWVhbi4+PNeao2UyqVCAkJQXR0tCjnJyKyJ5ufjUdITw9c0jbg8dX7sW7v6U4f91Pb0ITg9G0ITt+G2obmTwwT/ZnJwaempgYqlcr4ZFZxcTFUKhXOnj0LAEhLS8OqVauwbt06FBUVYcaMGdBqtcanvCyNV3yIiCwnwMsFn88YgjHh/mjSGzD/q2N45bPDqGvkcAOyDiaP8Tlw4ABGjBhhfH9tAHFycjLWrl2LyZMn4+LFi5g3bx7Ky8sRERGB7du3NxvwTERE0uSikOOdRyIwKMATC78twub8cziprsaKqVHo6clxPyQuk4NPQkLCLS9bzpw5EzNnzmx3UebEwc1ERJYnCAKm33Ub7ujpjlkfH8ShP8b9vD8lCtHB3mKXR3bMKtfqMife6iIiEs/wft3x9cxhuMPPHRU1DXj0g33YkNP5436IWiP54ENEROIK8nbFF88PwYNhPdGkN+CfXx5D+udHUN/EK/FkeZIPPnyqi4hIfK4KByx7NBLpI++ATAAyDpRg8sp9KNfUiV0a2RnJBx/e6iIisg6CIOC5u2/H2pQYeLo4QlVSidHLd6PgzBWxSyM7IvngQ0RE1uWu/t3x1cyhuMPPHRer6zFtLf9hSpbD4ENERBbXu5sbPp8xBA8M8kOT7vpAZ72eg56pc0k++HCMDxGRdXJzcoDysTvxYmI/Y5ty168iVkT2QPLBh2N8iIis17X5fq55f9evyCpS3+QTRB0j+eBDRES25YUMFU5XaMUugySKwYeIiKxGRFBXVNc14bmN+VxwlDqF5IMPx/gQEdmOtyeHw6eLAsfLqzH3iyMWmeGZq7vbF8kHH47xISKyHb4ezlj+2J2QywR8qSrDur2nxS6JJEbywYeIiGxL3G3dMHfkHQCA17YVIe/0ZZErIilh8CEiIqvz1LA+xrW9nv+oABequLQFmQeDDxERWR1BEPB/D4Whv28XXKyuR+qmAjTq9GKXRRLA4ENERFbJzckBK6ZEwd3JAXmnr+D1bUVil0QSIPngw6e6iIhs123du+Cth8MBAGv3nsaXqlKRKyJbJ/ngw6e6iIhs2/0D/ZA64nYAwN8/P4yi81UiV0S2TPLBh4iIbF/afQMwvJ8P6hr1eG5jPjRXG8UuiWwUgw8REVk9uUzAu49EIqCrC85cqkVahooruVO7MPgQEZFN8HJTYOXUKCgcZMg6fgHLfjgldklkgxh8iIjIZoQGeOK1caEAgKVZJ/HjiQsiV0S2hsGHiIhsysODg/BYbC8YDMALn6hQcrlW7JLIhjD4EBGRzZk/OgQRQV2hudqIOZ+oxC6nw7hQquVIPvhwHh8iIulxcpDj/Sl3opvb7yu5E7WV5IMP5/EhIpKmnp4uWPZYJGSC2JWQLZF88CEiIukacrsP0u7rb3yvOlspXjFkExh8iIjIpqUMDTZ+/UKGChequZI7tY7Bh4iIbJogXL/XdaG6HjM3HeRK7tQqBh8iIpIMNyc5cosv441vj4tdClkpBh8iIpKMf48fBAD4z+5ifHWoTORqyBox+BARkWTcF+KL5+7+YyX3zw7jBB91p//C4ENERJLy0v39MbRvN1xt1OG5jfmoquNK7nSdVQaf8ePHw8vLCxMnTryhvbKyEoMHD0ZERARCQ0OxatUqkSokIiJr5SCX4d1HIuHv6YziCi3SMg5xJXcyssrgM2fOHKxfv75Zu7u7O7Kzs6FSqbB//378+9//xqVLl0SokIiIrFm3Lk54f0oUFHIZdhap8d4uruROv7PK4JOQkAB3d/dm7XK5HK6urgCA+vp6GAwGGAxM8URE1Fx4UFf8a+xAAMBb35/ETycvilwRWQOTg092djZGjx4Nf39/CIKAzMzMZvsolUoEBwfD2dkZsbGxyM3NNUetAH6/3RUeHo7AwEC8/PLL8PHxMduxiYhIWh6J6YVHooNgMABzPjnIldzJ9OCj1WoRHh4OpVLZ4vaMjAykpaVh/vz5KCgoQHh4OJKSknDhwgXjPtfG6Pz3q6zs1o8edu3aFYcOHUJxcTE2bdoEtVrd4n719fWoqqq64UVERPbn1TEDERboicraRsz4KB91jTqxSyIRmRx8Ro4ciddeew3jx49vcfuSJUswffp0pKSkICQkBCtWrICrqyvWrFlj3EelUuHo0aPNXv7+/m2uw9fXF+Hh4fj5559b3L5w4UJ4enoaX0FBQaZ9o0REJAnOjnK8PyUK3m4KHC2twj8zj0pumERtQxOC07chOH0bahuaxC7Hqpl1jE9DQwPy8/ORmJh4/QQyGRITE5GTk9Ph46vValRX/z4ng0ajQXZ2NgYMGNDivnPnzoVGozG+SkpKOnx+IiKyTQFdXbDs0d9Xct+cfw6bcs+KXRKJxMGcB6uoqIBOp4Ovr+8N7b6+vjh+vO3ThycmJuLQoUPQarUIDAzE5s2bER8fjzNnzuCZZ54xDmqeNWsWBg0a1OIxnJyc4OTk1KHvh4iIpGNoXx+8nHQH/m/7cbz61TGE9PRAZC8vscsiCzNr8DGXnTt3ttgeExMDlUpl0rGUSiWUSiV0Ot7TJSKyd8/dfRsOlVRi+7FyzNhYgK2zh8FVIRe7LLIgs97q8vHxgVwubzbgWK1Ww8/Pz5ynarPU1FQUFhYiLy9PlPMTEZH1EAQBiyaF4fbubiivqsPMTQVo4krudsWswUehUCAqKgpZWVnGNr1ej6ysLMTHx5vzVG2mVCoREhKC6OhoUc5PRETWxd3ZESunRsFNIce+3y7j7Z2/iF0SWZDJwaempgYqlcp4y6m4uBgqlQpnz/4+UCwtLQ2rVq3CunXrUFRUhBkzZkCr1SIlJcWshbcVr/gQEdF/69vDHYsmhQMAPtxzWtxiyKJMHuNz4MABjBgxwvg+LS0NAJCcnIy1a9di8uTJuHjxIubNm4fy8nJERERg+/btzQY8ExERiemBQT3x7F23YWX2b2KXQhZkcvBJSEi45fwHM2fOxMyZM9tdlDlxcDMREbXm5aQBUJVUYn/xZQCAtr4JrgqrfO6HzMQq1+oyJ97qIiKi1jjIZXjr4XDj+2yu5yV5kg8+REREN+PtpjB+XdfEJ7ykTvLBh091ERER0TWSDz681UVERETXSD74EBEREV3D4ENERER2Q/LBh2N8iIiI6BrJBx+O8SEiIqJrJB98iIiIiK5h8CEiIiK7IfngwzE+REREdI3kgw/H+BAREdE1kg8+RERE1q5cUyd2CXaDwYeIiOgPBoM45/1SVWb8+lJNvThF2AkGHyIiIpE16K4vjvq3Tw+hScfFUjsLgw8REZEVyT19BW9+d0LsMiRL8sGHT3UREZGt+SD7N2w7fF7sMiRJ8sGHT3UREZEteXJoMADg5c8O4Rd1tbjFSJDkgw8REZEteSGxH+Jv64baBh2e3ZCP6rpGsUuSFAYfIiIiK+Igl2HZY5Ho6emM3yq0eGnzIRjEetxMghh8iIiIrIxPFye8PyUKCrkM3x1T4/2ffhW7JMlg8CEiIrJCEUFd8eqYgQCAxd+dwO5fKkSuSBoYfIiIiMTWyq2sR2OC8PDgQOgNwKyPC3DuSq2FC5MeBh8iIiIrJQgC/jU2FIMCPHGlthEzNhagrlEndlk2TfLBh/P4EBGRLXN2lOO9x+9EV1dHHCnVYP6Xx8QuyaZJPvhwHh8iImorA6zz6akgb1e8+0gkBAHIOFCCj3PPil2SzZJ88CEiIpKCu/p3x0v3DwAAzP/yGFQlleIWZKMYfIiIiGzEjLtvx30hvmjQ6fH8xnyu5N4ODD5EREQ2QiYT8NbD4bjNxw1lmjrM+vggV3I3EYMPERGRDfFwdsSKqVFwVcix99dLWLzjpNgl2RQGHyIiIhvT39cdb04MAwCs+OlXfF+oFrki28HgQ0REZIMeDPPH08P6AADmfnFE5GpsB4MPERGRyNr7EH36yDsQ28cbtQ2c1LCtrDL4jB8/Hl5eXpg4cWKL22tra9G7d2+89NJLFq6MiIjIejjIZVj+2J3w9XASuxSbYZXBZ86cOVi/fn2r219//XXExcVZsCIiIiLr1N3dCU8P7yN2GTbDKoNPQkIC3N3dW9z2yy+/4Pjx4xg5cqSFqyIiIrJOjnKr/HVulUz+k8rOzsbo0aPh7+8PQRCQmZnZbB+lUong4GA4OzsjNjYWubm55qgVAPDSSy9h4cKFZjseERER2Q+Tg49Wq0V4eDiUSmWL2zMyMpCWlob58+ejoKAA4eHhSEpKwoULF4z7REREIDQ0tNmrrKzspuf+8ssv0b9/f/Tv3/+WddbX16OqquqGFxEREdk3B1M/MHLkyJveZlqyZAmmT5+OlJQUAMCKFSuwbds2rFmzBunp6QAAlUrVrmL37duHTz75BJs3b0ZNTQ0aGxvh4eGBefPmNdt34cKFWLBgQbvOQ0REdso61yglMzLrTcGGhgbk5+cjMTHx+glkMiQmJiInJ6fDx1+4cCFKSkpw+vRpLF68GNOnT28x9ADA3LlzodFojK+SkpIOn5+IiIhsm8lXfG6moqICOp0Ovr6+N7T7+vri+PHjbT5OYmIiDh06BK1Wi8DAQGzevBnx8fEm1eLk5AQnJycolUoolUrodJzjgIiIyN6ZNfiYy86dO2+5z7Rp09p0rNTUVKSmpqKqqgqenp4drIyIiMj8DLzFZjFmvdXl4+MDuVwOtfrGNUPUajX8/PzMeSoiIiIik5k1+CgUCkRFRSErK8vYptfrkZWVZfKtKnNRKpUICQlBdHS0KOcnIiLqbILYBdgQk2911dTU4NSpU8b3xcXFUKlU8Pb2Rq9evZCWlobk5GQMHjwYMTExWLp0KbRarfEpL0vjrS4iIiK6xuTgc+DAAYwYMcL4Pi0tDQCQnJyMtWvXYvLkybh48SLmzZuH8vJyREREYPv27c0GPFsKBzcTERHRNSYHn4SEBBhuMQpr5syZmDlzZruLMide8SEiIqJruLgHERER2Q0GHyIiIrIbkg8+fKqLiIiIrrHKCQzN6doYH41Gg65du3KxUiJqprahCfr6WgBAVVUVmhSm/dXIz0vn87XaalF+T9TV1nToe7iqre7Q563Ztf641fjithIM5jqSlTt37hyCgoLELoOIiIjaoaSkBIGBgR0+jt0EH71ej7KyMri7u0MQrk/1FB0djby8vBY/09q2/26vqqpCUFAQSkpK4OHhYf7iTXSz78nSxzT1c23Z/1b7tLXfbtYu9T7tyPFM+Wxb923Pz+HNtln7zygg7T5t78/ozbZZe5/y793O61ODwYDq6mr4+/tDJuv4CB3pXAu7BZlM1mJSlMvlrf7QtLattXYPDw+r+AG82fdk6WOa+rm27H+rfUztt5sdT6p92pHjmfLZtu7bnp/Dm22z9p9RQNp92t6f0Ztts/Y+5d+7ndun5pyORvKDm28lNTXV5G03+4w16Iz62ntMUz/Xlv1vtY+p/Wbt/QmYv8aOHM+Uz7Z13/b8HN5sG/u08z7bmT+jN9tm7X3Kv3dtp0/t5lZXZ7o2OaJGo7GKf3lQx7FPpYX9KT3sU+mxVJ/a/RUfc3BycsL8+fPh5OQkdilkJuxTaWF/Sg/7VHos1ae84kNERER2g1d8iIiIyG4w+BAREZHdYPAhIiIiu8HgQ0RERHaDwYeIiIjsBoNPJ1u8eDEGDhyI0NBQbNy4UexyqJ3Gjx8PLy8vTJw48Yb2rVu3YsCAAejXrx9Wr14tUnXUHq31aWvtZP1a6ruSkhIkJCQgJCQEYWFh2Lx5s4gVkila6s/KykoMHjwYERERCA0NxapVq0w+Lh9n70RHjhxBcnIy9u7dC4PBgBEjRmD79u3o2rWr2KWRiXbt2oXq6mqsW7cOn332GQCgqakJISEh+PHHH+Hp6YmoqCjs3bsX3bp1E7laaouW+vRm7WT9Wuq78+fPQ61WIyIiAuXl5YiKisLJkyfh5uYmcrV0Ky31p06nQ319PVxdXaHVahEaGooDBw6Y9Pcur/h0oqKiIsTHx8PZ2RkuLi4IDw/H9u3bxS6L2iEhIQHu7u43tOXm5mLgwIEICAhAly5dMHLkSOzYsUOkCslULfXpzdrJ+rXUdz179kRERAQAwM/PDz4+Prh8+bII1ZGpWupPuVwOV1dXAEB9fT0MBgNMvX7D4HMT2dnZGD16NPz9/SEIAjIzM5vto1QqERwcDGdnZ8TGxiI3N9e4LTQ0FLt27UJlZSWuXLmCXbt2obS01ILfAQEd78fWlJWVISAgwPg+ICCA/WshndWnJB5L9Gl+fj50Oh2CgoLMVDW1pjP7s7KyEuHh4QgMDMTLL78MHx8fk2pj8LkJrVaL8PBwKJXKFrdnZGQgLS0N8+fPR0FBAcLDw5GUlIQLFy4AAEJCQjB79mzcc889mDBhAuLi4iCXyy35LRA63o9kfdin0tPZfXr58mU88cQT+OCDD8xZNrWiM/uza9euOHToEIqLi7Fp0yao1WrTijNQmwAwbNmy5Ya2mJgYQ2pqqvG9Tqcz+Pv7GxYuXNjiMZ566inD1q1bO7NMuoWO9OOPP/5oeOihh4zv9+zZYxg3bpzx/Zw5cwwfffRR5xROrTJnn96qnSzD3H1aV1dnGD58uGH9+vWdVjO1rjN+Rq+ZMWOGYfPmzSbVwys+7dTQ0ID8/HwkJiYa22QyGRITE5GTk2Nsu5ZeT5w4gdzcXCQlJVm8VmpdW/uxJTExMTh69ChKS0tRU1ODb7/9lv1rBTrSp2SdOtKnBoMB06ZNwz333IOpU6d2dqnUBh3pT7VajerqagCARqNBdnY2BgwYYNL5HUwvmQCgoqICOp0Ovr6+N7T7+vri+PHjxvdjx46FRqOBm5sbPvzwQzg48I/cmrS1HxMTE3Ho0CFotVoEBgZi8+bNiI+Px1tvvYURI0ZAr9fjlVde4RNdVqCjfdpaO4mnI32q0+mQkZGBsLAw4ziTDRs2YNCgQZb8FuhPOtKfcrkczzzzjHFQ86xZs0zuS/4W7mT8F6Y07Ny5s8X2MWPGYMyYMRauhsyhtT5trZ2sX2t9p9frLVwJmUNr/alSqTp0XN7qaicfHx/I5fJmg6rUajX8/PxEqopMxX6UHvap9LBPpUXs/mTwaSeFQoGoqChkZWUZ2/R6PbKysnhZ3IawH6WHfSo97FNpEbs/eavrJmpqanDq1Cnj++LiYqhUKnh7e6NXr15IS0tDcnIyBg8ejJiYGCxduhRarRYpKSkiVk3/jf0oPexT6WGfSotV96dJz4DZmR9//NEAoNkrOTnZuM+yZcsMvXr1MigUCkNMTIxh37594hVMLWI/Sg/7VHrYp9Jizf3JtbqIiIjIbnCMDxEREdkNBh8iIiKyGww+REREZDcYfIiIiMhuMPgQERGR3WDwISIiIrvB4ENERER2g8GHiIiI7AaDDxEREdkNBh8iIiKyGww+REREZDcYfIiIiMhu/H/IdQqG6q2+zQAAAABJRU5ErkJggg==",
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.4"
3
+ version: "1.0.6"
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.4"
8
+ version = "1.0.6"
9
9
  authors = [
10
10
  { name="Charles Gannon", email="cgannon@ucmerced.edu" },
11
11
  ]
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env python3
2
+ from subscript.defaults import ParamKeys
3
+ import numpy as np
4
+
5
+ KEY_MAP_SYMPHONY_DEFAULT = {
6
+ ParamKeys.mass_basic : {
7
+ 'SymphonyName' : 'mpeak',
8
+ 'PerSnap' : False,
9
+ 'conversion' : 1.0,
10
+ },
11
+ ParamKeys.mass_bound : {
12
+ 'SymphonyName' : 'mvir',
13
+ 'PerSnap' : True,
14
+ 'conversion' : 1.0,
15
+ },
16
+ ParamKeys.rvir : {
17
+ 'SymphonyName' : 'rvir',
18
+ 'PerSnap' : True,
19
+ 'conversion' : 1E-3,
20
+ },
21
+ ParamKeys.x : {
22
+ 'SymphonyName' : 'x',
23
+ 'PerSnap' : True,
24
+ 'conversion' : 1E-3,
25
+ },
26
+ ParamKeys.y : {
27
+ 'SymphonyName' : 'x',
28
+ 'PerSnap' : True,
29
+ 'conversion' : 1E-3,
30
+ },
31
+ ParamKeys.z : {
32
+ 'SymphonyName' : 'x',
33
+ 'PerSnap' : True,
34
+ 'conversion' : 1E-3,
35
+ },
36
+ ParamKeys.z_lastisolated: {
37
+ 'SymphonyName' : 'merger_snap',
38
+ 'PerSnap' : False,
39
+ 'conversion' : 1.0,
40
+ },
41
+ 'custom_id' : {
42
+ 'SymphonyName' : 'id',
43
+ 'PerSnap' : True,
44
+ 'conversion' : 1.0,
45
+ },
46
+ }
47
+
48
+ def symphony_to_galacticus_like_dict(sim_data, z_snap, key_map=KEY_MAP_SYMPHONY_DEFAULT, isnap=-1, tree_index=1):
49
+ ok = sim_data[0]['ok'][:, isnap]
50
+ h, hist = sim_data[0][ok], sim_data[1][ok]
51
+ out = {}
52
+
53
+ for gparamkey, symmap in key_map.items():
54
+ if symmap['PerSnap']:
55
+ val = np.astype(h[symmap['SymphonyName']][:, isnap], float)
56
+ else:
57
+ val = np.astype(hist[symmap['SymphonyName']], float)
58
+
59
+ val *= symmap['conversion']
60
+
61
+ # Hard code special cases
62
+ coord_indexes = {
63
+ ParamKeys.x: 0,
64
+ ParamKeys.y: 1,
65
+ ParamKeys.z: 2
66
+ }
67
+
68
+ # Split coordinates from 3 vector into individual entries
69
+ if gparamkey in coord_indexes.keys():
70
+ n = coord_indexes[gparamkey]
71
+ val = val[:, n]
72
+
73
+ # Only the snapshot indexes are stored, get the redshift for the given snapshot index
74
+ if gparamkey == ParamKeys.z_lastisolated:
75
+ val = z_snap[np.astype(val, int)]
76
+
77
+ out[gparamkey] = val
78
+
79
+ # Assign tree index to all subhalos
80
+ nodecount = out.values().__iter__().__next__().shape[0]
81
+ out['custom_node_tree'] = tree_index * np.ones(nodecount, dtype=int)
82
+
83
+ # The first halo is the host
84
+ out[ParamKeys.is_isolated] = np.ones(nodecount, dtype=int)
85
+ out[ParamKeys.is_isolated][0] = 1
86
+
87
+ return out
@@ -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.
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env python3
2
+ import numpy as np
3
+ from subscript.defaults import ParamKeys
4
+ from numpy import testing as npt
5
+ from subscript.external import symphony_to_galacticus_like_dict, KEY_MAP_SYMPHONY_DEFAULT
6
+
7
+
8
+ def test_symphony_conversion():
9
+ h_mock = np.array([[( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
10
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
11
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
12
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
13
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
14
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
15
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
16
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
17
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
18
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),
19
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),],
20
+ [(161191255, 1.1802858e+08, 10.73, 1.4001675, [-352.33643 , -466.7435 , 399.61328 ], [ 230.34 , 86.240005, -149.66 ], True, 11.92505 , 31.378775),
21
+ (161763033, 1.1762858e+08, 10.58, 2.1060712, [-314.90338 , -456.68347 , 377.55533 ], [ 239.53 , 99.67 , -161.12 ], True, 12.00846 , 30.496603),
22
+ (162334212, 1.1682858e+08, 10.83, 1.5075221, [-274.99142 , -444.41937 , 353.44006 ], [ 244.91 , 112.77 , -170.87 ], True, 12.077489 , 33.516068),
23
+ (162905122, 1.1601429e+08, 10.75, 1.677781 , [-235.31105 , -429.24124 , 326.8972 ], [ 249.5 , 126.96 , -182.73001 ], True, 12.145057 , 33.39693 ),
24
+ (163473737, 1.1601429e+08, 11.17, 1.9568021, [-192.91576 , -411.1923 , 297.21194 ], [ 255.76001 , 143.56999 , -195.86 ], True, 12.240316 , 38.10785 ),
25
+ (164041230, 1.1641429e+08, 10.75, 1.6198878, [-149.09872 , -389.31595 , 264.40155 ], [ 263.41 , 166.73001 , -210.83 ], True, 12.349269 , 34.10137 ),
26
+ (164614912, 1.1641429e+08, 10.82, 1.5401733, [-103.52247 , -361.36618 , 227.9414 ], [ 272.7 , 195.22 , -228.29 ], True, 12.4436655, 35.222027),
27
+ (165176558, 1.1601429e+08, 10.94, 1.2020737, [ -55.2754 , -326.9403 , 187.49542 ], [ 283.72 , 230.87999 , -247.72 ], True, 12.523146 , 37.016132),
28
+ (165729990, 1.1521429e+08, 10.46, 1.8375131, [ -4.342098, -285.045 , 142.50906 ], [ 291.55 , 276.11002 , -272.67 ], True, 12.587252 , 32.767822),
29
+ (166275341, 1.1360000e+08, 9.95, 1.1902572, [ 48.24502 , -232.74557 , 91.75982 ], [ 291.81 , 339.43 , -304.88998 ], True, 12.620098 , 28.667397),
30
+ ( -1, -1.0000000e+00, -1. , -1. , [ -1. , -1. , -1. ], [ -1. , -1. , -1. ], False, -1. , -1. ),]],
31
+ dtype=[('id', '<i4'), ('mvir', '<f4'), ('vmax', '<f4'), ('rvmax', '<f4'), ('x', '<f4', (3,)), ('v', '<f4', (3,)), ('ok', '?'), ('rvir', '<f4'), ('cvir', '<f4')]).T
32
+
33
+ hist_mock = np.array([(1.49857152e+08, 22.2 , 81, 6.6185818e-04, 13600455, 13600542, True, False, True, -1, 81, 232141, False, 1.21257144e+08, 0, 0, 0, 0, 0, 0),
34
+ (1.24471432e+08, 13.12, 134, 6.8571426e-05, 30015901, 30016099, True, False, True, -1, 134, 569486, False, 1.22057144e+08, 0, 0, 0, 0, 0, 0),
35
+ (1.21257144e+08, 12.83, 157, 2.1584741e-05, 29358255, 29358454, True, False, True, -1, 157, 561426, False, 1.21257144e+08, 0, 0, 0, 0, 0, 0),
36
+ (1.21257144e+08, 12.02, 225, 9.6484882e-06, 27526539, 27526714, True, False, True, -1, 225, 536412, False, 1.21257144e+08, 0, 0, 0, 0, 0, 0),
37
+ (1.21257144e+08, 13.89, 168, 4.8911315e-06, 31447571, 31447779, True, False, True, 307964, 127, 585027, False, 1.21257144e+08, 0, 0, 0, 0, 0, 0),
38
+ (1.24071432e+08, 13.45, 154, 2.6225385e-05, 29468890, 29469053, True, False, True, 272054, 153, 562801, False, 1.23671432e+08, 0, 0, 0, 0, 0, 0),
39
+ (1.21257144e+08, 12.65, 206, 8.1003436e-06, 105872378, 105872578, True, False, True, 1769091, 169, 1877999, False, 1.21257144e+08, 0, 0, 0, 0, 0, 0),
40
+ (1.21257144e+08, 16.5 , 140, 1.9619740e-05, 14126887, 14127033, True, False, True, 562239, 123, 247818, False, 1.21257144e+08, 0, 0, 0, 0, 0, 0),
41
+ (1.21257144e+08, 15.84, 165, 1.7540825e-06, 16509517, 16509676, True, False, True, 303394, 108, 307590, False, 1.21257144e+08, 0, 0, 0, 0, 0, 0),
42
+ (1.21257144e+08, 11.88, 230, 9.2452192e-06, 27391623, 27391782, True, False, True, -1, 230, 534378, False, 1.21257144e+08, 0, 0, 0, 0, 0, 0),
43
+ (1.21257144e+08, 15.84, 165, 1.7540825e-06, 16509517, 16509676, True, False, True, 303394, 108, 307590, False, 1.21257144e+08, 0, 0, 0, 0, 0, 0),],
44
+
45
+ dtype=[('mpeak', '<f4'), ('vpeak', '<f4'), ('merger_snap', '<i4'), ('merger_ratio', '<f4'), ('start', '<i4'), ('end', '<i4'), ('is_real', '?'), ('is_disappear', '?'), ('is_main_sub', '?'), ('preprocess', '<i4'), ('first_infall_snap', '<i4'), ('branch_idx', '<i4'), ('false_selection', '?'), ('mpeak_pre', '<f4'), ('conv_snap_discrete', '<i4'), ('conv_snap_eps', '<i4'), ('conv_snap_relax', '<i4'), ('conv_snap_relax_hydro', '<i4'), ('disrupt_snap', '<i4'), ('disrupt_snap_rs', '<i4')])
46
+
47
+ z_snap = np.array([1.90000003e+01, 1.87466623e+01, 1.84965337e+01, 1.82495730e+01,
48
+ 1.80057406e+01, 1.77649972e+01, 1.75273028e+01, 1.72926197e+01,
49
+ 1.70609089e+01, 1.68321335e+01, 1.66062556e+01, 1.63832393e+01,
50
+ 1.61630475e+01, 1.59456452e+01, 1.57309964e+01, 1.55190669e+01,
51
+ 1.53098215e+01, 1.51032269e+01, 1.48992489e+01, 1.46978550e+01,
52
+ 1.44990119e+01, 1.43026877e+01, 1.41088501e+01, 1.39174681e+01,
53
+ 1.37285100e+01, 1.35419455e+01, 1.33577443e+01, 1.31758762e+01,
54
+ 1.29963121e+01, 1.28190222e+01, 1.26439783e+01, 1.24711514e+01,
55
+ 1.23005139e+01, 1.21320376e+01, 1.19656956e+01, 1.18014605e+01,
56
+ 1.16393059e+01, 1.14792051e+01, 1.13211324e+01, 1.11650619e+01,
57
+ 1.10109685e+01, 1.08588267e+01, 1.07086124e+01, 1.05603006e+01,
58
+ 1.04138676e+01, 1.02692893e+01, 1.01265423e+01, 9.98560373e+00,
59
+ 9.84645019e+00, 9.70905948e+00, 9.57340890e+00, 9.43947677e+00,
60
+ 9.30724097e+00, 9.17668036e+00, 9.04777337e+00, 8.92049941e+00,
61
+ 8.79483744e+00, 8.67076738e+00, 8.54826874e+00, 8.42732195e+00,
62
+ 8.30790701e+00, 8.19000484e+00, 8.07359598e+00, 7.95866180e+00,
63
+ 7.84518333e+00, 7.73314229e+00, 7.62252060e+00, 7.51330000e+00,
64
+ 7.40546303e+00, 7.29899187e+00, 7.19386952e+00, 7.09007859e+00,
65
+ 6.98760252e+00, 6.88642436e+00, 6.78652795e+00, 6.68789678e+00,
66
+ 6.59051510e+00, 6.49436681e+00, 6.39943654e+00, 6.30570863e+00,
67
+ 6.21316807e+00, 6.12179960e+00, 6.03158860e+00, 5.94252017e+00,
68
+ 5.85458009e+00, 5.76775381e+00, 5.68202735e+00, 5.59738690e+00,
69
+ 5.51381846e+00, 5.43130869e+00, 5.34984395e+00, 5.26941122e+00,
70
+ 5.18999722e+00, 5.11158925e+00, 5.03417436e+00, 4.95774019e+00,
71
+ 4.88227409e+00, 4.80776402e+00, 4.73419765e+00, 4.66156325e+00,
72
+ 4.58984879e+00, 4.51904284e+00, 4.44913368e+00, 4.38011014e+00,
73
+ 4.31196082e+00, 4.24467484e+00, 4.17824107e+00, 4.11264881e+00,
74
+ 4.04788749e+00, 3.98394641e+00, 3.92081534e+00, 3.85848387e+00,
75
+ 3.79694203e+00, 3.73617965e+00, 3.67618701e+00, 3.61695422e+00,
76
+ 3.55847181e+00, 3.50073010e+00, 3.44371988e+00, 3.38743173e+00,
77
+ 3.33185665e+00, 3.27698546e+00, 3.22280938e+00, 3.16931948e+00,
78
+ 3.11650720e+00, 3.06436382e+00, 3.01288100e+00, 2.96205024e+00,
79
+ 2.91186335e+00, 2.86231223e+00, 2.81338871e+00, 2.76508497e+00,
80
+ 2.71739301e+00, 2.67030523e+00, 2.62381385e+00, 2.57791142e+00,
81
+ 2.53259038e+00, 2.48784347e+00, 2.44366331e+00, 2.40004283e+00,
82
+ 2.35697483e+00, 2.31445242e+00, 2.27246859e+00, 2.23101661e+00,
83
+ 2.19008965e+00, 2.14968116e+00, 2.10978446e+00, 2.07039319e+00,
84
+ 2.03150083e+00, 1.99310111e+00, 1.95518785e+00, 1.91775479e+00,
85
+ 1.88079593e+00, 1.84430518e+00, 1.80827670e+00, 1.77270454e+00,
86
+ 1.73758302e+00, 1.70290633e+00, 1.66866893e+00, 1.63486517e+00,
87
+ 1.60148964e+00, 1.56853683e+00, 1.53600148e+00, 1.50387820e+00,
88
+ 1.47216187e+00, 1.44084725e+00, 1.40992932e+00, 1.37940299e+00,
89
+ 1.34926333e+00, 1.31950549e+00, 1.29012455e+00, 1.26111581e+00,
90
+ 1.23247448e+00, 1.20419599e+00, 1.17627566e+00, 1.14870903e+00,
91
+ 1.12149155e+00, 1.09461887e+00, 1.06808654e+00, 1.04189033e+00,
92
+ 1.01602591e+00, 9.90489147e-01, 9.65275821e-01, 9.40381903e-01,
93
+ 9.15803281e-01, 8.91536026e-01, 8.67576129e-01, 8.43919762e-01,
94
+ 8.20563016e-01, 7.97502127e-01, 7.74733379e-01, 7.52253010e-01,
95
+ 7.30057427e-01, 7.08142963e-01, 6.86506117e-01, 6.65143314e-01,
96
+ 6.44051139e-01, 6.23226108e-01, 6.02664894e-01, 5.82364099e-01,
97
+ 5.62320479e-01, 5.42530722e-01, 5.22991667e-01, 5.03700085e-01,
98
+ 4.84652892e-01, 4.65846944e-01, 4.47279233e-01, 4.28946692e-01,
99
+ 4.10846392e-01, 3.92975343e-01, 3.75330664e-01, 3.57909512e-01,
100
+ 3.40709009e-01, 3.23726406e-01, 3.06958896e-01, 2.90403801e-01,
101
+ 2.74058386e-01, 2.57920038e-01, 2.41986092e-01, 2.26254000e-01,
102
+ 2.10721164e-01, 1.95385101e-01, 1.80243278e-01, 1.65293275e-01,
103
+ 1.50532623e-01, 1.35958961e-01, 1.21569883e-01, 1.07363089e-01,
104
+ 9.33362322e-02, 7.94870706e-02, 6.58133165e-02, 5.23127664e-02,
105
+ 3.89832442e-02, 2.58225479e-02, 1.28285742e-02, 4.44089210e-16])
106
+
107
+ out = symphony_to_galacticus_like_dict(
108
+ sim_data=(h_mock, hist_mock),
109
+ z_snap=z_snap,
110
+ key_map=KEY_MAP_SYMPHONY_DEFAULT,
111
+ isnap=-1,
112
+ tree_index=2
113
+ )
114
+ # Ensure output size is correct
115
+ npt.assert_equal(out[ParamKeys.mass_basic].shape, (10,))
116
+
117
+ # Ensure outputs are expected
118
+ mass_basic_expect = np.asarray((1.49857152e+08, 1.24471432e+08, 1.21257144e+08, 1.21257144e+08, 1.21257144e+08, 1.24071432e+08, 1.21257144e+08, 1.21257144e+08, 1.21257144e+08, 1.21257144e+08))
119
+ npt.assert_allclose(out[ParamKeys.mass_basic], mass_basic_expect)
120
+
121
+ mass_bound_expect = np.asarray((1.1802858e+08, 1.1762858e+08, 1.1682858e+08, 1.1601429e+08, 1.1601429e+08,1.1641429e+08, 1.1641429e+08, 1.1601429e+08, 1.1521429e+08, 1.1360000e+08))
122
+ npt.assert_allclose(out[ParamKeys.mass_bound], mass_bound_expect)
123
+
124
+ rvir_expect = 1E-3 * np.asarray((11.92505, 12.00846, 12.077489, 12.145057,12.240316,12.349269,12.4436655,12.523146,12.587252,12.620098))
125
+ npt.assert_allclose(out[ParamKeys.rvir], rvir_expect)
126
+
127
+ r_expect = 1E-3 * np.asarray(([-352.33643 , -466.7435 , 399.61328 ],
128
+ [-314.90338 , -456.68347 , 377.55533 ],
129
+ [-274.99142 , -444.41937 , 353.44006 ],
130
+ [-235.31105 , -429.24124 , 326.8972 ],
131
+ [-192.91576 , -411.1923 , 297.21194 ],
132
+ [-149.09872 , -389.31595 , 264.40155 ],
133
+ [-103.52247 , -361.36618 , 227.9414 ],
134
+ [ -55.2754 , -326.9403 , 187.49542 ],
135
+ [ -4.342098, -285.045 , 142.50906 ],
136
+ [ 48.24502 , -232.74557 , 91.75982 ]))
137
+
138
+ x_expect = r_expect[:, 0]
139
+ npt.assert_allclose(out[ParamKeys.x], x_expect)
140
+
141
+ y_expect = r_expect[:, 1]
142
+ npt.assert_allclose(out[ParamKeys.y], y_expect)
143
+
144
+ z_expect = r_expect[:, 2]
145
+ npt.assert_allclose(out[ParamKeys.z], z_expect)
146
+
147
+ z_lastisolated_expect = np.array([6.1217996 , 2.62381385, 1.70290633, 0.13595896, 1.34926333,
148
+ 1.8082767 , 0.44727923, 2.35697483, 1.44084725, 0.06581332])
149
+ npt.assert_allclose(out[ParamKeys.z_lastisolated], z_lastisolated_expect)
150
+
151
+ iso_expect = np.ones(10, dtype=int)
152
+ iso_expect[0] = 1
153
+ npt.assert_allclose(out[ParamKeys.is_isolated], iso_expect)
154
+
155
+ id_expect = np.asarray((161191255, 161763033, 162334212, 162905122, 163473737, 164041230, 164614912, 165176558, 165729990, 166275341))
156
+ npt.assert_allclose(out['custom_id'], id_expect)
157
+
158
+ tree_expect = 2 * np.ones(10, dtype=int)
159
+ npt.assert_allclose(out['custom_node_tree'], tree_expect)
160
+
161
+
162
+
163
+
164
+
165
+
166
+ if __name__ == '__main__':
167
+ test_symphony_conversion()
@@ -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