; docformat = 'rst' ;+ ; This file contains a set of functions for use with NLTE grids from ; `Nordlander, T., & Lind, K. 2017, A&A, 607, A75 <http://adsabs.harvard.edu/abs/2017A%26A...607A..75N>`. ; ; The grids and routines are available for download from ; `here <https://www.mso.anu.edu.au/~thomasn/NLTE/data/>`. ; ; Execute `.r al_nlte` to interactively load a grid of LTE and NLTE calculations, ; and compile the interpolation routines. Instructions will be printed to ; screen, including the coverage in parameter space and the line data. ; Typical use cases include interpolating NLTE curves of growth using ; `find_abund`, or applying NLTE corrections to LTE abundances using ; `interp_nlte_to_lte`. ; ; Note that equivalent widths are communicated in units of pm (=10^-9 m) ; throughout these routines, and stored as log(EW/pm) in the grids. ; ; ; :EXAMPLES: ; Example run for Arcturus, using NLTE_Al_mean3D_NordlanderLind2017.sav:: ; ; .compile al_nlte ; restore, 'NLTE_Al_mean3D_NordlanderLind2017.sav' ; load data ; Teff = 4247. & logg = 1.59 & FeH = -0.52 ; reference parameters from Jofre et al. 2014 ; line = [2,3,4,5,6,7,11,15,16,17,18,19,20,21] & n = n_elements(line) ; ; These <3D> LTE abundances were measured by profile fitting: ; LTE = [6.266,6.214,6.217,6.207,6.241,6.245,6.186,6.349,6.421,6.290,6.281,6.266,6.344,6.344] ; LTE = LTE - 6.43 - FeH ; translate A(Al) to [Al/Fe] ; ; Now compute NLTE corrections: ; dNLTE = interp_nlte_to_lte(line, LTE, replicate(Teff,n), replicate(logg,n), replicate(FeH,n), EW=EW, ltegrid=ltegrid, nltegrid=nltegrid, warnings=warnings) ; forprint,textout=2, /stdout, nltegrid.wavelength[line], LTE+dNLTE, LTE, dNLTE, EW*10, format='f10.3, 3f7.3, f10.2' ; ; Wavelength NLTE LTE dNLTE EW [mA] ; ; 6696.021 0.245 0.356 -0.111 88.08 ; ; 6698.671 0.232 0.304 -0.072 60.36 ; ; 7835.314 0.214 0.307 -0.093 65.35 ; ; 7836.134 0.186 0.297 -0.111 81.16 ; ; 8772.871 0.147 0.331 -0.184 99.09 ; ; 8773.900 0.117 0.335 -0.218 120.60 ; ; 10872.972 0.230 0.276 -0.046 29.70 ; ; 13123.420 0.175 0.439 -0.264 536.62 ; ; 13150.753 0.226 0.511 -0.285 457.62 ; ; 16718.952 0.175 0.380 -0.205 444.44 ; ; 16750.534 0.154 0.371 -0.217 556.92 ; ; 16763.331 0.263 0.356 -0.093 294.92 ; ; 21093.082 0.227 0.434 -0.207 357.34 ; ; 21163.762 0.179 0.434 -0.255 435.12 ; ; ; Example run using globular cluster data from Carretta et al. 2009, A&A, 505, ; 139, via Vizier - first, save the results of ; `this query <http://vizier.u-strasbg.fr/viz-bin/asu-fits?-source=J/A%2bA/505/139/stars&-out.all&o_[Al/Fe]=>0>` ; and name the output Carretta_etal_2009.fit. Symbols indicate NLTE abundances, ; and lines indicate the NLTE corrections:: ; ; .compile al_nlte ; restore, 'NLTE_Al_MARCS_NordlanderLind2017.sav' ; c = mrdfits('carretta_etal_2009.fit', 1) ; n = n_elements(c) ; LTE = c.__al_fe_ & FeH = c.__a_h_ ; ; Their analysis is based on the 6696-6698 A doublet. We assume here that ; ; the NLTE correction of the 6696 line is representative: ; dNLTE = interp_nlte_to_lte(replicate(2, n), LTE, c.teff, c.logg, FeH, EW=EW, ltegrid=ltegrid, nltegrid=nltegrid) ; NLTE = dNLTE + LTE ; plot, FeH, NLTE, psym=4, xtitle='[Fe/H]', ytitle='[Al/Fe]', title='NLTE corrected abundances' ; for i=0,n-1 do oplot, FeH[i]+[0,0], [LTE[i], NLTE[i]] ; ; .. image:: Example_Carretta_etal_2009.png ; ; :PROPERTIES: ; test: test ; ; :USES: ; `Astrolib <https://idlastro.gsfc.nasa.gov/>` ; ; :AUTHOR: ; Thomas Nordlander, RSAA/ANU - ; `Website <https://www.mso.anu.edu.au/~thomasn/NLTE/>` ; ; :HISTORY: ; Change history:: ; Written, 2017-12-20, TN ; Modified, 2018-01-22, TN: completely rewritten to use grids stored in ; structures. This improves portability and compatibility with GDL. ;- ;+ ; Find the nearest indices in an array to the value x. ; Note that these do not necessarily bracket the parameter, but could be using ; extrapolation. ; :PARAMS: ; array: in, required, type=fltarr ; x: in, required, type=float ; :KEYWORDS: ; log: in, optional, type=boolean ; Compute frac in logarithmic spacing ; frac: out, optional, type=float ; The linear distance between x and the upper index ; :RETURNS: ; A 2-element array (`fltarr(2)`) of the nearest indices in an array to the ; value x. ; :Private: ;- function find_index, array, x, frac=frac, log=log i = (sort(abs(array-x)))[0:1] ; find two nearest points i = i[sort(i)] ; sort ; compute fractional distance to upper bracket: case keyword_set(log) of 0: frac = (array[i[1]] - x) / (array[i[1]] - array[i[0]]) 1: frac = (alog10(array[i[1]]) - alog10(x)) / (alog10(array[i[1]]) - alog10(array[i[0]])) endcase return, i end ;+ ; Interpolate the curves of growth to a given equivalent width (units of pm). ; ; Note that the input parameters may be vectors if equivalent widths are given, ; in which case the output will also be vectors. All parameters must have the ; same length. A special case is allowed, where all parameters except `EW` ; are scalar. ; ; :Params: ; line: in, required, type=long/lonarr(n) ; Line indices ; EW: in, required, type=float/fltarr(n) ; Equivalent width in units of pm. ; Teff: in, required, type=float/fltarr(n) ; FeH: in, required, type=float/fltarr(n) ; logg: in, required, type=float/fltarr(n) ; :Returns: ; The abundance (`float`/`lonarr(n)`) is returned. ; ; :Keywords: ; grid: in, required, type=grid ; A structure containing an LTE or NLTE grid ; Warnings: out, optional, type=float/fltarr(n) ; Warnings and errors. These use a floating scale 0-1 to indicate the ; fraction of nodes used for interpolation that may be unreliable due to ; extrapolation. ;- function find_abund, line, teff, logg, feh, ew, grid=grid, warnings=warnings n = n_elements(line) ; If provided a grid, simply loop over it: if n gt 1 then begin abunds = fltarr(n) if arg_present(warnings) then warnings = fltarr(n) for i=0l, n-1 do begin abunds[i] = find_abund(line[i], teff[i], logg[i], feh[i], ew[i], grid=grid, warnings=arg_present(warnings) ? tmpwarning : 0) if arg_present(warnings) then warnings[i] = tmpwarning endfor return, abunds endif ti = find_index(grid.teff, teff[0], frac=tfrac) gi = find_index(grid.logg, logg[0], frac=gfrac) fi = find_index(grid.feh, feh[0], frac=ffrac) ; Avoid interpolating in metallicity: abundcorr = 0 if feh[0] lt min(grid.feh) then begin ; below lower edge fi = [0,0] & ffrac = 0. abundcorr = grid.feh[fi[0]] - feh[0] ; adjust [X/Fe] by the difference between the requested and available [Fe/H] endif if feh[0] gt max(grid.feh) then begin ; above upper edge fi = [0,0] + grid.nfeh-1 & ffrac = 0 abundcorr = grid.feh[fi[0]] - feh[0] ; adjust [X/Fe] by the difference between the requested and available [Fe/H] endif ; logg, then Teff, [Fe/H]: cog = reform(grid.logEW[*,ti, gi[0], fi, line[0]]*gfrac + grid.logEW[*,ti, gi[1], fi, line[0]]*(1-gfrac)) cog = reform(cog[*,0,*]*tfrac + cog[*,1,*]*(1-tfrac)) cog = cog[*,0]*ffrac + cog[*,1]*(1-ffrac) ; Interpolate the COG: i = where(finite(cog), nfinite) if nfinite gt 1 then begin abund = interpol(grid.abund[i], cog[i], alog10(ew)) endif else begin ; interpolation not possible warnings = 1 return, !values.f_nan endelse abund += abundcorr ; if [Fe/H] is outside the grid, we must adjust [X/Fe] here to account for this difference ; Also check whether any models were failed: if arg_present(warnings) then begin if total(finite(abund)) eq 0 then warnings = replicate(1, n_elements(abund)) else begin ; Simply execute the interpolation the exact same way we interpolated the COGs. ; The grid.interpolated binary array simply propagates through the interpolation. warnings = reform(grid.interpolated[*,ti, gi[0], fi]*gfrac + grid.interpolated[*,ti, gi[1], fi]*(1-gfrac)) warnings = reform(warnings[*,0,*]*tfrac + warnings[*,1,*]*(1-tfrac)) warnings = warnings[*,0]*ffrac + warnings[*,1]*(1-ffrac) warnings = interpol(warnings[i], cog[i], alog10(ew)) endelse endif return, abund end ;+ ; Interpolate the curves of growth to a given abundance. ; ; If no abundance is provided, then `grid.abund` will be used and an array of ; equivalent widths (the curve of growth) is returned. ; ; Note that the input parameters may be vectors, in which case the output will ; also be vectors. All parameters must have the same length. A special case ; is allowed, where all parameters except `XFE` are scalar. ; ; :Params: ; line: in, required, type=long/lonarr(n) ; Line indices ; XFE: in, optional, type=float/fltarr(n) ; Abundances [X/Fe] to find. If unspecified or not finite, `grid.abund` will ; be used instead. ; Teff: in, required, type=float/fltarr(n) ; FeH: in, required, type=float/fltarr(n) ; logg: in, required, type=float/fltarr(n) ; :Returns: ; The equivalent width (`float`/`lonarr(n)`) is returned in units of pm. ; ; :Keywords: ; grid: in, required, type=grid ; A structure containing an LTE or NLTE grid ; Warnings: out, optional, type=float/fltarr(n) ; Warnings and errors. These use a floating scale 0-1 to indicate the ; fraction of nodes used for interpolation that may be unreliable due to ; extrapolation. ;- function find_ew, line, teff, logg, feh, xfe, grid=grid, warnings=warnings n = n_elements(line) if n_elements(xfe) eq 0 || total(finite(xfe)) eq 0 then xfe = grid.abund ; If provided a grid, simply loop over it: if n gt 1 then begin EWs = fltarr(n) if arg_present(warnings) then warnings = fltarr(n) for i=0l, n-1 do begin EWs[i] = find_ew(line[i], teff[i], logg[i], feh[i], xfe[i], grid=grid, warnings=arg_present(warnings) ? tmpwarning : 0) if arg_present(warnings) then warnings[i] = tmpwarning endfor return, EWs endif ti = find_index(grid.teff, teff[0], frac=tfrac) gi = find_index(grid.logg, logg[0], frac=gfrac) fi = find_index(grid.feh, feh[0], frac=ffrac) ; logg, then Teff, [Fe/H]: cog = reform(grid.logEW[*,ti, gi[0], fi, line[0]]*gfrac + grid.logEW[*,ti, gi[1], fi, line[0]]*(1-gfrac)) cog = reform(cog[*,0,*]*tfrac + cog[*,1,*]*(1-tfrac)) cog = cog[*,0]*ffrac + cog[*,1]*(1-ffrac) ; Interpolate the COG: i = where(finite(cog), nfinite) if nfinite gt 1 then begin cog = interpol(cog[i], grid.abund[i], xfe) endif else begin ; interpolation not possible warnings = 1 return, !values.f_nan endelse ; Also check whether any models were failed: if arg_present(warnings) then begin if total(finite(cog)) eq 0 then warnings = replicate(1,n_elements(cog)) else begin ; Simply execute the interpolation the exact same way we interpolated the COGs. ; The grid.interpolated binary array simply propagates through the interpolation. warnings = reform(grid.interpolated[*,ti, gi[0], fi]*gfrac + grid.interpolated[*,ti, gi[1], fi]*(1-gfrac)) warnings = reform(warnings[*,0,*]*tfrac + warnings[*,1,*]*(1-tfrac)) warnings = warnings[*,0]*ffrac + warnings[*,1]*(1-ffrac) warnings = interpol(warnings[i], grid.abund[i], xfe) endelse endif return, cog end ;+ ; Find the abundance correction at a given LTE abundance [X/Fe]. A sequence of ; values can be provided, but note that all parameters must have the same ; number of elements. The difference `DeltaNLTE = A(NLTE)-A(LTE)` is returned. ; ; Note that the equivalent widths returned are slightly (0.01 dex) inconsistent ; with the interpolated NLTE corrections. Rather than interpolate and match ; COGs, the NLTE corrections themselves are interpolated. This typically ; results in smoother variations with abundance and avoids numerical noise. ; ; :PARAMS: ; line: in, required, type=long/lonarr(n) ; Line indices ; xfe: in, required, type=float/fltarr(n) ; LTE abundance [X/Fe] ; Teff: in, required, type=float/fltarr(n) ; logg: in, required, type=float/fltarr(n) ; feh: in, required, type=float/fltarr(n) ; ; :RETURNS: ; A scalar (`float`) or n-element array (`fltarr(n)`) with the NLTE correction ; at the requested LTE abundance. The NLTE correction is defined as the ; abundance difference `deltaNLTE = A(NLTE) - A(LTE)`. ; ; :KEYWORDS: ; LTEgrid: in, required, type=grid ; A structure containing an LTE grid ; NLTEgrid: in, required, type=grid ; A structure containing an NLTE grid ; EW: out, optional, type=float/fltarr(n) ; Equivalent width, in units of pm. ; Warnings: out, optional, type=float/fltarr(n) ; Warnings and errors. These use a floating scale 0-1 to indicate the ; fraction of nodes used for interpolation that may be unreliable due to ; extrapolation. ;- function interp_nlte_to_lte, line, xfe, teff, logg, feh, ew=ew, ltegrid=ltegrid, nltegrid=nltegrid, warnings=warnings n = n_elements(xfe) ; If provided a grid, simply loop over it: if n gt 1 then begin dNLTE = fltarr(n) ew = fltarr(n) warnings = fltarr(n) for i=0l, n-1 do begin dNLTE[i] = interp_nlte_to_lte(line[i], xfe[i], teff[i], logg[i], feh[i], ew=ewtmp, ltegrid=ltegrid, nltegrid=nltegrid, warnings=arg_present(warnings) ? tmpwarning : 0) ew[i] = ewtmp if arg_present(warnings) then warnings[i] = tmpwarning endfor return, dNLTE endif nlte = find_ew(line, teff, logg, feh, nltegrid.abund, grid=nltegrid, warnings=arg_present(warnings) ? warnings : 0) lte = find_ew(line, teff, logg, feh, nltegrid.abund, grid=ltegrid) ; Are COGs sufficiently complete for interpolation? i = where(finite(nlte), nfinite) if nfinite le 1 then begin ; only bogus data, or not enough to interpolate COGs: warnings = 1 ew = !values.f_nan return, !values.f_nan endif ; Find the requested LTE EW: ew = 10^interpol(lte, nltegrid.abund, xfe) ; Trick: rather than interpolate COGS and match to each other, ; we instead interpolate the abundance correction curve: dNLTE = interpol(interpol(nltegrid.abund[i],nlte[i],lte)-nltegrid.abund, nltegrid.abund, xfe) ; interpolate A(X)-dNLTE to the requested abundance ; Also check whether any models were failed: if arg_present(warnings) then begin if ~finite(dNLTE) then warnings = 1 else begin warnings = interpol(warnings, nltegrid.abund, xfe) endelse endif return, dNLTE end ;+ ; Find the abundance correction at a given NLTE abundance [X/Fe]. A sequence of ; values can be provided, but note that all parameters must have the same ; number of elements. The difference `DeltaNLTE = A(NLTE)-A(LTE)` is returned. ; ; Note that the equivalent widths returned are slightly (0.01 dex) inconsistent ; with the interpolated NLTE corrections. Rather than interpolate and match ; COGs, the NLTE corrections themselves are interpolated. This typically ; results in smoother variations with abundance and avoids numerical noise. ; ; :PARAMS: ; line: in, required, type=long/lonarr(n) ; Line indices ; xfe: in, required, type=float/fltarr(n) ; NLTE abundance [X/Fe] ; Teff: in, required, type=float/fltarr(n) ; logg: in, required, type=float/fltarr(n) ; feh: in, required, type=float/fltarr(n) ; ; :RETURNS: ; A scalar (`float`) or n-element array (`fltarr(n)`) with the NLTE correction ; at the requested LTE abundance. The NLTE correction is defined as the ; abundance difference `deltaNLTE = A(NLTE) - A(LTE)`. ; ; :KEYWORDS: ; LTEgrid: in, required, type=grid ; A structure containing an LTE grid ; NLTEgrid: in, required, type=grid ; A structure containing an NLTE grid ; EW: out, optional, type=float/fltarr(n) ; Equivalent width, in units of pm. ; Warnings: out, optional, type=float/fltarr(n) ; Warnings and errors. These use a floating scale 0-1 to indicate the ; fraction of nodes used for interpolation that may be unreliable due to ; extrapolation. ;- function interp_lte_to_nlte, line, xfe, teff, logg, feh, ew=ew, ltegrid=ltegrid, nltegrid=nltegrid, warnings=warnings common nltegrid, wn, wl, ag,tg,gg,fg, na,nt,ng,nf, wg, interpolated n = n_elements(xfe) ; If provided a grid, simply loop over it: if n gt 1 then begin dNLTE = fltarr(n) ew = fltarr(n) warnings = fltarr(n) for i=0l, n-1 do begin dNLTE[i] = interp_lte_to_nlte(line[i], xfe[i], teff[i], logg[i], feh[i], ew=ewtmp, lte=ltegrid, nlte=nltegrid, warnings=arg_present(warnings) ? tmpwarning : 0) ew[i] = ewtmp if arg_present(warnings) then warnings[i] = tmpwarning endfor return, dNLTE endif nlte = find_ew(line, teff, logg, feh, nltegrid.abund, grid=nltegrid, warnings=arg_present(warnings) ? warnings : 0) lte = find_ew(line, teff, logg, feh, nltegrid.abund, grid=ltegrid) ; Are COGs sufficiently complete for interpolation? i = where(finite(nlte), nfinite) if nfinite le 1 then begin ; only bogus data, or not enough to interpolate COGs: warnings = 1 ew = !values.f_nan return, !values.f_nan endif ; Find the requested NLTE EW: ew = 10^interpol(nlte[i], nltegrid.abund[i], xfe) ; Trick: rather than interpolate COGS and match to each other, ; we instead interpolate the abundance correction curve: dNLTE = interpol(nltegrid.abund[i]-interpol(nltegrid.abund,lte,nlte[i]), nltegrid.abund[i], xfe) ; interpolate A(X)-dNLTE to the requested abundance ; dNLTE = interpol(ag[i]-interpol(ag,lte,nlte[i]), nlte[i], alog10(ew)) ; Also check whether models used converged: if arg_present(warnings) then begin if ~finite(dNLTE) then warnings = 1 else begin warnings = interpol(warnings[i], nltegrid.abund[i], xfe) endelse endif return, dNLTE end ; Does a grid already exist in memory? if n_elements(ltegrid) eq 0 && ~keyword_set(filename) then begin files = file_search('*sav', count=nfiles) if nfiles eq 0 then begin print, 'Note, no grids available in current directory. You need to manually locate and restore a suitable grid before continuing. You can also at any point replace the "ltegrid" and "nltegrid" variables by manually restoring a grid.' stop endif else begin print, 'These grids are available: ' for i=0,nfiles-1 do print, i, files[i], format='(i3, 2x, a)' print, 'You can select a grid to load by typing its number, or you can enter an empty string and then load it manually ' str = '' readf, 0, str str = stregex(str, '[0-9]+', /extract) if strlen(str) gt 0 then begin n = long(str) filename = files[n] endif ; Still no grid in memory, and none was requested: if ~keyword_set(filename) && n_elements(ltegrid) eq 0 then begin print, 'Exiting grid selection, returning to prompt. Please load a grid manually and then continue by running .c' stop endif endelse endif ; Did the user request a grid via the filename variable, or by keyboard selection in the previous section? if n_elements(ltegrid) eq 0 && keyword_set(filename) then begin if ~keyword_set(silent) then print, 'Loading grid ', filename restore, filename filename = 0 endif ; Ensure a grid has been loaded: while n_elements(ltegrid) eq 0 do begin print, 'Please load a grid before continuing, or exit this routine.' stop endwhile print, 'Two functions for NLTE-correction interpolation are provided:' print, ' NLTEcorrection = interp_nlte_to_lte(line, xfe, teff, logg, feh, ew=ew, ltegrid=ltegrid, nltegrid=nltegrid, warnings=warnings): NLTE correction at a reference LTE abundance [X/Fe]' print, ' NLTEcorrection = interp_lte_to_nlte(line, xfe, teff, logg, feh, ew=ew, ltegrid=ltegrid, nltegrid=nltegrid, warnings=warnings): NLTE correction at a reference NLTE abundance [X/Fe]' print,' line: the line index (above)' print,' xfe, teff, logg, feh: [X/Fe], Teff, logg, [Fe/H]' print,' ew: the interpolated equivalent width (in units of pm)' print,' warnings: a scale from 0 to 1 indicating the unreliability of interpolation. A nonzero number indicates that the abundance correction must be used with caution, due to stability problems in that region of parameter space. A value near or equal to 1 indicates that the abundance correction is entirely unreliable.' print, ' The input parameters may be arrays.' print, 'The curves of growth can also be interpolated directly: ' print, ' NLTE = find_abund(line, teff, logg, feh, ew, grid=nltegrid, warnings=warnings)' print, ' LTE = find_abund(line, teff, logg, feh, ew, grid=ltegrid, warnings=warnings)' print, 'Or correspondingly to find an EW: ' print, ' NLTE = find_ew(line, teff, logg, feh, xfe, grid=nltegrid, warnings=warnings)' print, ' LTE = find_ew(line, teff, logg, feh, xfe, grid=ltegrid, warnings=warnings)' print, ' Input parameters have the same definitions as above.' print, '' print, 'Note that equivalent widths are always in units of pm (= 10 mA).' print, 'The reference solar abundance in the grid is A(Al) = 6.43.' print, '' nconverged = total(total(finite(nltegrid.logew[*,*,*,*, 0]) and ~nltegrid.interpolated, 1), 3) print, 'The current NLTE grid covers these nodes in parameter space: ' print, 'Teff [K]: ', nltegrid.teff, format='(a12, 100i6)' print, 'logg [cgs]: ', nltegrid.logg, format='(a12, 100f6.2)' print, '[Fe/H]: ', nltegrid.feh, format='(a12, 100f6.2)' print, '[X/Fe]: ', nltegrid.abund, format='(a12, 100f6.2)' print, 'indices: ', indgen(nltegrid.nteff > nltegrid.nlogg > nltegrid.nfeh > nltegrid.nabund), format='(a12, 100i6)' print, 'The HR diagram is sparse, and looks like this: ' for gi=0,nltegrid.nlogg-1 do print, nltegrid.logg[gi], (['', '.', '+'])[reverse((nconverged[*,gi] gt 0) + (nconverged[*,gi] gt (nltegrid.nfeh*nltegrid.nabund/2)))], format='(f10.2, 100a3)' ind = nltegrid.nteff - 1 - indgen((nltegrid.nteff+1)/2)*2 print, 'logg/Teff', nltegrid.teff[ind], format='(a10, 100i6)' print, ' where + and . denote that most or any of the models with varying [Fe/H] and [X/Fe] are available.' print, '' print, 'The grid contains these spectral lines: ' print, 'line', 'Ion', 'Wave [A]', 'Transition', 'E_low', 'loggf', 'alpha sigma', format='(a-5, a-6, a10, 2x, a-24, 2x, 2a7, 1x, a)' for i=0,nltegrid.nlines-1 do print, i, nltegrid.spec[nltegrid.irad[i]]+' ', string(nltegrid.wavelength[i], format='(f10.3)'), nltegrid.conf[nltegrid.irad[i]]+' '+nltegrid.term[nltegrid.irad[i]], nltegrid.conf[nltegrid.jrad[i]]+' '+nltegrid.term[nltegrid.jrad[i]], string(nltegrid.ev[nltegrid.irad[i]], format='(f7.3)'), nltegrid.loggf[i], nltegrid.gwrep[i], format='(i3,2x, a-6, a10, 2x, a-10," -> ",a-10, 2x, a7,f7.3,2x, a)' print, ' line: the line index (0-'+strtrim(nltegrid.nlines,2)+')' print, ' E_low: energy of the lower state, in units of eV' print, ' alpha and sigma: constants describing collisional broadening (often called Van der Waals broadening) - see the paper for description and references' print, ' Note that the resonance lines must be used with caution. The nearby very strong Ca II H & K lines are likely to strongly distort the continuum, so that equivalent widths tabulated here are unreliable. NLTE corrections are at most indicative, and we urge the use of direct synthesis and profile fitting.' print, '' end