Ejemplo n.º 1
0
    def createInterfaces(self):
        """
        Dynamically discover all available interfaces and call their factories, potentially adding
        them to the stack.

        An operator contains an ordered list of interfaces. These communicate between
        the core ARMI structure and auxiliary computational modules and/or external codes.
        At specified interaction points in a run, the list of interfaces is executed.

        Each interface optionally defines interaction "hooks" for each of the interaction points.
        The normal interaction points are BOL, BOC, every node, EOC, and EOL. If an interface defines
        an interactBOL method, that will run at BOL, and so on.

        The majority of ARMI capabilities lie within interfaces, and this architecture provides
        much of the flexibility of ARMI.

        See Also
        --------
        addInterface : Adds a particular interface to the interface stack.
        armi.interfaces.STACK_ORDER : A system to determine the required order of interfaces.
        armi.interfaces.getActiveInterfaceInfo : Collects the interface classes from relevant
            packages.
        """
        interfaceList = interfaces.getActiveInterfaceInfo(self.cs)

        for klass, kwargs in interfaceList:
            self.addInterface(klass(self.r, self.cs), **kwargs)
Ejemplo n.º 2
0
def copyInterfaceInputs(cs, destination: str, sourceDir: Optional[str] = None):
    """
    Copy sets of files that are considered "input" from each active interface.

    This enables developers to add new inputs in a plugin-dependent/
    modular way.

    In parameter sweeps, these often have a sourceDir associated with them that is
    different from the cs.inputDirectory.
    """
    activeInterfaces = interfaces.getActiveInterfaceInfo(cs)
    sourceDir = sourceDir or cs.inputDirectory
    for klass, kwargs in activeInterfaces:
        if not kwargs.get("enabled", True):
            # Don't consider disabled interfaces
            continue
        interfaceFileNames = klass.specifyInputs(cs)
        for label, relativeGlobs in interfaceFileNames.items():
            for relativeGlob in relativeGlobs:
                for sourceFullPath in glob.glob(
                        os.path.join(sourceDir, relativeGlob)):
                    if not sourceFullPath:
                        continue
                    _sourceDir, sourceName = os.path.split(sourceFullPath)
                    pathTools.copyOrWarn(label, sourceFullPath,
                                         os.path.join(destination, sourceName))
Ejemplo n.º 3
0
    def _listInputFiles(cs):
        """
        Gathers information about the input files of this case.

        Returns
        -------
        inputInfo : list
            (label, fileName, shaHash) tuples
        """

        pathToLoading = pathlib.Path(cs.inputDirectory) / cs["loadingFile"]

        if pathToLoading.is_file():
            includedBlueprints = [
                inclusion[0]
                for inclusion in textProcessors.findYamlInclusions(pathToLoading)
            ]
        else:
            includedBlueprints = []

        inputInfo = []
        inputFiles = (
            [
                ("Case Settings", cs.caseTitle + ".yaml"),
                ("Blueprints", cs["loadingFile"]),
            ]
            + [("Included blueprints", inclBp) for inclBp in includedBlueprints]
            + [("Geometry", cs["geomFile"])]
        )

        activeInterfaces = interfaces.getActiveInterfaceInfo(cs)
        for klass, kwargs in activeInterfaces:
            if not kwargs.get("enabled", True):
                # Don't consider disabled interfaces
                continue
            interfaceFileNames = klass.specifyInputs(cs)
            for label, fileNames in interfaceFileNames.items():
                for fName in fileNames:
                    inputFiles.append((label, fName))

        if cs["reloadDBName"] and cs["runType"] == RunTypes.SNAPSHOTS:
            inputFiles.append(("Database", cs["reloadDBName"]))
        for label, fName in inputFiles:
            shaHash = (
                "MISSING"
                if (not fName or not os.path.exists(fName))
                else utils.getFileSHA1Hash(fName, digits=10)
            )
            inputInfo.append((label, fName, shaHash))

        return inputInfo
Ejemplo n.º 4
0
Archivo: case.py Proyecto: bakta5/armi
def copyInterfaceInputs(cs, destination):
    """
    Copy sets of files that are considered "input" from each active interface.

    This enables developers to add new inputs in a plugin-dependent/
    modular way.
    """
    activeInterfaces = interfaces.getActiveInterfaceInfo(cs)
    for klass, kwargs in activeInterfaces:
        if not kwargs.get("enabled", True):
            # Don't consider disabled interfaces
            continue
        interfaceFileNames = klass.specifyInputs(cs)
        for label, fileNames in interfaceFileNames.items():
            for f in fileNames:
                pathTools.copyOrWarn(
                    label, pathTools.armiAbsPath(cs.inputDirectory, f),
                    destination)
