input_output.read_config

Parse config files.

  1"""Parse config files."""
  2from misc import read_input_csv as ricsv
  3from copy import deepcopy
  4from input_output.organize import Organize_input
  5import tomli
  6import tomli_w
  7import yaml
  8from yaml.loader import FullLoader
  9import numpy as np
 10
 11
 12def convert_txt_to_yaml(init_file):
 13    # Read .pipt or .popt file
 14    pr, fwd = read_txt(init_file)
 15
 16    # Write dictionaries to yaml file with same base file name
 17    new_file = change_file_extension(init_file, 'yaml')
 18    with open(new_file, 'wb') as f:
 19        if 'daalg' in pr:
 20            yaml.dump({'dataassim': pr, 'fwdsim': fwd}, f)
 21        else:
 22            yaml.dump({'optim': pr, 'fwdsim': fwd}, f)
 23
 24
 25def read_yaml(init_file):
 26    """
 27    Read .yaml input file, parse and return dictionaries for PIPT/POPT.
 28
 29    Parameters
 30    ----------
 31    init_file : str
 32        .yaml file
 33
 34    Returns
 35    -------
 36    keys_da : dict
 37        Parsed keywords from dataassim
 38    keys_fwd : dict
 39        Parsed keywords from fwdsim
 40    """
 41    # Make a !ndarray tag to convert a sequence to np.array
 42    def ndarray_constructor(loader, node):
 43        array = loader.construct_sequence(node)
 44        return np.array(array)
 45
 46    # Add constructor to yaml with tag !ndarray
 47    yaml.add_constructor('!ndarray', ndarray_constructor)
 48
 49    # Read
 50    with open(init_file, 'rb') as fid:
 51        y = yaml.load(fid, Loader=FullLoader)
 52
 53    # Check for dataassim and fwdsim
 54    if 'optim' in y.keys():
 55        keys_pr = y['optim']
 56        check_mand_keywords_opt(keys_pr)
 57    elif 'dataassim' in y.keys():
 58        keys_pr = y['datasssim']
 59        check_mand_keywords_da(keys_pr)
 60    else:
 61        raise KeyError
 62    if 'fwdsim' in y.keys():
 63        keys_fwd = y['fwdsim']
 64    else:
 65        raise KeyError
 66
 67    # Organize keywords
 68    org = Organize_input(keys_pr, keys_fwd)
 69    org.organize()
 70
 71    return org.get_keys_pr(), org.get_keys_fwd()
 72
 73
 74def convert_txt_to_toml(init_file):
 75    # Read .pipt or .popt file
 76    pr, fwd = read_txt(init_file)
 77
 78    # Write dictionaries to toml file with same base file name
 79    new_file = change_file_extension(init_file, 'toml')
 80    with open(new_file, 'wb') as f:
 81        if 'daalg' in pr:
 82            tomli_w.dump({'dataassim': pr, 'fwdsim': fwd}, f)
 83        else:
 84            tomli_w.dump({'optim': pr, 'fwdsim': fwd}, f)
 85
 86
 87def read_toml(init_file):
 88    """
 89    Read .toml configuration file, parse and output dictionaries for PIPT/POPT
 90
 91    Parameters
 92    ----------
 93    init_file : str
 94        toml configuration file
 95    """
 96    # Read
 97    with open(init_file, 'rb') as fid:
 98        t = tomli.load(fid)
 99
