Skip to content

Commit

Permalink
Adding tests and test crumbs for settings and bookkeeping (#1542)
Browse files Browse the repository at this point in the history
  • Loading branch information
john-science authored Dec 12, 2023
1 parent 1bc3b6f commit 2bbd300
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 24 deletions.
33 changes: 20 additions & 13 deletions armi/bookkeeping/db/database3.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,23 +201,14 @@ def open(self):
"Cannot open database with permission `{}`".format(self._permission)
)

# open the database, and write a bunch of metadata to it
runLog.info("Opening database file at {}".format(os.path.abspath(filePath)))
self.h5db = h5py.File(filePath, self._permission)
self.h5db.attrs["successfulCompletion"] = False
self.h5db.attrs["version"] = meta.__version__
self.h5db.attrs["databaseVersion"] = self.version
self.h5db.attrs["user"] = context.USER
self.h5db.attrs["python"] = sys.version
self.h5db.attrs["armiLocation"] = os.path.dirname(context.ROOT)
self.h5db.attrs["startTime"] = context.START_TIME
self.h5db.attrs["machines"] = numpy.array(context.MPI_NODENAMES).astype("S")
# store platform data
platform_data = uname()
self.h5db.attrs["platform"] = platform_data.system
self.h5db.attrs["hostname"] = platform_data.node
self.h5db.attrs["platformRelease"] = platform_data.release
self.h5db.attrs["platformVersion"] = platform_data.version
self.h5db.attrs["platformArch"] = platform_data.processor
self.writeSystemAttributes(self.h5db)

# store app and plugin data
app = getApp()
self.h5db.attrs["appName"] = app.name
Expand All @@ -228,9 +219,25 @@ def open(self):
]
ps = numpy.array([str(p[0]) + ":" + str(p[1]) for p in ps]).astype("S")
self.h5db.attrs["pluginPaths"] = ps
# store the commit hash of the local repo
self.h5db.attrs["localCommitHash"] = Database3.grabLocalCommitHash()

@staticmethod
def writeSystemAttributes(h5db):
"""Write system attributes to the database."""
h5db.attrs["user"] = context.USER
h5db.attrs["python"] = sys.version
h5db.attrs["armiLocation"] = os.path.dirname(context.ROOT)
h5db.attrs["startTime"] = context.START_TIME
h5db.attrs["machines"] = numpy.array(context.MPI_NODENAMES).astype("S")

# store platform data
platform_data = uname()
h5db.attrs["platform"] = platform_data.system
h5db.attrs["hostname"] = platform_data.node
h5db.attrs["platformRelease"] = platform_data.release
h5db.attrs["platformVersion"] = platform_data.version
h5db.attrs["platformArch"] = platform_data.processor

