Example #1
0
def summarizePinDesign(core):
    r"""Prints out some information about the pin assembly/duct design.

    Handles multiple types of dimensions simplistically by taking the average.

    Parameters
    ----------
    core : armi.reactor.reactors.Core

    """
    designInfo = collections.defaultdict(list)

    try:
        for b in core.getBlocks(Flags.FUEL):
            fuel = b.getComponent(Flags.FUEL)
            duct = b.getComponent(Flags.DUCT)
            clad = b.getComponent(Flags.CLAD)
            wire = b.getComponent(Flags.WIRE)
            designInfo["hot sd"].append(b.getSmearDensity(cold=False))
            designInfo["sd"].append(b.getSmearDensity())
            designInfo["ductThick"].append(
                (duct.getDimension("op") - duct.getDimension("ip")) *
                5.0)  # convert to mm and divide by 2
            designInfo["cladThick"].append(
                (clad.getDimension("od") - clad.getDimension("id")) * 5.0)
            pinOD = clad.getDimension("od") * 10.0
            wireOD = wire.getDimension("od") * 10.0
            pitch = pinOD + wireOD  # pitch has half a wire on each side.
            assemPitch = b.getPitch() * 10  # convert cm to mm.
            designInfo["pinOD"].append(pinOD)
            designInfo["wireOD"].append(wireOD)
            designInfo["pin pitch"].append(pitch)
            pinToDuctGap = b.getPinToDuctGap()
            if pinToDuctGap is not None:
                designInfo["pinToDuct"].append(b.getPinToDuctGap() * 10.0)
            designInfo["assemPitch"].append(assemPitch)
            designInfo["duct gap"].append(assemPitch -
                                          duct.getDimension("op") * 10.0)
            designInfo["nPins"].append(b.p.nPins)
            designInfo["zrFrac"].append(fuel.getMassFrac("ZR"))

        # assumption made that all lists contain only numerical data
        designInfo = {
            key: numpy.average(data)
            for key, data in designInfo.items()
        }

        dimensionless = {"sd", "hot sd", "zrFrac", "nPins"}
        for key, average_value in designInfo.items():
            dim = "{0:10s}".format(key)
            val = "{0:.4f}".format(average_value)
            if key not in dimensionless:
                val += " mm"
            report.setData(dim, val, report.PIN_ASSEM_DESIGN)

        a = core.refAssem
        report.setData(
            "Fuel Height (cm):",
            "{0:.2f}".format(a.getHeight(Flags.FUEL)),
            report.PIN_ASSEM_DESIGN,
        )
        report.setData(
            "Plenum Height (cm):",
            "{0:.2f}".format(a.getHeight(Flags.PLENUM)),
            report.PIN_ASSEM_DESIGN,
        )
        runLog.info(report.ALL[report.PIN_ASSEM_DESIGN])

        first_fuel_block = core.getFirstBlock(Flags.FUEL)
        runLog.info(
            "Design & component information for first fuel block {}".format(
                first_fuel_block))

        runLog.info(first_fuel_block.setAreaFractionsReport())

        for component_ in sorted(first_fuel_block):
            runLog.info(component_.setDimensionReport())

    except Exception as error:  # pylint: disable=broad-except
        runLog.warning("Pin summarization failed to work")
        runLog.warning(error)
Example #2
0
def _setGeneralCoreDesignData(cs, coreDesignTable):
    report.setData("Case Title", "{}".format(cs.caseTitle), coreDesignTable,
                   report.DESIGN)
    report.setData("Run Type", "{}".format(cs["runType"]), coreDesignTable,
                   report.DESIGN)
    report.setData("Geometry File", "{}".format(cs["geomFile"]),
                   coreDesignTable, report.DESIGN)
    report.setData("Loading File", "{}".format(cs["loadingFile"]),
                   coreDesignTable, report.DESIGN)
    report.setData(
        "Fuel Shuffling Logic File",
        "{}".format(cs["shuffleLogic"]),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Reactor State Loading",
        "{}".format(cs["loadStyle"]),
        coreDesignTable,
        report.DESIGN,
    )
    if cs["loadStyle"] == "fromDB":
        report.setData(
            "Database File",
            "{}".format(cs["reloadDBName"]),
            coreDesignTable,
            report.DESIGN,
        )
        report.setData(
            "Starting Cycle",
            "{}".format(cs["startCycle"]),
            coreDesignTable,
            report.DESIGN,
        )
        report.setData(
            "Starting Node",
            "{}".format(cs["startNode"]),
            coreDesignTable,
            report.DESIGN,
        )
