Skip to content

process_funcs

A selection of functions for using the PROCESS code

get_neqns_itervars(wdir='.')

Returns the number of equations and a list of variable names of all iteration variables

Source code in process/core/io/process_funcs.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def get_neqns_itervars(wdir="."):
    """Returns the number of equations and a list of variable
    names of all iteration variables
    """
    # Load dicts from dicts JSON file
    dicts = get_dicts()
    in_dat = InDat(pjoin(wdir, "IN.DAT"))

    ixc_list = in_dat.data["ixc"].get_value

    itervars = []
    for var in ixc_list:
        if var != "":
            itervars += [dicts["DICT_IXC_SIMPLE"][str(var)]]

    assert in_dat.number_of_itvars == len(itervars)

    return in_dat.number_of_constraints, itervars

update_ixc_bounds(wdir='.')

updates the lower and upper bounds in DICT_IXC_BOUNDS from IN.DAT

Source code in process/core/io/process_funcs.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
def update_ixc_bounds(wdir="."):
    """updates the lower and upper bounds in DICT_IXC_BOUNDS
    from IN.DAT
    """
    # Load dicts from dicts JSON file
    dicts = get_dicts()
    in_dat = InDat(pjoin(wdir, "IN.DAT"))

    bounds = in_dat.data["bounds"].get_value

    for key, value in bounds.items():
        name = dicts["DICT_IXC_SIMPLE"][key]

        if "l" in value:
            dicts["DICT_IXC_BOUNDS"][name]["lb"] = float(value["l"])
        if "u" in value:
            dicts["DICT_IXC_BOUNDS"][name]["ub"] = float(value["u"])

get_variable_range(itervars, factor, wdir='.')

Returns the lower and upper bounds of the variable range for each iteration variable.

For f-values the allowed range is equal to their process bounds.

Parameters:

Name Type Description Default
itervars

string list of all iteration variable names

required
factor

defines the variation range for non-f-values by setting them to value * factor and value / factor respectively while taking their process bounds into account.

required
wdir

(Default value = ".")

'.'
Source code in process/core/io/process_funcs.py
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def get_variable_range(itervars, factor, wdir="."):
    """Returns the lower and upper bounds of the variable range
    for each iteration variable.

    For f-values the allowed range is equal to their process bounds.

    Parameters
    ----------
    itervars :
        string list of all iteration variable names
    factor :
        defines the variation range for non-f-values by
        setting them to value * factor and value / factor
        respectively while taking their process bounds
        into account.
    wdir :
         (Default value = ".")
    """
    # Load dicts from dicts JSON file
    dicts = get_dicts()
    in_dat = InDat(pjoin(wdir, "IN.DAT"))

    lbs = []
    ubs = []

    iteration_variables = numerics.lablxc

    for varname in itervars:
        iteration_variable_index = iteration_variables.index(varname)
        lb = numerics.boundl[iteration_variable_index]
        ub = numerics.boundu[iteration_variable_index]
        # for f-values we set the same range as in process
        if varname[0] == "f" and (varname not in dicts["NON_F_VALUES"]):
            lbs += [lb]
            ubs += [ub]

        # for non-f-values we modify the range with the factor
        else:
            value = get_from_indat_or_default(in_dat, varname)

            if value is None:
                print(f"Error: Iteration variable {varname} has None value!")
                exit()

            # to allow the factor to have some influence
            if value == 0.0:
                value = 1.0

            # assure value is within bounds!
            if value < lb:
                value = lb
            elif value > ub:
                value = ub

            if value > 0:
                lbs += [max(value / factor, lb)]
                ubs += [min(value * factor, ub)]
            else:
                lbs += [min(value / factor, lb)]
                ubs += [max(value * factor, ub)]

        if lbs[-1] > ubs[-1]:
            print(
                f"Error: Iteration variable {varname} has BOUNDL={lbs[-1]} >"
                f"BOUNDU={ubs[-1]}\n Update process_dicts or input file!",
                file=stderr,
            )

            exit()
        # assert lbs[-1] < ubs[-1]

    return lbs, ubs

check_in_dat()

Tests IN.DAT during setup: 1)Are ixc bounds outside of allowed input ranges?

