jaxion 0.0.6__tar.gz → 0.0.7__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.
- {jaxion-0.0.6 → jaxion-0.0.7}/PKG-INFO +1 -1
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/defaults.json +8 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/particles.py +104 -1
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/simulation.py +37 -9
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/visualization.py +8 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion.egg-info/PKG-INFO +1 -1
- {jaxion-0.0.6 → jaxion-0.0.7}/tests/test_examples.py +4 -4
- {jaxion-0.0.6 → jaxion-0.0.7}/LICENSE +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/README.md +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/__init__.py +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/analysis.py +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/constants.py +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/cosmology.py +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/gravity.py +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/hydro.py +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/quantum.py +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion/utils.py +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion.egg-info/SOURCES.txt +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion.egg-info/dependency_links.txt +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion.egg-info/requires.txt +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/jaxion.egg-info/top_level.txt +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/pyproject.toml +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/requirements.txt +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/setup.cfg +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/tests/test_analysis.py +0 -0
- {jaxion-0.0.6 → jaxion-0.0.7}/tests/test_cosmology.py +0 -0
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
"default": 1.0,
|
|
49
49
|
"description": "simulation end time [kpc/(km/s)] or [redshift] (cosmology=true)."
|
|
50
50
|
},
|
|
51
|
+
"safety_factor": {
|
|
52
|
+
"default": 1.0,
|
|
53
|
+
"description": "safety factor for time stepping."
|
|
54
|
+
},
|
|
51
55
|
"adaptive": {
|
|
52
56
|
"default": false,
|
|
53
57
|
"description": "switch on for adaptive time stepping."
|
|
@@ -95,6 +99,10 @@
|
|
|
95
99
|
"particle_mass": {
|
|
96
100
|
"default": 1.0,
|
|
97
101
|
"description": "particle mass [M_sun]."
|
|
102
|
+
},
|
|
103
|
+
"accrete_gas": {
|
|
104
|
+
"default": false,
|
|
105
|
+
"description": "switch on to accrete gas."
|
|
98
106
|
}
|
|
99
107
|
},
|
|
100
108
|
"cosmology": {
|
|
@@ -18,7 +18,7 @@ def get_cic_indices_and_weights(pos, dx, resolution):
|
|
|
18
18
|
return i, ip1, weight_i, weight_ip1
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
def bin_particles(pos, dx, resolution,
|
|
21
|
+
def bin_particles(pos, m_particles, dx, resolution, multiple_masses):
|
|
22
22
|
"""Bin the particles into the grid using cloud-in-cell weights."""
|
|
23
23
|
nx = resolution
|
|
24
24
|
n_particle = pos.shape[0]
|
|
@@ -27,6 +27,10 @@ def bin_particles(pos, dx, resolution, m_particle):
|
|
|
27
27
|
|
|
28
28
|
def deposit_particle(s, rho):
|
|
29
29
|
"""Deposit the particle mass into the grid."""
|
|
30
|
+
if multiple_masses:
|
|
31
|
+
m_particle = m_particles[s]
|
|
32
|
+
else:
|
|
33
|
+
m_particle = m_particles
|
|
30
34
|
fac = m_particle / (dx * dx * dx)
|
|
31
35
|
rho = rho.at[i[s, 0], i[s, 1], i[s, 2]].add(
|
|
32
36
|
w_i[s, 0] * w_i[s, 1] * w_i[s, 2] * fac
|
|
@@ -112,3 +116,102 @@ def particles_drift(pos, vel, dt, box_size):
|
|
|
112
116
|
pos = jnp.mod(pos, jnp.array([box_size, box_size, box_size]))
|
|
113
117
|
|
|
114
118
|
return pos
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def particles_accrete_gas(mass, rho, pos, G, sound_speed, dx, dt):
|
|
122
|
+
"""Accrete gas onto particles (Bondi)."""
|
|
123
|
+
n_particle = pos.shape[0]
|
|
124
|
+
resolution = rho.shape[0]
|
|
125
|
+
i, ip1, w_i, w_ip1 = get_cic_indices_and_weights(pos, dx, resolution)
|
|
126
|
+
d_mass = jnp.zeros_like(mass)
|
|
127
|
+
d_rho = jnp.zeros_like(rho)
|
|
128
|
+
lam = jnp.exp(1.5) / 4.0 # ≈ 1.12
|
|
129
|
+
vol = dx**3
|
|
130
|
+
|
|
131
|
+
def accrete(s, deltas):
|
|
132
|
+
"""Deposit the particle mass into the grid."""
|
|
133
|
+
d_mass, d_rho = deltas
|
|
134
|
+
dM_fac = dt * 4.0 * jnp.pi * lam * (G * mass[s]) ** 2 / sound_speed**3
|
|
135
|
+
# dM = dM_fac * rho
|
|
136
|
+
|
|
137
|
+
dm = w_i[s, 0] * w_i[s, 1] * w_i[s, 2] * dM_fac * rho[i[s, 0], i[s, 1], i[s, 2]]
|
|
138
|
+
d_rho = d_rho.at[i[s, 0], i[s, 1], i[s, 2]].add(-dm / vol)
|
|
139
|
+
d_mass = d_mass.at[s].add(dm)
|
|
140
|
+
|
|
141
|
+
dm = (
|
|
142
|
+
w_ip1[s, 0]
|
|
143
|
+
* w_i[s, 1]
|
|
144
|
+
* w_i[s, 2]
|
|
145
|
+
* dM_fac
|
|
146
|
+
* rho[ip1[s, 0], i[s, 1], i[s, 2]]
|
|
147
|
+
)
|
|
148
|
+
d_rho = d_rho.at[ip1[s, 0], i[s, 1], i[s, 2]].add(-dm / vol)
|
|
149
|
+
d_mass = d_mass.at[s].add(dm)
|
|
150
|
+
|
|
151
|
+
dm = (
|
|
152
|
+
w_i[s, 0]
|
|
153
|
+
* w_ip1[s, 1]
|
|
154
|
+
* w_i[s, 2]
|
|
155
|
+
* dM_fac
|
|
156
|
+
* rho[i[s, 0], ip1[s, 1], i[s, 2]]
|
|
157
|
+
)
|
|
158
|
+
d_rho = d_rho.at[i[s, 0], ip1[s, 1], i[s, 2]].add(-dm / vol)
|
|
159
|
+
d_mass = d_mass.at[s].add(dm)
|
|
160
|
+
|
|
161
|
+
dm = (
|
|
162
|
+
w_i[s, 0]
|
|
163
|
+
* w_i[s, 1]
|
|
164
|
+
* w_ip1[s, 2]
|
|
165
|
+
* dM_fac
|
|
166
|
+
* rho[i[s, 0], i[s, 1], ip1[s, 2]]
|
|
167
|
+
)
|
|
168
|
+
d_rho = d_rho.at[i[s, 0], i[s, 1], ip1[s, 2]].add(-dm / vol)
|
|
169
|
+
d_mass = d_mass.at[s].add(dm)
|
|
170
|
+
|
|
171
|
+
dm = (
|
|
172
|
+
w_ip1[s, 0]
|
|
173
|
+
* w_ip1[s, 1]
|
|
174
|
+
* w_i[s, 2]
|
|
175
|
+
* dM_fac
|
|
176
|
+
* rho[ip1[s, 0], ip1[s, 1], i[s, 2]]
|
|
177
|
+
)
|
|
178
|
+
d_rho = d_rho.at[ip1[s, 0], ip1[s, 1], i[s, 2]].add(-dm / vol)
|
|
179
|
+
d_mass = d_mass.at[s].add(dm)
|
|
180
|
+
|
|
181
|
+
dm = (
|
|
182
|
+
w_ip1[s, 0]
|
|
183
|
+
* w_i[s, 1]
|
|
184
|
+
* w_ip1[s, 2]
|
|
185
|
+
* dM_fac
|
|
186
|
+
* rho[ip1[s, 0], i[s, 1], ip1[s, 2]]
|
|
187
|
+
)
|
|
188
|
+
d_rho = d_rho.at[ip1[s, 0], i[s, 1], ip1[s, 2]].add(-dm / vol)
|
|
189
|
+
d_mass = d_mass.at[s].add(dm)
|
|
190
|
+
|
|
191
|
+
dm = (
|
|
192
|
+
w_i[s, 0]
|
|
193
|
+
* w_ip1[s, 1]
|
|
194
|
+
* w_ip1[s, 2]
|
|
195
|
+
* dM_fac
|
|
196
|
+
* rho[i[s, 0], ip1[s, 1], ip1[s, 2]]
|
|
197
|
+
)
|
|
198
|
+
d_rho = d_rho.at[i[s, 0], ip1[s, 1], ip1[s, 2]].add(-dm / vol)
|
|
199
|
+
d_mass = d_mass.at[s].add(dm)
|
|
200
|
+
|
|
201
|
+
dm = (
|
|
202
|
+
w_ip1[s, 0]
|
|
203
|
+
* w_ip1[s, 1]
|
|
204
|
+
* w_ip1[s, 2]
|
|
205
|
+
* dM_fac
|
|
206
|
+
* rho[ip1[s, 0], ip1[s, 1], ip1[s, 2]]
|
|
207
|
+
)
|
|
208
|
+
d_rho = d_rho.at[ip1[s, 0], ip1[s, 1], ip1[s, 2]].add(-dm / vol)
|
|
209
|
+
d_mass = d_mass.at[s].add(dm)
|
|
210
|
+
|
|
211
|
+
return d_mass, d_rho
|
|
212
|
+
|
|
213
|
+
d_mass, d_rho = jax.lax.fori_loop(0, n_particle, accrete, (d_mass, d_rho))
|
|
214
|
+
mass = mass + d_mass
|
|
215
|
+
rho = rho + d_rho
|
|
216
|
+
|
|
217
|
+
return mass, rho
|
|
@@ -9,7 +9,12 @@ from .constants import constants
|
|
|
9
9
|
from .quantum import quantum_kick, quantum_drift, quantum_velocity
|
|
10
10
|
from .gravity import calculate_gravitational_potential
|
|
11
11
|
from .hydro import hydro_fluxes, hydro_accelerate
|
|
12
|
-
from .particles import
|
|
12
|
+
from .particles import (
|
|
13
|
+
particles_accelerate,
|
|
14
|
+
particles_drift,
|
|
15
|
+
particles_accrete_gas,
|
|
16
|
+
bin_particles,
|
|
17
|
+
)
|
|
13
18
|
from .cosmology import get_supercomoving_time_interval, get_next_scale_factor
|
|
14
19
|
from .utils import (
|
|
15
20
|
set_up_parameters,
|
|
@@ -95,7 +100,7 @@ class Simulation:
|
|
|
95
100
|
xones, static_argnums=0, in_shardings=None, out_shardings=sharding
|
|
96
101
|
)
|
|
97
102
|
|
|
98
|
-
#
|
|
103
|
+
# custom functions
|
|
99
104
|
self.custom_kick = None
|
|
100
105
|
self.custom_drift = None
|
|
101
106
|
self.custom_density = None
|
|
@@ -126,6 +131,11 @@ class Simulation:
|
|
|
126
131
|
if self.params["physics"]["particles"]:
|
|
127
132
|
self.state["pos"] = jnp.zeros((self.num_particles, 3))
|
|
128
133
|
self.state["vel"] = jnp.zeros((self.num_particles, 3))
|
|
134
|
+
if self.params["particles"]["accrete_gas"]:
|
|
135
|
+
self.state["mass"] = (
|
|
136
|
+
jnp.zeros(self.num_particles)
|
|
137
|
+
+ self.params["particles"]["particle_mass"]
|
|
138
|
+
)
|
|
129
139
|
|
|
130
140
|
if load_from_checkpoint:
|
|
131
141
|
options = ocp.CheckpointManagerOptions()
|
|
@@ -262,17 +272,19 @@ class Simulation:
|
|
|
262
272
|
if self.params["physics"]["hydro"]:
|
|
263
273
|
rho_bar += jnp.mean(state["rho"])
|
|
264
274
|
if self.params["physics"]["particles"]:
|
|
265
|
-
m_particle = self.params["particles"]["particle_mass"]
|
|
266
|
-
n_particles = self.num_particles
|
|
267
275
|
box_size = self.box_size
|
|
268
|
-
|
|
276
|
+
if self.params["particles"]["accrete_gas"]:
|
|
277
|
+
rho_bar += jnp.sum(state["mass"]) / box_size**3
|
|
278
|
+
else:
|
|
279
|
+
m_particle = self.params["particles"]["particle_mass"]
|
|
280
|
+
n_particles = self.num_particles
|
|
281
|
+
rho_bar += m_particle * n_particles / box_size**3
|
|
269
282
|
if self.custom_density is not None:
|
|
270
283
|
rho_bar += jnp.mean(self.custom_density(state))
|
|
271
284
|
return rho_bar
|
|
272
285
|
|
|
273
286
|
def _calc_grav_potential(self, state, k_sq):
|
|
274
287
|
G = constants["gravitational_constant"]
|
|
275
|
-
m_particle = self.params["particles"]["particle_mass"]
|
|
276
288
|
rho_bar = self._calc_rho_bar(state)
|
|
277
289
|
rho_tot = 0.0
|
|
278
290
|
if self.params["physics"]["quantum"]:
|
|
@@ -280,7 +292,17 @@ class Simulation:
|
|
|
280
292
|
if self.params["physics"]["hydro"]:
|
|
281
293
|
rho_tot += state["rho"]
|
|
282
294
|
if self.params["physics"]["particles"]:
|
|
283
|
-
|
|
295
|
+
multiple_masses = self.params["particles"]["accrete_gas"]
|
|
296
|
+
if multiple_masses:
|
|
297
|
+
m_particles = state["mass"]
|
|
298
|
+
rho_tot += bin_particles(
|
|
299
|
+
state["pos"], m_particles, self.dx, self.resolution, multiple_masses
|
|
300
|
+
)
|
|
301
|
+
else:
|
|
302
|
+
m_particles = self.params["particles"]["particle_mass"]
|
|
303
|
+
rho_tot += bin_particles(
|
|
304
|
+
state["pos"], m_particles, self.dx, self.resolution, multiple_masses
|
|
305
|
+
)
|
|
284
306
|
if self.custom_density is not None:
|
|
285
307
|
rho_tot += self.custom_density(state)
|
|
286
308
|
if self.params["physics"]["cosmology"]:
|
|
@@ -319,8 +341,8 @@ class Simulation:
|
|
|
319
341
|
num_cells = self.resolution**3
|
|
320
342
|
m_per_hbar = self.m_per_hbar
|
|
321
343
|
|
|
322
|
-
|
|
323
|
-
dt_kin =
|
|
344
|
+
safety = self.params["time"]["safety_factor"]
|
|
345
|
+
dt_kin = safety * (m_per_hbar / 6.0) * (dx * dx)
|
|
324
346
|
t_start = self.params["time"]["start"]
|
|
325
347
|
t_end = self.params["time"]["end"]
|
|
326
348
|
t_span = t_end - t_start
|
|
@@ -332,6 +354,7 @@ class Simulation:
|
|
|
332
354
|
use_particles = self.params["physics"]["particles"]
|
|
333
355
|
use_cosmology = self.params["physics"]["cosmology"]
|
|
334
356
|
use_external_potential = self.params["physics"]["external_potential"]
|
|
357
|
+
accrete_gas = self.params["particles"]["accrete_gas"]
|
|
335
358
|
save = self.params["output"]["save"]
|
|
336
359
|
use_custom = self.custom_kick is not None or self.custom_drift is not None
|
|
337
360
|
if use_custom:
|
|
@@ -435,6 +458,11 @@ class Simulation:
|
|
|
435
458
|
state["pos"] = particles_drift(state["pos"], state["vel"], dt, box_size)
|
|
436
459
|
if use_custom:
|
|
437
460
|
state = custom_drift(state, k_sq, dt)
|
|
461
|
+
if use_hydro and accrete_gas:
|
|
462
|
+
G = constants["gravitational_constant"]
|
|
463
|
+
state["mass"], state["rho"] = particles_accrete_gas(
|
|
464
|
+
state["mass"], state["rho"], state["pos"], G, c_sound, dx, dt
|
|
465
|
+
)
|
|
438
466
|
|
|
439
467
|
return state
|
|
440
468
|
|
|
@@ -82,6 +82,14 @@ def plot_sim(state, checkpoint_dir, i, params):
|
|
|
82
82
|
vmax=vmax,
|
|
83
83
|
extent=[0, nx, 0, nx],
|
|
84
84
|
)
|
|
85
|
+
if params["physics"]["particles"]:
|
|
86
|
+
# draw particles
|
|
87
|
+
box_size = params["domain"]["box_size"]
|
|
88
|
+
sx = (state["pos"][:, 0] / box_size) * nx
|
|
89
|
+
sy = (state["pos"][:, 1] / box_size) * nx
|
|
90
|
+
plt.plot(
|
|
91
|
+
sx, sy, color="red", marker=".", linestyle="None", markersize=5
|
|
92
|
+
)
|
|
85
93
|
ax.set_aspect("equal")
|
|
86
94
|
ax.get_xaxis().set_visible(False)
|
|
87
95
|
ax.get_yaxis().set_visible(False)
|
|
@@ -41,13 +41,13 @@ def test_heating_stars():
|
|
|
41
41
|
)
|
|
42
42
|
assert sim.resolution == 32
|
|
43
43
|
assert sim.state["t"] > 0.0
|
|
44
|
-
assert jnp.mean(jnp.abs(sim.state["psi"])) == pytest.approx(2574.
|
|
44
|
+
assert jnp.mean(jnp.abs(sim.state["psi"])) == pytest.approx(2574.395, rel=rel_tol)
|
|
45
45
|
assert jnp.mean(jnp.abs(sim.state["vel"][:, 0])) == pytest.approx(
|
|
46
|
-
16.
|
|
46
|
+
16.625353, rel=rel_tol
|
|
47
47
|
)
|
|
48
48
|
assert jnp.mean(jnp.abs(sim.state["vel"][:, 1])) == pytest.approx(
|
|
49
|
-
17.
|
|
49
|
+
17.345486, rel=rel_tol
|
|
50
50
|
)
|
|
51
51
|
assert jnp.mean(jnp.abs(sim.state["vel"][:, 2])) == pytest.approx(
|
|
52
|
-
18.
|
|
52
|
+
18.218296, rel=rel_tol
|
|
53
53
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|