Example #3
0
def setNeutronBalancesReport(core):
    """Determines the various neutron balances over the full core

    Parameters
    ----------
    core  : armi.reactor.reactors.Core

    """

    if not core.getFirstBlock().p.rateCap:
        runLog.warning(
            "No rate information (rateCap, rateAbs, etc.) available "
            "on the blocks. Skipping balance summary.")
        return

    cap = core.calcAvgParam("rateCap", volumeAveraged=False, generationNum=2)
    absorb = core.calcAvgParam("rateAbs",
                               volumeAveraged=False,
                               generationNum=2)
    fis = core.calcAvgParam("rateFis", volumeAveraged=False, generationNum=2)
    n2nProd = core.calcAvgParam("rateProdN2n",
                                volumeAveraged=False,
                                generationNum=2)
    fisProd = core.calcAvgParam("rateProdFis",
                                volumeAveraged=False,
                                generationNum=2)

    leak = n2nProd + fisProd - absorb

    report.setData(
        "Fission",
        "{0:.5e} ({1:.2%})".format(fisProd, fisProd / (fisProd + n2nProd)),
        report.NEUT_PROD,
    )
    report.setData(
        "n, 2n",
        "{0:.5e} ({1:.2%})".format(n2nProd, n2nProd / (fisProd + n2nProd)),
        report.NEUT_PROD,
    )
    report.setData(
        "Capture",
        "{0:.5e} ({1:.2%})".format(cap, cap / (absorb + leak)),
        report.NEUT_LOSS,
    )
    report.setData(
        "Fission",
        "{0:.5e} ({1:.2%})".format(fis, fis / (absorb + leak)),
        report.NEUT_LOSS,
    )
    report.setData(
        "Absorption",
        "{0:.5e} ({1:.2%})".format(absorb, absorb / (absorb + leak)),
        report.NEUT_LOSS,
    )
    report.setData(
        "Leakage",
        "{0:.5e} ({1:.2%})".format(leak, leak / (absorb + leak)),
        report.NEUT_LOSS,
    )

    runLog.info(report.ALL[report.NEUT_PROD])  # TODO: print in "lite"
    runLog.info(report.ALL[report.NEUT_LOSS])