100    # Check for dataassim and fwdsim
101    if 'ensemble' in t.keys():
102        keys_en = t['ensemble']
103        check_mand_keywords_en(keys_en)
104    else:
105        keys_en = None
106    if 'optim' in t.keys():
107        keys_pr = t['optim']
108        check_mand_keywords_opt(keys_pr)
109    elif 'dataassim' in t.keys():
110        keys_pr = t['dataassim']
111        check_mand_keywords_da(keys_pr)
112    else:
113        raise KeyError
114    if 'fwdsim' in t.keys():
115        keys_fwd = t['fwdsim']
116    else:
117        raise KeyError
118
119    # Organize keywords
120    org = Organize_input(keys_pr, keys_fwd, keys_en)
121    org.organize()
122
123    return org.get_keys_pr(), org.get_keys_fwd(), org.get_keys_en()
124
125
126def read_txt(init_file):
127    """
128    Read a PIPT or POPT input file (.pipt or .popt), parse and output dictionaries for data assimilation or
129    optimization,  and simulator classes.
130
131    Parameters
132    ----------
133    init_file: str
134        PIPT init. file containing info. to run the inversion algorithm
135
136    Returns
137    -------
138    keys_pr : dict
139        Parsed keywords from DATAASSIM or OPTIM
140    keys_fwd : dict
141        Parsed keywords from FWDSSIM
142    """
143
144    # Check for .pipt suffix
145    if not init_file.endswith('.pipt') and not init_file.endswith('.popt'):
146        raise FileNotFoundError(f'No PIPT or POPT input file (.pipt or .popt) found! If {init_file} is  '
147                                f'a PIPT or POPT input file, change suffix to .pipt or .popt')
148
149    # Read the init file and output lines without comments (lines starting with '#')
150    lines = read_clean_file(init_file)
151
152    # Find where the separate parts are located in the file. FWDSIM will always be a part, but the
153    # inversion/optimiztation part may be DATAASSIM or OPTIM
154    prind = None
155    pr_part = None
156    fwdsimind = None
157    for i in range(len(lines)):
158        if lines[i].strip().lower() == 'dataassim' or lines[i].strip().lower() == 'optim':
159            prind = i
160            pr_part = lines[i].strip().lower()
161        elif lines[i].strip().lower() == 'fwdsim':
162            fwdsimind = i
163
164    # Split the file into the two separate parts. Each part will (only) contain the keywords of each part:
165    if prind < fwdsimind:  # Data assim. part is the first part of file
166        lines_pr = lines[2:fwdsimind]
167        lines_fwd = lines[fwdsimind + 2:]
168    else:  # Fwd sim. part is the first part of file
169        lines_fwd = lines[2:prind]
170        lines_pr = lines[prind + 2:]
171
172    # Get rid of empty lines in lines_pr and lines_fwd
173    clean_lines_pr = remove_empty_lines(lines_pr)
174    clean_lines_fwd = remove_empty_lines(lines_fwd)
175
176    # Assign the keys and values to different dictionaries depending on whether we have data assimilation (DATAASSIM)
177    # or optimization (OPTIM). FWDSIM info is always assigned to keys_fwd
178    keys_pr = None
179    if pr_part == 'dataassim':
180        keys_pr = parse_keywords(clean_lines_pr)
181        check_mand_keywords_da(keys_pr)
182    elif pr_part == 'optim':
183        keys_pr = parse_keywords(clean_lines_pr)
184        check_mand_keywords_opt(keys_pr)
185    keys_fwd = parse_keywords(clean_lines_fwd)
186    check_mand_keywords_fwd(keys_fwd)
187
188    org = Organize_input(keys_pr, keys_fwd)
189    org.organize()
190
191    return org.get_keys_pr(), org.get_keys_fwd()
192
193
194def read_clean_file(init_file):
195    """
196    Read PIPT init. file and lines that are not comments (marked with octothorpe)
197
198    Parameters
199    ----------
200    init_file: str
201        Name of file to remove all comments. WHOLE filename needed (with suffix!)
202
203    Returns
204    -------
205    lines: list
206        Lines from init. file converted to list entries
207    """
208    # Read file except lines starting with an octothorpe (#) and return the python variable
209    with open(init_file, 'r') as f:
210        lines = [line for line in f.readlines() if not line.startswith('#')]
211
212    # Return clean lines
213    return lines
214
215
216def remove_empty_lines(lines):
217    """
218    Small method for finding empty lines in a read file.
219
220    Parameters
221    ----------
222    lines: list
223        List of lines from a file
224
225    Returns
226    -------
227    lines_clean: list
228        List of clean lines (without empty entries)
229    """
230    # Loop over lines to find '\n'
231    sep = []
232    for i in range(len(lines)):
233        if lines[i] == '\n':
234            sep.append(i)
235
236    # Make clean output
237    lines_clean = []
238    for i in range(len(sep)):
239        if i == 0:
240            lines_clean.append(lines[0:sep[i]])
241        else:
242            lines_clean.append(lines[sep[i-1] + 1:sep[i]])
243
244    # Return
245    return lines_clean
246
247
248def parse_keywords(lines):
249    """
250    Here we parse the lines in the init. file to a Python dictionary. The keys of the dictionary is the keywords
251    in the PIPT init. file, and the information in each keyword is stored in each key of the
252    dictionary. To know how the keyword-information is organized in the keys of the dictionary, confront the
253    manual located in the doc folder.
254
255    Parameters
256    ----------
257    lines: list
258        List of (clean) lines from the PIPT init. file.
259
260    Returns
261    -------
262    keys: dict
263        Dictionary with all info. from the init. file.
264    """
265    # Init. the dictionary
266    keys = {}
267
268    # Loop over all input keywords and store in the dictionary.
269    for i in range(len(lines)):
270        if lines[i] != []:  # Check for empty list (corresponds to empty line in file)
271            try:  # Try first to store the info. in keyword as float in a 1D list
272                # A scalar, which we store as scalar...
273                if len(lines[i][1:]) == 1 and len(lines[i][1:][0].split()) == 1:
274                    keys[lines[i][0].strip().lower()] = float(lines[i][1:][0])
275                else:
276                    keys[lines[i][0].strip().lower()] = [float(x) for x in lines[i][1:]]
277            except:
278                try:  # Store as float in 2D list
279                    if len(lines[i][1:]) == 1:  # Check if it is actually a 1D array disguised as 2D
280                        keys[lines[i][0].strip().lower()] = \
281                            [float(x) for x in lines[i][1:][0].split()]
282                    else:  # if not store as 2D list
283                        keys[lines[i][0].strip().lower()] = \
284                            [[float(x) for x in col.split()] for col in lines[i][1:]]
285                except:  # Keyword contains string(s), not floats
286                    if len(lines[i][1:]) == 1:  # If 1D list
287                        # If it is a scalar store as single input
288                        if len(lines[i][1:][0].split('\t')) == 1:
289                            keys[lines[i][0].strip().lower()] = lines[i][1:][0].strip().lower()
290                        else:  # Store as 1D list
291                            keys[lines[i][0].strip().lower()] = \
292                                [x.rstrip('\n').lower()
293                                 for x in lines[i][1:][0].split('\t') if x != '']
294                    else:  # It is a 2D list
295                        # Check each row in 2D list. If it is single column (i.e., one string per row),
296                        # we make it a 1D list of strings; if not, we make it a 2D list of strings.
297                        one_col = True
298                        for j in range(len(lines[i][1:])):
299                            if len(lines[i][1:][j].split('\t')) > 1:
300                                one_col = False
301                                break
302                        if one_col is True:  # Only one column
303                            keys[lines[i][0].strip().lower()] = \
304                                [x.rstrip('\n').lower() for x in lines[i][1:]]
305                        else:  # Store as 2D list
306                            keys[lines[i][0].strip().lower()] = \
307                                [[x.rstrip('\n').lower() for x in col.split('\t') if x != '']
308                                    for col in lines[i][1:]]
309
310    # Need to check if there are any only-string-keywords that actually contains floats, and convert those to
311    # floats (the above loop only handles pure float or pure string input, hence we do a quick fix for mixed
312    # lists here)
313    # Loop over all keys in dict. and check every "pure" string keys for floats
314    for i in keys:
315        if isinstance(keys[i], list):  # Check if key is a list
316            if isinstance(keys[i][0], list):  # Check if it is a 2D list
317                for j in range(len(keys[i])):  # Loop over all sublists
318                    # Check sublist for strings
319                    if all(isinstance(x, str) for x in keys[i][j]):
320                        for k in range(len(keys[i][j])):  # Loop over enteries in sublist
321                            try:  # Try to make float
322                                keys[i][j][k] = float(keys[i][j][k])  # Scalar
323                            except:
324                                try:  # 1D array
325                                    keys[i][j][k] = [float(x)
326                                                     for x in keys[i][j][k].split()]
327                                except:  # If it is actually a string, pass over
328                                    pass
329            else:  # It is a 1D list
330                # Check if list only contains strings
331                if all(isinstance(x, str) for x in keys[i]):
332                    for j in range(len(keys[i])):  # Loop over all entries in list
333                        try:  # Try to make float
334                            keys[i][j] = float(keys[i][j])
335                        except:
336                            try:
337                                keys[i][j] = [float(x) for x in keys[i][j].split()]
338                            except:  # If it is actually a string, pass over
339                                pass
340
341    # Return dict.
342    return keys
343
344
345def check_mand_keywords_fwd(keys_fwd):
346    """Check for mandatory keywords in `FWDSIM` part, and output error if they are not present"""
347
348    # Mandatory keywords in FWDSIM
349    assert 'parallel' in keys_fwd, 'PARALLEL not in FWDSIM!'
350    assert 'datatype' in keys_fwd, 'DATATYPE not in FWDSIM!'
351
352
353def check_mand_keywords_da(keys_da):
354    """Check for mandatory keywords in `DATAASSIM` part, and output error if they are not present"""
355
356    # Mandatory keywords in DATAASSIM
357    assert 'truedataindex' in keys_da, 'TRUEDATAINDEX not in DATAASSIM!'
358    assert 'assimindex' in keys_da, 'ASSIMINDEX not in DATAASSIM!'
359    assert 'truedata' in keys_da, 'TRUEDATA not in DATAASSIM!'
360    assert 'datavar' in keys_da, 'DATAVAR not in DATAASSIM!'
361    assert 'obsname' in keys_da, 'OBSNAME not in DATAASSIM!'
362    assert 'energy' in keys_da, 'ENERGY not in DATAASSIM!'
363
364
365def check_mand_keywords_opt(keys_opt):
366    """Check for mandatory keywords in `OPTIM` part, and output error if they are not present"""
367pass
368
369
370def check_mand_keywords_en(keys_en):
371    """Check for mandatory keywords in `ENSEMBLE` part, and output error if they are not present"""
372
373    # Mandatory keywords in ENSEMBLE
374    assert 'ne' in keys_en, 'NE not in ENSEMBLE!'
375    assert 'state' in keys_en, 'STATE not in ENSEMBLE!'
376    if 'importstaticvar' not in keys_en:
377        assert filter(list(keys_en.keys()),
378                      'prior_*') != [], 'No PRIOR_<STATICVAR> in DATAASSIM'
379
380def change_file_extension(filename, new_extension):
381    if '.' in filename:
382        name, old_extension = filename.rsplit('.', 1)
383        new_filename = name + '.' + new_extension
384    else:
385        new_filename = filename + '.' + new_extension
386    return new_filename
def convert_txt_to_yaml(init_file):
13def convert_txt_to_yaml(init_file):
14    # Read .pipt or .popt file
15    pr, fwd = read_txt(init_file)
16
17    # Write dictionaries to yaml file with same base file name
18    new_file = change_file_extension(init_file, 'yaml')
19    with open(new_file, 'wb') as f:
20        if 'daalg' in pr:
21            yaml.dump({'dataassim': pr, 'fwdsim': fwd}, f)
22        else:
23            yaml.dump({'optim': pr, 'fwdsim': fwd}, f)
def read_yaml(init_file):
26def read_yaml(init_file):
27    """
28    Read .yaml input file, parse and return dictionaries for PIPT/POPT.
29
30    Parameters
31    ----------
32    init_file : str
33        .yaml file
34
35    Returns
36    -------
37    keys_da : dict
38        Parsed keywords from dataassim
39    keys_fwd : dict
40        Parsed keywords from fwdsim
41    """
42    # Make a !ndarray tag to convert a sequence to np.array
43    def ndarray_constructor(loader, node):
44        array = loader.construct_sequence(node)
45        return np.array(array)
46
47    # Add constructor to yaml with tag !ndarray
48    yaml.add_constructor('!ndarray', ndarray_constructor)
49
50    # Read
51    with open(init_file, 'rb') as fid:
52        y = yaml.load(fid, Loader=FullLoader)
53
54    # Check for dataassim and fwdsim
55    if 'optim' in y.keys():
56        keys_pr = y['optim']
57        check_mand_keywords_opt(keys_pr)
58    elif 'dataassim' in y.keys():
59        keys_pr = y['datasssim']
60        check_mand_keywords_da(keys_pr)
61    else:
62        raise KeyError
63    if 'fwdsim' in y.keys():
64        keys_fwd = y['fwdsim']
65    else:
66        raise KeyError
67
68    # Organize keywords
69    org = Organize_input(keys_pr, keys_fwd)
70    org.organize()
71
72    return org.get_keys_pr(), org.get_keys_fwd()

