# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from armi import runLog
from armi.cli.entryPoint import EntryPoint
# Params that are well-known to vary from run to run. In the future we should probably
# derive this from a parameter category so that it is extensible
DEFAULT_EXCLUSIONS = (
"^.*/minutesSinceStart$",
"^.*/maxProcessMemoryInMB$",
"^.*/minProcessMemoryInMB$",
)
# Parameters that under normal circumstances would be the same, but may not be
# faithfully represented by an old database format.
CONVERTED_EXCLUSIONS = DEFAULT_EXCLUSIONS + (
"^.*/serialNum$",
"^.*/temperatureInC$",
"^.*/volume$",
"^.*/layout/temperatures$",
)
[docs]class CompareCases(EntryPoint):
"""Compare the databases from two ARMI cases."""
name = "compare"
def _addComparisonOptions(self):
parser = self.parser
parser.add_argument(
"--tolerance",
default=0.01,
action="store",
type=float,
help=(
"If a test database entry differs by more than this percent "
"from the reference database, then it will be marked "
"as a difference between the two databases."
),
)
parser.add_argument(
"--weights",
nargs="*",
action="store",
help="Period separated key/value pairs for database table weights",
)
parser.add_argument(
"--exclude",
default=CONVERTED_EXCLUSIONS,
action="store",
nargs="+",
help=("Patterns for parameters to ignore in comparisons"),
)
parser.add_argument(
"--timestepCompare",
default=None,
action="store",
nargs="+",
help=(
"List of timesteps to compare. Note that any timestep not listed will "
"not be compared. Format the cycle and node separated by a period. E.g. "
"0.0 0.1 1.2 3.3 will compare c0n0, c0n1, c1n2, c3n3 and skip all others"
),
)
[docs] def addOptions(self):
self._addComparisonOptions()
parser = self.parser
parser.add_argument(
"refDB",
type=str,
help="The database to be used as the reference, baseline case.",
)
parser.add_argument(
"cmpDB",
type=str,
help="The database to be used as the comparison, evaluated case.",
)
parser.add_argument(
"--output", "-o", type=str, default="", help="Output file name."
)
[docs] def parse(self, args):
EntryPoint.parse(self, args)
if self.args.timestepCompare:
self.args.timestepCompare = list(
tuple(map(int, step.split("."))) for step in self.args.timestepCompare
)
if self.args.weights:
self.args.weights = dict(w.split(".") for w in self.args.weights)
[docs] def invoke(self):
from armi.bookkeeping.db import compareDatabases
diffs = compareDatabases(
self.args.refDB,
self.args.cmpDB,
tolerance=self.args.tolerance,
exclusions=self.args.exclude,
timestepCompare=self.args.timestepCompare,
)
return diffs.nDiffs()
[docs]class CompareSuites(CompareCases):
"""Do a case-by-case comparison between two CaseSuites."""
name = "compare-suites"
[docs] def addOptions(self):
self._addComparisonOptions()
self.parser.add_argument(
"reference",
type=str,
help="The root directory of the reference, or baseline, suite.",
)
self.parser.add_argument(
"comparison",
type=str,
help="The root directory of the comparison, or evaluated, suite.",
)
self.parser.add_argument(
"--patterns",
"-p",
nargs="*",
type=str,
default=["*.yaml"],
help="Pattern to use while searching for ARMI settings files.",
)
self.parser.add_argument(
"--additional_comparisons",
nargs="*",
type=str,
default=[],
help="Pattern tests that were not run but should appear in table.",
)
self.parser.add_argument(
"--ignore",
"-i",
nargs="*",
type=str,
default=[],
help="Pattern to search for inputs to ignore.",
)
[docs] def invoke(self):
from armi import cases
if not os.path.exists(self.args.reference):
runLog.error(
"Could not find reference directory {}".format(self.args.reference)
)
sys.exit(1)
if not os.path.exists(self.args.comparison):
runLog.error(
"Could not find comparison directory {}".format(self.args.comparison)
)
sys.exit(1)
refSuite = cases.CaseSuite(self.cs)
# contains all tests that user had access to
allTests = []
for pat in self.args.patterns + self.args.additional_comparisons:
allTests.append(pat)
refSuite.discover(
rootDir=self.args.reference,
patterns=allTests,
ignorePatterns=self.args.ignore,
)
cmpSuite = cases.CaseSuite(self.cs)
cmpSuite.discover(
rootDir=self.args.comparison,
patterns=self.args.patterns,
ignorePatterns=self.args.ignore,
)
nIssues = refSuite.compare(
cmpSuite,
weights=self.args.weights,
tolerance=self.args.tolerance,
exclusion=self.args.exclude,
timestepCompare=self.args.timestepCompare,
)
if nIssues > 0:
sys.exit(nIssues)