diff --git a/armi/bookkeeping/__init__.py b/armi/bookkeeping/__init__.py
index 4cf09980c..97c634a4e 100644
--- a/armi/bookkeeping/__init__.py
+++ b/armi/bookkeeping/__init__.py
@@ -110,12 +110,13 @@ def getReportContents(r, cs, report, stage, blueprint):
"""
from armi.cli import reportsEntryPoint
+ from armi.bookkeeping import newReports as reports
from armi.bookkeeping import newReportUtils
- if stage == reportsEntryPoint.ReportStage.Begin:
+ if stage == reports.ReportStage.Begin:
newReportUtils.insertGeneralReportContent(cs, r, report, stage)
if blueprint is not None:
newReportUtils.insertBlueprintContent(r, cs, report, blueprint)
- elif stage == reportsEntryPoint.ReportStage.End:
+ elif stage == reports.ReportStage.End:
newReportUtils.insertEndOfLifeContent(r, report)
return
diff --git a/armi/bookkeeping/newReportUtils.py b/armi/bookkeeping/newReportUtils.py
index 6084e3417..7f584d74a 100644
--- a/armi/bookkeeping/newReportUtils.py
+++ b/armi/bookkeeping/newReportUtils.py
@@ -10,7 +10,6 @@
from armi.utils import plotting
from armi.utils import units
from armi.utils import iterables
-from armi.cli.reportsEntryPoint import ReportStage
from armi.materials import custom
@@ -37,7 +36,7 @@ def insertGeneralReportContent(cs, r, report, stage):
"""
# These items only happen once at BOL
- if stage == ReportStage.Begin:
+ if stage == newReports.ReportStage.Begin:
comprehensiveBOLContent(cs, r, report)
insertDesignContent(r, report)
diff --git a/armi/bookkeeping/newReports.py b/armi/bookkeeping/newReports.py
index 116205873..74a299658 100644
--- a/armi/bookkeeping/newReports.py
+++ b/armi/bookkeeping/newReports.py
@@ -1,3 +1,5 @@
+from enum import Enum
+from enum import auto
import collections
import shutil
import os
@@ -86,7 +88,7 @@ def writeReports(self):
),
"report.js",
)
- fileurl = doc.renderToFile("ReportContent.html", 0)
+ fileurl = doc.renderToFile("index.html", 0)
return fileurl
def get(self, section, default=None):
@@ -566,6 +568,12 @@ def render(self, level, idPrefix="") -> htmltree.HtmlElement:
)
+class ReportStage(Enum):
+ Begin = auto()
+ Standard = auto()
+ End = auto()
+
+
def encode64(file_path):
"""Encodes the contents of the file indicated by the path
diff --git a/armi/bookkeeping/report/reportInterface.py b/armi/bookkeeping/report/reportInterface.py
index bfb64333e..d9f81546f 100644
--- a/armi/bookkeeping/report/reportInterface.py
+++ b/armi/bookkeeping/report/reportInterface.py
@@ -117,7 +117,6 @@ def generateDesignReport(self, generateFullCoreMap, showBlockAxMesh):
def interactEOL(self):
"""Adds the data to the report, and generates it"""
- self.cs.setSettingsReport()
b = self.o.r.core.getFirstBlock(Flags.FUEL)
b.setAreaFractionsReport()
diff --git a/armi/bookkeeping/tests/test_report.py b/armi/bookkeeping/tests/test_report.py
index 2d3082232..57213e45f 100644
--- a/armi/bookkeeping/tests/test_report.py
+++ b/armi/bookkeeping/tests/test_report.py
@@ -26,7 +26,6 @@
from armi.utils import directoryChangers
from armi.physics.neutronics.reports import neutronicsPlotting
import armi.bookkeeping.newReports
-from armi.cli.reportsEntryPoint import ReportStage
class TestReportContentCreation(unittest.TestCase):
@@ -75,7 +74,7 @@ def testReportContents(self):
r=self.r,
cs=self.o.cs,
report=reportTest,
- stage=ReportStage.Begin,
+ stage=newReports.ReportStage.Begin,
blueprint=self.r.blueprints,
)
@@ -108,7 +107,7 @@ def testWriteReports(self):
reportTest.writeReports()
# Want to check that two
exists...
times = 0
- with open("ReportContent.html") as f:
+ with open("index.html") as f:
for line in f:
if "
" in line:
times = times + 1
diff --git a/armi/cases/case.py b/armi/cases/case.py
index f20465cef..4c459cd50 100644
--- a/armi/cases/case.py
+++ b/armi/cases/case.py
@@ -45,11 +45,10 @@
from armi import operators
from armi import runLog
from armi import interfaces
+from armi.cli import reportsEntryPoint
from armi.reactor import blueprints
from armi.reactor import systemLayoutInput
from armi.reactor import reactors
-from armi.bookkeeping import report
-from armi.bookkeeping.report import reportInterface
from armi.bookkeeping.db import compareDatabases
from armi.utils import pathTools
from armi.utils.directoryChangers import DirectoryChanger
@@ -491,21 +490,8 @@ def checkInputs(self):
def summarizeDesign(self, generateFullCoreMap=True, showBlockAxialMesh=True):
"""Uses the ReportInterface to create a fancy HTML page describing the design inputs."""
- settings.setMasterCs(self.cs)
- o = self.initializeOperator()
- with DirectoryChanger(self.cs.inputDirectory, dumpOnException=False):
- # There are global variables that are modified when a report is
- # generated, so reset it all
- six.moves.reload_module(report) # pylint: disable=too-many-function-args
- self.cs.setSettingsReport()
- rpi = o.getInterface("report")
-
- if rpi is None:
- rpi = reportInterface.ReportInterface(o.r, o.cs)
-
- rpi.generateDesignReport(generateFullCoreMap, showBlockAxialMesh)
- report.DESIGN.writeHTML()
- runLog.important("Design report summary was successfully generated")
+
+ _ = reportsEntryPoint.createReportFromSettings(self.cs)
def buildCommand(self, python="python"):
"""
diff --git a/armi/cases/tests/test_cases.py b/armi/cases/tests/test_cases.py
index cc5c93b45..eb4dbf654 100644
--- a/armi/cases/tests/test_cases.py
+++ b/armi/cases/tests/test_cases.py
@@ -89,7 +89,11 @@ def test_summarizeDesign(self):
case = cases.Case(cs)
c2 = case.clone()
c2.summarizeDesign(True, True)
- self.assertTrue(os.path.exists("Core Design Report.html"))
+ self.assertTrue(
+ os.path.exists(
+ os.path.join("{}-reports".format(c2.cs.caseTitle), "index.html")
+ )
+ )
def test_independentVariables(self):
"""Ensure that independentVariables added to a case move with it."""
diff --git a/armi/cli/reportsEntryPoint.py b/armi/cli/reportsEntryPoint.py
index e9663badb..9e270b249 100644
--- a/armi/cli/reportsEntryPoint.py
+++ b/armi/cli/reportsEntryPoint.py
@@ -1,11 +1,15 @@
-from enum import Enum
-from enum import auto
+import pathlib
import webbrowser
import armi
from armi.cli import entryPoint
-from armi.reactor.reactors import factory
+from armi.reactor import reactors
from armi.utils import runLog
+from armi import settings
+from armi.utils import directoryChangers
+from armi.reactor import blueprints
+from armi.bookkeeping import newReports as reports
+from armi.bookkeeping.db import databaseFactory
class ReportsEntryPoint(entryPoint.EntryPoint):
@@ -23,10 +27,10 @@ def __init__(self):
def addOptions(self):
self.parser.add_argument("-h5db", help="Input database path", type=str)
self.parser.add_argument(
- "-bp", help="Input blueprint (optional)", type=str, default=None
+ "--bp", help="Input blueprint (optional)", type=str, default=None
)
self.parser.add_argument(
- "-settings", help="Settings File (optional", type=str, default=None
+ "--settings", help="Settings File (optional)", type=str, default=None
)
self.parser.add_argument(
"--output-name",
@@ -67,45 +71,23 @@ def addOptions(self):
# self.createOptionFromSetting("imperialunits", "-i")
def invoke(self):
- from armi import settings
- from armi.reactor import blueprints
- from armi.bookkeeping.newReports import ReportContent
- from armi.bookkeeping.db import databaseFactory
- from armi.utils import directoryChangers
nodes = self.args.nodes
- report = ReportContent("Overview")
- app = armi.getApp()
- if app is None:
- raise RuntimeError("NEED APP!")
- pm = app._pm
if self.args.h5db is None:
# Just do begining stuff, no database is given...
if self.cs is not None:
- cs = self.cs
- settings.setMasterCs(self.cs)
- blueprint = blueprints.loadFromCs(cs)
- r = factory(cs, blueprint)
- report.title = r.name
+ site = createReportFromSettings(cs)
+ if self.args.view:
+ webbrowser.open(site)
else:
raise RuntimeError(
"No Settings with Blueprint or Database, cannot gerenate a report"
)
- with directoryChangers.ForcedCreationDirectoryChanger("reportsOutputFiles"):
- _ = pm.hook.getReportContents(
- r=r,
- cs=cs,
- report=report,
- stage=ReportStage.Begin,
- blueprint=blueprint,
- )
- site = report.writeReports()
- if self.args.view:
- webbrowser.open(site)
-
else:
+ report = reports.ReportContent("Overview")
+ pm = armi.getPluginManagerOrFail()
db = databaseFactory(self.args.h5db, "r")
if self.args.bp is not None:
blueprint = self.args.bp
@@ -119,18 +101,18 @@ def invoke(self):
cs = db.loadCS()
if self.args.bp is None:
blueprint = db.loadBlueprints()
- r = factory(cs, blueprint)
+ r = reactors.factory(cs, blueprint)
report.title = r.name
pluginContent = (
armi.getPluginManagerOrFail().hook.getReportContents(
r=r,
cs=cs,
report=report,
- stage=ReportStage.Begin,
+ stage=reports.ReportStage.Begin,
blueprint=blueprint,
)
)
- stage = ReportStage.Standard
+ stage = reports.ReportStage.Standard
for cycle, node in dbNodes:
if nodes is not None and (cycle, node) not in nodes:
continue
@@ -153,7 +135,7 @@ def invoke(self):
pluginContent = pm.hook.getReportContents(
r=r, cs=cs, report=report, stage=stage, blueprint=blueprint
)
- stage = ReportStage.End
+ stage = reports.ReportStage.End
pluginContent = pm.hook.getReportContents(
r=r, cs=cs, report=report, stage=stage, blueprint=blueprint
)
@@ -162,7 +144,35 @@ def invoke(self):
webbrowser.open(site)
-class ReportStage(Enum):
- Begin = auto()
- Standard = auto()
- End = auto()
+def createReportFromSettings(cs):
+ """
+ Create BEGINNING reports, given a settings file.
+
+ This will construct a reactor from the given settings and create BOL reports for
+ that reactor/settings.
+ """
+
+ # not sure if this is necessary, but need to investigate more to understand possible
+ # side-effects before removing. Probably better to get rid of all uses of
+ # getMasterCs(), then we can remove all setMasterCs() calls without worrying.
+ settings.setMasterCs(cs)
+
+ blueprint = blueprints.loadFromCs(cs)
+ r = reactors.factory(cs, blueprint)
+ report = reports.ReportContent("Overview")
+ pm = armi.getPluginManagerOrFail()
+ report.title = r.name
+
+ with directoryChangers.ForcedCreationDirectoryChanger(
+ "{}-reports".format(cs.caseTitle)
+ ):
+ _ = pm.hook.getReportContents(
+ r=r,
+ cs=cs,
+ report=report,
+ stage=reports.ReportStage.Begin,
+ blueprint=blueprint,
+ )
+ site = report.writeReports()
+
+ return site
diff --git a/armi/physics/neutronics/reports.py b/armi/physics/neutronics/reports.py
index b56c0af79..6de905274 100644
--- a/armi/physics/neutronics/reports.py
+++ b/armi/physics/neutronics/reports.py
@@ -1,8 +1,5 @@
from collections import defaultdict
-# parts of report for neutronics
-from armi.cli.reportsEntryPoint import ReportStage
-
from armi.bookkeeping import newReportUtils
from armi.bookkeeping import newReports
from armi.reactor.flags import Flags
@@ -22,10 +19,12 @@ def insertNeutronicsReport(r, cs, report, stage):
collecting contents for.
"""
- if stage == ReportStage.Begin:
+ if stage == newReports.ReportStage.Begin:
insertNeutronicsBOLContent(r, cs, report)
- elif stage == ReportStage.Standard or stage == ReportStage.End:
+ elif (
+ stage == newReports.ReportStage.Standard or stage == newReports.ReportStage.End
+ ):
neutronicsPlotting(r, report, cs)
diff --git a/armi/plugins.py b/armi/plugins.py
index ef6aa9fa4..3abbcf0ba 100644
--- a/armi/plugins.py
+++ b/armi/plugins.py
@@ -539,21 +539,27 @@ def mpiActionRequiresReset(cmd) -> bool:
@staticmethod
@HOOKSPEC
- def getReportContents(r, cs, report, stage, blueprint): # ReportContent
+ def getReportContents(r, cs, report, stage, blueprint) -> None:
"""
To generate a report.
+ For more information, see :doc:`/developer/reports`.
+
Parameters
----------
- r : a reactor
- cs : case settings
- report : current report object to add to
- blueprint : blueprint for a reactor (if None, only partial contents created)
- stage : begin/standard/or end (stage of the report for
- when inserting BOL vs. EOL content)
+ r : Reactor
+
+ cs : Settings
+
+ report : ReportContent
+ Report object to add contents to
- For more information, see the documentation at https://terrapower.github.io/armi/developer/reports.html
+ stage : ReportStage
+ begin/standard/or end (stage of the report for when inserting BOL vs. EOL
+ content)
+ blueprint : Blueprint, optional
+ for a reactor (if None, only partial contents created)
"""
diff --git a/armi/settings/caseSettings.py b/armi/settings/caseSettings.py
index 5938c0307..db88fac03 100644
--- a/armi/settings/caseSettings.py
+++ b/armi/settings/caseSettings.py
@@ -332,53 +332,6 @@ def writeToYamlStream(self, stream, style="short"):
writer.writeYaml(stream)
return writer
- def setSettingsReport(self):
- """Puts settings into the report manager"""
- from armi.bookkeeping import report
-
- report.setData("caseTitle", self.caseTitle, report.RUN_META)
- report.setData(
- "outputFileExtension", self["outputFileExtension"], report.RUN_META
- )
-
- report.setData(
- "Total Core Power", "%8.5E MWt" % (self["power"] / 1.0e6), report.RUN_META
- )
- if not self["cycleLengths"]:
- report.setData(
- "Cycle Length", "%8.5f days" % self["cycleLength"], report.RUN_META
- )
- report.setData(
- "BU Groups", str(self["buGroups"]), report.RUN_META
- ) # str to keep the list together in the report
-
- for key in [
- "nCycles",
- "burnSteps",
- "skipCycles",
- "cycleLength",
- "numProcessors",
- ]:
- report.setData(key, self[key], report.CASE_PARAMETERS)
-
- for key in self.environmentSettings:
- report.setData(key, self[key], report.RUN_META, [report.ENVIRONMENT])
-
- for key in ["genXS", "neutronicsKernel"]:
- report.setData(key, self[key], report.CASE_CONTROLS, [report.ENVIRONMENT])
-
- for key in ["boundaries", "neutronicsKernel", "neutronicsType", "fpModel"]:
- report.setData(key, self[key], report.RUN_META, [report.NEUTRONICS])
-
- for key in ["reloadDBName", "startCycle", "startNode"]:
- report.setData(key, self[key], report.SNAPSHOT)
-
- for key in ["power", "Tin", "Tout"]:
- report.setData(key, self[key], report.REACTOR_PARAMS)
-
- for key in ["buGroups"]:
- report.setData(key, self[key], report.BURNUP_GROUPS)
-
def updateEnvironmentSettingsFrom(self, otherCs):
r"""Updates the environment settings in this object based on some other cs
(from the GUI, most likely)