Read .yaml input file, parse and return dictionaries for PIPT/POPT.

Parameters
  • init_file (str): .yaml file
Returns
  • keys_da (dict): Parsed keywords from dataassim
  • keys_fwd (dict): Parsed keywords from fwdsim
def convert_txt_to_toml(init_file):
75def convert_txt_to_toml(init_file):
76    # Read .pipt or .popt file
77    pr, fwd = read_txt(init_file)
78
79    # Write dictionaries to toml file with same base file name
80    new_file = change_file_extension(init_file, 'toml')
81    with open(new_file, 'wb') as f:
82        if 'daalg' in pr:
83            tomli_w.dump({'dataassim': pr, 'fwdsim': fwd}, f)
84        else:
85            tomli_w.dump({'optim': pr, 'fwdsim': fwd}, f)
def read_toml(init_file):
 88def read_toml(init_file):
 89    """
 90    Read .toml configuration file, parse and output dictionaries for PIPT/POPT
 91
 92    Parameters
 93    ----------
 94    init_file : str
 95        toml configuration file
 96    """
 97    # Read
 98    with open(init_file, 'rb') as fid:
 99        t = tomli.load(fid)
100
101    # Check for dataassim and fwdsim
102    if 'ensemble' in t.keys():
103        keys_en = t['ensemble']
104        check_mand_keywords_en(keys_en)
105    else:
106        keys_en = None
107    if 'optim' in t.keys():
108        keys_pr = t['optim']
109        check_mand_keywords_opt(keys_pr)
110    elif 'dataassim' in t.keys():
111        keys_pr = t['dataassim']
112        check_mand_keywords_da(keys_pr)
113    else:
114        raise KeyError
115    if 'fwdsim' in t.keys():
116        keys_fwd = t['fwdsim']
117    else:
118        raise KeyError
119
120    # Organize keywords
121    org = Organize_input(keys_pr, keys_fwd, keys_en)
122    org.organize()
123
124    return org.get_keys_pr(), org.get_keys_fwd(), org.get_keys_en()

