-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocess_output.py
More file actions
143 lines (118 loc) · 5.11 KB
/
Copy pathprocess_output.py
File metadata and controls
143 lines (118 loc) · 5.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import numpy as np
import struct
import spectrum_models as sm
# Helper functions
def get_good_n_chunks(n_los, nmax=1000, nmin=1):
"""
Find a suitable integer that divides n_los
into an integer number of chunks
"""
for n in range(nmax, nmin, -1):
if np.mod(n_los, n) == 0:
return n
raise ValueError('Could not find a suitable n_chunks')
def read_int(f):
return struct.unpack('i', f.read(4))[0]
def get_trans_frac_in_chunks(transmissions_file, line_model,
halo_masses, params_dict,
n_chunks=None, line_model_args={}):
"""
Process the transmission functions in the given output
file and calculate the transmitted fraction given the
supplied line model
:param transmissions_file: The filename containing the transmissions
:param line_model: Callable that gives the line flux as a function
of wavelength in Angstrom. This function must also accept a
kwargs dict with additional parameters. One parameter will
always be called 'mass', and contain the halo mass,
log(Mh/Ms)
:param halo_masses: Array containing the masses of each
halo
:param params_dict: Dictionary containing parameters
:param n_chunks: The number of chunks to use when reading
the file. If None, try to find a suitable value
:param line_model_args: Dictionary containing extra arguments
for the line model function. The halo mass will be automatically
added
:return: Array with the transmitted fractions
"""
# Extract info from parameters
specres = params_dict['specres_bins']
wavel = np.linspace(params_dict['wavel_lower'],
params_dict['wavel_upper'], specres)
# The output files can be very large, and need to be read in chunks
fractions_out = []
with open(transmissions_file, 'rb') as f:
record_size, n_records, n_los = read_transmissions_header(f, specres)
# Find the number of chunks to use when reading the file
if n_chunks is None:
n_chunks = get_good_n_chunks(n_los=n_los)
chunk_size = record_size/n_chunks
assert np.mod(chunk_size, specres) == 0
assert n_records == 1
# Read each record
los_idx = 0
for chunk in range(n_chunks):
print 'Reading chunk ', chunk, ' of ', n_chunks
tau = np.fromfile(f, dtype='float32', count=chunk_size)
tau[tau != tau] = 1e10 # Try to prevent numerical problems
tau[tau < 0] = 0.
tau = tau.reshape((chunk_size/specres, specres))
trans_func = np.exp(-tau)
for i in xrange(trans_func.shape[0]):
line_model_args['mass'] = \
halo_masses[float(los_idx)/n_los*len(halo_masses)]
intrinsic_spectrum = line_model(wavel, **line_model_args)
trans_frac = sm.get_transmitted_fraction(intrinsic_spectrum,
trans_func[i, :],
wavel)
fractions_out.append(trans_frac)
los_idx += 1
return np.array(fractions_out)
def get_tau(transmissions_file, params_dict):
"""
Read a raw output file from SimpleTransfer and
return a matrix with dimensions (n_los, n_spec_bins)
containing the optical depth as a function of wavelength
The transmission function is related to tau as:
T = exp(-tau)
:param transmissions_file: The name of the file to read
:param params_dict: Dictionary containing paramters
:return: (wavel, tau) tuple. tau is a matrix containing
the optical depth. It has dimensions (n_los, n_spec_bins)
"""
# Extract info from parameters
specres = params_dict['specres_bins']
wavel = np.linspace(params_dict['wavel_lower'],
params_dict['wavel_upper'], specres)
with open(transmissions_file, 'rb') as f:
record_size, n_records, n_los = read_transmissions_header(f, specres)
tau = np.zeros(n_los*specres, dtype='float32')
for i in range(n_records):
_ = read_int(f) # FORTRAN record separators
if i < n_records-1:
tau[i*record_size:(i+1)*record_size] = np.fromfile(f, dtype='float32',
count=record_size)
else:
tau[i*record_size:] = np.fromfile(f, dtype='float32',
count=n_los*specres-i*record_size)
_ = read_int(f)
tau[tau != tau] = 1e10 # Try to prevent numerical problems
tau[tau < 0] = 0.
tau = tau.reshape((n_los, specres))
return wavel, tau
def read_transmissions_header(f, specres):
"""
Read the header of a transmissions file
:param f: File object
:param specres: Spectral resolution
:return: recsize, n_records, n_los
"""
# Read the FORTRAN record separator
_ = read_int(f)
n_records = read_int(f)
n_los = read_int(f)
_ = read_int(f)
ifrac = n_los/n_records
recsize = ifrac*specres
return recsize, n_records, n_los