예제 #1
0
    def _moveFiles(self):
        # check for orificed flow bounds files. These will often be named based on the
        # case that this one is dependent upon, but not always. For example, testSassys
        # is dependent on the safety case but requires physics bounds files.  now copy
        # the files over
        copyFilesFrom = [
            filePath for possiblePat in self.cs["copyFilesFrom"]
            for filePath in glob.glob(possiblePat)
        ]
        copyFilesTo = self.cs["copyFilesTo"]

        if len(copyFilesTo) in (len(copyFilesFrom), 0, 1):
            # if any files to copy, then use the first as the default, i.e. len() == 1,
            # otherwise assume '.'
            default = copyFilesTo[0] if any(copyFilesTo) else "."
            for filename, dest in itertools.zip_longest(copyFilesFrom,
                                                        copyFilesTo,
                                                        fillvalue=default):
                pathTools.copyOrWarn("copyFilesFrom", filename, dest)
        else:
            runLog.error(
                "cs['copyFilesTo'] must either be length 1, 0, or have the same number of entries as "
                "cs['copyFilesFrom']. Actual values:\n"
                "    copyFilesTo   : {}\n"
                "    copyFilesFrom : {}".format(copyFilesTo, copyFilesFrom))
            raise InputError("Failed to process copyFilesTo/copyFilesFrom")
예제 #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))
예제 #3
0
파일: case.py 프로젝트: 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)
예제 #4
0
    def retrieveOutputFiles(self, runPath):
        """
        Copy interesting output files from local disks to shared network disk.

        Run this if you want copies of the local output files.
        This copies output from the runPath to the current working directory,
        which is generally the shared network drive.

        See Also
        --------
        specifyOutputFilesToRetrieve : says which ones to copy back.
        armi.utils.directoryChangers.DirectoryChanger.retrieveFiles : should be used instead of this.

        Notes
        -----
        This could be done in a separate thread to let processing continue while I/O spins.

        """
        for sourceName, destinationName in self._outputFilesNamesToRetrieve:
            workingFileName = os.path.join(runPath, sourceName)
            pathTools.copyOrWarn("output file", workingFileName,
                                 destinationName)
예제 #5
0
파일: case.py 프로젝트: 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
예제 #6
0
파일: case.py 프로젝트: ntouran/armi
    def clone(self, additionalFiles=None, title=None, modifiedSettings=None):
        """
        Clone existing ARMI inputs to current directory with optional settings modifications.

        Since each case depends on multiple inputs, this is a safer way to move cases
        around without having to wonder if you copied all the files appropriately.

        Parameters
        ----------
        additionalFiles : list (optional)
            additional file paths to copy to cloned case
        title : str (optional)
            title of new case
        modifiedSettings : dict (optional)
            settings to set/modify before creating the cloned case

        Raises
        ------
        RuntimeError
            If the source and destination are the same

        """
        cloneCS = self.cs.duplicate()

        if modifiedSettings is not None:
            cloneCS = cloneCS.modified(newSettings=modifiedSettings)

        clone = Case(cloneCS)
        clone.cs.path = pathTools.armiAbsPath(title or self.title) + ".yaml"

        if pathTools.armiAbsPath(clone.cs.path) == pathTools.armiAbsPath(
                self.cs.path):
            raise RuntimeError(
                "The source file and destination file are the same: {}\n"
                "Cannot use armi-clone to modify armi settings file.".format(
                    pathTools.armiAbsPath(clone.cs.path)))

        newSettings = copyInterfaceInputs(self.cs, clone.cs.inputDirectory)
        newCs = clone.cs.modified(newSettings=newSettings)
        clone.cs = newCs

        runLog.important("writing settings file {}".format(clone.cs.path))
        clone.cs.writeToYamlFile(clone.cs.path)
        runLog.important("finished writing {}".format(clone.cs))

        fromPath = lambda fname: pathTools.armiAbsPath(self.cs.inputDirectory,
                                                       fname)

        for inputFileSetting in ["loadingFile", "geomFile"]:
            fileName = self.cs[inputFileSetting]
            if fileName:
                pathTools.copyOrWarn(
                    inputFileSetting,
                    fromPath(fileName),
                    os.path.join(clone.cs.inputDirectory, fileName),
                )
            else:
                runLog.warning(
                    "skipping {}, there is no file specified".format(
                        inputFileSetting))

        with open(self.cs["loadingFile"], "r") as f:
            # The root for handling YAML includes is relative to the YAML file, not the
            # settings file
            root = (pathlib.Path(self.cs.inputDirectory) /
                    pathlib.Path(self.cs["loadingFile"]).parent)
            cloneRoot = (pathlib.Path(clone.cs.inputDirectory) /
                         pathlib.Path(clone.cs["loadingFile"]).parent)
            for includePath, mark in textProcessors.findYamlInclusions(
                    f, root=root):
                if not includePath.is_absolute():
                    includeSrc = root / includePath
                    includeDest = cloneRoot / includePath
                else:
                    # don't bother copying absolute files
                    continue
                if not includeSrc.exists():
                    raise OSError(
                        "The input file file `{}` referenced at {} does not exist."
                        .format(includeSrc, mark))
                pathTools.copyOrWarn(
                    "auxiliary input file `{}` referenced at {}".format(
                        includeSrc, mark),
                    includeSrc,
                    includeDest,
                )

        for fileName in additionalFiles or []:
            pathTools.copyOrWarn("additional file", fromPath(fileName),
                                 clone.cs.inputDirectory)

        return clone
