def __init__(self, destination, filesToMove=None, filesToRetrieve=None): """Establish the new and return directories""" self.initial = pathTools.armiAbsPath(os.getcwd()) self.destination = None if destination is not None: self.destination = pathTools.armiAbsPath(destination) self._filesToMove = filesToMove or [] self._filesToRetrieve = filesToRetrieve or []
def createQueryRevertBadPathToDefault(inspector, settingName, initialLambda=None): """ Return a query to revert a bad path to its default. Parameters ---------- inspector: Inspector the inspector who's settings are being queried settingName: str name of the setting to inspect initialLambda: None or callable function If ``None``, the callable argument for :py:meth:`addQuery` is does the setting's path exist. If more complicated callable arguments are needed, they can be passed in as the ``initialLambda`` setting. """ if initialLambda is None: initialLambda = lambda: (not os.path.exists( pathTools.armiAbsPath(inspector.cs[settingName]) ) and inspector.cs.getSetting(settingName).offDefault ) # solution is to revert to default query = Query( initialLambda, "Setting {} points to a nonexistent location:\n{}".format( settingName, inspector.cs[settingName]), "Revert to default location?", inspector.cs.getSetting(settingName).revertToDefault, ) return query
def addQueryBadLocationWillLikelyFail(self, settingName): """Add a query indicating the current path for ``settingName`` does not exist and will likely fail.""" self.addQuery( lambda: not os.path.exists( pathTools.armiAbsPath(self.cs[settingName])), "Setting {} points to nonexistent location\n{}\nFailure extremely likely" .format(settingName, self.cs[settingName]), "", self.NO_ACTION, )
def _prepToRead(self, fName): if self._failOnLoad: raise exceptions.StateError( "Cannot load settings file after processing of command " "line options begins.\nYou may be able to fix this by " "reordering the command line arguments, and making sure " "the settings file `{}` comes before any modified settings.". format(fName)) path = pathTools.armiAbsPath(fName) return settingsIO.SettingsReader(self), path
def writeToXMLFile(self, fName, style="short"): """Write out settings to an xml file Parameters ---------- fName : str the file to write to style : str the method of XML output to be used when creating the xml file for the current state of settings """ self.path = pathTools.armiAbsPath(fName) writer = settingsIO.SettingsWriter(self, style=style) with open(self.path, "w") as stream: writer.writeXml(stream) return writer
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)
def writeToYamlFile(self, fName, style="short"): """ Write settings to a yaml file. Notes ----- This resets the current CS's path to the newly written path. Parameters ---------- fName : str the file to write to style : str the method of output to be used when creating the file for the current state of settings """ self.path = pathTools.armiAbsPath(fName) with open(self.path, "w") as stream: writer = self.writeToYamlStream(stream, style) return writer
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
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, )
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