Source code in process/core/io/process_funcs.py
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
def check_in_dat():
    """Tests IN.DAT during setup:
    1)Are ixc bounds outside of allowed input ranges?
    """
    # Load dicts from dicts JSON file
    dicts = get_dicts()

    in_dat = InDat()

    # Necessary for the correct use of this function as well as
    # get_variable_range
    update_ixc_bounds()

    # 1) Are ixc bounds outside of allowed input ranges?

    ixc_list = in_dat.data["ixc"].get_value

    for itervarno in ixc_list:
        itervarname = dicts["DICT_IXC_SIMPLE"][str(itervarno)]
        try:
            lowerinputbound = dicts["DICT_INPUT_BOUNDS"][itervarname]["lb"]
        except KeyError as err:
            # arrays do not have input bound checks
            if "(" in itervarname:
                continue

            print("Error in check_in_dat():")
            print("There seems to be some information missing from the dicts.")
            print("Please flag this up for a developer to investigate!")
            print(itervarname, err)
            print(dicts["DICT_INPUT_BOUNDS"][itervarname])
            exit()

        if dicts["DICT_IXC_BOUNDS"][itervarname]["lb"] < lowerinputbound:
            print(
                "Warning: boundl for ",
                itervarname,
                " lies out of allowed input range!\n Reset boundl(",
                itervarno,
                ") to ",
                lowerinputbound,
                file=stderr,
            )
            dicts["DICT_IXC_BOUNDS"][itervarname]["lb"] = lowerinputbound
            set_variable_in_indat(
                in_dat, "boundl(" + str(itervarno) + ")", lowerinputbound
            )
            sleep(1)

        upperinputbound = dicts["DICT_INPUT_BOUNDS"][itervarname]["ub"]

        if dicts["DICT_IXC_BOUNDS"][itervarname]["ub"] > upperinputbound:
            print(
                "Warning: boundu for",
                itervarname,
                f"lies out of allowed input range!\n Reset boundu({itervarno}) to",
                upperinputbound,
                file=stderr,
            )
            dicts["DICT_IXC_BOUNDS"][itervarname]["ub"] = upperinputbound
            set_variable_in_indat(
                in_dat, "boundu(" + str(itervarno) + ")", upperinputbound
            )
            sleep(1)

    in_dat.write_in_dat(output_filename="IN.DAT")

check_input_error(wdir='.')

Checks, if an input error has occurred. Stops as a consequence. Will also fail if the MFILE.DAT isn't found.

Source code in process/core/io/process_funcs.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
def check_input_error(wdir="."):
    """Checks, if an input error has occurred.
    Stops as a consequence.
    Will also fail if the MFILE.DAT isn't found.
    """
    try:
        mfile_path = Path(wdir) / "MFILE.DAT"

        if mfile_path.exists():
            mfile_path_str = str(mfile_path)
            mfile = MFile(filename=mfile_path_str)
        else:
            raise FileNotFoundError("MFile doesn't exist")

        error_id = mfile.data["error_id"].get_scan(-1)

        if error_id == 130:
            print(
                "Error in input file. Please check OUT.DAT for more information.",
                file=stderr,
            )
            exit()
    except Exception:
        logger.exception("Check input error exception")
        raise

process_stopped(wdir='.')

Checks the process Mfile whether it has prematurely stopped.

Source code in process/core/io/process_funcs.py
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
def process_stopped(wdir="."):
    """Checks the process Mfile whether it has
    prematurely stopped.
    """
    # Check for MFILE
    try:
        m_file = MFile(filename=pjoin(wdir, "MFILE.DAT"))
    except FileNotFoundError as err:
        print(f"No MFILE has been found! FYI:qn {err}", file=stderr)
        print("Code continues to run!", file=stderr)
        return True

    # Get error status; missing key indicates premature exit of Process
    # (usually a STOP 1)
    try:
        error_status = m_file.data["error_status"].get_scan(-1)
    except KeyError:
        return True

    # Process did prematurely exit
    return error_status >= 3

process_warnings(wdir='.')

Checks the process Mfile whether any warnings have occurred.

Source code in process/core/io/process_funcs.py
273
274
275
276
277
278
279
280
281
def process_warnings(wdir="."):
    """Checks the process Mfile whether any
    warnings have occurred.
    """

    m_file = MFile(filename=pjoin(wdir, "MFILE.DAT"))
    error_status = m_file.data["error_status"].get_scan(-1)

    return error_status >= 2

mfile_exists()

checks whether MFILE.DAT exists

Source code in process/core/io/process_funcs.py
284
285
286
287
288
289
290
291
292
293
def mfile_exists():
    """checks whether MFILE.DAT exists"""

    try:
        with open("MFILE.DAT") as m_file:
            m_file.close()
        return True

    except FileNotFoundError:
        return False

no_unfeasible_mfile(wdir='.')

returns the number of unfeasible points in a scan in MFILE.DAT