Example #4
0
def makeCoreAndAssemblyMaps(r,
                            cs,
                            generateFullCoreMap=False,
                            showBlockAxMesh=True):
    r"""Create core and assembly design plots

    Parameters
    ----------
    r : armi.reactor.reactors.Reactor
    cs: armi.settings.caseSettings.Settings
    generateFullCoreMap : bool, default False
    showBlockAxMesh : bool, default True
    """
    assemsInCore = list(r.blueprints.assemblies.values())
    core = r.core
    for plotNum, assemBatch in enumerate(iterables.chunk(
            assemsInCore, MAX_ASSEMS_PER_ASSEM_PLOT),
                                         start=1):
        assemPlotImage = copy(report.ASSEM_TYPES)
        assemPlotImage.title = assemPlotImage.title + " ({})".format(plotNum)
        report.data.Report.groupsOrderFirst.insert(-1, assemPlotImage)
        report.data.Report.componentWellGroups.insert(-1, assemPlotImage)
        assemPlotName = os.path.abspath(
            f"{core.name}AssemblyTypes{plotNum}.png")
        plotting.plotAssemblyTypes(
            core.parent.blueprints,
            assemPlotName,
            assemBatch,
            maxAssems=MAX_ASSEMS_PER_ASSEM_PLOT,
            showBlockAxMesh=showBlockAxMesh,
        )

    # Create radial core map
    if generateFullCoreMap:
        core.growToFullCore(cs)

    counts = {
        assemDesign.name: len(core.getChildrenOfType(assemDesign.name))
        for assemDesign in r.blueprints.assemDesigns
    }
    # assemDesigns.keys is ordered based on input, assemOrder only contains types that are in the core
    assemOrder = [
        aType for aType in r.blueprints.assemDesigns.keys()
        if counts[aType] > 0
    ]
    data = [assemOrder.index(a.p.type) for a in core]
    labels = [r.blueprints.assemDesigns[a.p.type].specifier for a in core]
    legendMap = [(
        ai,
        assemDesign.specifier,
        "{} ({})".format(assemDesign.name, counts[assemDesign.name]),
    ) for ai, assemDesign in enumerate(r.blueprints.assemDesigns)
                 if counts[assemDesign.name] > 0]

    fName = "".join(
        [cs.caseTitle, "RadialCoreMap.", cs["outputFileExtension"]])
    plotting.plotFaceMap(
        core,
        title="{} Radial Core Map".format(cs.caseTitle),
        fName=fName,
        cmapName="RdYlBu",
        data=data,
        labels=labels,
        legendMap=legendMap,
        axisEqual=True,
        bare=True,
        titleSize=10,
        fontSize=8,
    )
    plotting.close()

    report.setData("Radial Core Map", os.path.abspath(fName), report.FACE_MAP,
                   report.DESIGN)