Read .toml configuration file, parse and output dictionaries for PIPT/POPT

Parameters
  • init_file (str): toml configuration file
def read_txt(init_file):
127def read_txt(init_file):
128    """
129    Read a PIPT or POPT input file (.pipt or .popt), parse and output dictionaries for data assimilation or
130    optimization,  and simulator classes.
131
132    Parameters
133    ----------
134    init_file: str
135        PIPT init. file containing info. to run the inversion algorithm
136
137    Returns
138    -------
139    keys_pr : dict
140        Parsed keywords from DATAASSIM or OPTIM
141    keys_fwd : dict
142        Parsed keywords from FWDSSIM
143    """
144
145    # Check for .pipt suffix
146    if not init_file.endswith('.pipt') and not init_file.endswith('.popt'):
147        raise FileNotFoundError(f'No PIPT or POPT input file (.pipt or .popt) found! If {init_file} is  '
148                                f'a PIPT or POPT input file, change suffix to .pipt or .popt')
149
150    # Read the init file and output lines without comments (lines starting with '#')
151    lines = read_clean_file(init_file)
152
153    # Find where the separate parts are located in the file. FWDSIM will always be a part, but the
154    # inversion/optimiztation part may be DATAASSIM or OPTIM
155    prind = None
156    pr_part = None
157    fwdsimind = None
158    for i in range(len(lines)):
159        if lines[i].strip().lower() == 'dataassim' or lines[i].strip().lower() == 'optim':
160            prind = i
161            pr_part = lines[i].strip().lower()
162        elif lines[i].strip().lower() == 'fwdsim':
163            fwdsimind = i
164
165    # Split the file into the two separate parts. Each part will (only) contain the keywords of each part:
166    if prind < fwdsimind:  # Data assim. part is the first part of file
167        lines_pr = lines[2:fwdsimind]
168        lines_fwd = lines[fwdsimind + 2:]
169    else:  # Fwd sim. part is the first part of file
170        lines_fwd = lines[2:prind]
171        lines_pr = lines[prind + 2:]
172
173    # Get rid of empty lines in lines_pr and lines_fwd
174    clean_lines_pr = remove_empty_lines(lines_pr)
175    clean_lines_fwd = remove_empty_lines(lines_fwd)
176
177    # Assign the keys and values to different dictionaries depending on whether we have data assimilation (DATAASSIM)
178    # or optimization (OPTIM). FWDSIM info is always assigned to keys_fwd
179    keys_pr = None
180    if pr_part == 'dataassim':
181        keys_pr = parse_keywords(clean_lines_pr)
182        check_mand_keywords_da(keys_pr)
183    elif pr_part == 'optim':
184        keys_pr = parse_keywords(clean_lines_pr)
185        check_mand_keywords_opt(keys_pr)
186    keys_fwd = parse_keywords(clean_lines_fwd)
187    check_mand_keywords_fwd(keys_fwd)
188
189    org = Organize_input(keys_pr, keys_fwd)
190    org.organize()
191
192    return org.get_keys_pr(), org.get_keys_fwd()

