def cleanAllArmiTempDirs(olderThanDays: int): """ Delete all ARMI-related files from other unrelated runs after `olderThanDays` days (in case this failed on earlier runs). .. warning:: This will break any concurrent runs that are still running. This is a useful utility in HPC environments when some runs crash sometimes. """ # pylint: disable=import-outside-toplevel # avoid cyclic import from armi.utils.pathTools import cleanPath gracePeriod = datetime.timedelta(days=olderThanDays) now = datetime.datetime.now() thisRunFolder = os.path.basename(_FAST_PATH) for dirname in os.listdir(APP_DATA): dirPath = os.path.join(APP_DATA, dirname) if not os.path.isdir(dirPath): continue try: fromThisRun = dirname == thisRunFolder # second chance to delete _rank, dateString = dirname.split("-") dateOfFolder = datetime.datetime.strptime(dateString, "%Y%m%d%H%M%S%f") runIsOldAndLikleyComplete = (now - dateOfFolder) > gracePeriod if runIsOldAndLikleyComplete or fromThisRun: # Delete old files cleanPath(dirPath) except: # pylint: disable=bare-except pass
def deleteCache(cachedFolder): """ Remove this folder. Requires safeword because this is potentially extremely destructive. """ if "Output_Cache" not in cachedFolder: raise RuntimeError( "Cache location must contain safeword: `Output_Cache`.") cleanPath(cachedFolder)
def __exit__(self, exc_type, exc_value, traceback): DirectoryChanger.__exit__(self, exc_type, exc_value, traceback) try: pathTools.cleanPath(self.destination, context.MPI_RANK) except PermissionError: if os.name == "nt": runLog.warning( "There is an issue where Windows will not agree to delete private directories." "That is, if you create a directory with a name starting with a period, the " "TempDirChanger will not be able to clean it (for instance, a '.git' dir)." ) context.waitAll()
def cleanTempDirs(olderThanDays=None): """ Clean up temporary files after a run. The Windows HPC system sends a SIGBREAK signal when the user cancels a job, which is NOT handled by ``atexit``. Notably SIGBREAK doesn't exist off Windows. For the SIGBREAK signal to work with a Microsoft HPC, the ``TaskCancelGracePeriod`` option must be configured to be non-zero. This sets the period between SIGBREAK and SIGTERM/SIGINT. To do cleanups in this case, we must use the ``signal`` module. Actually, even then it does not work because MS ``mpiexec`` does not pass signals through. Parameters ---------- olderThanDays: int, optional If provided, deletes other ARMI directories if they are older than the requested time. """ # pylint: disable=import-outside-toplevel # avoid cyclic import from armi import runLog from armi.utils.pathTools import cleanPath disconnectAllHdfDBs() printMsg = runLog.getVerbosity() <= DEBUG if _FAST_PATH_IS_TEMPORARY and os.path.exists(_FAST_PATH): if printMsg: print( "Cleaning up temporary files in: {}".format(_FAST_PATH), file=sys.stdout, ) try: cleanPath(_FAST_PATH) except Exception as error: # pylint: disable=broad-except for outputStream in (sys.stderr, sys.stdout): if printMsg: print( "Failed to delete temporary files in: {}\n" " error: {}".format(_FAST_PATH, error), file=outputStream, ) if olderThanDays is not None: cleanAllArmiTempDirs(olderThanDays)
def test_cleanPathMpi(self): # """Simple tests of cleanPath(), in the MPI scenario""" with TemporaryDirectoryChanger(): # TEST 0: File is not safe to delete, due to name pathing filePath0 = "test0_cleanPathNoMpi" open(filePath0, "w").write("something") self.assertTrue(os.path.exists(filePath0)) with self.assertRaises(Exception): pathTools.cleanPath(filePath0, mpiRank=context.MPI_RANK) context.waitAll() # TEST 1: Delete a single file filePath1 = "test1_cleanPathNoMpi_mongoose" open(filePath1, "w").write("something") self.assertTrue(os.path.exists(filePath1)) pathTools.cleanPath(filePath1, mpiRank=context.MPI_RANK) context.waitAll() self.assertFalse(os.path.exists(filePath1)) # TEST 2: Delete an empty directory dir2 = "mongoose" os.mkdir(dir2) self.assertTrue(os.path.exists(dir2)) pathTools.cleanPath(dir2, mpiRank=context.MPI_RANK) context.waitAll() self.assertFalse(os.path.exists(dir2)) # TEST 3: Delete a directory with two files inside # create directory dir3 = "mongoose" os.mkdir(dir3) # throw in a couple of simple text files open(os.path.join(dir3, "file1.txt"), "w").write("something1") open(os.path.join(dir3, "file2.txt"), "w").write("something2") # delete the directory and test self.assertTrue(os.path.exists(dir3)) self.assertTrue(os.path.exists(os.path.join(dir3, "file1.txt"))) self.assertTrue(os.path.exists(os.path.join(dir3, "file2.txt"))) pathTools.cleanPath(dir3, mpiRank=context.MPI_RANK) context.waitAll() self.assertFalse(os.path.exists(dir3))
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)) pathTools.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) # 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 __exit__(self, exc_type, exc_value, traceback): DirectoryChanger.__exit__(self, exc_type, exc_value, traceback) pathTools.cleanPath(self.destination)