Source code for endf_parserpy.utils.endf6_plumbing

############################################################
#
# Author(s):       Georg Schnabel
# Email:           g.schnabel@iaea.org
# Creation date:   2022/05/30
# Last modified:   2025/06/02
# License:         MIT
# Copyright (c) 2022-2024 International Atomic Energy Agency (IAEA)
#
############################################################

from endf_parserpy.interpreter.endf_utils import split_sections
import re


__all__ = [
    "set_library",
    "get_description",
    "set_description",
    "insert_description",
    "update_directory",
]


def set_library(endf_dic, libtype):
    mt451 = endf_dic[1][451]
    if libtype == "ENDF/B-VII.0":
        mt451["NLIB"] = 0
        mt451["NVER"] = 7
        mt451["LREL"] = 0
        txt = "ENDF/B-VII.0"
    elif libtype == "ENDF/B-VII.1":
        mt451["NLIB"] = 0
        mt451["NVER"] = 7
        mt451["LREL"] = 1
        txt = "ENDF/B-VII.1"
    elif libtype == "ENDF/B-VIII.0":
        mt451["NLIB"] = 0
        mt451["NVER"] = 8
        mt451["LREL"] = 0
        txt = "ENDF/B-VIII.0"
    elif libtype == "FENDL-3.2":
        mt451["NLIB"] = 33
        mt451["NVER"] = 3
        mt451["LREL"] = 2
        txt = "FENDL-3.2"
    else:
        raise TypeError("Unknown library type")
    # update the human readable library specification
    if "DESCRIPTION" not in mt451:
        raise ValueError("No description in MF1/MT451 found")
    descr = mt451["DESCRIPTION"]
    if 3 not in descr:
        raise IndexError("No third line found in description")
    if not re.match("---- *[A-Z][^ ]+", descr[3]):
        raise ValueError("Signature of line three is wrong")
    new_descr_line = ("----" + txt).ljust(22) + descr[3][22:]
    descr[3] = new_descr_line


[docs] def get_description(endf_dic): """Retrieve the description from MF1/MT451 section. Parameters ---------- endf_dic : dict Dictionary with ENDF-6 data Returns ------- str String with the description extracted from MF1/MT451 """ descr_dic = endf_dic[1][451]["DESCRIPTION"] descr_list = [] for k in sorted(descr_dic.keys()): descr_list.append(descr_dic[k]) return "\n".join(descr_list)
[docs] def set_description(endf_dic, text): """Set the description in the MF1/MT451 section. Updates the ``DESCRIPTION`` variable in ``endf_dic[1][451]`` and adjusts the corresponding counter variable ``NWD``. Parameters ---------- endf_dic : dict Dictionary with ENDF-6 data text : str String with description. Lines with more than 66 characters are trimmed. """ lines = text.splitlines() numlines = len(lines) endf_dic[1][451]["NWD"] = numlines + 5 descr_dic = {} for k in range(1, numlines + 1): descr_dic[k] = lines[k - 1].ljust(66) endf_dic[1][451]["DESCRIPTION"] = descr_dic
[docs] def insert_description(endf_dic, text, after_line=0): """Insert text in the description in MF1/MT451. Insert the text provided into the `DESCRIPTION` in `endf_dic[1][451]` and adjusts the corresponding counter variable `NWD`. Parameters ---------- endf_dic : dict Dictionary with ENDF-6 data text : str String with text to be inserted. after_line : int After which line ``text`` should be inserted. ``after_line=0`` inserted the text provided at the very beginning. """ descr = get_description(endf_dic) lines = descr.splitlines() newlines = lines[:after_line] + text.splitlines() if after_line < len(lines): newlines += lines[after_line:] newdescr = "\n".join(newlines) set_description(endf_dic, newdescr)
[docs] def update_directory(endf_dic, parser=None, lines=None, read_opts=None): """Update the ENDF directory in MF1/MT451. Parameters ---------- endf_dic : dict Dictionary of appropriate structure with ENDF-6 data. parser : EndfParserBase An :class:`~endf_parserpy.EndfParserBase` instance lines: list[str] A list of strings with the ENDF-6 formatted data corresponding to the data in ``endf_dict``. If this argument is provided, the ``parser`` argument will be ignored. read_opts : dict A dictionary with reading options provided as ``read_opts`` argument overrides the reading options of the :class:`~endf_parserpy.EndfParserBase` instance. """ if read_opts is None: read_opts = {} active_read_opts = {} if not lines: if not parser: raise TypeError("provide either`parser` or `lines` argument") lines = parser.write(endf_dic) active_read_opts.update(parser.read_opts) active_read_opts.update(read_opts) active_read_opts["ignore_missing_tpid"] = True # determine the lengths of the sections # the checks for mf=0 and mt=0 are here # to not consider the tape head as a section mfdic = split_sections(lines, read_opts=active_read_opts) countdic = {} numsecs = 0 for mf, mfsec in mfdic.items(): if mf == 0: continue countdic.setdefault(mf, {}) for mt, mtsec in mfsec.items(): if mt == 0: continue numsecs += 1 countdic[mf][mt] = len(mtsec) # record the length of MF1/MT451 itself mf1mt451_len = 4 + endf_dic[1][451]["NWD"] + numsecs countdic[1][451] = mf1mt451_len # build up a MOD dic to retrieve the # previous value of MOD (modified version number) moddic = {} mt451 = endf_dic[1][451] ilist = mt451["MFx"].keys() if "MFx" in mt451 else tuple() for i in ilist: curmf = mt451["MFx"][i] curmt = mt451["MTx"][i] curmod = mt451["MOD"][i] moddic[(curmf, curmt)] = curmod # construct the dictionaries MFx = {} MTx = {} NCx = {} MOD = {} i = 0 for mf, mfsec in countdic.items(): for mt, count in mfsec.items(): i += 1 MFx[i] = mf MTx[i] = mt NCx[i] = countdic[mf][mt] MOD[i] = moddic.get((mf, mt), 0) # update MT451 mt451["MFx"] = MFx mt451["MTx"] = MTx mt451["NCx"] = NCx mt451["MOD"] = MOD # finally, update the counter NXC mt451["NXC"] = numsecs