Read a PIPT or POPT input file (.pipt or .popt), parse and output dictionaries for data assimilation or optimization, and simulator classes.

Parameters
  • init_file (str): PIPT init. file containing info. to run the inversion algorithm
Returns
  • keys_pr (dict): Parsed keywords from DATAASSIM or OPTIM
  • keys_fwd (dict): Parsed keywords from FWDSSIM
def read_clean_file(init_file):
195def read_clean_file(init_file):
196    """
197    Read PIPT init. file and lines that are not comments (marked with octothorpe)
198
199    Parameters
200    ----------
201    init_file: str
202        Name of file to remove all comments. WHOLE filename needed (with suffix!)
203
204    Returns
205    -------
206    lines: list
207        Lines from init. file converted to list entries
208    """
209    # Read file except lines starting with an octothorpe (#) and return the python variable
210    with open(init_file, 'r') as f:
211        lines = [line for line in f.readlines() if not line.startswith('#')]
212
213    # Return clean lines
214    return lines

Read PIPT init. file and lines that are not comments (marked with octothorpe)

Parameters
  • init_file (str): Name of file to remove all comments. WHOLE filename needed (with suffix!)
Returns
  • lines (list): Lines from init. file converted to list entries
def remove_empty_lines(lines):
217def remove_empty_lines(lines):
218    """
219    Small method for finding empty lines in a read file.
220
221    Parameters
222    ----------
223    lines: list
224        List of lines from a file
225
226    Returns
227    -------
228    lines_clean: list
229        List of clean lines (without empty entries)
230    """
231    # Loop over lines to find '\n'
232    sep = []
233    for i in range(len(lines)):
234        if lines[i] == '\n':
235            sep.append(i)
236
237    # Make clean output
238    lines_clean = []
239    for i in range(len(sep)):
240        if i == 0:
241            lines_clean.append(lines[0:sep[i]])
242        else:
243            lines_clean.append(lines[sep[i-1] + 1:sep[i]])
244
245    # Return
246    return lines_clean