예제 #7
0
파일: operator.py 프로젝트: guruprad/armi
    def snapshotRequest(self, cycle, node):
        """
        Process a snapshot request at this time.

        This copies various physics input and output files to a special folder that
        follow-on analysis be executed upon later.

        Notes
        -----
        This was originally used to produce MC2/DIF3D inputs for external
        parties (who didn't have ARMI) to review. Since then, the concept
        of snapshots has evolved with respect to the
        :py:class:`~armi.operators.snapshots.OperatorSnapshots`.
        """
        runLog.info("Producing snapshot for cycle {0} node {1}".format(
            cycle, node))
        self.r.core.zones.summary()

        newFolder = "snapShot{0}_{1}".format(cycle, node)
        if os.path.exists(newFolder):
            runLog.important(
                "Deleting existing snapshot data in {0}".format(newFolder))
            utils.cleanPath(newFolder)  # careful with cleanPath!
            # give it a minute.
            time.sleep(1)

        if os.path.exists(newFolder):
            runLog.warning(
                "Deleting existing snapshot data in {0} failed".format(
                    newFolder))
        else:
            os.mkdir(newFolder)

        inf = "{0}{1:03d}{2:03d}.inp".format(self.cs.caseTitle, cycle, node)
        writer = self.getInterface("dif3d")

        if not writer:
            writer = self.getInterface("rebus")
        if not writer:
            runLog.warning(
                "There are no interface attached that can write a snapshot input"
            )
        else:
            writer.writeInput(os.path.join(newFolder, inf))

        # copy the cross section inputs
        for fileName in os.listdir("."):
            if "mcc" in fileName and re.search(r"[A-Z]AF?\d?.inp", fileName):
                base, ext = os.path.splitext(fileName)
                # add the cycle and timenode to the XS input file names so that a rx-coeff case that runs
                # in here won't overwrite them.
                shutil.copy(
                    fileName,
                    os.path.join(
                        newFolder,
                        "{0}_{1:03d}_{2:d}{3}".format(base, cycle, node, ext)),
                )

        isoFName = "ISOTXS-c{0}".format(cycle)
        pathTools.copyOrWarn("ISOTXS for snapshot", isoFName,
                             pathTools.armiAbsPath(newFolder, "ISOTXS"))
        pathTools.copyOrWarn(
            "DIF3D output for snapshot",
            self.cs.caseTitle + "{0:03d}.out".format(cycle),
            newFolder,
        )
        pathTools.copyOrWarn("Shuffle logic for snapshot",
                             self.cs["shuffleLogic"], newFolder)
        pathTools.copyOrWarn("Geometry file for snapshot", self.cs["geomFile"],
                             newFolder)
        pathTools.copyOrWarn("Loading definition for snapshot",
                             self.cs["loadingFile"], newFolder)
        pathTools.copyOrWarn(
            "Flow history for snapshot",
            self.cs.caseTitle + ".flow_history.txt",
            newFolder,
        )
        pathTools.copyOrWarn(
            "Pressure history for snapshot",
            self.cs.caseTitle + ".pressure_history.txt",
            newFolder,
        )
예제 #8
0
파일: case.py 프로젝트: bakta5/armi
    def clone(self, additionalFiles=None, title=None, modifiedSettings=None):
        """
        Clone existing ARMI inputs to current directory with optional settings modifications.

        Since each case depends on multiple inputs, this is a safer
        way to move cases around without having to wonder if you
        copied all the files appropriately.

        Parameters
        ----------
        additionalFiles : list (optional)
            additional file paths to copy to cloned case
        title : str (optional)
            title of new case
        modifiedSettings : dict (optional)
            settings to set/modify before creating the cloned case

        Raises
        ------
        RuntimeError
            If the source and destination are the same

        """
        cloneCS = self.cs.duplicate()

        if modifiedSettings is not None:
            cloneCS.update(modifiedSettings)

        clone = Case(cloneCS)
        clone.cs.path = pathTools.armiAbsPath(title or self.title) + ".yaml"

        if pathTools.armiAbsPath(clone.cs.path) == pathTools.armiAbsPath(
                self.cs.path):
            raise RuntimeError(
                "The source file and destination file are the same: {}\n"
                "Cannot use armi-clone to modify armi settings file.".format(
                    pathTools.armiAbsPath(clone.cs.path)))

        runLog.important("writing settings file {}".format(clone.cs.path))
        clone.cs.writeToYamlFile(clone.cs.path)
        runLog.important("finished writing {}".format(clone.cs))

        fromPath = lambda fname: pathTools.armiAbsPath(self.cs.inputDirectory,
                                                       fname)

        for inputFileSetting in [
                "loadingFile",
                "geomFile",
                "shuffleLogic",
                "explicitRepeatShuffles",
        ]:
            fileName = self.cs[inputFileSetting]
            if fileName:
                pathTools.copyOrWarn(
                    inputFileSetting,
                    fromPath(fileName),
                    os.path.join(clone.cs.inputDirectory, fileName),
                )
            else:
                runLog.warning(
                    "skipping {}, there is no file specified".format(
                        inputFileSetting))

        copyInterfaceInputs(self.cs, clone.cs.inputDirectory)

        for grid in self.bp.gridDesigns or []:
            if grid.latticeFile:
                pathTools.copyOrWarn(
                    "system lattice for {}".format(grid.name),
                    fromPath(grid.latticeFile),
                    clone.cs.inputDirectory,
                )

        for fileName in additionalFiles or []:
            pathTools.copyOrWarn("additional file", fromPath(fileName),
                                 clone.cs.inputDirectory)

        return clone
예제 #9
0
파일: case.py 프로젝트: rikita933/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, 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