Source code in process/core/io/process_funcs.py
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
def no_unfeasible_mfile(wdir="."):
    """returns the number of unfeasible points
    in a scan in MFILE.DAT
    """

    m_file = MFile(filename=pjoin(wdir, "MFILE.DAT"))

    # no scans
    if not m_file.data["isweep"].exists:
        if m_file.data["ifail"].get_scan(-1) == 1:
            return 0
        return 1

    ifail = m_file.data["ifail"].get_scans()
    try:
        return len(ifail) - ifail.count(1)
    except TypeError:
        # This seems to occur, if ifail is not in MFILE!
        # This probably means in the mfile library a KeyError
        # should be raised not only a message to stdout!
        return 100000

vary_iteration_variables(itervars, lbs, ubs, generator)

Routine to change the iteration variables in IN.DAT within given bounds.

Parameters:

Name Type Description Default
itervars

string list of all iteration variable names

required
lbs

float list of lower bounds for variables

required
ubs

float list of upper bounds for variables

required
generator

Generator numpy generator to create random numbers

required
Source code in process/core/io/process_funcs.py
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
def vary_iteration_variables(itervars, lbs, ubs, generator):
    """Routine to change the iteration variables in IN.DAT
    within given bounds.

    Parameters
    ----------
    itervars :
        string list of all iteration variable names
    lbs :
        float list of lower bounds for variables
    ubs :
        float list of upper bounds for variables
    generator :
        Generator numpy generator to create random numbers
    """

    in_dat = InDat()

    new_values = []

    for varname, lbnd, ubnd in zip(itervars, lbs, ubs, strict=False):
        new_value = generator.uniform(lbnd, ubnd)
        new_values += [new_value]
        in_dat.add_parameter(varname, new_value)

    in_dat.write_in_dat(output_filename="IN.DAT")

    return new_values

get_solution_from_mfile(neqns, nvars, wdir='.')

returns ifail - error_value of VMCON/PROCESS the objective functions the square root of the sum of the squares of the constraints a list of the final iteration variable values a list of the final constraint residue values

If the run was a scan, the values of the last scan point will be returned.

Source code in process/core/io/process_funcs.py
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
def get_solution_from_mfile(neqns, nvars, wdir="."):
    """returns
    ifail - error_value of VMCON/PROCESS
    the objective functions
    the square root of the sum of the squares of the constraints
    a list of the final iteration variable values
    a list of the final constraint residue values

    If the run was a scan, the values of the last scan point
    will be returned.
    """
    m_file = MFile(filename=pjoin(wdir, "MFILE.DAT"))

    ifail = m_file.data["ifail"].get_scan(-1)

    # figure of merit objective function
    objective_function = m_file.data["f"].get_scan(-1)

    # estimate of the constraints
    constraints = m_file.data["sqsumsq"].get_scan(-1)

    table_sol = [
        m_file.data[f"itvar{var_no + 1:03}"].get_scan(-1) for var_no in range(nvars)
    ]
    table_res = [
        m_file.data[f"normres{con_no + 1:03}"].get_scan(-1) for con_no in range(neqns)
    ]

    if ifail != 1:
        return ifail, "0", "0", ["0"] * nvars, ["0"] * neqns

    return ifail, objective_function, constraints, table_sol, table_res

get_from_indat_or_default(in_dat, varname)

quick function to get variable value from IN.DAT or PROCESS default value

Source code in process/core/io/process_funcs.py
383
384
385
386
387
388
389
390
391
392
def get_from_indat_or_default(in_dat, varname):
    """quick function to get variable value from IN.DAT
    or PROCESS default value"""
    dicts = get_dicts()
    if varname in in_dat.data:
        return in_dat.data[varname].get_value
    # Load dicts from dicts JSON file
    dicts = get_dicts()

    return dicts["DICT_DEFAULT"][varname]

set_variable_in_indat(in_dat, varname, value)

quick function that sets a variable value in IN.DAT and creates it if necessary

Source code in process/core/io/process_funcs.py
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
def set_variable_in_indat(in_dat, varname, value):
    """quick function that sets a variable value in
    IN.DAT and creates it if necessary"""

    varname = varname.lower()
    if "bound" in varname:
        number = (varname.split("("))[1].split(")")[0]
        if "boundu" in varname:
            in_dat.add_bound(number, "u", value)
        else:
            in_dat.add_bound(number, "l", value)

    elif "(" in varname:
        name = varname.split("(")[0]
        # Fortran numbering converted to Python numbering!
        identity = int((varname.split("("))[1].split(")")[0]) - 1
        in_dat.change_array(name, identity, float(value))

    else:
        in_dat.add_parameter(varname, value)