Small method for finding empty lines in a read file.

Parameters
  • lines (list): List of lines from a file
Returns
  • lines_clean (list): List of clean lines (without empty entries)
def parse_keywords(lines):
249def parse_keywords(lines):
250    """
251    Here we parse the lines in the init. file to a Python dictionary. The keys of the dictionary is the keywords
252    in the PIPT init. file, and the information in each keyword is stored in each key of the
253    dictionary. To know how the keyword-information is organized in the keys of the dictionary, confront the
254    manual located in the doc folder.
255
256    Parameters
257    ----------
258    lines: list
259        List of (clean) lines from the PIPT init. file.
260
261    Returns
262    -------
263    keys: dict
264        Dictionary with all info. from the init. file.
265    """
266    # Init. the dictionary
267    keys = {}
268
269    # Loop over all input keywords and store in the dictionary.
270    for i in range(len(lines)):
271        if lines[i] != []:  # Check for empty list (corresponds to empty line in file)
272            try:  # Try first to store the info. in keyword as float in a 1D list
273                # A scalar, which we store as scalar...
274                if len(lines[i][1:]) == 1 and len(lines[i][1:][0].split()) == 1:
275                    keys[lines[i][0].strip().lower()] = float(lines[i][1:][0])
276                else:
277                    keys[lines[i][0].strip().lower()] = [float(x) for x in lines[i][1:]]
278            except:
279                try:  # Store as float in 2D list
280                    if len(lines[i][1:]) == 1:  # Check if it is actually a 1D array disguised as 2D
281                        keys[lines[i][0].strip().lower()] = \
282                            [float(x) for x in lines[i][1:][0].split()]
283                    else:  # if not store as 2D list
284                        keys[lines[i][0].strip().lower()] = \
285                            [[float(x) for x in col.split()] for col in lines[i][1:]]
286                except:  # Keyword contains string(s), not floats
287                    if len(lines[i][1:]) == 1:  # If 1D list
288                        # If it is a scalar store as single input
289                        if len(lines[i][1:][0].split('\t')) == 1:
290                            keys[lines[i][0].strip().lower()] = lines[i][1:][0].strip().lower()
291                        else:  # Store as 1D list
292                            keys[lines[i][0].strip().lower()] = \
293                                [x.rstrip('\n').lower()
294                                 for x in lines[i][1:][0].split('\t') if x != '']
295                    else:  # It is a 2D list
296                        # Check each row in 2D list. If it is single column (i.e., one string per row),
297                        # we make it a 1D list of strings; if not, we make it a 2D list of strings.
298                        one_col = True
299                        for j in range(len(lines[i][1:])):
300                            if len(lines[i][1:][j].split('\t')) > 1:
301                                one_col = False
302                                break
303                        if one_col is True:  # Only one column
304                            keys[lines[i][0].strip().lower()] = \
305                                [x.rstrip('\n').lower() for x in lines[i][1:]]
306                        else:  # Store as 2D list
307                            keys[lines[i][0].strip().lower()] = \
308                                [[x.rstrip('\n').lower() for x in col.split('\t') if x != '']
309                                    for col in lines[i][1:]]
310
311    # Need to check if there are any only-string-keywords that actually contains floats, and convert those to
312    # floats (the above loop only handles pure float or pure string input, hence we do a quick fix for mixed
313    # lists here)
314    # Loop over all keys in dict. and check every "pure" string keys for floats
315    for i in keys:
316        if isinstance(keys[i], list):  # Check if key is a list
317            if isinstance(keys[i][0], list):  # Check if it is a 2D list
318                for j in range(len(keys[i])):  # Loop over all sublists
319                    # Check sublist for strings
320                    if all(isinstance(x, str) for x in keys[i][j]):
321                        for k in range(len(keys[i][j])):  # Loop over enteries in sublist
322                            try:  # Try to make float
323                                keys[i][j][k] = float(keys[i][j][k])  # Scalar
324                            except:
325                                try:  # 1D array
326                                    keys[i][j][k] = [float(x)
327                                                     for x in keys[i][j][k].split()]
328                                except:  # If it is actually a string, pass over
329                                    pass
330            else:  # It is a 1D list
331                # Check if list only contains strings
332                if all(isinstance(x, str) for x in keys[i]):
333                    for j in range(len(keys[i])):  # Loop over all entries in list
334                        try:  # Try to make float
335                            keys[i][j] = float(keys[i][j])
336                        except:
337                            try:
338                                keys[i][j] = [float(x) for x in keys[i][j].split()]
339                            except:  # If it is actually a string, pass over
340                                pass
341
342    # Return dict.
343    return keys