Ejemplo n.º 5
0
Archivo: case.py Proyecto: ntouran/armi
def copyInterfaceInputs(cs,
                        destination: str,
                        sourceDir: Optional[str] = None) -> Dict[str, str]:
    """
    Copy sets of files that are considered "input" from each active interface.

    This enables developers to add new inputs in a plugin-dependent/ modular way.

    In parameter sweeps, these often have a sourceDir associated with them that is
    different from the cs.inputDirectory.

    Parameters
    ----------
    cs : CaseSettings
        The source case settings to find input files

    destination: str
        The target directory to copy input files to

    sourceDir: str, optional
        The directory from which to copy files. Defaults to cs.inputDirectory

    Notes
    -----

    This may seem a bit overly complex, but a lot of the behavior is important. Relative
    paths are copied into the target directory, which in some cases requires updating
    the setting that pointed to the file in the first place. This is necessary to avoid
    case dependencies in relavive locations above the input directory, which can lead to
    issues when cloneing case suites. In the future this could be simplified by adding a
    concept for a suite root directory, below which it is safe to copy files without
    needing to update settings that point with a relative path to files that are below
    it.

    """
    activeInterfaces = interfaces.getActiveInterfaceInfo(cs)
    sourceDir = sourceDir or cs.inputDirectory
    sourceDirPath = pathlib.Path(sourceDir)
    destPath = pathlib.Path(destination)

    newSettings = {}

    assert destPath.is_dir()

    for klass, _ in activeInterfaces:
        interfaceFileNames = klass.specifyInputs(cs)
        # returned files can be absolute paths, relative paths, or even glob patterns.
        # Since we don't have an explicit way to signal about these, we sort of have to
        # guess. In future, it might be nice to have interfaces specify which
        # explicitly.
        for key, files in interfaceFileNames.items():

            if not isinstance(key, settings.Setting):
                try:
                    key = cs.getSetting(key)
                except NonexistentSetting(key):
                    raise ValueError(
                        "{} is not a valid setting. Ensure the relevant specifyInputs method uses a correct setting name."
                        .format(key))
            label = key.name

            for f in files:
                path = pathlib.Path(f)
                if path.is_absolute() and path.exists() and path.is_file():
                    # looks like an extant, absolute path; no need to do anything
                    pass
                else:
                    # An OSError can occur if a wildcard is included in the file name so
                    # this is wrapped in a try/except to circumvent instances where an
                    # interface requests to copy multiple files based on some prefix/suffix.
                    try:
                        if not (path.exists() and path.is_file()):
                            runLog.extra(
                                f"Input file `{f}` not found. Checking for file at path `{sourceDirPath}`"
                            )
                    except OSError:
                        pass

                    # relative path/glob. Should be safe to just use glob resolution.
                    # Note that `glob.glob` is being used here rather than `pathlib.glob` because
                    # `pathlib.glob` for Python 3.7.2 does not handle case sensitivity for file and
                    # path names. This is required for copying and using Python scripts (e.g., fuel management,
                    # control logic, etc.).
                    srcFiles = [
                        pathlib.Path(os.path.join(sourceDirPath, g))
                        for g in glob.glob(os.path.join(sourceDirPath, f))
                    ]
                    for sourceFullPath in srcFiles:
                        if not sourceFullPath:
                            continue
                        sourceName = os.path.basename(sourceFullPath.name)
                        destFilePath = os.path.abspath(destPath / sourceName)
                        pathTools.copyOrWarn(label, sourceFullPath,
                                             destFilePath)
                    if len(srcFiles) == 0:
                        runLog.warning(
                            f"No input files for `{label}` could be resolved "
                            f"with the following file path: `{f}`.")
                    elif len(srcFiles) > 1:
                        runLog.warning(
                            f"Input files for `{label}` resolved to more "
                            f"than one file; cannot update settings safely. "
                            f"Discovered input files: {srcFiles}")
                    elif len(srcFiles) == 1:
                        newSettings[label] = str(destFilePath)

    return newSettings
Ejemplo n.º 6
0
def copyInterfaceInputs(cs,
                        destination: str,
                        sourceDir: Optional[str] = None) -> Dict[str, str]:
    """
    Copy sets of files that are considered "input" from each active interface.

    This enables developers to add new inputs in a plugin-dependent/ modular way.

    In parameter sweeps, these often have a sourceDir associated with them that is
    different from the cs.inputDirectory.

    Parameters
    ----------
    cs : CaseSettings
        The source case settings to find input files

    destination: str
        The target directory to copy input files to

    sourceDir: str, optional
        The directory from which to copy files. Defaults to cs.inputDirectory

    Notes
    -----

    This may seem a bit overly complex, but a lot of the behavior is important. Relative
    paths are copied into the target directory, which in some cases requires updating
    the setting that pointed to the file in the first place. This is necessary to avoid
    case dependencies in relavive locations above the input directory, which can lead to
    issues when cloneing case suites. In the future this could be simplified by adding a
    concept for a suite root directory, below which it is safe to copy files without
    needing to update settings that point with a relative path to files that are below
    it.

    """
    activeInterfaces = interfaces.getActiveInterfaceInfo(cs)
    sourceDir = sourceDir or cs.inputDirectory
    sourceDirPath = pathlib.Path(sourceDir)
    destPath = pathlib.Path(destination)

    newSettings = {}

    assert destPath.is_dir()

    for klass, kwargs in activeInterfaces:
        interfaceFileNames = klass.specifyInputs(cs)
        # returned files can be absolute paths, relative paths, or even glob patterns.
        # Since we don't have an explicit way to signal about these, we sort of have to
        # guess. In future, it might be nice to have interfaces specify which
        # explicitly.
        for key, files in interfaceFileNames.items():
            if isinstance(key, settings.Setting):
                label = key.name
            else:
                label = key

            for f in files:
                path = pathlib.Path(f)
                if path.is_absolute() and path.exists() and path.is_file():
                    # looks like an extant, absolute path; no need to do anything
                    pass
                else:
                    # relative path/glob. Should be safe to just use glob resolution
                    srcFiles = list(sourceDirPath.glob(f))
                    for sourceFullPath in srcFiles:
                        if not sourceFullPath:
                            continue
                        _sourceDir, sourceName = os.path.split(sourceFullPath)
                        sourceName = sourceFullPath.name
                        destFile = (destPath /
                                    sourceName).relative_to(destPath)
                        pathTools.copyOrWarn(label, sourceFullPath,
                                             destPath / sourceName)

                    if len(srcFiles) > 1:
                        runLog.warning(
                            f"Input files for `{label}` resolved to more "
                            "than one file; cannot update settings safely.")
                    elif isinstance(key, settings.Setting):
                        newSettings[key.name] = str(destFile)

    return newSettings