2222]
2323
2424
25+ # Do this here as calling this each time adds significant overhead
26+ # when parsing a file.
27+ ELEMENT_NAME_MAPPING = {
28+ z : plasmapy .particles .element_name (z ) for z in range (1 ,31 )
29+ }
30+
31+
2532def read_master_time (hydrad_root , read_from_cfg = False ):
2633 """
2734 Get array of times that correspond to each timestep for the entire simulation.
@@ -155,10 +162,14 @@ def read_phy_file(filename):
155162 'electron_heat_flux' : 'erg s-1 cm-2' ,
156163 'hydrogen_heat_flux' : 'erg s-1 cm-2' ,
157164 }
158- return astropy .table .QTable .read (
159- filename ,
160- format = 'ascii' ,
161- names = columns ,
165+ return astropy .table .QTable .from_pandas (
166+ read_csv (
167+ filename ,
168+ sep = r'\s+' ,
169+ header = None ,
170+ engine = 'c' ,
171+ names = columns ,
172+ ),
162173 units = units ,
163174 )
164175
@@ -175,38 +186,35 @@ def read_ine_file(filename, n_s):
175186 ----------
176187 filename: path-like
177188 n_s: `int`
189+ The number of grid cells in the snapshot corresponding to this file.
178190 """
179- # TODO: clean this up somehow? I've purposefully included
180- # a lot of comments because the format of this file makes
181- # the parsing code quite opaque
182- with pathlib .Path (filename ).open () as f :
191+ # This file is grouped into n_s groups each of length n_el + 1 (because the first entry is
192+ # the spatial coordinate) such that the total number of lines is n_s*(n_el + 1).
193+ # Each line in the group (except the first line) has Z+2 entries corresponding to Z followed
194+ # by the ionization fraction of the Z+1 ionization stages of element Z at the spatial
195+ # coordinate specified in the first line of the group.
196+ # Because of the complexity of the structure of this file, we need to parse it line by line.
197+ with filename .open (mode = 'r' ) as f :
183198 lines = f .readlines ()
184- # First parse all of the population fraction arrays
185- # NOTE: Have to calculate the number of elements we have
186- # computed population fractions for as we do not necessarily
187- # know this ahead of time
188- n_e = int (len (lines )/ n_s - 1 )
189- # The file is arranged in n_s groups of n_e+1 lines each where the first
190- # line is the coordinate and the subsequent lines are the population fraction
191- # for each element, with each column corresponding to an ion of that element
192- # First, separate by coordinate
193- pop_lists = [lines [i * (n_e + 1 )+ 1 :(i + 1 )* (n_e + 1 )] for i in range (n_s )]
194- # Convert each row of each group into a floating point array
195- pop_lists = [[np .array (l .split (), dtype = float ) for l in p ] for p in pop_lists ]
196- # NOTE: each row has Z+2 entries as the first entry is the atomic number Z
197- # Get these from just the first group as the number of elements is the same
198- # for each
199- Z = np .array ([p [0 ] for p in pop_lists [0 ]], dtype = int )
200- pop_arrays = [np .zeros ((n_s , z + 1 )) for z in Z ]
201- for i , p in enumerate (pop_lists ):
202- for j , line in enumerate (p ):
203- pop_arrays [j ][i , :] = line [1 :] # Skip first entry, it is the atomic number
204- columns = []
199+ n_el = int (len (lines )/ n_s - 1 )
200+ # The innermost loop parses the ionization fraction for all ionization stages of a given element Z
201+ # at all spatial coordinates and casts it to an array. This innermost array has dimensions (n_s,Z+1).
202+ # The outermost array iterates over all elements. The result is a list of length n_el where each entry
203+ # contains the ionization fractions at all ionization stages of a given element at all spatial coordinates.
204+ data = [
205+ np .asarray (
206+ [lines [(1 + n_el )* i_s + 1 + i_z ].split ()[1 :] for i_s in range (n_s )],
207+ dtype = np .float64
208+ )
209+ for i_z in range (n_el )
210+ ]
211+ Z = [x .shape [1 ]- 1 for x in data ]
212+ colnames = []
205213 for z in Z :
206- el_name = plasmapy .particles .element_name ( z )
207- columns += [ f' { el_name } _ { i + 1 } ' for i in range ( z + 1 )]
208- data = np . hstack ([ p for p in pop_arrays ])
209- return astropy .table .QTable (data = data , names = columns )
214+ # A precomputed mapping between Z and element name is used as calling plasmapy.particles.element_name
215+ # each time leads to significant overhead.
216+ colnames += [ f' { ELEMENT_NAME_MAPPING [ z ] } _ { i } ' for i in range ( 1 , z + 2 )]
217+ return astropy .table .Table (data = np . hstack ( data ) , names = colnames , copy = False )
210218
211219
212220def read_trm_file (filename ):
0 commit comments