Here we parse the lines in the init. file to a Python dictionary. The keys of the dictionary is the keywords in the PIPT init. file, and the information in each keyword is stored in each key of the dictionary. To know how the keyword-information is organized in the keys of the dictionary, confront the manual located in the doc folder.

Parameters
  • lines (list): List of (clean) lines from the PIPT init. file.
Returns
  • keys (dict): Dictionary with all info. from the init. file.
def check_mand_keywords_fwd(keys_fwd):
346def check_mand_keywords_fwd(keys_fwd):
347    """Check for mandatory keywords in `FWDSIM` part, and output error if they are not present"""
348
349    # Mandatory keywords in FWDSIM
350    assert 'parallel' in keys_fwd, 'PARALLEL not in FWDSIM!'
351    assert 'datatype' in keys_fwd, 'DATATYPE not in FWDSIM!'

Check for mandatory keywords in FWDSIM part, and output error if they are not present

def check_mand_keywords_da(keys_da):
354def check_mand_keywords_da(keys_da):
355    """Check for mandatory keywords in `DATAASSIM` part, and output error if they are not present"""
356
357    # Mandatory keywords in DATAASSIM
358    assert 'truedataindex' in keys_da, 'TRUEDATAINDEX not in DATAASSIM!'
359    assert 'assimindex' in keys_da, 'ASSIMINDEX not in DATAASSIM!'
360    assert 'truedata' in keys_da, 'TRUEDATA not in DATAASSIM!'
361    assert 'datavar' in keys_da, 'DATAVAR not in DATAASSIM!'
362    assert 'obsname' in keys_da, 'OBSNAME not in DATAASSIM!'
363    assert 'energy' in keys_da, 'ENERGY not in DATAASSIM!'