Example #5
0
def _setGeneralCoreParametersData(core, cs, coreDesignTable):
    blocks = core.getBlocks()
    totalMass = sum(b.getMass() for b in blocks)
    fissileMass = sum(b.getFissileMass() for b in blocks)
    heavyMetalMass = sum(b.getHMMass() for b in blocks)
    totalVolume = sum(b.getVolume() for b in blocks)
    report.setData(" ", "", coreDesignTable, report.DESIGN)
    report.setData(
        "Core Power",
        "{:.2f} MWth".format(cs["power"] / units.WATTS_PER_MW),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Base Capacity Factor",
        "{}".format(cs["availabilityFactor"]),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Cycle Length",
        "{} days".format(cs["cycleLength"]),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData("Burnup Cycles", "{}".format(cs["nCycles"]),
                   coreDesignTable, report.DESIGN)
    report.setData(
        "Burnup Steps per Cycle",
        "{}".format(cs["burnSteps"]),
        coreDesignTable,
        report.DESIGN,
    )
    corePowerMult = int(core.powerMultiplier)
    report.setData(
        "Core Total Volume",
        "{:.2f} cc".format(totalVolume * corePowerMult),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Core Fissile Mass",
        "{:.2f} kg".format(fissileMass / units.G_PER_KG * corePowerMult),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Core Heavy Metal Mass",
        "{:.2f} kg".format(heavyMetalMass / units.G_PER_KG * corePowerMult),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Core Total Mass",
        "{:.2f} kg".format(totalMass / units.G_PER_KG * corePowerMult),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Number of Assembly Rings",
        "{}".format(core.getNumRings()),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Number of Assemblies",
        "{}".format(len(core.getAssemblies() * corePowerMult)),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Number of Fuel Assemblies",
        "{}".format(len(core.getAssemblies(Flags.FUEL) * corePowerMult)),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Number of Control Assemblies",
        "{}".format(len(core.getAssemblies(Flags.CONTROL) * corePowerMult)),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Number of Reflector Assemblies",
        "{}".format(len(core.getAssemblies(Flags.REFLECTOR) * corePowerMult)),
        coreDesignTable,
        report.DESIGN,
    )
    report.setData(
        "Number of Shield Assemblies",
        "{}".format(len(core.getAssemblies(Flags.SHIELD) * corePowerMult)),
        coreDesignTable,
        report.DESIGN,
    )
Example #6
0
    def setDimensionReport(self):
        """Gives a report of the dimensions of this component."""
        reportGroup = None
        for componentType, componentReport in self._COMP_REPORT_GROUPS.items():
            if componentType in self.getName():
                reportGroup = componentReport
                break
        if not reportGroup:
            return "No report group designated for {} component.".format(
                self.getName())
        reportGroup.header = [
            "",
            "Tcold ({0})".format(self.inputTemperatureInC),
            "Thot ({0})".format(self.temperatureInC),
        ]

        dimensions = {
            k: self.p[k]
            for k in self.DIMENSION_NAMES
            if k not in ("modArea", "area") and self.p[k] is not None
        }  # py3 cannot format None
        # Set component name and material
        report.setData("Name", [self.getName(), ""], reportGroup)
        report.setData("Material", [self.getProperties().name, ""],
                       reportGroup)

        for dimName in dimensions:
            niceName = _NICE_DIM_NAMES.get(dimName, dimName)
            refVal = self.getDimension(dimName, cold=True)
            hotVal = self.getDimension(dimName)
            try:
                report.setData(niceName, [refVal, hotVal], reportGroup)
            except ValueError:
                runLog.warning(
                    "{0} has an invalid dimension for {1}. refVal: {2} hotVal: {3}"
                    .format(self, dimName, refVal, hotVal))

        # calculate thickness if applicable.
        suffix = None
        if "id" in dimensions:
            suffix = "d"
        elif "ip" in dimensions:
            suffix = "p"

        if suffix:
            coldIn = self.getDimension("i{0}".format(suffix), cold=True)
            hotIn = self.getDimension("i{0}".format(suffix))
            coldOut = self.getDimension("o{0}".format(suffix), cold=True)
            hotOut = self.getDimension("o{0}".format(suffix))

        if suffix and coldIn > 0.0:
            hotThick = (hotOut - hotIn) / 2.0
            coldThick = (coldOut - coldIn) / 2.0
            vals = (
                "Thickness (cm)",
                "{0:.7f}".format(coldThick),
                "{0:.7f}".format(hotThick),
            )
            report.setData(vals[0], [vals[1], vals[2]], reportGroup)

        return report.ALL[reportGroup]
Example #7
0
def plotBlockFlux(core,
                  fName=None,
                  bList=None,
                  peak=False,
                  adjoint=False,
                  bList2=[]):
    """
    Produce energy spectrum plot of real and/or adjoint flux in one or more blocks.

    Parameters
    ----------
    core : Core
        Core object
    fName : str, optional
        the name of the plot file to produce. If none, plot will be shown. A text file with
        the flux values will also be generated if this is non-empty.
    bList : iterable, optional
        is a single block or a list of blocks to average over. If no bList, full core is assumed.
    peak : bool, optional
        a flag that will produce the peak as well as the average on the plot.
    adjoint : bool, optional
        plot the adjoint as well.
    bList2 :
        a separate list of blocks that will also be plotted on a separate axis on the same plot.
        This is useful for comparing flux in some blocks with flux in some other blocks.

    Notes
    -----
    This is not a great method. It should be cleand up and migrated into ``utils.plotting``.
    """
    class BlockListFlux(object):
        def __init__(self,
                     nGroup,
                     blockList=[],
                     adjoint=False,
                     peak=False,
                     primary=False):
            if blockList:
                self.blockList = blockList
                self.nGroup = nGroup
                self.avgFlux = numpy.zeros(self.nGroup)
                self.peakFlux = numpy.zeros(self.nGroup)
                self.peak = peak
                self.adjoint = adjoint
                if self.adjoint:
                    self.labelAvg = "Average Adjoint Flux"
                    self.labelPeak = "Peak Adjoint Flux"
                else:
                    self.labelAvg = "Average Flux"
                    self.labelPeak = "Peak Flux"
                if primary:
                    self.lineAvg = "-"
                    self.linePeak = "-"
                else:
                    self.lineAvg = "r--"
                    self.linePeak = "k--"

        def calcAverage(self):
            for b in self.blockList:
                thisFlux = numpy.array(b.getMgFlux(adjoint=self.adjoint))
                self.avgFlux += numpy.array(thisFlux)
                if sum(thisFlux) > sum(self.peakFlux):
                    self.peakFlux = thisFlux
            self.avgFlux = self.avgFlux / len(bList)

        def setEnergyStructure(self, upperEnergyBounds):
            self.E = [eMax / 1e6 for eMax in upperEnergyBounds]

        def makePlotHistograms(self):
            self.eHistogram, self.avgHistogram = makeHistogram(
                self.E, self.avgFlux)
            if self.peak:
                _, self.peakHistogram = makeHistogram(self.E, self.peakFlux)

        def checkSize(self):
            if not len(self.E) == len(self.avgFlux):
                runLog.error(self.avgFlux)
                raise

        def getTable(self):
            return enumerate(zip(self.E, self.avgFlux, self.peakFlux))

    if bList is None:
        bList = core.getBlocks()
    bList = list(bList)
    if adjoint and bList2:
        runLog.warning("Cannot plot adjoint flux with bList2 argument")
        return
    elif adjoint:
        bList2 = bList
    try:
        G = len(core.lib.neutronEnergyUpperBounds)
    except:
        runLog.warning("No ISOTXS library attached so no flux plots.")
        return

    BlockListFluxes = set()
    bf1 = BlockListFlux(G, blockList=bList, peak=peak, primary=True)
    BlockListFluxes.add(bf1)
    if bList2:
        bf2 = BlockListFlux(G, blockList=bList2, adjoint=adjoint, peak=peak)
        BlockListFluxes.add(bf2)

    for bf in BlockListFluxes:
        bf.calcAverage()
        bf.setEnergyStructure(core.lib.neutronEnergyUpperBounds)
        bf.checkSize()
        bf.makePlotHistograms()

    if fName:
        # write a little flux text file.
        txtFileName = os.path.splitext(fName)[0] + ".txt"
        with open(txtFileName, "w") as f:
            f.write("{0:16s} {1:16s} {2:16s}\n".format("Energy_Group",
                                                       "Average_Flux",
                                                       "Peak_Flux"))
            for g, (eMax, avgFlux, peakFlux) in bf1.getTable():
                f.write("{0:12E} {1:12E} {2:12E}\n".format(
                    eMax, avgFlux, peakFlux))

    if max(bf1.avgFlux) <= 0.0:
        runLog.warning("Cannot plot flux with maxval=={0} in {1}".format(
            maxVal, bList[0]))
        return

    plt.figure()
    plt.plot(bf1.eHistogram, bf1.avgHistogram, bf1.lineAvg, label=bf1.labelAvg)
    if peak:
        plt.plot(bf1.eHistogram,
                 bf1.peakHistogram,
                 bf1.linePeak,
                 label=bf1.labelPeak)
    ax = plt.gca()
    ax.set_xscale("log")
    ax.set_yscale("log")
    plt.xlabel("Energy (MeV)")
    plt.ylabel("Flux (n/cm$^2$/s)")
    if peak or bList2:
        plt.legend(loc="lower right")
    plt.grid(color="0.70")
    if bList2:
        if adjoint:
            plt.twinx()
            plt.ylabel("Adjoint Flux (n/cm$^2$/s)", rotation=270)
            ax2 = plt.gca()
            ax2.set_yscale("log")
        plt.plot(bf2.eHistogram,
                 bf2.avgHistogram,
                 bf2.lineAvg,
                 label=bf2.labelAvg)
        if peak and not adjoint:
            plt.plot(bf2.eHistogram,
                     bf2.peakHistogram,
                     bf2.linePeak,
                     label=bf2.labelPeak)
        plt.legend(loc="lower left")
    plt.title("Group flux")

    if fName:
        plt.savefig(fName)
        report.setData(
            "Flux Plot {}".format(os.path.split(fName)[1]),
            os.path.abspath(fName),
            report.FLUX_PLOT,
        )
    else:
        plt.show()