def test_createFormattedStrWithDelimiter(self): # Test with a random list of strings dataList = ["hello", "world", "1", "2", "3", "4", "5"] maxNumberOfValuesBeforeDelimiter = 3 delimiter = "\n" outputStr = utils.createFormattedStrWithDelimiter( dataList=dataList, maxNumberOfValuesBeforeDelimiter=maxNumberOfValuesBeforeDelimiter, delimiter=delimiter, ) self.assertEqual(outputStr, "hello, world, 1,\n2, 3,\n4, 5\n") outputStr = utils.createFormattedStrWithDelimiter( dataList=dataList, maxNumberOfValuesBeforeDelimiter=0, delimiter=delimiter, ) self.assertEqual(outputStr, "hello, world, 1, 2, 3, 4, 5\n") # test with an empty list dataList = [] outputStr = utils.createFormattedStrWithDelimiter( dataList=dataList, maxNumberOfValuesBeforeDelimiter=maxNumberOfValuesBeforeDelimiter, delimiter=delimiter, ) self.assertEqual(outputStr, "")
def buildZones(core, cs): """ Build/update the zones. Zones are groups of assembly locations used for various purposes such as defining SASSYS channels and reactivity coefficients. The zoning option is determined by the ``zoningStrategy`` setting. """ zones = Zones(core, cs) zoneOption = cs[globalSettings.CONF_ZONING_STRATEGY] if "byRingZone" in zoneOption: zones.update(_buildRingZoneZones(core, cs)) elif "manual" in zoneOption: zones.update(_buildManualZones(core, cs)) elif "byFuelType" in zoneOption: zones.update(_buildAssemTypeZones(core, cs, Flags.FUEL)) elif "byOrifice" in zoneOption: zones.update(_buildZonesByOrifice(core, cs)) elif "everyFA" in zoneOption: zones.update(_buildZonesforEachFA(core, cs)) else: raise ValueError( "Invalid `zoningStrategy` grouping option {}".format(zoneOption) ) if cs["createAssemblyTypeZones"]: zones.update(_buildAssemTypeZones(core, cs, Flags.FUEL)) # Summarize the zone information headers = [ "Zone\nNumber", "\nName", "\nAssemblies", "\nLocations", "Symmetry\nFactor", "Hot\nZone", ] zoneSummaryData = [] for zi, zone in enumerate(zones, 1): assemLocations = utils.createFormattedStrWithDelimiter( zone, maxNumberOfValuesBeforeDelimiter=6 ) zoneSummaryData.append( (zi, zone.name, len(zone), assemLocations, zone.symmetry, zone.hotZone) ) runLog.info( "Assembly zone definitions:\n" + tabulate.tabulate( tabular_data=zoneSummaryData, headers=headers, tablefmt="armi" ), single=True, ) return zones
def _resolveNuclides(self, cs): """ Process elements and determine how to expand them to natural isotopics. Also builds meta-data about which nuclides are in the problem. This system works by building a dictionary in the ``elementsToExpand`` attribute with ``Element`` keys and list of ``NuclideBase`` values. The actual expansion of elementals to isotopics occurs during :py:meth:`Component construction <armi.reactor.blueprints.componentBlueprint. ComponentBlueprint._constructMaterial>`. """ from armi import utils actives = set() inerts = set() undefBurnChainActiveNuclides = set() if self.nuclideFlags is None: self.nuclideFlags = isotopicOptions.genDefaultNucFlags() self.elementsToExpand = [] for nucFlag in self.nuclideFlags: # this returns any nuclides that are flagged specifically for expansion by input expandedElements = nucFlag.fileAsActiveOrInert( actives, inerts, undefBurnChainActiveNuclides) self.elementsToExpand.extend(expandedElements) inerts -= actives self.customIsotopics = self.customIsotopics or isotopicOptions.CustomIsotopics( ) ( elementalsToKeep, expansions, ) = isotopicOptions.autoSelectElementsToKeepFromSettings(cs) nucsFromInput = actives | inerts # join # Flag all elementals for expansion unless they've been flagged otherwise by # user input or automatic lattice/datalib rules. for elemental in nuclideBases.instances: if not isinstance(elemental, nuclideBases.NaturalNuclideBase): # `elemental` may be a NaturalNuclideBase or a NuclideBase # skip all NuclideBases continue if elemental in elementalsToKeep: continue if elemental.name in actives: currentSet = actives actives.remove(elemental.name) elif elemental.name in inerts: currentSet = inerts inerts.remove(elemental.name) else: # This was not specified in the nuclide flags at all. # If a material with this in its composition is brought in # it's nice from a user perspective to allow it. # But current behavior is that all nuclides in problem # must be declared up front. continue self.elementsToExpand.append(elemental.element) if (elemental.name in self.nuclideFlags and self.nuclideFlags[elemental.name].expandTo): # user-input has precedence newNuclides = [ nuclideBases.byName[nn] for nn in self.nuclideFlags[ elemental.element.symbol].expandTo ] elif (elemental in expansions and elemental.element.symbol in self.nuclideFlags): # code-specific expansion required newNuclides = expansions[elemental] # overlay code details onto nuclideFlags for other parts of the code # that will use them. # CRAP: would be better if nuclideFlags did this upon reading s.t. # order didn't matter. On the other hand, this is the only place in # the code where NuclideFlags get built and have user settings around # (hence "resolve"). # This must be updated because the operative expansion code just uses the flags # # Also, if this element is not in nuclideFlags at all, we just don't add it self.nuclideFlags[elemental.element.symbol].expandTo = [ nb.name for nb in newNuclides ] else: # expand to all possible natural isotopics newNuclides = elemental.element.getNaturalIsotopics() for nb in newNuclides: currentSet.add(nb.name) if self.elementsToExpand: runLog.info( "Will expand {} elementals to have natural isotopics".format( ", ".join(element.symbol for element in self.elementsToExpand))) self.activeNuclides = ordered_set.OrderedSet(sorted(actives)) self.inertNuclides = ordered_set.OrderedSet(sorted(inerts)) self.allNuclidesInProblem = ordered_set.OrderedSet( sorted(actives.union(inerts))) # Inform user which nuclides are truncating the burn chain. if undefBurnChainActiveNuclides: runLog.info( tabulate.tabulate( [[ "Nuclides truncating the burn-chain:", utils.createFormattedStrWithDelimiter( list(undefBurnChainActiveNuclides)), ]], tablefmt="plain", ), single=True, )
def splitZones(core, cs, zones): """ Split the existing zone style into smaller zones via number of blocks and assembly type. Parameters ---------- core: Core The Core object to which the Zones belong cs: Case settings The case settings for the run zones: Zones The Zones to split Returns ------- zones: Zones Notes ----- Zones are collections of locations grouped by some user input. Calling this method transforms a collection of zones into another collection of zones further broken down by assembly type and number of blocks. Each new zone only contains assemblies of the same type and block count. any other arbitrary grouping method. A subZone is a further breakdown of a zone. Examples -------- If the original zone was ringZone3 and ringZone3 contained three assemblies, one of them being a burner with nine blocks, one being a burner with 8 blocks and one control assembly with 3 blocks three splitZones would be produced and ringZone3 would be deleted. The the zones would be named ringZone3_Burner_8, ringZone3_Burner_9, ringZone3_Control_3. """ if not cs["splitZones"]: return zones # We should make this unchangeable originalZoneNames = tuple([zone.name for zone in zones]) splitZoneToOriginalZonesMap = {} subZoneNameSeparator = "-" for name in originalZoneNames: assems = core.getAssemblies(zones=name) for a in assems: # figure out what type of assembly we have flavor = a.getType().replace( " ", subZoneNameSeparator) # replace spaces subZoneName = (name + subZoneNameSeparator + flavor + subZoneNameSeparator + str(len(a))) splitZoneToOriginalZonesMap[subZoneName] = name try: zone = zones[subZoneName] except KeyError: zone = Zone(subZoneName) zones.add(zone) zone.append(a.getLocation()) # now remove the original non separated zone zones.removeZone(name) # Summarize the zone information headers = [ "Zone\nNumber", "\nName", "Original\nName", "\nAssemblies", "\nLocations", "Symmetry\nFactor", "Hot\nZone", ] zoneSummaryData = [] for zi, zone in enumerate(zones, 1): assemLocations = utils.createFormattedStrWithDelimiter( zone, maxNumberOfValuesBeforeDelimiter=6) zoneSummaryData.append(( zi, zone.name, splitZoneToOriginalZonesMap[zone.name], len(zone), assemLocations, zone.symmetry, zone.hotZone, )) runLog.info( "The setting `splitZones` is enabled. Building subzones from core zones:\n" + tabulate.tabulate( tabular_data=zoneSummaryData, headers=headers, tablefmt="armi"), single=True, ) return zones
def _resolveNuclides(self, cs): """Expands the density of any elemental nuclides to its natural isotopics.""" from armi import utils # expand burn-chain to only contain nuclides, no elements actives = set() inerts = set() undefBurnChainActiveNuclides = set() if self.nuclideFlags is None: self.nuclideFlags = genDefaultNucFlags() for nucFlag in self.nuclideFlags: nucFlag.prepForCase(actives, inerts, undefBurnChainActiveNuclides) inerts -= actives self.customIsotopics = self.customIsotopics or CustomIsotopics() self.elementsToExpand = [] elementalsToSkip = self._selectNuclidesToExpandForModeling(cs) # if elementalsToSkip=[CR], we expand everything else. e.g. CR -> CR (unchanged) nucsFromInput = actives | inerts # join for elemental in nuclideBases.instances: if not isinstance(elemental, nuclideBases.NaturalNuclideBase): continue if elemental.name not in nucsFromInput: continue # we've now confirmed this elemental is in the problem if elemental in elementalsToSkip: continue nucsInProblem = actives if elemental.name in actives else inerts nucsInProblem.remove(elemental.name) self.elementsToExpand.append(elemental.element) for nb in elemental.element.getNaturalIsotopics(): nucsInProblem.add(nb.name) if self.elementsToExpand: runLog.info( "Expanding {} elementals to have natural isotopics".format( ", ".join(element.symbol for element in self.elementsToExpand))) self.activeNuclides = ordered_set.OrderedSet(sorted(actives)) self.inertNuclides = ordered_set.OrderedSet(sorted(inerts)) self.allNuclidesInProblem = ordered_set.OrderedSet( sorted(actives.union(inerts))) # Inform user that the burn-chain may not be complete if undefBurnChainActiveNuclides: runLog.info( tabulate.tabulate( [[ "Nuclides truncating the burn-chain:", utils.createFormattedStrWithDelimiter( list(undefBurnChainActiveNuclides)), ]], tablefmt="plain", ), single=True, )