; docformat = 'rst'
;+
; :Description:
; Reads an OBSFLUX-type file generated by cmfgen and parses its content to extract each variable in it.
;
; Also works for obs_fin, even though it has less variables in it.
;
; More precisely, the format assumed is a text file where:
;
; Scalars occupy one line, with their name followed by : followed by their value.
;
; Arrays occupy one line for the name, followed by however many lines with however many numbers in each
; with the numbers in each line separated by blanks (space or tab).
;
; An array ends when a name (of the next variable) or the end of the file is reached.
;
; Blank lines anywhere are ignored.
;
; :Returns:
; The results are packed in a structure, see the end of the function for definition of members.
;
; :Params:
; file : in, optional, default='OBSFLUX'
; String with the name of the file to read.
;
; :Examples:
; To read everything from the file 'OBSFLUX'::
;
; obs=pp_cmfread('OBSFLUX')
; print,obs.nscal
; ; 6
; for i=0,obs.nscal-1 do print,obs.scal[i]
; ;{ Total Line luminosity 0.0000000}
; ;{ Total Dielectronic and Implicit Recombination Luminosity 0.0000000}
; ;{ Total Mechanical Luminosity 1531.0000}
; ;{ Total Shock Luminosity 0.0000000}
; ;{ X-ray Luminosity (> 0.1 keV) 0.0000000}
; ;{ X-ray Luminosity (> 1 keV) 0.0000000}
;
; :Author: Paulo Penteado (pp.penteado@gmail.com), Aug/2009
;-
function pp_cmfread,file
compile_opt idl2
;Defaults
file=(n_elements(file) eq 1) ? file : 'OBSFLUX'
;read the lines into a string array
nlines=file_lines(file)
if (nlines eq 0) then message,'file is empty'
lines=strarr(nlines)
openr,unit,file,/get_lun
readf,unit,lines
free_lun,unit
;find and remove the blank lines
lines=lines[where(strlen(strcompress(lines,/remove_all)) ne 0)]
nlines=n_elements(lines)
;find the lines with scalars (identified by :)
sid=strpos(lines,':')
scal_ind=where((sid ne -1),nscalars)
arr_ind=where((sid eq -1))
;extract the scalars
scal=0
if (nscalars ne 0) then begin
scal=replicate({name:'',value:0d0},nscalars)
for i=0,nscalars-1 do begin
tmp=strsplit(lines[scal_ind[i]],':',/extract)
scal[i].name=strtrim(strcompress(tmp[0]),2)
scal[i].value=tmp[1]
endfor
endif
;remove the lines with scalars
lines=lines[arr_ind]
nlines=n_elements(lines)
narr=0
arr=0
if (nlines ne 0) then begin ;find the lines with the name of each array
; fpexpr='^[-+]?(([0-9]*\.?[0-9]+)|([0-9]+\.?[0-9]*))([eEdD][-+]?[0-9]+)?$'
;the expression above matches every floating point string I could think of
; text=bytarr(nlines) ;1 for lines that do not contain only floating point numbers
; for i=0,nlines-1 do begin ;test if each part of each line is a floating point number
; stmp=strsplit(lines[i],/extract,count=itmp)
; text[i]=(total(stregex(stmp,fpexpr,/bool)) ne itmp)
; endfor
fpexpr='^[-+]?(([0-9]*\.?[0-9]+)|([0-9]+\.?[0-9]*))([eEdD][-+]?[0-9]+)?'
;the expression above matches every string starting with floating point string I could think of
lines=strtrim(lines,2)
text=~stregex(lines,fpexpr,/bool)
w=where(text,narr)
w=[w,nlines]
if (narr ne 0) then begin ;process each array
arr=replicate({name:'',values:ptr_new()},narr)
for i=0,narr-1 do begin
atmp=0d0
for line=w[i]+1,w[i+1]-1 do begin ;start at the first line after the name of the array
stmp=strsplit(lines[line],/extract) ;separate the columns of this line
atmp=[atmp,stmp] ;convert them to double and append to the temporary array
endfor
arr[i].name=strtrim(strcompress(lines[w[i]]),2)
arr[i].values=ptr_new(atmp[1:*],/no_copy)
endfor
endif
endif
;return structure
ret={nscal:nscalars,$ ;number of scalars read
scal:scal,$ ;vector of structures, with one (name,value) pair for each scalar read (0 if nscal=0)
narr:narr,$ ;number of arrays read
arr:arr} ;vector of structures, with one (name,values) pair for each array read (0 if narr=0)
return,ret
end