@staticmethod
def grabLocalCommitHash():
"""
Expand Down
48 changes: 42 additions & 6 deletions armi/bookkeeping/db/tests/test_databaseInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,41 @@ def setUp(self):
def tearDown(self):
self.td.__exit__(None, None, None)

def test_writeSystemAttributes(self):
"""Test the writeSystemAttributes method.
.. test:: Validate that we can directly write system attributes to a database file.
:id: T_ARMI_DB_QA0
:tests: R_ARMI_DB_QA
"""
with h5py.File("test_writeSystemAttributes.h5", "w") as h5:
Database3.writeSystemAttributes(h5)

with h5py.File("test_writeSystemAttributes.h5", "r") as h5:
self.assertIn("user", h5.attrs)
self.assertIn("python", h5.attrs)
self.assertIn("armiLocation", h5.attrs)
self.assertIn("startTime", h5.attrs)
self.assertIn("machines", h5.attrs)
self.assertIn("platform", h5.attrs)
self.assertIn("hostname", h5.attrs)
self.assertIn("platformRelease", h5.attrs)
self.assertIn("platformVersion", h5.attrs)
self.assertIn("platformArch", h5.attrs)

def test_metaData_endSuccessfully(self):
def goodMethod(cycle, node):
pass
"""Test databases have the correct metadata in them.
.. test:: Validate that databases have system attributes written to them during the usual workflow.
:id: T_ARMI_DB_QA1
:tests: R_ARMI_DB_QA
"""
# the power should start at zero
self.assertEqual(self.r.core.p.power, 0)

def goodMethod(cycle, node):
pass

self.o.interfaces.append(MockInterface(self.o.r, self.o.cs, goodMethod))
with self.o:
self.o.operate()
Expand All @@ -152,15 +180,23 @@ def goodMethod(cycle, node):
with h5py.File(self.o.cs.caseTitle + ".h5", "r") as h5:
self.assertTrue(h5.attrs["successfulCompletion"])
self.assertEqual(h5.attrs["version"], version)

self.assertIn("caseTitle", h5.attrs)
self.assertIn("geomFile", h5["inputs"])
self.assertIn("settings", h5["inputs"])
self.assertIn("blueprints", h5["inputs"])

# validate system attributes
self.assertIn("user", h5.attrs)
self.assertIn("python", h5.attrs)
self.assertIn("armiLocation", h5.attrs)
self.assertIn("startTime", h5.attrs)
self.assertIn("machines", h5.attrs)
self.assertIn("caseTitle", h5.attrs)
self.assertIn("geomFile", h5["inputs"])
self.assertIn("settings", h5["inputs"])
self.assertIn("blueprints", h5["inputs"])
self.assertIn("platform", h5.attrs)
self.assertIn("hostname", h5.attrs)
self.assertIn("platformRelease", h5.attrs)
self.assertIn("platformVersion", h5.attrs)
self.assertIn("platformArch", h5.attrs)

# after operating, the power will be greater than zero
self.assertGreater(self.r.core.p.power, 1e9)
Expand Down
5 changes: 4 additions & 1 deletion armi/bookkeeping/historyTracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,17 @@ class HistoryTrackerInterface(interfaces.Interface):
"""
Makes reports of the state that individual assemblies encounter.
.. impl:: This interface allows users to retrieve run data from somewhere other than the database.
:id: I_ARMI_HIST_TRACK
:implements: R_ARMI_HIST_TRACK
Attributes
----------
detailAssemblyNames : list
List of detail assembly names in the reactor
time : list
list of reactor time in years
"""

name = "history"
Expand Down
61 changes: 58 additions & 3 deletions armi/bookkeeping/tests/test_historyTracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ def test_calcMGFluence(self):
armi.bookeeping.db.hdf.hdfDB.readBlocksHistory requires
historical_values[historical_indices] to be cast as a list to read more than the
first energy group. This test shows that this behavior is preserved.
.. test:: Demonstrate that a parameter stored at differing time nodes can be recovered.
:id: T_ARMI_HIST_TRACK0
:tests: R_ARMI_HIST_TRACK
"""
o = self.o
b = o.r.core.childrenByLocator[o.r.core.spatialGrid[0, 0, 0]].getFirstBlock(
Expand All @@ -115,9 +119,8 @@ def test_calcMGFluence(self):
bVolume = b.getVolume()
bName = b.name

hti = o.getInterface("history")

# duration is None in this DB
hti = o.getInterface("history")
timesInYears = [duration or 1.0 for duration in hti.getTimeSteps()]
timeStepsToRead = [
utils.getCycleNodeFromCumulativeNode(i, self.o.cs)
Expand All @@ -128,7 +131,7 @@ def test_calcMGFluence(self):
mgFluence = None
for ts, years in enumerate(timesInYears):
cycle, node = utils.getCycleNodeFromCumulativeNode(ts, self.o.cs)
# b.p.mgFlux is vol integrated
# b.p.mgFlux is vol integrated
mgFlux = hti.getBlockHistoryVal(bName, "mgFlux", (cycle, node)) / bVolume
timeInSec = years * 365 * 24 * 3600
if mgFluence is None:
Expand All @@ -143,6 +146,58 @@ def test_calcMGFluence(self):
hti.unloadBlockHistoryVals()
self.assertIsNone(hti._preloadedBlockHistory)

def test_historyParameters(self):
"""Retrieve various paramaters from the history.
.. test:: Demonstrate that various parameters stored at differing time nodes can be recovered.
:id: T_ARMI_HIST_TRACK1
:tests: R_ARMI_HIST_TRACK
"""
o = self.o
b = o.r.core.childrenByLocator[o.r.core.spatialGrid[0, 0, 0]].getFirstBlock(
Flags.FUEL
)
b.getVolume()
bName = b.name

# duration is None in this DB
hti = o.getInterface("history")
timesInYears = [duration or 1.0 for duration in hti.getTimeSteps()]
timeStepsToRead = [
utils.getCycleNodeFromCumulativeNode(i, self.o.cs)
for i in range(len(timesInYears))
]
hti.preloadBlockHistoryVals([bName], ["power"], timeStepsToRead)

# read some parameters
params = {}
for param in ["height", "pdens", "power"]:
params[param] = []
for ts, years in enumerate(timesInYears):
cycle, node = utils.getCycleNodeFromCumulativeNode(ts, self.o.cs)

params[param].append(
hti.getBlockHistoryVal(bName, param, (cycle, node))
)

# verify the height parameter doesn't change over time
self.assertGreater(params["height"][0], 0)
self.assertEqual(params["height"][0], params["height"][1])

# verify the power parameter is retrievable from the history
self.assertEqual(o.cs["power"], 1000000000.0)
self.assertAlmostEqual(params["power"][0], 360, delta=0.1)
self.assertEqual(params["power"][0], params["power"][1])

# verify the power density parameter is retrievable from the history
self.assertAlmostEqual(params["pdens"][0], 0.0785, delta=0.001)
self.assertEqual(params["pdens"][0], params["pdens"][1])

# test that unloadBlockHistoryVals() is working
self.assertIsNotNone(hti._preloadedBlockHistory)
hti.unloadBlockHistoryVals()
self.assertIsNone(hti._preloadedBlockHistory)

def test_historyReport(self):
"""
Test generation of history report.
Expand Down
6 changes: 6 additions & 0 deletions armi/operators/tests/test_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,12 @@ def setUp(self):
self.detailedOperator = Operator(self.standaloneDetailedCS)

def test_getPowerFractions(self):
"""Test that the power fractions are calculated correctly.
.. test:: Test the powerFractions are retrieved correctly for multiple cycles.
:id: T_ARMI_SETTINGS_POWER1
:tests: R_ARMI_SETTINGS_POWER
"""
self.assertEqual(
self.detailedOperator.powerFractions, self.powerFractionsSolution
)
Expand Down
2 changes: 1 addition & 1 deletion armi/reactor/tests/test_reactors.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ def test_getSetParameters(self):
:tests: R_ARMI_PARAM_PART
.. test:: Ensure there is a setting for total core power.
:id: T_ARMI_SETTINGS_POWER
:id: T_ARMI_SETTINGS_POWER0
:tests: R_ARMI_SETTINGS_POWER
"""
# Test at reactor level
Expand Down
27 changes: 27 additions & 0 deletions armi/settings/tests/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,33 @@ def test_updateEnvironmentSettingsFrom(self):
self.cs.updateEnvironmentSettingsFrom(newEnv)
self.assertEqual(self.cs["verbosity"], "9")

def test_metaData(self):
"""Test we can get and set the important settings metadata.
.. test:: Test getting and setting import settings metadata.
:id: T_ARMI_SETTINGS_META
:tests: R_ARMI_SETTINGS_META
"""
# test get/set on caseTitle
self.assertEqual(self.cs.caseTitle, "armi")
testTitle = "test_metaData"
self.cs.caseTitle = testTitle
self.assertEqual(self.cs.caseTitle, testTitle)

# test get/set on comment
self.assertEqual(self.cs["comment"], "")
testComment = "Comment: test_metaData"
self.cs = self.cs.modified(newSettings={"comment": testComment})
self.assertEqual(self.cs["comment"], testComment)

# test get/set on version
self.assertEqual(len(self.cs["versions"]), 0)
self.cs = self.cs.modified(newSettings={"versions": {"something": 1.234}})

d = self.cs["versions"]
self.assertEqual(len(d), 1)
self.assertEqual(d["something"], 1.234)


class TestAddingOptions(unittest.TestCase):
def setUp(self):
Expand Down

0 comments on commit 2bbd300

Please sign in to comment.