In [1]:
import numpy as np
import pandas as pd
import warnings
In [2]:
def find_row(fname, string1, string2='', num_row=False):
    """ Description """
    with open(fname, encoding='ISO-8859-1') as f:
        n = 0
        for line in f:        
            n += 1
            if string1 in line and string2 in line:
                break
    
    if num_row:
        return n-1
    
    else:                
        return line
In [3]:
def oscillator_strengths(fname):
    """ Description """
    args = {}
    args['header'] = None
    args['index_col'] = False
    args['sep'] = '\s*\|\s*|-?\s+-?|(?<=[^ED\s])-(?=[^\s])'
    args['skiprows'] = find_row(fname, "Transition", "Lam", num_row=True) +1
    
    n = find_row(fname, "Number of transitions").split()[0]
    args['nrows'] = int(n)

    columns = ['State A', 'State B', 'f', 'A', 'Lam(A)', 'i', 'j', 'Lam(obs)', '% Acc']
    
  
    try:
        data = pd.read_csv(fname, **args)
    
    except pd.errors.EmptyDataError:
        data = pd.DataFrame(columns=columns)
        warnings.warn('Empty table')
    
    
    # Assign column names by file content
    if data.shape[1] == 9:
        data.columns = columns
        
    elif data.shape[1] == 10:  # This shouldn't happen (e.g. si2_osc_kurucz)
        data.columns = columns + ['?']
        data = data.drop(columns=['?'])
    
    elif data.shape[1] == 8:
        data.columns = columns[:-2] + ['#']
        data = data.drop(columns=['#'])
        data['Lam(obs)'] = np.nan
        data['% Acc'] = np.nan
    
    else:
        warnings.warn('Inconsistent number of columns')
        
    
    # Fix for Fortran float type 'D'
    if data.shape[0] > 0 and 'D' in str(data['f'][0]):
        data['f'] = data['f'].str.replace('D', 'E').map(np.float)
        data['A'] = data['A'].str.replace('D', 'E').map(np.float)
    
        
    return data
In [4]:
oscillator_strengths('../CMFGEN/atomic/FE/VI/8may97/fevi_osc_kb_rk.dat').head(20)
/home/epassaro/miniconda3/envs/carsus/lib/python3.6/site-packages/ipykernel_launcher.py:16: ParserWarning: Falling back to the 'python' engine because the 'c' engine does not support regex separators (separators > 1 char and different from '\s+' are interpreted as regex); you can avoid this warning by specifying engine='python'.
  app.launch_new_instance()
Out[4]:
State A State B f A Lam(A) i j Lam(obs) % Acc
0 3d3(3)4Fe[3/2] 3d2(3F)4p4Go[5/2] 1.940000e-02 9.870800e+08 295.634 1 36 NaN NaN
1 3d3(3)4Fe[3/2] 3d2(3F)4p4Fo[3/2] 9.065000e-02 6.971100e+09 294.516 1 38 NaN NaN
2 3d3(3)4Fe[3/2] 3d2(3F)4p4Fo[5/2] 1.765000e-02 9.091600e+08 293.820 1 39 NaN NaN
3 3d3(3)4Fe[3/2] 3d2(3F)4p2Fo[5/2] 8.831000e-04 4.608600e+07 291.910 1 43 NaN NaN
4 3d3(3)4Fe[3/2] 3d2(3F)4p4Do[3/2] 4.965000e-03 3.901100e+08 291.366 1 45 NaN NaN
5 3d3(3)4Fe[3/2] 3d2(3F)4p4Do[1/2] 4.875000e-02 7.679100e+09 291.020 1 47 NaN NaN
6 3d3(3)4Fe[3/2] 3d2(3F)4p4Do[5/2] 1.425000e-04 7.510700e+06 290.467 1 48 NaN NaN
7 3d3(3)4Fe[3/2] 3d2(3F)4p2Do[3/2] 1.100000e-02 8.715800e+08 290.147 1 49 NaN NaN
8 3d3(3)4Fe[3/2] 3d2(3F)4p2Do[5/2] 6.520000e-04 3.469200e+07 289.095 1 51 NaN NaN
9 3d3(3)4Fe[3/2] 3d2(3P)4p2So[1/2] 9.018000e-07 1.489000e+05 284.248 1 54 NaN NaN
10 3d3(3)4Fe[3/2] 3d2(3P)4p4So[3/2] 5.648000e-07 4.765500e+04 281.170 1 55 NaN NaN
11 3d3(3)4Fe[3/2] 3d2(1D)4p2Po[3/2] 3.171000e-06 2.707200e+05 279.521 1 56 NaN NaN
12 3d3(3)4Fe[3/2] 3d2(1D)4p2Fo[5/2] 3.056000e-06 1.745000e+05 279.069 1 57 NaN NaN
13 3d3(3)4Fe[3/2] 3d2(1D)4p2Po[1/2] 1.381000e-02 2.375800e+09 278.475 1 58 NaN NaN
14 3d3(3)4Fe[3/2] 3d2(3P)4p4Do[1/2] 2.123000e-03 3.658300e+08 278.245 1 59 NaN NaN
15 3d3(3)4Fe[3/2] 3d2(3P)4p4Do[3/2] 6.141000e-03 5.302300e+08 277.947 1 60 NaN NaN
16 3d3(3)4Fe[3/2] 3d2(3P)4p4Do[5/2] 4.470000e-04 2.586300e+07 277.233 1 62 NaN NaN
17 3d3(3)4Fe[3/2] 3d2(1D)4p2Do[3/2] 3.288000e-04 2.871800e+07 276.351 1 63 NaN NaN
18 3d3(3)4Fe[3/2] 3d2(1D)4p2Do[5/2] 4.944000e-05 2.890700e+06 275.784 1 65 NaN NaN
19 3d3(3)4Fe[3/2] 3d2(3P)4p4Po[1/2] 3.412000e-06 6.029200e+05 274.766 1 66 NaN NaN