Creating SWIFT Initial Condition files from MUSIC Gadget outputs¶
Suppose you want to create cosmological IC files for SWIFT using MUSIC. First thing you need is a configuration file for MUSIC, e.g. IC_gadget.conf
# FILE IC_gadget.conf
[setup]
boxlength = 10
zstart = 10
levelmin = 4
levelmin_TF = 4
levelmax = 4
padding = 4
overlap = 4
ref_center = 0.5, 0.5, 0.5
ref_extent = 0.2, 0.2, 0.2
align_top = no
baryons = yes
use_2LPT = yes
use_LLA = no
periodic_TF = yes
[cosmology]
Omega_m = 0.276
Omega_L = 0.724
w0 = -1.0
wa = 0.0
Omega_b = 0.045
H0 = 70.3
sigma_8 = 0.811
nspec = 0.961
transfer = eisenstein
[random]
seed[7] = 12345
seed[8] = 23456
seed[9] = 34567
seed[10] = 45678
seed[11] = 56789
seed[12] = 67890
[output]
##generic MUSIC data format (used for testing)
##requires HDF5 installation and HDF5 enabled in Makefile
#format = generic
#filename = debug.hdf5
##ENZO - also outputs the settings for the parameter file
##requires HDF5 installation and HDF5 enabled in Makefile
#format = enzo
#filename = ic.enzo
##Gadget-2 (type=1: high-res particles, type=5: rest)
format = gadget2
filename = minimal_cosmo.dat
##Grafic2 compatible format for use with RAMSES
##option 'ramses_nml'=yes writes out a startup nml file
#format = grafic2
#filename = ics_ramses
#ramses_nml = yes
##TIPSY compatible with PKDgrav and Gasoline
#format = tipsy
#filename = ics_tipsy.dat
## NYX compatible output format
##requires boxlib installation and boxlib enabled in Makefile
#format = nyx
#filename = init
[poisson]
fft_fine = yes
accuracy = 1e-5
pre_smooth = 3
post_smooth = 3
smoother = gs
laplace_order = 6
grad_order = 6
for detailed instructions, look at the MUSIC documentation.
This should produce a gadget-2 type IC file called minimal_cosmo.dat
.
Next, we need to convert minimal_cosmo.dat
to a SWIFT IC file. This happens in two steps:
first you need to store the initial conditions in the format that SWIFT uses.
Secondly, some adjustments are necessary. E.g. the particle types are not the same in gadget and SWIFT, and SWIFT needs some extra flags and initial smoothing lengths for particles.
Using pNbody, this can be done with a simple script like the one below.
IMPORTANT NOTES
It might be necessary to check the units that are in use. The SWIFT IC file contains units as well, which will be preferred to the ones in the parameter file. pNbody however only assumes default gadget units, while MUSIC doesn’t. The default MUSIC units are:
UnitLength_in_cm 3.08568025e24 ; 1.0 Mpc
UnitMass_in_g 1.989e43 ; 1.0e10 solar masses
UnitVelocity_in_cm_per_s 1e5 ; 1 km/sec
while pNbody
assumes:
UnitLength_in_cm 3.08568025e21 ; 1.0 kpc
UnitMass_in_g 1.989e43 ; 1.0e10 solar masses
UnitVelocity_in_cm_per_s 1e5 ; 1 km/sec
this can be for example avoided by using the gadget_usekpc = yes
parameter in the MUSIC config file.
You also might need to type in the boxsize yourself.
#!/usr/bin/python3
usage="""
This script converts a gadget2 (non-hdf5) type initial condition file
(e.g. made with MUSIC) to a swift type IC file.
Needs pNbody to be installed.
Usage:
pNbody-gad2swift.py gadget-IC.dat [outputfilename_swift.dat]
outputfilename_swift.dat is optional. If you don't
specify it, the script will create a file called
<gadget-ic-filename-you-gave-as-first-argument>-SWIFT.dat
"""
from pNbody import *
from h5py import File
from sys import argv
import numpy as np
from os import path
# number of particle type
N_type = 6
debug = True
#====================================
def get_filenames():
#====================================
"""
Gets filename(s) from cmdline args.
Inputfile must be specified as arg1, outputfile is optional
and will be generated if not provided.
"""
try:
file_in = argv[1]
except IndexError:
print(usage)
quit()
try:
file_out = argv[2]
except IndexError:
# If no second file was given, generate file_out filename
# assume suffix is after last period in filename
cut = 0
append = '-SWIFT.hdf5'
for i in range(len(file_in)):
if file_in[-i-1] == '.':
cut = len(file_in)-i-1
break
if cut > 0:
file_out = file_in[:cut]+append
else:
file_out = file_in+append
return file_in, file_out
#====================================
def fix_particle_types(file_out):
#====================================
"""
Change particle types in order to match the implemented types.
Changes the particle types in the hdf5 file itself and overwrites
it.
"""
#--------------------------------------------------------------
def groupName(part_type):
return "PartType%i" % part_type
#--------------------------------------------------------------
#--------------------------------------------------------------
def changeType(f, old, new):
"""
Change particle types in the file f.
"""
# check if directory exists
old_group = groupName(old)
if old_group not in f:
while True:
ans = input("Changing particle types - cannot find group '%s' ; Should I continue? [y/n] " % old)
if ans=='y' or ans == 'Y':
return
elif ans == 'n' or ans == 'N':
raise IOError("Cannot find group '%s'" % old)
old = f[old_group]
new_group = groupName(new)
if new_group not in f:
f.create_group(new_group)
new = f[new_group]
print('check')
for name in old:
if debug:
print("Moving '%s' from '%s' to '%s'"
% (name, old_group, new_group))
tmp = old[name][:]
del old[name]
if name in new:
new_tmp = new[name][:]
if debug:
print("Found previous data:", tmp.shape, new_tmp.shape)
tmp = np.append(tmp, new_tmp, axis=0)
del new[name]
if debug:
print("With new shape:", tmp.shape)
new.create_dataset(name, tmp.shape)
new[name][:] = tmp
del f[old_group]
#--------------------------------------------------------------
#--------------------------------------------------------------
def countPart(f):
"""
Count particles again.
"""
npart = []
for i in range(N_type):
name = groupName(i)
if name in f:
grp = f[groupName(i)]
N = grp["Masses"].shape[0]
else:
N = 0
npart.append(N)
f["Header"].attrs["NumPart_ThisFile"] = npart
f["Header"].attrs["NumPart_Total"] = npart
f["Header"].attrs["NumPart_Total_HighWord"] = [0]*N_type
return
#--------------------------------------------------------------
f = File(file_out)
changeType(f, 2, 1)
changeType(f, 3, 1)
changeType(f, 4, 1)
changeType(f, 5, 1)
# Re-count particles properly
countPart(f)
f.close()
print("Finished changing SWIFT-type file appropriately for use.")
return
#===================================================
def convert_gadget_to_swift(file_in, file_out):
#===================================================
"""
Converts a non-hdf5 type gadget2 IC file to the SWIFT
format.
(it should also work with hdf5-type gadget files,
pNbody should figure out the initial file type by itself)
"""
nb = Nbody(file_in, ftype="gadget")
# change ftype
nb = nb.set_ftype("swift")
# Set units if necessary
# wont work this way. Do unit setting manually.
# nb.set_local_system_of_units(UnitLength_in_cm=1,UnitVelocity_in_cm_per_s=1,UnitMass_in_g=1)
units = ["UnitLength_in_cm", "UnitVelocity_in_cm_per_s", "UnitMass_in_g"]
unitd = nb.unitsparameters.get_dic()
print("WARNING:")
print("This script assumes gadget default units, which are:")
for u in units:
print("{0:30}{1:12.4E}".format(u, unitd[u]))
while True:
ans = input("Do you wish to change them manually? [y/n] ")
if ans=='y' or ans == 'Y':
i = 0
while i<len(units):
u = units[i]
inp = input("Enter a value for "+u+": [leave empty to keep] ")
try:
val = float(inp)
except ValueError:
if (inp==""):
i+=1
continue
else:
print("Didn't understand input. Try again.")
continue
nb.unitsparameters.set(u, val)
i+=1
print("Units are now:")
for u in units:
unitd = nb.unitsparameters.get_dic()
print("{0:30}{1:12.4E}".format(u, unitd[u]))
break
elif ans == 'n' or ans == 'N':
break
# set default parameters
boxsizeguess = 1.2 * (nb.pos.max() - nb.pos.min())
print("WARNING:")
print("This script made a guess for the boxsize, which is ", boxsizeguess)
while True:
ans = input("Do you wish to change them manually? [y/n] ")
if ans=='y' or ans == 'Y':
inp = input("Enter a value for the boxsize: ")
try:
val = float(inp)
except ValueError:
print("Didn't understand input. Try again.")
continue
nb.boxsize = val
break
elif ans == 'n' or ans == 'N':
nb.boxsize = boxsizeguess
break
nb.periodic = 0
nb.flag_entropy_ics = 0
# compute smoothing length
hsml = nb.get_rsp_approximation()
nb.rsp = hsml
# write new file
nb.rename(file_out)
nb.write()
print("Written SWIFT-type file ", file_out)
return
#==================================
if __name__ == "__main__":
#==================================
file_in, file_out = get_filenames()
convert_gadget_to_swift(file_in, file_out)
fix_particle_types(file_out)
[ ]: