makecloud 1.0.0__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.
- makecloud-1.0.0/MakeCloud.py +659 -0
- makecloud-1.0.0/PKG-INFO +34 -0
- makecloud-1.0.0/README.md +19 -0
- makecloud-1.0.0/calcGMCProps.py +111 -0
- makecloud-1.0.0/makecloud/__init__.py +0 -0
- makecloud-1.0.0/makecloud/params.txt +250 -0
- makecloud-1.0.0/makecloud.egg-info/PKG-INFO +34 -0
- makecloud-1.0.0/makecloud.egg-info/SOURCES.txt +12 -0
- makecloud-1.0.0/makecloud.egg-info/dependency_links.txt +1 -0
- makecloud-1.0.0/makecloud.egg-info/entry_points.txt +2 -0
- makecloud-1.0.0/makecloud.egg-info/requires.txt +4 -0
- makecloud-1.0.0/makecloud.egg-info/top_level.txt +3 -0
- makecloud-1.0.0/pyproject.toml +34 -0
- makecloud-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Usage: MakeCloud.py [options]
|
|
4
|
+
|
|
5
|
+
Options:
|
|
6
|
+
-h --help Show this screen.
|
|
7
|
+
--R=<pc> Outer radius of the cloud in pc [default: 10.0]
|
|
8
|
+
--M=<msun> Mass of the cloud in msun [default: 2e4]
|
|
9
|
+
--filename=<name> Name of the IC file to be generated
|
|
10
|
+
--N=<N> Number of gas particles [default: 2000000]
|
|
11
|
+
--density_exponent=<f> Power law exponent of the density profile [default: 0.0]
|
|
12
|
+
--spin=<f> Spin parameter: fraction of binding energy in solid-body rotation [default: 0.0]
|
|
13
|
+
--omega_exponent=<f> Powerlaw exponent of rotational frequency as a function of cylindrical radius [default: 0.0]
|
|
14
|
+
--turb_slope=<f> Slope of the turbulent power spectra [default: 2.0]
|
|
15
|
+
--turb_sol=<f> Fraction of turbulence in solenoidal modes [default: 0.5]
|
|
16
|
+
--alpha_turb=<f> Turbulent virial parameter (BM92 convention: 2Eturb/|Egrav|) [default: 2.]
|
|
17
|
+
--bturb=<f> Magnetic energy as a fraction of the binding energy [default: 0.1]
|
|
18
|
+
--bfixed=<f> Magnetic field in magnitude in code units, used instead of bturb if not set to zero [default: 0]
|
|
19
|
+
--minmode=<N> Minimum populated turbulent wavenumber for Gaussian initial velocity field, in units of pi/R [default: 2]
|
|
20
|
+
--turb_path=<name> Path to store turbulent velocity fields so that we only need to generate them once (defaults to ~/turb)
|
|
21
|
+
--glass_path=<name> Contains the the path of the glass file (defaults to your home directory)
|
|
22
|
+
--boxsize=<f> Simulation box size
|
|
23
|
+
--Mstar=<msun> Mass of the star/black hole, if any [default: 0.0]
|
|
24
|
+
--v_star=<vx,vy,vz> Velocity of the star [default: 0.0,0.0,0.0]
|
|
25
|
+
--x_star=<x,y,z> Position of the star, defaults to center of the box
|
|
26
|
+
--star_stage=<N> Evolutionary stage of the star/black hole [default: 7]
|
|
27
|
+
--derefinement Apply radial derefinement to ambient cells outside of 3* cloud radius
|
|
28
|
+
--no_diffuse_gas Remove diffuse ISM envelope fills the rest of the box with uniform density.
|
|
29
|
+
--phimode=<f> Relative amplitude of m=2 density perturbation (e.g. for Boss-Bodenheimer test) [default: 0.0]
|
|
30
|
+
--localdir Changes directory defaults assuming all files are used from local directory.
|
|
31
|
+
--B_unit=<gauss> Unit of magnetic field in gauss [default: 1.0]
|
|
32
|
+
--length_unit=<pc> Unit of length in pc [default: 1]
|
|
33
|
+
--mass_unit=<msun> Unit of mass in M_sun [default: 1]
|
|
34
|
+
--v_unit=<m/s> Unit of velocity in m/s [default: 1e3]
|
|
35
|
+
--unit_system=<name> Units system to adopt (options: starforge_classic (m/s - pc - Msun - T), FIRE (km/s - kpc - 1e10Msun - uG)) [default: None]
|
|
36
|
+
--turb_seed=<N> Random seed for turbulence initialization [default: 42]
|
|
37
|
+
--tmax=<N> Maximum time to run the simulation to, in units of the freefall time [default: 5]
|
|
38
|
+
--nsnap=<N> Number of snapshots per freefall time [default: 150]
|
|
39
|
+
--param_only Just makes the parameters file, not the IC
|
|
40
|
+
--fixed_ncrit=<f> Fixes ncrit to a specific value [default: 0.0]
|
|
41
|
+
--makebox Creates a second box IC of equivalent volume and mass to the cloud
|
|
42
|
+
--impact_dist=<b> Initial separation between cloud centers of mass in units of the cloud radius (0 is no cloud-cloud collision) [default: 0.0]
|
|
43
|
+
--impact_param=<b> Impact parameter of cloud-cloud collision in units of the cloud radius [default: 0.0]
|
|
44
|
+
--v_impact=<v> Impact velocity, in units of the cloud's RMS turbulent velocity [default: 1.0]
|
|
45
|
+
--impact_axis=<x> Axis along which collision occurs (z is along magnetic field lines) [default: x]
|
|
46
|
+
--makecylinder Creates a third, cylindrical IC of equivalent volume and mass to the cloud
|
|
47
|
+
--cyl_aspect_ratio=<f> Sets the aspect ratio of the cylinder, i.e. Length/Diameter [default: 10]
|
|
48
|
+
--Z=<solar> Metallicity of the cloud in Solar units (just for params file) [default: 1.0]
|
|
49
|
+
--ISRF=<solar> Interstellar radiation background of the cloud in Solar neighborhood units (just for params file) [default: 1.0]
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
import os
|
|
53
|
+
import numpy as np
|
|
54
|
+
from scipy import fftpack, interpolate
|
|
55
|
+
from scipy.spatial.distance import cdist
|
|
56
|
+
import h5py
|
|
57
|
+
from docopt import docopt
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_glass_coords(N_gas, glass_path, center_on_cell=False):
|
|
61
|
+
x = h5py.File(glass_path)["Coordinates"][:]
|
|
62
|
+
if not center_on_cell: # if we don't want a cell at the exact box center
|
|
63
|
+
np.random.seed(42)
|
|
64
|
+
x = (x + np.random.rand(x.shape[1])) % 1.0
|
|
65
|
+
Nx = len(x)
|
|
66
|
+
|
|
67
|
+
while len(x) * np.pi * 4 / 3 / 8 < N_gas:
|
|
68
|
+
print(
|
|
69
|
+
"Need %d particles, have %d. Tessellating 8 copies of the glass file to get required particle number"
|
|
70
|
+
% (N_gas * 8 / (4 * np.pi / 3), len(x))
|
|
71
|
+
)
|
|
72
|
+
x = np.concatenate(
|
|
73
|
+
[
|
|
74
|
+
x / 2 + i * np.array([0.5, 0, 0]) + j * np.array([0, 0.5, 0]) + k * np.array([0, 0, 0.5])
|
|
75
|
+
for i in range(2)
|
|
76
|
+
for j in range(2)
|
|
77
|
+
for k in range(2)
|
|
78
|
+
]
|
|
79
|
+
)
|
|
80
|
+
print("Glass loaded!")
|
|
81
|
+
order = x.max(axis=1).argsort()
|
|
82
|
+
return x[order]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def TurbField(res=256, minmode=2, maxmode=64, slope=2.0, sol_weight=1.0, seed=42):
|
|
86
|
+
freqs = fftpack.fftfreq(res)
|
|
87
|
+
freq3d = np.array(np.meshgrid(freqs, freqs, freqs, indexing="ij"))
|
|
88
|
+
intfreq = np.around(freq3d * res)
|
|
89
|
+
kSqr = np.sum(np.abs(freq3d) ** 2, axis=0)
|
|
90
|
+
intkSqr = np.sum(np.abs(intfreq) ** 2, axis=0)
|
|
91
|
+
VK = []
|
|
92
|
+
|
|
93
|
+
# apply ~k^-2 exp(-k^2/kmax^2) filter to white noise to get x, y, and z components of velocity field
|
|
94
|
+
for i in range(3):
|
|
95
|
+
np.random.seed(seed + i)
|
|
96
|
+
rand_phase = fftpack.fftn(
|
|
97
|
+
np.random.normal(size=kSqr.shape)
|
|
98
|
+
) # fourier transform of white noise
|
|
99
|
+
vk = rand_phase * (float(minmode) / res) ** 2 / (np.power(kSqr, slope/2.0) + 1e-300)
|
|
100
|
+
vk[intkSqr == 0] = 0.0
|
|
101
|
+
vk[intkSqr < minmode**2] *= (
|
|
102
|
+
intkSqr[intkSqr < minmode**2] ** 2 / minmode**4
|
|
103
|
+
) # smoother filter than mode-freezing; should give less "ringing" artifacts
|
|
104
|
+
vk *= np.exp(-intkSqr / maxmode**2)
|
|
105
|
+
|
|
106
|
+
VK.append(vk)
|
|
107
|
+
VK = np.array(VK)
|
|
108
|
+
|
|
109
|
+
vk_new = np.zeros_like(VK)
|
|
110
|
+
|
|
111
|
+
# do projection operator to get the correct mix of compressive and solenoidal
|
|
112
|
+
for i in range(3):
|
|
113
|
+
for j in range(3):
|
|
114
|
+
if i == j:
|
|
115
|
+
vk_new[i] += sol_weight * VK[j]
|
|
116
|
+
vk_new[i] += (1 - 2 * sol_weight) * freq3d[i] * freq3d[j] / (kSqr + 1e-300) * VK[j]
|
|
117
|
+
vk_new[:, kSqr == 0] = 0.0
|
|
118
|
+
VK = vk_new
|
|
119
|
+
|
|
120
|
+
vel = np.array([fftpack.ifftn(vk).real for vk in VK]) # transform back to real space
|
|
121
|
+
vel -= np.average(vel, axis=(1, 2, 3))[:, np.newaxis, np.newaxis, np.newaxis]
|
|
122
|
+
vel = vel / np.sqrt(np.sum(vel**2, axis=0).mean()) # normalize so that RMS is 1
|
|
123
|
+
return np.array(vel)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _load_params_template():
|
|
128
|
+
local = os.path.join(os.path.dirname(os.path.realpath(__file__)), "params.txt")
|
|
129
|
+
if os.path.exists(local):
|
|
130
|
+
return open(local).read()
|
|
131
|
+
from importlib.resources import files
|
|
132
|
+
return files("makecloud").joinpath("params.txt").read_text()
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def main():
|
|
136
|
+
arguments = docopt(__doc__)
|
|
137
|
+
R = float(arguments["--R"])
|
|
138
|
+
M_gas = float(arguments["--M"])
|
|
139
|
+
N_gas = int(float(arguments["--N"]) + 0.5)
|
|
140
|
+
M_star = float(arguments["--Mstar"])
|
|
141
|
+
v_star = np.array([float(v) for v in arguments["--v_star"].split(",")])
|
|
142
|
+
spin = float(arguments["--spin"])
|
|
143
|
+
omega_exponent = float(arguments["--omega_exponent"])
|
|
144
|
+
turbulence = float(arguments["--alpha_turb"]) / 2
|
|
145
|
+
seed = int(float(arguments["--turb_seed"]) + 0.5)
|
|
146
|
+
tmax = int(float(arguments["--tmax"]))
|
|
147
|
+
nsnap = int(float(arguments["--nsnap"]))
|
|
148
|
+
turb_slope = float(arguments["--turb_slope"])
|
|
149
|
+
turb_sol = float(arguments["--turb_sol"])
|
|
150
|
+
magnetic_field = float(arguments["--bturb"])
|
|
151
|
+
bfixed = float(arguments["--bfixed"])
|
|
152
|
+
minmode = int(arguments["--minmode"])
|
|
153
|
+
filename = arguments["--filename"]
|
|
154
|
+
diffuse_gas = not arguments["--no_diffuse_gas"]
|
|
155
|
+
param_only = arguments["--param_only"]
|
|
156
|
+
if arguments["--unit_system"] is not None:
|
|
157
|
+
match arguments["--unit_system"]:
|
|
158
|
+
case "starforge_classic":
|
|
159
|
+
length_unit_pc = 1
|
|
160
|
+
mass_unit_Msun = 1
|
|
161
|
+
v_unit_SI = 1
|
|
162
|
+
B_unit_gauss = 1e4
|
|
163
|
+
case "FIRE":
|
|
164
|
+
length_unit_pc = 1e3
|
|
165
|
+
mass_unit_Msun = 1e10
|
|
166
|
+
v_unit_SI = 1e3
|
|
167
|
+
B_unit_gauss = 1
|
|
168
|
+
else:
|
|
169
|
+
length_unit_pc = float(arguments["--length_unit"])
|
|
170
|
+
mass_unit_Msun = float(arguments["--mass_unit"])
|
|
171
|
+
v_unit_SI = float(arguments["--v_unit"])
|
|
172
|
+
B_unit_gauss = float(arguments["--B_unit"])
|
|
173
|
+
|
|
174
|
+
t_unit = length_unit_pc / v_unit_SI
|
|
175
|
+
|
|
176
|
+
G = 4300.71 * v_unit_SI**-2 * mass_unit_Msun / length_unit_pc
|
|
177
|
+
makebox = arguments["--makebox"]
|
|
178
|
+
impact_param = float(arguments["--impact_param"])
|
|
179
|
+
impact_dist = float(arguments["--impact_dist"])
|
|
180
|
+
v_impact = float(arguments["--v_impact"])
|
|
181
|
+
impact_axis = arguments["--impact_axis"]
|
|
182
|
+
makecylinder = arguments["--makecylinder"]
|
|
183
|
+
cyl_aspect_ratio = float(arguments["--cyl_aspect_ratio"])
|
|
184
|
+
fixed_ncrit = float(arguments["--fixed_ncrit"])
|
|
185
|
+
density_exponent = float(arguments["--density_exponent"])
|
|
186
|
+
metallicity = float(arguments["--Z"])
|
|
187
|
+
ISRF = float(arguments["--ISRF"])
|
|
188
|
+
if arguments["--turb_path"]:
|
|
189
|
+
turb_path = arguments["--turb_path"]
|
|
190
|
+
else:
|
|
191
|
+
turb_path = os.path.expanduser("~") + "/turb"
|
|
192
|
+
if arguments["--glass_path"]:
|
|
193
|
+
glass_path = arguments["--glass_path"]
|
|
194
|
+
else:
|
|
195
|
+
prefix = os.path.expanduser("~") + "/.makecloud_glass"
|
|
196
|
+
glass_path = prefix + "/glass_256.hdf5"
|
|
197
|
+
if not os.path.exists(glass_path):
|
|
198
|
+
if not os.path.isdir(prefix):
|
|
199
|
+
os.mkdir(prefix)
|
|
200
|
+
import urllib.request
|
|
201
|
+
|
|
202
|
+
print("Downloading glass file...")
|
|
203
|
+
urllib.request.urlretrieve(
|
|
204
|
+
"https://users.flatironinstitute.org/~mgrudic/glass/glass_256.hdf5",
|
|
205
|
+
glass_path,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
if arguments["--boxsize"] is not None:
|
|
209
|
+
boxsize = float(arguments["--boxsize"])
|
|
210
|
+
else:
|
|
211
|
+
boxsize = 10 * R
|
|
212
|
+
|
|
213
|
+
if arguments["--x_star"]:
|
|
214
|
+
x_star = np.array([float(x) for x in arguments["--x_star"].split(",")])
|
|
215
|
+
else: # default to center of box
|
|
216
|
+
x_star = np.repeat(0.5 * boxsize, 3)
|
|
217
|
+
|
|
218
|
+
derefinement = arguments["--derefinement"]
|
|
219
|
+
|
|
220
|
+
res_effective = int(N_gas ** (1.0 / 3.0) + 0.5)
|
|
221
|
+
phimode = float(arguments["--phimode"])
|
|
222
|
+
|
|
223
|
+
filename = (
|
|
224
|
+
"M%3.2g_" % (M_gas)
|
|
225
|
+
+ ("Mstar%g_" % (M_star) if M_star > 0 else "")
|
|
226
|
+
+ ("rho_exp%g_" % (-density_exponent) if density_exponent < 0 else "")
|
|
227
|
+
+ "R%g_Z%g_S%g_A%g_B%g_I%g_Res%d_n%d_sol%g"
|
|
228
|
+
% (
|
|
229
|
+
R,
|
|
230
|
+
metallicity,
|
|
231
|
+
spin,
|
|
232
|
+
2 * turbulence,
|
|
233
|
+
magnetic_field,
|
|
234
|
+
ISRF,
|
|
235
|
+
res_effective,
|
|
236
|
+
minmode,
|
|
237
|
+
# turb_slope,
|
|
238
|
+
turb_sol,
|
|
239
|
+
)
|
|
240
|
+
+ ("_%d" % seed)
|
|
241
|
+
+ ("_collision_%g_%g_%g_%s" % (impact_dist, impact_param, v_impact, impact_axis) if impact_dist > 0 else "")
|
|
242
|
+
+ ".hdf5"
|
|
243
|
+
)
|
|
244
|
+
filename = filename.replace("+", "").replace("e0", "e")
|
|
245
|
+
filename = "".join(filename.split())
|
|
246
|
+
|
|
247
|
+
dm = M_gas / N_gas
|
|
248
|
+
dm_solar = dm / mass_unit_Msun
|
|
249
|
+
rho_avg = 3 * M_gas / R**3 / (4 * np.pi)
|
|
250
|
+
if dm_solar < 0.1: # if we're doing something marginally IMF-resolving
|
|
251
|
+
softening = 3.11e-5 # ~6.5 AU, minimum sink radius is 2.8 times that (~18 AU)
|
|
252
|
+
ncrit = 1e13 # ~100x the opacity limit
|
|
253
|
+
else: # something more FIRE-like, where we rely on a sub-grid prescription turning gas into star particles
|
|
254
|
+
softening = 0.1
|
|
255
|
+
ncrit = 100
|
|
256
|
+
|
|
257
|
+
if fixed_ncrit:
|
|
258
|
+
ncrit = fixed_ncrit
|
|
259
|
+
|
|
260
|
+
tff = (3 * np.pi / (32 * G * rho_avg)) ** 0.5
|
|
261
|
+
L = (4 * np.pi * R**3 / 3) ** (1.0 / 3) # volume-equivalent box size
|
|
262
|
+
vrms = (6 / 5 * G * M_gas / R) ** 0.5 * turbulence**0.5
|
|
263
|
+
|
|
264
|
+
if turbulence:
|
|
265
|
+
tcross = L / vrms
|
|
266
|
+
else:
|
|
267
|
+
tcross = tff
|
|
268
|
+
|
|
269
|
+
turbenergy = (
|
|
270
|
+
0.019111097819633344 * vrms**3 / L
|
|
271
|
+
) # ST_Energy sets the dissipation rate of SPECIFIC energy ~ v^2 / (L/v) ~ v^3/L
|
|
272
|
+
|
|
273
|
+
paramsfile = _load_params_template()
|
|
274
|
+
|
|
275
|
+
jet_particle_mass = min(dm, max(1e-4, dm / 10.0))
|
|
276
|
+
MS_wind_particle_mass = (
|
|
277
|
+
jet_particle_mass / 10
|
|
278
|
+
) # MS winds have lower mdot than jets, so we should be able to better resolve them this way
|
|
279
|
+
|
|
280
|
+
replacements = {
|
|
281
|
+
"NAME": filename.replace(".hdf5", ""),
|
|
282
|
+
"DTSNAP": tff / nsnap,
|
|
283
|
+
"MAXTIMESTEP": tff / (nsnap),
|
|
284
|
+
"SOFTENING": softening,
|
|
285
|
+
"GASSOFT": 2.0e-8,
|
|
286
|
+
"TMAX": tff * tmax,
|
|
287
|
+
"RHOMAX": ncrit,
|
|
288
|
+
"BOXSIZE": boxsize,
|
|
289
|
+
"OUTFOLDER": "output",
|
|
290
|
+
"JET_PART_MASS": jet_particle_mass,
|
|
291
|
+
"MS_WIND_PART_MASS": MS_wind_particle_mass,
|
|
292
|
+
"BH_SEED_MASS": dm / 2.0,
|
|
293
|
+
"TURBDECAY": tcross / 2,
|
|
294
|
+
"TURBENERGY": turbenergy,
|
|
295
|
+
"TURBFREQ": tcross / 20,
|
|
296
|
+
"TURB_KMIN": int(100 * 2 * np.pi / L) / 100.0,
|
|
297
|
+
"TURB_KMAX": int(100 * 4 * np.pi / (L) + 1) / 100.0,
|
|
298
|
+
"TURB_SIGMA": (M_gas/2e4)**0.5 * (R/10)**-0.5 * 600 * turbulence**0.5,
|
|
299
|
+
"TURB_MINLAMBDA": int(100 * R / 2) / 100,
|
|
300
|
+
"TURB_MAXLAMBDA": int(100 * R * 2) / 100,
|
|
301
|
+
"TURB_COHERENCE_TIME": tcross / 2,
|
|
302
|
+
"UNIT_L": 3.085678e18 * length_unit_pc,
|
|
303
|
+
"UNIT_M": 1.989e33 * mass_unit_Msun,
|
|
304
|
+
"UNIT_V": v_unit_SI * 1e2,
|
|
305
|
+
"UNIT_B": B_unit_gauss,
|
|
306
|
+
"ZINIT": metallicity,
|
|
307
|
+
"ISRF": ISRF,
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
for k, r in replacements.items():
|
|
311
|
+
paramsfile = paramsfile.replace(k, (r if isinstance(r, str) else "{:.2e}".format(r)))
|
|
312
|
+
|
|
313
|
+
open("params_" + filename.replace(".hdf5", "") + ".txt", "w").write(paramsfile)
|
|
314
|
+
if makebox:
|
|
315
|
+
replacements_box = replacements.copy()
|
|
316
|
+
replacements_box["NAME"] = filename.replace(".hdf5", "_BOX")
|
|
317
|
+
replacements_box["BOXSIZE"] = L
|
|
318
|
+
replacements_box["TURB_MINLAMBDA"] = int(100 * L / 2) / 100
|
|
319
|
+
replacements_box["TURB_MAXLAMBDA"] = int(100 * L * 2) / 100
|
|
320
|
+
paramsfile = _load_params_template()
|
|
321
|
+
for k in replacements_box.keys():
|
|
322
|
+
paramsfile = paramsfile.replace(k, str(replacements_box[k]))
|
|
323
|
+
open("params_" + filename.replace(".hdf5", "") + "_BOX.txt", "w").write(paramsfile)
|
|
324
|
+
if makecylinder:
|
|
325
|
+
# Get cylinder params
|
|
326
|
+
R_cyl = R * np.sqrt(np.pi / (4 * cyl_aspect_ratio)) # surface density equivalent cylinder
|
|
327
|
+
L_cyl = R_cyl * 2 * cyl_aspect_ratio
|
|
328
|
+
vrms_cyl = (
|
|
329
|
+
(2 * G * M_gas / L_cyl) ** 0.5 * turbulence** 0.5
|
|
330
|
+
) # the potential is different for a cylinder than for a sphere, so we need to rescale vrms to get the right alpha, using E_grav_cyl = -GM**2/L
|
|
331
|
+
vrms_cyl *= 0.71 # additional scaling found numerically to make the stirring run reproduce the right alpha and filament length (similarly determined numerical factor added to GIZMO)
|
|
332
|
+
tcross_cyl = 2 * R_cyl / vrms_cyl
|
|
333
|
+
boxsize_cyl = L_cyl * 1.5 + R_cyl * 5 # the box should fit the cylinder and be many times bigger than its width
|
|
334
|
+
print("Cylinder params: L=%g R=%g boxsize=%g vrms=%g" % (L_cyl, R_cyl, boxsize_cyl, vrms_cyl))
|
|
335
|
+
replacements_cyl = replacements.copy()
|
|
336
|
+
replacements_cyl["NAME"] = filename.replace(".hdf5", "_CYL")
|
|
337
|
+
replacements_cyl["BOXSIZE"] = boxsize_cyl
|
|
338
|
+
# New driving params
|
|
339
|
+
replacements_cyl["TURB_MINLAMBDA"] = int(100 * R_cyl) / 100
|
|
340
|
+
replacements_cyl["TURB_MAXLAMBDA"] = int(100 * R_cyl * 4) / 100
|
|
341
|
+
replacements_cyl["TURB_SIGMA"] = vrms_cyl
|
|
342
|
+
replacements_cyl["TURB_COHERENCE_TIME"] = tcross_cyl / 2
|
|
343
|
+
# Legacy driving params, probably needs tuning
|
|
344
|
+
replacements_cyl["TURBDECAY"] = tcross_cyl / 2
|
|
345
|
+
replacements_cyl["TURBENERGY"] = 0.019111097819633344 * vrms_cyl**3 / R_cyl
|
|
346
|
+
replacements_cyl["TURBFREQ"] = tcross_cyl / 20
|
|
347
|
+
replacements_cyl["TURB_KMIN"] = int(100 * 2 * np.pi / R_cyl) / 100.0
|
|
348
|
+
replacements_cyl["TURB_KMAX"] = int(100 * 4 * np.pi / (R_cyl) + 1) / 100.0
|
|
349
|
+
paramsfile = _load_params_template()
|
|
350
|
+
for k in replacements_cyl.keys():
|
|
351
|
+
paramsfile = paramsfile.replace(k, str(replacements_cyl[k]))
|
|
352
|
+
open("params_" + filename.replace(".hdf5", "") + "_CYL.txt", "w").write(paramsfile)
|
|
353
|
+
|
|
354
|
+
if param_only:
|
|
355
|
+
print("Parameters only run, exiting...")
|
|
356
|
+
exit()
|
|
357
|
+
|
|
358
|
+
mgas = np.repeat(dm, N_gas)
|
|
359
|
+
|
|
360
|
+
x = get_glass_coords(N_gas, glass_path)
|
|
361
|
+
Nx = len(x)
|
|
362
|
+
x = 2 * (x - 0.5)
|
|
363
|
+
print("Computing radii...")
|
|
364
|
+
r = cdist(x, [np.zeros(3)])[:, 0]
|
|
365
|
+
print("Done! Sorting coordinates...")
|
|
366
|
+
x = x[r.argsort()][:N_gas]
|
|
367
|
+
print("Done! Rescaling...")
|
|
368
|
+
x *= (float(Nx) / N_gas * 4 * np.pi / 3 / 8) ** (1.0 / 3) * R
|
|
369
|
+
print("Done! Recomupting radii...")
|
|
370
|
+
r = cdist(x, [np.zeros(3)])[:, 0]
|
|
371
|
+
if np.any(r == 0):
|
|
372
|
+
raise ValueError(
|
|
373
|
+
"found point with r=0 in the glass file, we don't handle this case throughout our calculations yet. Stopping."
|
|
374
|
+
)
|
|
375
|
+
x, r = x / r.max(), r / r.max()
|
|
376
|
+
print("Doing density profile...")
|
|
377
|
+
rnew = r ** (3.0 / (3 + density_exponent)) * R
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
x = x * (rnew / r)[:, None]
|
|
381
|
+
r = np.sum(x**2, axis=1) ** 0.5
|
|
382
|
+
r_order = r.argsort()
|
|
383
|
+
x, r = np.take(x, r_order, axis=0), r[r_order]
|
|
384
|
+
|
|
385
|
+
if not os.path.exists(turb_path):
|
|
386
|
+
os.makedirs(turb_path)
|
|
387
|
+
fname = turb_path + "/vturb%d_beta%g_sol%g_seed%d.npy" % (minmode, turb_slope, turb_sol, seed)
|
|
388
|
+
if not os.path.isfile(fname):
|
|
389
|
+
vt = TurbField(minmode=minmode, slope = turb_slope, sol_weight=turb_sol, seed=seed)
|
|
390
|
+
nmin, nmax = vt.shape[-1] // 4, 3 * vt.shape[-1] // 4
|
|
391
|
+
vt = vt[
|
|
392
|
+
:, nmin:nmax, nmin:nmax, nmin:nmax
|
|
393
|
+
] # we take the central cube of size L/2 so that opposide sides of the cloud are not correlated
|
|
394
|
+
np.save(fname, vt)
|
|
395
|
+
else:
|
|
396
|
+
vt = np.load(fname)
|
|
397
|
+
|
|
398
|
+
xgrid = np.linspace(-R, R, vt.shape[-1])
|
|
399
|
+
v = []
|
|
400
|
+
for i in range(3):
|
|
401
|
+
v.append(interpolate.interpn((xgrid, xgrid, xgrid), vt[i, :, :, :], x))
|
|
402
|
+
v = np.array(v).T
|
|
403
|
+
print("Coordinates obtained!")
|
|
404
|
+
|
|
405
|
+
Mr = mgas.cumsum()
|
|
406
|
+
ugrav = G * np.sum(Mr / r * mgas)
|
|
407
|
+
v -= np.average(v, axis=0)
|
|
408
|
+
Eturb = 0.5 * dm * np.sum(v**2)
|
|
409
|
+
v *= np.sqrt(turbulence * ugrav / Eturb)
|
|
410
|
+
E_rot_target = spin * ugrav
|
|
411
|
+
Rcyl = np.sqrt(x[:, 0] ** 2 + x[:, 1] ** 2)
|
|
412
|
+
omega = Rcyl**omega_exponent
|
|
413
|
+
vrot = np.cross(np.c_[np.zeros_like(omega), np.zeros_like(omega), omega], x)
|
|
414
|
+
Erot_actual = np.sum(0.5 * mgas[:, None] * vrot**2)
|
|
415
|
+
vrot *= np.sqrt(E_rot_target / Erot_actual)
|
|
416
|
+
v += vrot
|
|
417
|
+
|
|
418
|
+
B = np.c_[np.zeros(N_gas), np.zeros(N_gas), np.ones(N_gas)]
|
|
419
|
+
vA_unit = (
|
|
420
|
+
3.429e8 * B_unit_gauss * (M_gas) ** -0.5 * R**1.5 * np.sqrt(4 * np.pi / 3) / v_unit_SI
|
|
421
|
+
) # alfven speed for unit magnetic field
|
|
422
|
+
uB = 0.5 * M_gas * vA_unit**2 # magnetic energy we would have for unit magnetic field
|
|
423
|
+
if bfixed > 0:
|
|
424
|
+
B = B * bfixed
|
|
425
|
+
else:
|
|
426
|
+
B = B * np.sqrt(magnetic_field * ugrav / uB) # renormalize to desired magnetic energy
|
|
427
|
+
|
|
428
|
+
v = v - np.average(v, axis=0)
|
|
429
|
+
x = x - np.average(x, axis=0)
|
|
430
|
+
|
|
431
|
+
r, phi = np.sum(x**2, axis=1) ** 0.5, np.arctan2(x[:, 1], x[:, 0])
|
|
432
|
+
theta = np.arccos(x[:, 2] / r)
|
|
433
|
+
phi += phimode * np.sin(2 * phi) / 2
|
|
434
|
+
x = r[:, np.newaxis] * np.c_[np.cos(phi) * np.sin(theta), np.sin(phi) * np.sin(theta), np.cos(theta)]
|
|
435
|
+
|
|
436
|
+
if makecylinder:
|
|
437
|
+
|
|
438
|
+
def ind_in_cylinder(x, L_cyl, R_cyl):
|
|
439
|
+
return (np.abs(x[:, 0]) < L_cyl / 2) & (np.sum(x[:, 1:] ** 2, axis=1) < R_cyl**2)
|
|
440
|
+
|
|
441
|
+
# Just get a roughly homogeneous cylinder along the x axis, we will stir it anyway
|
|
442
|
+
N_cyl = 0
|
|
443
|
+
while N_cyl <= N_gas: # should be very unlikely that we need to repeat, but let's check to be sure
|
|
444
|
+
x_cyl = np.random.rand(2 * N_gas, 3) * 2 - 1
|
|
445
|
+
x_cyl[:, 0] *= L_cyl / 2
|
|
446
|
+
x_cyl[:, 1] *= R_cyl
|
|
447
|
+
x_cyl[:, 2] *= R_cyl
|
|
448
|
+
x_cyl = x_cyl[ind_in_cylinder(x_cyl, L_cyl, R_cyl)]
|
|
449
|
+
N_cyl = len(x_cyl)
|
|
450
|
+
# print("N_cyl: %g N_gas: %g"%(N_cyl,N_gas))
|
|
451
|
+
x_cyl = x_cyl[:N_gas] # keep only the right amount of gas
|
|
452
|
+
# Let's add some initial velocity to make the driving phase shorter, let's start with a rotational component
|
|
453
|
+
v_cyl = np.cross([1, 0, 0], x_cyl, axis=-1) / R_cyl
|
|
454
|
+
# tangential with magnitude increasing linearly
|
|
455
|
+
v_cyl *= vrms_cyl
|
|
456
|
+
|
|
457
|
+
u = np.ones_like(mgas) * 0.101 / 2.0 # /2 needed because it is molecular
|
|
458
|
+
|
|
459
|
+
if impact_dist > 0:
|
|
460
|
+
x = np.concatenate([x, x])
|
|
461
|
+
impact_dir = {
|
|
462
|
+
"x": np.array([1.0, 0, 0]),
|
|
463
|
+
"y": np.array([0, 1, 0]),
|
|
464
|
+
"z": np.array([0, 0, 1]),
|
|
465
|
+
}[impact_axis]
|
|
466
|
+
impact_param_dir = {
|
|
467
|
+
"x": np.array([0, 1, 0]),
|
|
468
|
+
"y": np.array([0, 0, 1]),
|
|
469
|
+
"z": np.array([1, 0, 0]),
|
|
470
|
+
}[impact_axis]
|
|
471
|
+
x[:N_gas] += impact_dist * R * impact_dir
|
|
472
|
+
x[N_gas:] -= impact_dist * R * impact_dir
|
|
473
|
+
x[:N_gas] += 0.5 * impact_param * R * impact_param_dir
|
|
474
|
+
x[N_gas:] -= 0.5 * impact_param * R * impact_param_dir
|
|
475
|
+
v = np.concatenate([v, v])
|
|
476
|
+
vrms = np.sum(v**2, axis=1).mean() ** 0.5
|
|
477
|
+
v[:N_gas] -= v_impact * vrms * impact_dir
|
|
478
|
+
v[N_gas:] += v_impact * vrms * impact_dir
|
|
479
|
+
B = np.concatenate([B, B])
|
|
480
|
+
u = np.concatenate([u, u])
|
|
481
|
+
mgas = np.concatenate([mgas, mgas])
|
|
482
|
+
|
|
483
|
+
u = (
|
|
484
|
+
np.ones_like(mgas) * (200 / v_unit_SI) ** 2
|
|
485
|
+
) # start with specific internal energy of (200m/s)^2, this is overwritten unless starting with restart flag 2###### #0.101/2.0 #/2 needed because it is molecular
|
|
486
|
+
|
|
487
|
+
if diffuse_gas:
|
|
488
|
+
# assuming 10K vs 10^4K gas: factor of ~10^3 density contrast
|
|
489
|
+
rho_warm = M_gas * 3 / (4 * np.pi * R**3) / 1000
|
|
490
|
+
if derefinement:
|
|
491
|
+
M_warm = (boxsize**3 - (4 * np.pi * R**3 / 3)) * rho_warm # mass of diffuse box-filling medium
|
|
492
|
+
N_warm = int(M_warm / (dm))
|
|
493
|
+
x0 = get_glass_coords(N_gas, glass_path)
|
|
494
|
+
Nx = len(x0)
|
|
495
|
+
x0 = 2 * (x0 - 0.5)
|
|
496
|
+
r0 = (x0 * x0).sum(1) ** 0.5
|
|
497
|
+
x0, r0 = x0[r0.argsort()], r0[r0.argsort()]
|
|
498
|
+
# first lay down the stuff within 3*R
|
|
499
|
+
N_warm = int(4 * np.pi * rho_warm * (3 * R) ** 3 / 3 / dm) # number of cells within 3R
|
|
500
|
+
x_warm = x0[:N_warm] * 3 * R / r0[N_warm - 1] # uniform density of cells within 3R
|
|
501
|
+
x0 = x0[
|
|
502
|
+
N_warm:
|
|
503
|
+
] # now we take the ones outside the initial sphere and map them to a n(R) ~ R^-3 profile so that we get constant number of cells per log radius interval
|
|
504
|
+
r0 = r0[N_warm:]
|
|
505
|
+
rnew = 3 * R * np.exp(np.arange(len(x0)) / N_warm / 3)
|
|
506
|
+
x_warm = np.concatenate([x_warm, (rnew / r0)[:, None] * x0], axis=0)
|
|
507
|
+
x_warm = x_warm[np.max(np.abs(x_warm), axis=1) < boxsize / 2]
|
|
508
|
+
N_warm = len(x_warm)
|
|
509
|
+
R_warm = (x_warm * x_warm).sum(1) ** 0.5
|
|
510
|
+
mgas = np.concatenate([mgas, np.clip(dm * (R_warm / (3 * R)) ** 3, dm, np.inf)])
|
|
511
|
+
else:
|
|
512
|
+
M_warm = boxsize**3 * rho_warm # mass of diffuse box-filling medium
|
|
513
|
+
N_warm = int(M_warm / dm) # get glass with N_warm particles
|
|
514
|
+
x_warm = get_glass_coords(N_warm, glass_path)[:N_warm]
|
|
515
|
+
x_warm /= x_warm.max()
|
|
516
|
+
x_warm = boxsize * x_warm - boxsize / 2
|
|
517
|
+
if impact_dist == 0:
|
|
518
|
+
x_warm = x_warm[np.sum(x_warm**2, axis=1) > R**2]
|
|
519
|
+
N_warm = len(x_warm)
|
|
520
|
+
mgas = np.concatenate([mgas, np.repeat(mgas.sum() / len(mgas), N_warm)])
|
|
521
|
+
x = np.concatenate([x, x_warm])
|
|
522
|
+
v = np.concatenate([v, np.zeros((N_warm, 3))])
|
|
523
|
+
Bmag = np.average(np.sum(B**2, axis=1)) ** 0.5
|
|
524
|
+
B = np.concatenate([B, np.repeat(Bmag, N_warm)[:, np.newaxis] * np.array([0, 0, 1])])
|
|
525
|
+
u = np.concatenate([u, np.repeat(101.0, N_warm)])
|
|
526
|
+
|
|
527
|
+
if makecylinder:
|
|
528
|
+
# The magnetic field is paralell to the cylinder (true at low densities, so probably fine for IC)
|
|
529
|
+
B_cyl = np.concatenate([B, np.repeat(Bmag, N_warm)[:, np.newaxis] * np.array([1, 0, 0])])
|
|
530
|
+
# Add diffuse medium
|
|
531
|
+
M_warm_cyl = (boxsize_cyl**3 - (4 * np.pi * R**3 / 3)) * rho_warm
|
|
532
|
+
N_warm_cyl = int(M_warm_cyl / (dm))
|
|
533
|
+
x_warm = boxsize_cyl * np.random.rand(N_warm_cyl, 3) - boxsize_cyl / 2 # will be recentered later
|
|
534
|
+
x_warm = x_warm[~ind_in_cylinder(x_warm, L_cyl, R_cyl)] # keep only warm gas outside the cylinder
|
|
535
|
+
# print("N_warm_cyl: %g N_warm_cyl_kept %g "%(N_warm_cyl,len(x_warm)))
|
|
536
|
+
N_warm_cyl = len(x_warm)
|
|
537
|
+
x_cyl = np.concatenate([x_cyl, x_warm])
|
|
538
|
+
v_cyl = np.concatenate([v_cyl, np.zeros((N_warm, 3))])
|
|
539
|
+
|
|
540
|
+
else:
|
|
541
|
+
N_warm = 0
|
|
542
|
+
|
|
543
|
+
rho = np.repeat(3 * M_gas / (4 * np.pi * R**3), len(mgas))
|
|
544
|
+
if diffuse_gas:
|
|
545
|
+
rho[-N_warm:] /= 1000
|
|
546
|
+
h = (32 * mgas / rho) ** (1.0 / 3)
|
|
547
|
+
|
|
548
|
+
x += boxsize / 2 # cloud is always centered at (boxsize/2,boxsize/2,boxsize/2)
|
|
549
|
+
if makecylinder:
|
|
550
|
+
x_cyl += boxsize_cyl / 2
|
|
551
|
+
|
|
552
|
+
print("Writing snapshot...")
|
|
553
|
+
|
|
554
|
+
F = h5py.File(filename, "w")
|
|
555
|
+
F.create_group("PartType0")
|
|
556
|
+
F.create_group("Header")
|
|
557
|
+
F["Header"].attrs["NumPart_ThisFile"] = [
|
|
558
|
+
len(mgas),
|
|
559
|
+
0,
|
|
560
|
+
0,
|
|
561
|
+
0,
|
|
562
|
+
0,
|
|
563
|
+
(1 if M_star > 0 else 0),
|
|
564
|
+
]
|
|
565
|
+
F["Header"].attrs["NumPart_Total"] = [
|
|
566
|
+
len(mgas),
|
|
567
|
+
0,
|
|
568
|
+
0,
|
|
569
|
+
0,
|
|
570
|
+
0,
|
|
571
|
+
(1 if M_star > 0 else 0),
|
|
572
|
+
]
|
|
573
|
+
F["Header"].attrs["BoxSize"] = boxsize
|
|
574
|
+
F["Header"].attrs["Time"] = 0.0
|
|
575
|
+
F["PartType0"].create_dataset("Masses", data=mgas)
|
|
576
|
+
F["PartType0"].create_dataset("Coordinates", data=x)
|
|
577
|
+
F["PartType0"].create_dataset("Velocities", data=v)
|
|
578
|
+
F["PartType0"].create_dataset("ParticleIDs", data=1 + np.arange(len(mgas)))
|
|
579
|
+
F["PartType0"].create_dataset("InternalEnergy", data=u)
|
|
580
|
+
|
|
581
|
+
if M_star > 0:
|
|
582
|
+
F.create_group("PartType5")
|
|
583
|
+
# Let's add the sink at the center
|
|
584
|
+
F["PartType5"].create_dataset("Masses", data=np.array([M_star]))
|
|
585
|
+
F["PartType5"].create_dataset("Coordinates", data=[x_star]) # at the center
|
|
586
|
+
F["PartType5"].create_dataset("Velocities", data=[v_star]) # at rest
|
|
587
|
+
F["PartType5"].create_dataset("ParticleIDs", data=np.array([F["PartType0/ParticleIDs"][:].max() + 1]))
|
|
588
|
+
# Advanced properties for sinks
|
|
589
|
+
F["PartType5"].create_dataset("BH_Mass", data=M_star) # all the mass in the sink/protostar/star
|
|
590
|
+
F["PartType5"].create_dataset("BH_Mass_AlphaDisk", data=np.array([0.0])) # starts with no disk
|
|
591
|
+
F["PartType5"].create_dataset("BH_Mdot", data=np.array([0.0])) # starts with no mdot
|
|
592
|
+
F["PartType5"].create_dataset("BH_Specific_AngMom", data=np.array([0.0])) # starts with no angular momentum
|
|
593
|
+
F["PartType5"].create_dataset("SinkRadius", data=np.array([softening])) # Sinkradius set to softening
|
|
594
|
+
F["PartType5"].create_dataset("StellarFormationTime", data=np.array([0.0]))
|
|
595
|
+
F["PartType5"].create_dataset("ProtoStellarAge", data=np.array([0.0]))
|
|
596
|
+
F["PartType5"].create_dataset("ProtoStellarStage", data=np.array([5], dtype=np.int32), dtype=np.int32)
|
|
597
|
+
# Stellar properties
|
|
598
|
+
# if (central_star or central_SN):
|
|
599
|
+
# if central_star:
|
|
600
|
+
# print("Assuming central sink is a ZAMS star")
|
|
601
|
+
# starts as ZAMS star
|
|
602
|
+
# else:
|
|
603
|
+
# print("Assuming central sink is a ZAMS star about to go supernova")
|
|
604
|
+
# F["PartType5"].create_dataset("ProtoStellarStage", data=np.array([6],dtype=np.int32), dtype=np.int32) #starts as ZAMS star going SN
|
|
605
|
+
# Set guess for ZAMS stellar radius, will be overwritten
|
|
606
|
+
if (M_star) > 1.0:
|
|
607
|
+
R_ZAMS = (M_star) ** 0.57
|
|
608
|
+
else:
|
|
609
|
+
R_ZAMS = (M_star) ** 0.8
|
|
610
|
+
F["PartType5"].create_dataset("ProtoStellarRadius_inSolar", data=np.array([R_ZAMS])) # Sinkradius set to softening
|
|
611
|
+
F["PartType5"].create_dataset("StarLuminosity_Solar", data=np.array([0.0])) # dummy
|
|
612
|
+
F["PartType5"].create_dataset("Mass_D", data=np.array([0.0])) # No D left
|
|
613
|
+
|
|
614
|
+
if magnetic_field > 0.0:
|
|
615
|
+
F["PartType0"].create_dataset("MagneticField", data=B)
|
|
616
|
+
F.close()
|
|
617
|
+
|
|
618
|
+
if makebox:
|
|
619
|
+
F = h5py.File(filename.replace(".hdf5", "_BOX.hdf5"), "w")
|
|
620
|
+
F.create_group("PartType0")
|
|
621
|
+
F.create_group("Header")
|
|
622
|
+
F["Header"].attrs["NumPart_ThisFile"] = [len(mgas), 0, 0, 0, 0, 0]
|
|
623
|
+
F["Header"].attrs["NumPart_Total"] = [len(mgas), 0, 0, 0, 0, 0]
|
|
624
|
+
F["Header"].attrs["MassTable"] = [M_gas / len(mgas), 0, 0, 0, 0, 0]
|
|
625
|
+
F["Header"].attrs["BoxSize"] = (4 * np.pi * R**3 / 3) ** (1.0 / 3)
|
|
626
|
+
F["Header"].attrs["Time"] = 0.0
|
|
627
|
+
F["PartType0"].create_dataset("Masses", data=mgas[: len(mgas)])
|
|
628
|
+
F["PartType0"].create_dataset(
|
|
629
|
+
"Coordinates",
|
|
630
|
+
data=np.random.rand(len(mgas), 3) * F["Header"].attrs["BoxSize"],
|
|
631
|
+
)
|
|
632
|
+
F["PartType0"].create_dataset("Velocities", data=np.zeros((len(mgas), 3)))
|
|
633
|
+
F["PartType0"].create_dataset("ParticleIDs", data=1 + np.arange(len(mgas)))
|
|
634
|
+
F["PartType0"].create_dataset("InternalEnergy", data=u)
|
|
635
|
+
if magnetic_field > 0.0:
|
|
636
|
+
F["PartType0"].create_dataset("MagneticField", data=B[: len(mgas)])
|
|
637
|
+
F.close()
|
|
638
|
+
|
|
639
|
+
if makecylinder:
|
|
640
|
+
F = h5py.File(filename.replace(".hdf5", "_CYL.hdf5"), "w")
|
|
641
|
+
F.create_group("PartType0")
|
|
642
|
+
F.create_group("Header")
|
|
643
|
+
F["Header"].attrs["NumPart_ThisFile"] = [N_gas + N_warm_cyl, 0, 0, 0, 0, 0]
|
|
644
|
+
F["Header"].attrs["NumPart_Total"] = [N_gas + N_warm_cyl, 0, 0, 0, 0, 0]
|
|
645
|
+
F["Header"].attrs["MassTable"] = [dm, 0, 0, 0, 0, 0]
|
|
646
|
+
F["Header"].attrs["BoxSize"] = boxsize_cyl
|
|
647
|
+
F["Header"].attrs["Time"] = 0.0
|
|
648
|
+
F["PartType0"].create_dataset("Masses", data=mgas)
|
|
649
|
+
F["PartType0"].create_dataset("Coordinates", data=x_cyl)
|
|
650
|
+
F["PartType0"].create_dataset("Velocities", data=v_cyl)
|
|
651
|
+
F["PartType0"].create_dataset("ParticleIDs", data=1 + np.arange(N_gas + N_warm_cyl))
|
|
652
|
+
F["PartType0"].create_dataset("InternalEnergy", data=u)
|
|
653
|
+
if magnetic_field > 0.0:
|
|
654
|
+
F["PartType0"].create_dataset("MagneticField", data=B_cyl)
|
|
655
|
+
F.close()
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
if __name__ == "__main__":
|
|
659
|
+
main()
|
makecloud-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: makecloud
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Generate turbulent molecular cloud initial conditions for GIZMO/STARFORGE simulations
|
|
5
|
+
Author: Dávid Guszejnov
|
|
6
|
+
Author-email: "Michael Y. Grudić" <mgrudic@flatironinstitute.org>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/mikegrudic/MakeCloud
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: numpy
|
|
12
|
+
Requires-Dist: scipy
|
|
13
|
+
Requires-Dist: h5py
|
|
14
|
+
Requires-Dist: docopt
|
|
15
|
+
|
|
16
|
+
# MakeCloud
|
|
17
|
+
|
|
18
|
+
Requires the following packages:
|
|
19
|
+
numpy
|
|
20
|
+
scipy
|
|
21
|
+
h5py
|
|
22
|
+
docopt
|
|
23
|
+
|
|
24
|
+
If you want to use glassy initial conditions, you will need <a href=https://data.obs.carnegiescience.edu/starforge/glass_orig.npy>this file</a>, and you should point the script to it via the --glass_path option.
|
|
25
|
+
|
|
26
|
+
By default, we generate turbulent velocity fields on the fly but then store that data somewhere so we don't have to do all those FFTs again next. You'll have to specify the path where the files get stored via the --turb_path option.
|
|
27
|
+
|
|
28
|
+
#Usage
|
|
29
|
+
|
|
30
|
+
Run python MakeCloud.py -h for instructions
|
|
31
|
+
|
|
32
|
+
e.g. if I wanted a 10^6 solar mass cloud of radius 100pc, resolved in 10^6 gas cells, I would do
|
|
33
|
+
|
|
34
|
+
python MakeCloud.py --M=1e6 --R=100 --N=1000000
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# MakeCloud
|
|
2
|
+
|
|
3
|
+
Requires the following packages:
|
|
4
|
+
numpy
|
|
5
|
+
scipy
|
|
6
|
+
h5py
|
|
7
|
+
docopt
|
|
8
|
+
|
|
9
|
+
If you want to use glassy initial conditions, you will need <a href=https://data.obs.carnegiescience.edu/starforge/glass_orig.npy>this file</a>, and you should point the script to it via the --glass_path option.
|
|
10
|
+
|
|
11
|
+
By default, we generate turbulent velocity fields on the fly but then store that data somewhere so we don't have to do all those FFTs again next. You'll have to specify the path where the files get stored via the --turb_path option.
|
|
12
|
+
|
|
13
|
+
#Usage
|
|
14
|
+
|
|
15
|
+
Run python MakeCloud.py -h for instructions
|
|
16
|
+
|
|
17
|
+
e.g. if I wanted a 10^6 solar mass cloud of radius 100pc, resolved in 10^6 gas cells, I would do
|
|
18
|
+
|
|
19
|
+
python MakeCloud.py --M=1e6 --R=100 --N=1000000
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simple routines to calculate the cloud's: radius,
|
|
3
|
+
average density, surface density, free-fall time (in years),
|
|
4
|
+
and number of particles (N) given a cloud mass and cell mass
|
|
5
|
+
resolution to choose
|
|
6
|
+
|
|
7
|
+
Written by: Anna Rosen, 11/2/22
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import math
|
|
11
|
+
import numpy
|
|
12
|
+
|
|
13
|
+
MSUN = 1.989e33 # g
|
|
14
|
+
PCCM = 3.086e18 # cm
|
|
15
|
+
G = 6.6743e-8 # cm^3 g^-1 s
|
|
16
|
+
SECYR = 3600 * 24 * 365.25 # s
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def calcRhoAve(Mcl, Rcl=None, Sigma=1):
|
|
20
|
+
"""
|
|
21
|
+
Inputs:
|
|
22
|
+
#cloud mass = Mcl [Msun]
|
|
23
|
+
#cloud radius = Rcl [pc]
|
|
24
|
+
#Sigma = Cloud surface density, default = 1 g/cm^2
|
|
25
|
+
|
|
26
|
+
Output:
|
|
27
|
+
rho_ave [g/cm^3]
|
|
28
|
+
"""
|
|
29
|
+
if Rcl is None and Sigma > 0.0:
|
|
30
|
+
print(
|
|
31
|
+
"No Rcl supplied, calc. Rcl assuming Sigma = %.2e g/cm^2" % Sigma
|
|
32
|
+
)
|
|
33
|
+
Rcl = calcRcl(Mcl, Sigma)
|
|
34
|
+
else:
|
|
35
|
+
print("Error: must supple Rcl (in pc) or Sigma > 0")
|
|
36
|
+
M = Mcl * MSUN
|
|
37
|
+
R = Rcl * PCCM
|
|
38
|
+
rho_ave = 3 * M / (4 * math.pi * R**3.0)
|
|
39
|
+
print("Average cloud density = %.2e g/cm^3" % rho_ave)
|
|
40
|
+
return rho_ave
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def calcRcl(Mcl, Sigma):
|
|
44
|
+
"""
|
|
45
|
+
Inputs:
|
|
46
|
+
#cloud mass = Mcl [Msun]
|
|
47
|
+
#cloud surface density = Sigma [g/cm^2]
|
|
48
|
+
|
|
49
|
+
Output:
|
|
50
|
+
Rcl [pc]
|
|
51
|
+
"""
|
|
52
|
+
M = Mcl * MSUN
|
|
53
|
+
Rcl = (M / (math.pi * Sigma)) ** 0.5 / PCCM
|
|
54
|
+
print("Cloud Radius = %.2f pc" % Rcl)
|
|
55
|
+
return Rcl
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def calc_SurfaceDensity(Mcl, Rcl):
|
|
59
|
+
"""
|
|
60
|
+
Inputs:
|
|
61
|
+
#cloud mass = Mcl [Msun]
|
|
62
|
+
#cloud radius = Sigma [g/cm^2]
|
|
63
|
+
|
|
64
|
+
Output:
|
|
65
|
+
Sigma [g/cm^2]
|
|
66
|
+
"""
|
|
67
|
+
M = Mcl * MSUN
|
|
68
|
+
R = Rcl * PCCM
|
|
69
|
+
Sigma = M / (math.pi * R**3.0)
|
|
70
|
+
print("Cloud surface density = %.2e g/cm^2" % Sigma)
|
|
71
|
+
return rho_ave
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def calc_tff(Mcl, Rcl=None, Sigma=1):
|
|
75
|
+
"""
|
|
76
|
+
Inputs:
|
|
77
|
+
#cloud mass = Mcl [Msun]
|
|
78
|
+
#cloud surface density = Sigma [g/cm^2]
|
|
79
|
+
|
|
80
|
+
Output:
|
|
81
|
+
tff [yr]
|
|
82
|
+
"""
|
|
83
|
+
if Rcl is None and Sigma > 0.0:
|
|
84
|
+
print(
|
|
85
|
+
"No Rcl supplied, calc. Rcl assuming Sigma = %.2e g/cm^2" % Sigma
|
|
86
|
+
)
|
|
87
|
+
Rcl = calcRcl(Mcl, Sigma)
|
|
88
|
+
else:
|
|
89
|
+
print("Error: must supple Rcl (in pc) or Sigma > 0")
|
|
90
|
+
|
|
91
|
+
rho_ave = calcRhoAve(Mcl, Rcl=Rcl, Sigma=1)
|
|
92
|
+
|
|
93
|
+
tff = (3 * math.pi / (32 * G * rho_ave)) ** 0.5 / SECYR
|
|
94
|
+
print("tff = %.2f yr" % tff)
|
|
95
|
+
return tff
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def calc_Npart(Mcl, massRes=1e-3):
|
|
99
|
+
"""
|
|
100
|
+
Inputs:
|
|
101
|
+
#cloud mass = Mcl [Msun]
|
|
102
|
+
#mass/cell [Msun]
|
|
103
|
+
|
|
104
|
+
Output:
|
|
105
|
+
N [particles]
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
N = Mcl / massRes
|
|
109
|
+
print("For Mcl = %.2e Msun, Mcell = %.2e" % (Mcl, massRes))
|
|
110
|
+
print("N = %.2e particles" % N)
|
|
111
|
+
return N
|
|
File without changes
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
%-------------------------------------------------------------------------
|
|
2
|
+
%---- This file contains the input parameters needed at run-time for
|
|
3
|
+
% simulations. It is based on and closely resembles the GADGET-3
|
|
4
|
+
% parameterfile (format of which and parsing routines written by
|
|
5
|
+
% Volker Springel [volker.springel@h-its.org]). It has been updated
|
|
6
|
+
% with new naming conventions and additional variables as needed by
|
|
7
|
+
% Phil Hopkins [phopkins@caltech.edu] for GIZMO.
|
|
8
|
+
%-------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
%---- Relevant files (filenames and directories)
|
|
11
|
+
InitCondFile NAME
|
|
12
|
+
OutputDir OUTFOLDER
|
|
13
|
+
|
|
14
|
+
%---- File formats (input and output)
|
|
15
|
+
ICFormat 3 % 1=unformatted (gadget) binary, 3=hdf5, 4=cluster
|
|
16
|
+
SnapFormat 3 % 1=unformatted (gadget) binary, 3=hdf5
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
%---- Output parameters
|
|
20
|
+
RestartFile restart
|
|
21
|
+
SnapshotFileBase snapshot
|
|
22
|
+
OutputListOn 0 % =1 to use list in "OutputListFilename"
|
|
23
|
+
OutputListFilename output_times.txt % list of times (in code units) for snaps
|
|
24
|
+
NumFilesPerSnapshot 1
|
|
25
|
+
NumFilesWrittenInParallel 1 % must be < N_processors & power of 2
|
|
26
|
+
|
|
27
|
+
%---- Output frequency
|
|
28
|
+
TimeOfFirstSnapshot 0. % time (code units) of first snapshot
|
|
29
|
+
TimeBetSnapshot DTSNAP % time between (if OutputListOn=0), code units
|
|
30
|
+
TimeBetStatistics DTSNAP % time between additional statistics (e.g. energy)
|
|
31
|
+
|
|
32
|
+
%---- CPU run-time and checkpointing time-limits
|
|
33
|
+
TimeLimitCPU 172800 % in seconds
|
|
34
|
+
CpuTimeBetRestartFile 7200 % in seconds
|
|
35
|
+
ResubmitOn 0
|
|
36
|
+
ResubmitCommand my-scriptfile
|
|
37
|
+
|
|
38
|
+
%---- Desired simulation beginning and end times (in code units) for run
|
|
39
|
+
TimeBegin 0.0 % Beginning of the simulation
|
|
40
|
+
TimeMax TMAX % End of the simulation
|
|
41
|
+
|
|
42
|
+
%---- Maximum and minimum timesteps allowed
|
|
43
|
+
MaxSizeTimestep MAXTIMESTEP % in code units, set for your problem
|
|
44
|
+
MinSizeTimestep 1.0e-15 % set this very low, or get the wrong answer
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
%---- System of units
|
|
48
|
+
UnitLength_in_cm UNIT_L
|
|
49
|
+
UnitMass_in_g UNIT_M
|
|
50
|
+
UnitVelocity_in_cm_per_s UNIT_V
|
|
51
|
+
UnitMagneticField_in_gauss UNIT_B
|
|
52
|
+
GravityConstantInternal 0 % calculated by code if =0
|
|
53
|
+
|
|
54
|
+
%---- Cosmological parameters
|
|
55
|
+
ComovingIntegrationOn 0 % is it cosmological? (yes=1, no=0)
|
|
56
|
+
BoxSize BOXSIZE % in code units
|
|
57
|
+
Omega0 0. % =0 for non-cosmological
|
|
58
|
+
OmegaLambda 0. % =0 for non-cosmological
|
|
59
|
+
OmegaBaryon 0. % =0 for non-cosmological
|
|
60
|
+
HubbleParam 1. % little 'h'; =1 for non-cosmological runs
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
%----- Memory allocation
|
|
64
|
+
%MaxMemSize 5000 % sets maximum MPI process memory use in MByte
|
|
65
|
+
PartAllocFactor 5.0 % memory load allowed for better cpu balance
|
|
66
|
+
BufferSize 500 % in MByte
|
|
67
|
+
|
|
68
|
+
%---- Rebuild domains when >this fraction of particles active
|
|
69
|
+
TreeDomainUpdateFrequency 0.005 % 0.0005-0.05, dept on core+particle number
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
%---- (Optional) Initial hydro temperature & temperature floor (in Kelvin)
|
|
73
|
+
InitGasTemp 1e4 % set by IC file if =0
|
|
74
|
+
MinGasTemp 2.73 % don't trust cooling function below ~5K, whether dust, molecular lines, or photoelectric heating
|
|
75
|
+
InitRadiationTemp 20. % Initial and/or boundary radiation temperature (for RT_INFRARED)
|
|
76
|
+
|
|
77
|
+
%---- Hydro reconstruction (kernel) parameters
|
|
78
|
+
DesNumNgb 32 % domain-reconstruction kernel number: 32 standard, 60-114 for quintic
|
|
79
|
+
MaxHsml 1.0e10 % minimum gas kernel length (some very large value to prevent errors)
|
|
80
|
+
MinGasHsmlFractional 0 % minimum kernel length relative to gas force softening (<= 1)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
%---- Gravitational softening lengths
|
|
84
|
+
%----- Softening lengths per particle type. If ADAPTIVE_GRAVSOFT is set, these
|
|
85
|
+
%-------- are the minimum softening allowed for each type -------
|
|
86
|
+
%-------- (units are co-moving for cosmological integrations)
|
|
87
|
+
SofteningGas 1e-10 % gas (particle type=0) (in co-moving code units)
|
|
88
|
+
SofteningHalo 0.020 % dark matter/collisionless particles (type=1)
|
|
89
|
+
SofteningDisk 0.150 % collisionless particles (type=2)
|
|
90
|
+
SofteningBulge 0.500 % collisionless particles (type=3)
|
|
91
|
+
SofteningStars SOFTENING % stars spawned from gas (type=4)
|
|
92
|
+
SofteningBndry SOFTENING % black holes (if active), or collisionless (type=5)
|
|
93
|
+
|
|
94
|
+
%---- if these are set in cosmo runs, SofteningX switches from comoving to physical
|
|
95
|
+
%------- units when the comoving value exceeds the choice here
|
|
96
|
+
%------- (these are ignored, and *only* the above are used, for non-cosmo runs)
|
|
97
|
+
SofteningGasMaxPhys 0.0005 % e.g. switch to 0.5pc physical below z=1
|
|
98
|
+
SofteningHaloMaxPhys 0.010
|
|
99
|
+
SofteningDiskMaxPhys 0.075
|
|
100
|
+
SofteningBulgeMaxPhys 0.250
|
|
101
|
+
SofteningStarsMaxPhys 0.0005
|
|
102
|
+
SofteningBndryMaxPhys 0.0005
|
|
103
|
+
%----- parameters for adaptive gravitational softening
|
|
104
|
+
AGS_DesNumNgb 32 % neighbor number for calculating adaptive gravsoft
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
%-------------------------------------------------------------------------
|
|
110
|
+
%-------------------------------------------------------------------------
|
|
111
|
+
%---------- Physics Modules ----------------------------------------------
|
|
112
|
+
%-------------------------------------------------------------------------
|
|
113
|
+
%-------------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
%------------------------------------------------------------
|
|
117
|
+
%------------------ Additional Fluid Physics ----------------
|
|
118
|
+
%------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
%---- Magneto-Hydrodynamics Parameters (MAGNETIC on)
|
|
121
|
+
%----- Initial B-Field Strengths (if MHD_B_SET_IN_PARAMS on, otherwise read from IC file)
|
|
122
|
+
BiniX 1.0e-8 % initial B_x, in code units
|
|
123
|
+
BiniY 1.0e-8 % initial B_y, in code units
|
|
124
|
+
BiniZ 1.0e-8 % initial B_z, in code units
|
|
125
|
+
|
|
126
|
+
%---- Thermal Conduction (CONDUCTION on)
|
|
127
|
+
%----- set coefficient kappa [code units] or, if CONDUCTION_SPITZER on, multiplies value
|
|
128
|
+
ConductionCoeff 1.0 % set/multiply conduction coefficient
|
|
129
|
+
|
|
130
|
+
%---- Navier-Stokes Viscosity (VISCOSITY on)
|
|
131
|
+
%--- set coefficients eta,zeta [code units] or, if VISCOSITY_BRAGINSKII on, multiplies value
|
|
132
|
+
ShearViscosityCoeff 1.0 % set/multiply shear viscosity coefficient
|
|
133
|
+
BulkViscosityCoeff 1.0 % set/multiply bulk viscosity coefficient
|
|
134
|
+
|
|
135
|
+
%---- Turbulent Diffusion Master Switch (TURB_DIFFUSION on)
|
|
136
|
+
TurbDiffusionCoefficient 1.0 % Normalizes diffusion rates relative to Smagorinsky-Lilly theory [best calibration] (~0.5-2)
|
|
137
|
+
|
|
138
|
+
%---- Cosmic Ray + Gas Fluids (COSMIC_RAYS on)
|
|
139
|
+
CosmicRayDiffusionCoeff 1.0 % multiplies anisotropic diffusion/streaming coefficients
|
|
140
|
+
|
|
141
|
+
%---- Dust-Gas Mixtures (GRAIN_FLUID on)
|
|
142
|
+
Grain_Internal_Density 1.0 % internal/material density of grains in g/cm^3
|
|
143
|
+
Grain_Size_Min 1.e-6 % minimum grain size in cm
|
|
144
|
+
Grain_Size_Max 1.e-4 % maximum grain size in cm
|
|
145
|
+
Grain_Size_Spectrum_Powerlaw 0.5 % power-law distribution of grain sizes (dm/dlnr~r^x)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
%-------------------------------------------------------------------------
|
|
149
|
+
%------------------ Star, Black Hole, and Galaxy Formation ---------------
|
|
150
|
+
%-------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
%---- Star Formation parameters (GALSF on)
|
|
154
|
+
CritPhysDensity RHOMAX % critical physical density for star formation (cm^(-3))
|
|
155
|
+
SfEffPerFreeFall 1.0 % SFR/(Mgas/tfreefall) for gas which meets SF criteria
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
%-------------- FIRE (PFH) explicit star formation & feedback model (FIRE on)
|
|
160
|
+
%--- initial metallicity of gas & stars in simulation
|
|
161
|
+
InitMetallicity ZINIT % initial gas+stellar metallicity (in solar)
|
|
162
|
+
InitStellarAge 0.0 % initial mean age (in Gyr; for stars in sim ICs)
|
|
163
|
+
%--- local radiation-pressure driven winds (GALSF_FB_FIRE_RT_LOCALRP)
|
|
164
|
+
WindMomentumLoading 1.0 % fraction of photon momentum to couple
|
|
165
|
+
%--- SneII Heating Model (GALSF_FB_MECHANICAL)
|
|
166
|
+
SNeIIEnergyFrac 1.0 % fraction of mechanical energy to couple
|
|
167
|
+
%--- HII region photo-heating model (GALSF_FB_FIRE_RT_HIIHEATING)
|
|
168
|
+
HIIRegion_fLum_Coupled 1.0 % fraction of ionizing photons allowed to see gas
|
|
169
|
+
%--- long-range radiation pressure acceleration (GALSF_FB_FIRE_RT_LONGRANGE)
|
|
170
|
+
PhotonMomentum_Coupled_Fraction 1.0 % fraction of L to allow incident
|
|
171
|
+
PhotonMomentum_fUV 0.0 % incident SED f(L) in UV (minimum scattering)
|
|
172
|
+
PhotonMomentum_fOPT 0.0 % incident SED f(L) in optical/near-IR
|
|
173
|
+
%--- gas return/recycling
|
|
174
|
+
GasReturnFraction 1.0 % fraction of gas mass returned (relative to ssp)
|
|
175
|
+
GasReturnEnergy 1.0 % fraction of returned gas energy+momentum (relative to ssp)
|
|
176
|
+
%--- cosmic rays (COSMIC_RAYS)
|
|
177
|
+
CosmicRay_SNeFraction 0.1 % fraction of SNe ejecta kinetic energy into cosmic rays (~10%)
|
|
178
|
+
|
|
179
|
+
InterstellarRadiationFieldStrength ISRF % interstellar radiation field intensity relative to values measured in Solar neighborhood
|
|
180
|
+
|
|
181
|
+
%-------------- Black Hole accretion & formation (BLACK_HOLES on)
|
|
182
|
+
%--- formation/seeding
|
|
183
|
+
SeedSinkMass BH_SEED_MASS % initial mass (on-the-fly or single galaxy)
|
|
184
|
+
SeedAlphaDiskMass 0.0 % initial mass in the alpha disk (BH_ALPHADISK_ACCRETION)
|
|
185
|
+
SeedSinkMinRedshift 2.0 % minimum redshift where new BH particles are seeded (lower-z ceases seeding)
|
|
186
|
+
SeedSinkMassSigma 0.5 % lognormal standard deviation (in dex) in initial BH seed masses
|
|
187
|
+
%----- (specific options for on-the-fly friends-of-friends based BH seeding: FOF on)
|
|
188
|
+
MinFoFMassForNewSeed 10. % minimum mass of FOF group (stars or DM) to get seed, in code units
|
|
189
|
+
TimeBetOnTheFlyFoF 1.01 % time (in code units, e.g. scale-factor) between on-the-fly FOF searches
|
|
190
|
+
%--- accretion
|
|
191
|
+
SinkAccretionFactor 1.0 % multiplier for mdot (relative to model)
|
|
192
|
+
SinkEddingtonFactor 1e100 % fraction of eddington to cap (can be >1)
|
|
193
|
+
SinkNgbFactor 1.0 % multiplier for kernel neighbors for BH
|
|
194
|
+
SinkMaxAccretionRadius BOXSIZE % max radius for BH neighbor search/accretion (code units)
|
|
195
|
+
SinkRadiativeEfficiency 5e-7 % radiative efficiency (for accretion and feedback)
|
|
196
|
+
%--- feedback
|
|
197
|
+
SinkFeedbackFactor 1.0 % generic feedback strength multiplier
|
|
198
|
+
BH_FluxMomentumFactor 0.0 % multiply radiation pressure (BH_PHOTONMOMENTUM), set it to zero to avoid launching gas from rad. pressure
|
|
199
|
+
Sink_f_accretion 0.7 % fraction of gas swallowed by BH (BH_WIND options)
|
|
200
|
+
Sink_v_outflow 100. % velocity (km/s) of BAL outflow (BH_WIND options)
|
|
201
|
+
Sink_internal_temperature 1.0e3 % internal temperature (K) of BAL outflow (BH_WIND_SPAWN)
|
|
202
|
+
Sink_wind_particle_mass JET_PART_MASS % mass of 'virtual wind particles' in code units (BH_WIND_SPAWN)
|
|
203
|
+
Sink_wind_particle_mass_MS MS_WIND_PART_MASS % mass of 'virtual wind particles' in MS stellar winds, if 0 then Sink_wind_particle_mass is used, in code units (SINGLE_STAR_FB_WINDS)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
%-------------------------------------------------------------------------
|
|
207
|
+
%------------------ Grackle cooling module -----------------
|
|
208
|
+
%-------------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
%-------------- Grackle UVB file (COOL_GRACKLE on)
|
|
211
|
+
GrackleDataFile CloudyData_UVB=HM2012.h5
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
%-------------------------------------------------------------------------
|
|
216
|
+
%------------------ Driven Turbulence (Large-Eddy boxes) -----------------
|
|
217
|
+
%-------------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
%-------------- Turbulent stirring parameters (TURB_DRIVING on)
|
|
220
|
+
TurbDrive_ApproxRMSVturb TURB_SIGMA
|
|
221
|
+
TurbDrive_MinWavelength TURB_MINLAMBDA
|
|
222
|
+
TurbDrive_MaxWavelength TURB_MAXLAMBDA
|
|
223
|
+
TurbDrive_SolenoidalFraction 1
|
|
224
|
+
TurbDrive_CoherenceTime TURB_COHERENCE_TIME
|
|
225
|
+
TurbDrive_DrivingSpectrum 1
|
|
226
|
+
TurbDrive_RandomNumberSeed 42
|
|
227
|
+
TurbDrive_TimeBetweenTurbUpdates DTSNAP
|
|
228
|
+
TurbDrive_TimeBetTurbSpectrum DTSNAP
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
%-------------------------------------------------------------------------------------------------
|
|
232
|
+
%------------------ Non-Standard Dark Matter, Dark Energy, Gravity, or Expansion -----------------
|
|
233
|
+
%-------------------------------------------------------------------------------------------------
|
|
234
|
+
|
|
235
|
+
%-------------- Parameters for non-standard or time-dependent Gravity/Dark Energy/Expansion (GR_TABULATED_COSMOLOGY on)
|
|
236
|
+
DarkEnergyConstantW -1 % time-independent DE parameter w, used only if no table
|
|
237
|
+
TabulatedCosmologyFile CosmoTbl % table with cosmological parameters
|
|
238
|
+
|
|
239
|
+
%--- Developer-Mode Parameters (usually hard-coded, but set manually if DEVELOPER_MODE is on) --------
|
|
240
|
+
ErrTolTheta 0.5 % 0.7=standard
|
|
241
|
+
ErrTolForceAcc 0.0025 % 0.0025=standard
|
|
242
|
+
ErrTolIntAccuracy 0.01 % <0.02
|
|
243
|
+
CourantFac 0.2 % <0.20
|
|
244
|
+
MaxRMSDisplacementFac 0.125 % <0.25
|
|
245
|
+
MaxNumNgbDeviation 0.05 % <<DesNumNgb (values<1 are fine)
|
|
246
|
+
AGS_MaxNumNgbDeviation 0.10 % tolerance in Nngb (make larger than gas)
|
|
247
|
+
%---- Magneto-Hydrodynamics Developer-Mode Parameters (MAGNETIC on)
|
|
248
|
+
%--- Dedner 2002 div-cleaning parameters
|
|
249
|
+
DivBcleaningParabolicSigma 1.0 % (3D~0.7-1.0,2D~0.2-0.3)
|
|
250
|
+
DivBcleaningHyperbolicSigma 1.0 % (~1)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: makecloud
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Generate turbulent molecular cloud initial conditions for GIZMO/STARFORGE simulations
|
|
5
|
+
Author: Dávid Guszejnov
|
|
6
|
+
Author-email: "Michael Y. Grudić" <mgrudic@flatironinstitute.org>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/mikegrudic/MakeCloud
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: numpy
|
|
12
|
+
Requires-Dist: scipy
|
|
13
|
+
Requires-Dist: h5py
|
|
14
|
+
Requires-Dist: docopt
|
|
15
|
+
|
|
16
|
+
# MakeCloud
|
|
17
|
+
|
|
18
|
+
Requires the following packages:
|
|
19
|
+
numpy
|
|
20
|
+
scipy
|
|
21
|
+
h5py
|
|
22
|
+
docopt
|
|
23
|
+
|
|
24
|
+
If you want to use glassy initial conditions, you will need <a href=https://data.obs.carnegiescience.edu/starforge/glass_orig.npy>this file</a>, and you should point the script to it via the --glass_path option.
|
|
25
|
+
|
|
26
|
+
By default, we generate turbulent velocity fields on the fly but then store that data somewhere so we don't have to do all those FFTs again next. You'll have to specify the path where the files get stored via the --turb_path option.
|
|
27
|
+
|
|
28
|
+
#Usage
|
|
29
|
+
|
|
30
|
+
Run python MakeCloud.py -h for instructions
|
|
31
|
+
|
|
32
|
+
e.g. if I wanted a 10^6 solar mass cloud of radius 100pc, resolved in 10^6 gas cells, I would do
|
|
33
|
+
|
|
34
|
+
python MakeCloud.py --M=1e6 --R=100 --N=1000000
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
MakeCloud.py
|
|
2
|
+
README.md
|
|
3
|
+
calcGMCProps.py
|
|
4
|
+
pyproject.toml
|
|
5
|
+
makecloud/__init__.py
|
|
6
|
+
makecloud/params.txt
|
|
7
|
+
makecloud.egg-info/PKG-INFO
|
|
8
|
+
makecloud.egg-info/SOURCES.txt
|
|
9
|
+
makecloud.egg-info/dependency_links.txt
|
|
10
|
+
makecloud.egg-info/entry_points.txt
|
|
11
|
+
makecloud.egg-info/requires.txt
|
|
12
|
+
makecloud.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "makecloud"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Generate turbulent molecular cloud initial conditions for GIZMO/STARFORGE simulations"
|
|
9
|
+
authors = [
|
|
10
|
+
{name = "Michael Y. Grudić", email = "mgrudic@flatironinstitute.org"},
|
|
11
|
+
{name = "Dávid Guszejnov"},
|
|
12
|
+
]
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
license = {text = "MIT"}
|
|
15
|
+
requires-python = ">=3.10"
|
|
16
|
+
dependencies = [
|
|
17
|
+
"numpy",
|
|
18
|
+
"scipy",
|
|
19
|
+
"h5py",
|
|
20
|
+
"docopt",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://github.com/mikegrudic/MakeCloud"
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
makecloud = "MakeCloud:main"
|
|
28
|
+
|
|
29
|
+
[tool.setuptools]
|
|
30
|
+
py-modules = ["MakeCloud", "calcGMCProps"]
|
|
31
|
+
packages = ["makecloud"]
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.package-data]
|
|
34
|
+
makecloud = ["params.txt"]
|