def defineValidators(inspector): """Define settings validation for the DRAGON plugin.""" if inspector.cs["xsKernel"] != CONF_OPT_DRAGON: # No need to validate DRAGON settings if DRAGON is not being used. return [] queries = [ settingsValidation.Query( lambda: shutil.which(inspector.cs[CONF_DRAGON_PATH]) is None, f"The path specified in the `{CONF_DRAGON_PATH}` setting does not exist: " f"{inspector.cs[CONF_DRAGON_PATH]}", "Please update executable location to the correct location.", inspector.NO_ACTION, ), settingsValidation.Query( lambda: not os.path.exists(inspector.cs[CONF_DRAGON_DATA_PATH]), "The path specified to the dragon nuclear data file in the " f"`{CONF_DRAGON_DATA_PATH}` setting does not exist: " f"{inspector.cs[CONF_DRAGON_DATA_PATH]}", "Please update nuclear data location to the correct location.", inspector.NO_ACTION, ), settingsValidation.Query( lambda: len( energyGroups.getGroupStructure(inspector.cs["groupStructure"])) > 33, "DRAGON does not run well with more than 33 groups due to calculating " "<400 fine groups. This few number of fine groups may not map well onto " "more than 33 groups.", "Proceed with caution, or choose a group structure with less than 33 groups.", inspector.NO_ACTION, ), settingsValidation.Query( lambda: "7r0" in inspector.cs[CONF_DRAGON_DATA_PATH], "ENDF/B-VII.0 is selected for DRAGON, but Mo98 is not available in this " "library. Your run will likely fail if there is any Mo in your system. ", "It is recommended that the nuclear data be switched to ENDF/B-VII.1 or" "ENDF/B-VIII.0, or Mo98 be removed from nuclear modeling.", inspector.NO_ACTION, ), settingsValidation.Query( lambda: not os.path.exists(inspector.cs[CONF_DRAGON_TEMPLATE_PATH] ), "The path specified to the DRAGON template file in the " f"`{CONF_DRAGON_TEMPLATE_PATH}` setting does not exist: " f"{inspector.cs[CONF_DRAGON_TEMPLATE_PATH]}", "Please update to the correct location.", inspector.NO_ACTION, ), ] return queries
def defineSettingsValidators(inspector): """ Check neutronics settings. """ from armi.operators import settingsValidation # avoid cyclic import from armi.scripts.migration.crossSectionBlueprintsToSettings import ( migrateCrossSectionsFromBlueprints, ) queries = [] def blueprintsHasOldXSInput(path): with directoryChangers.DirectoryChanger(inspector.cs.inputDirectory): with open(os.path.expandvars(path)) as f: for line in f: if line.startswith("cross sections:"): return True return False queries.append( settingsValidation.Query( lambda: inspector.cs["loadingFile"] and blueprintsHasOldXSInput(inspector.cs["loadingFile"]), "The specified blueprints input file '{0}' contains compound cross section settings. " "".format(inspector.cs["loadingFile"]), "Automatically move them to the settings file, {}? WARNING: if multiple settings files point " "to this blueprints input you must manually update the others.".format( inspector.cs.path ), lambda: migrateCrossSectionsFromBlueprints(inspector.cs), ) ) return queries
def defineSettingValidators(inspector): """Define DIF3D-related setting validations.""" queries = [ settingsValidation.Query( lambda: (inspector.cs[neutronicsSettings.CONF_NEUTRONICS_KERNEL ] == CONF_OPT_DIF3DNODAL and neutronics. adjointCalculationRequested(inspector.cs)) and inspector. cs[CONF_COARSE_MESH_REBALANCE] > -1, "The DIF3D nodal approximation will not converge for the adjoint flux solution if the " f"`{CONF_COARSE_MESH_REBALANCE}` setting is enabled.", f"Disable `{CONF_COARSE_MESH_REBALANCE}`?", lambda: inspector._assignCS(CONF_COARSE_MESH_REBALANCE, -1), ), settingsValidation.Query( lambda: inspector.cs[neutronicsSettings.CONF_NEUTRONICS_KERNEL] == CONF_OPT_DIF3DNODAL and inspector.cs[ CONF_ASYMP_EXTRAP_OF_NODAL_CALC] == -1, f"The value of `{CONF_ASYMP_EXTRAP_OF_NODAL_CALC}` is not valid " f"for {CONF_OPT_DIF3DNODAL}", "Set value to 0 to perform asymptotic source extrapolation?", lambda: inspector._assignCS(CONF_ASYMP_EXTRAP_OF_NODAL_CALC, 0), ), settingsValidation.Query( lambda: inspector.cs[neutronicsSettings.CONF_NEUTRONICS_KERNEL] == CONF_OPT_VARIANT and not inspector.cs[ CONF_VARIANT_TRANSPORT_AND_SCATTER_ORDER], f"The value of `{CONF_VARIANT_TRANSPORT_AND_SCATTER_ORDER}` must be set " f"for {CONF_OPT_VARIANT}", "Set value to P3P3?", lambda: inspector._assignCS( CONF_VARIANT_TRANSPORT_AND_SCATTER_ORDER, "P3P3"), ), settingsValidation.Query( lambda: shutil.which(inspector.cs[CONF_DIF3D_PATH]) is None, "The provided DIF3D executable cannot be found: {}".format( inspector.cs[CONF_DIF3D_PATH]), "Please update executable location to the valid location.", inspector.NO_ACTION, ), ] return queries
def defineSettingsValidators(inspector): """ Implementation of settings inspections for fuel cycle settings. """ queries = [] queries.append( settingsValidation.Query( lambda: bool(inspector.cs["shuffleLogic"]) ^ bool(inspector.cs[ "fuelHandlerName"]), "A value was provided for `fuelHandlerName` or `shuffleLogic`, but not " "the other. Either both `fuelHandlerName` and `shuffleLogic` should be " "defined, or neither of them.", "", inspector.NO_ACTION, )) # Check for code fixes for input code on the fuel shuffling outside the version control of ARMI # These are basically auto-migrations for untracked code using # the ARMI API. (This may make sense at a higher level) regex_solutions = [ ( r"(#{0,20}?)[^\s#]*output\s*?\((.*?)(,\s*[1-3]{1}\s*)\)", r"\1runLog.important(\2)", ), ( r"(#{0,20}?)[^\s#]*output\s*?\((.*?)(,\s*[4-5]{1,2}\s*)\)", r"\1runLog.info(\2)", ), ( r"(#{0,20}?)[^\s#]*output\s*?\((.*?)(,\s*[6-8]{1,2}\s*)\)", r"\1runLog.extra(\2)", ), ( r"(#{0,20}?)[^\s#]*output\s*?\((.*?)(,\s*\d{1,2}\s*)\)", r"\1runLog.debug(\2)", ), (r"(#{0,20}?)[^\s#]*output\s*?\((.*?)\)", r"\1runLog.important(\2)"), (r"output = self.cs.output", r""), (r"cs\.getSetting\(\s*([^\)]+)\s*\)", r"cs[\1]"), (r"cs\.setSetting\(\s*([^\)]+)\s*,\s*([^\)]+)\s*\)", r"cs[\1] = \2"), ( r"import\s*armi\.components\s*as\s*components", r"from armi.reactor import components", ), (r"\[['\"]caseTitle['\"]\]", r".caseTitle"), ( r"self.r.core.bolAssems\['(.*?)'\]", r"self.r.blueprints.assemblies['\1']", ), (r"copyAssembly", r"duplicate"), ] def _locateRegexOccurences(): with open(inspector._csRelativePath( inspector.cs["shuffleLogic"])) as src: src = src.read() matches = [] for pattern, _sub in regex_solutions: matches += re.findall(pattern, src) return matches def _applyRegexSolutions(): srcFile = inspector._csRelativePath(inspector.cs["shuffleLogic"]) destFile = os.path.splitext(srcFile)[0] + "migrated.py" with open(srcFile) as src, open(destFile, "w") as dest: srcContent = src.read() # get the buffer content regexContent = srcContent # keep the before and after changes separate for pattern, sub in regex_solutions: regexContent = re.sub(pattern, sub, regexContent) if regexContent != srcContent: dest.write("from armi import runLog\n") dest.write(regexContent) inspector.cs["shuffleLogic"] = destFile queries.append( settingsValidation.Query( lambda: " " in inspector.cs["shuffleLogic"], "Spaces are not allowed in shuffleLogic file location. You have specified {0}. " "Shuffling will not occur.".format( inspector.cs["shuffleLogic"]), "", inspector.NO_ACTION, )) def _clearShufflingInput(): inspector._assignCS("shuffleLogic", "") inspector._assignCS("fuelHandlerName", "") queries.append( settingsValidation.Query( lambda: inspector.cs["shuffleLogic"] and not inspector. _csRelativePathExists(inspector.cs["shuffleLogic"]), "The specified shuffle logic file '{0}' cannot be found. " "Shuffling will not occur.".format( inspector.cs["shuffleLogic"]), "Clear specified file value?", _clearShufflingInput, )) queries.append( settingsValidation.Query( lambda: inspector.cs["shuffleLogic"] and inspector. _csRelativePathExists(inspector.cs["shuffleLogic"] ) and _locateRegexOccurences(), "The shuffle logic file {} uses deprecated code." " It will not work unless you permit some automated changes to occur." " The logic file will be backed up to the current directory under a timestamped name" "".format(inspector.cs["shuffleLogic"]), "Proceed?", _applyRegexSolutions, )) return queries