Skip to content

Commit

Permalink
Add restart reproducibility test to checksum pytests
Browse files Browse the repository at this point in the history
  • Loading branch information
jo-basevi committed Mar 22, 2024
1 parent b973c06 commit 1fc583f
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 13 deletions.
29 changes: 27 additions & 2 deletions test/models/accessom2.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import f90nml
import re
from pathlib import Path
from typing import Dict, Any

from models.model import Model

Expand Down Expand Up @@ -36,13 +37,13 @@ def set_model_runtime(self,
nml['date_manager_nml']['restart_period'] = [years, months, seconds]
nml.write(self.accessom2_config, force=True)

def output_exists(self):
def output_exists(self) -> bool:
"""Check for existing output file"""
return self.output_file.exists()

def extract_checksums(self,
output_directory: Path = None,
schema_version: str = None):
schema_version: str = None) -> Dict[str, Any]:
"""Parse output file and create checksum using defined schema"""
if output_directory:
output_filename = output_directory / 'access-om2.out'
Expand Down Expand Up @@ -89,3 +90,27 @@ def extract_checksums(self,
f"Unsupported checksum schema version: {schema_version}")

return checksums

def check_checksums_over_restarts(self,
long_run_checksum: Dict[str, Any],
short_run_checksum_0: Dict[str, Any],
short_run_checksum_1: Dict[str, Any]
) -> bool:
"""Compare a checksums from a long run (e.g. 2 days) against
checksums from 2 short runs (e.g. 1 day)"""
short_run_checksums = short_run_checksum_0['output']
for field, checksums in short_run_checksum_1['output'].items():
if field not in short_run_checksums:
short_run_checksums[field] = checksums
else:
short_run_checksums[field].extend(checksums)

matching_checksums = True
for field, checksums in long_run_checksum['output'].items():
for checksum in checksums:
if (field not in short_run_checksums or
checksum not in short_run_checksums[field]):
print(f"Unequal checksum: {field}: {checksum}")
matching_checksums = False

return matching_checksums
13 changes: 12 additions & 1 deletion test/models/model.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
"""Generic Model class"""
from pathlib import Path
from typing import Dict, Any


class Model(object):
def __init__(self, experiment):
self.experiment = experiment

def extract_checksums(self, output_directory: Path = None):
def extract_checksums(self,
output_directory: Path,
schema_version: str):
"""Extract checksums from output directory"""
raise NotImplementedError

Expand All @@ -20,3 +23,11 @@ def set_model_runtime(self,
def output_exists(self):
"""Check for existing output files"""
raise NotImplementedError

def check_checksums_over_restarts(self,
long_run_checksum,
short_run_checksum_0,
short_run_checksum_1) -> bool:
"""Compare a checksums from a long run (e.g. 2 days) against
checksums from 2 short runs (e.g. 1 day)"""
raise NotImplementedError
18 changes: 8 additions & 10 deletions test/test_bit_reproducibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ def test_bit_repro_repeat(self, output_path: Path, control_path: Path):

assert produced == expected

@pytest.mark.slow
@pytest.mark.skip(reason="TODO:Check checksum comparision across restarts")
@pytest.mark.checksum
def test_restart_repro(self, output_path: Path, control_path: Path):
"""
Test that a run reproduces across restarts.
Expand Down Expand Up @@ -104,16 +103,15 @@ def test_restart_repro(self, output_path: Path, control_path: Path):
checksums_1d_0 = exp_2x1day.extract_checksums()
checksums_1d_1 = exp_2x1day.extract_checksums(exp_2x1day.output001)

# Adding checksums over two outputs might need to be model specific?
checksums_2x1d = checksums_1d_0['output'] + checksums_1d_1['output']

checksums_2d = exp_2day.extract_checksums()

matching_checksums = True
for item in checksums_2d['output']:
if item not in checksums_2x1d:
print("Unequal checksum:", item)
matching_checksums = False
# Use model specific comparision method for checksums
model = exp_2day.model
matching_checksums = model.check_checksums_over_restarts(
long_run_checksum=checksums_2d,
short_run_checksum_0=checksums_1d_0,
short_run_checksum_1=checksums_1d_1
)

if not matching_checksums:
# Write checksums out to file
Expand Down

0 comments on commit 1fc583f

Please sign in to comment.