Check for mandatory keywords in DATAASSIM part, and output error if they are not present

def check_mand_keywords_opt(keys_opt):
366def check_mand_keywords_opt(keys_opt):
367    """Check for mandatory keywords in `OPTIM` part, and output error if they are not present"""

Check for mandatory keywords in OPTIM part, and output error if they are not present

def check_mand_keywords_en(keys_en):
371def check_mand_keywords_en(keys_en):
372    """Check for mandatory keywords in `ENSEMBLE` part, and output error if they are not present"""
373
374    # Mandatory keywords in ENSEMBLE
375    assert 'ne' in keys_en, 'NE not in ENSEMBLE!'
376    assert 'state' in keys_en, 'STATE not in ENSEMBLE!'
377    if 'importstaticvar' not in keys_en:
378        assert filter(list(keys_en.keys()),
379                      'prior_*') != [], 'No PRIOR_<STATICVAR> in DATAASSIM'

Check for mandatory keywords in ENSEMBLE part, and output error if they are not present

def change_file_extension(filename, new_extension):
381def change_file_extension(filename, new_extension):
382    if '.' in filename:
383        name, old_extension = filename.rsplit('.', 1)
384        new_filename = name + '.' + new_extension
385    else:
386        new_filename = filename + '.' + new_extension
387    return new_filename