Source code for compass.landice.tests.ensemble_generator.branch_ensemble
import os
import pickle
import sys
import numpy as np
from compass.landice.tests.ensemble_generator.branch_ensemble.branch_run import ( # noqa
BranchRun,
)
from compass.landice.tests.ensemble_generator.ensemble_manager import (
EnsembleManager,
)
from compass.testcase import TestCase
[docs]
class BranchEnsemble(TestCase):
"""
A test case for performing an ensemble of
simulations for uncertainty quantification studies.
"""
[docs]
def __init__(self, test_group):
"""
Create the test case
Parameters
----------
test_group : compass.landice.tests.ensemble_generator.EnsembleGenerator
The test group that this test case belongs to
"""
name = 'branch_ensemble'
super().__init__(test_group=test_group, name=name)
# We don't want to initialize all the individual runs
# So during init, we only add the run manager
self.add_step(EnsembleManager(test_case=self))
[docs]
def configure(self):
"""
Configure a parameter ensemble of MALI simulations.
Start by identifying the start and end run numbers to set up
from the config.
Next, read a pre-defined unit parameter vector that can be used
for assigning parameter values to each ensemble member.
The main work is using the unit parameter vector to set parameter
values for each parameter to be varied, over prescribed ranges.
Then create the ensemble member as a step in the test case by calling
the EnsembleMember constructor.
Finally, add this step to the test case's step_to_run. This normally
happens automatically if steps are added to the test case in the test
case constructor, but because we waited to add these steps until this
configure phase, we must explicitly add the steps to steps_to_run.
"""
config = self.config
section = config['branch_ensemble']
spinup_test_dir = section.get('spinup_test_dir')
branch_year = section.getint('branch_year')
# Determine start and end run numbers being requested
self.start_run = section.getint('start_run')
self.end_run = section.getint('end_run')
# Determine whether to only set up filtered runs
self.set_up_filtered_only = section.getboolean('set_up_filtered_only')
self.ensemble_pickle_file = section.get('ensemble_pickle_file')
if self.set_up_filtered_only:
with open(self.ensemble_pickle_file, 'rb') as f:
[param_info, qoi_info] = pickle.load(f)
filtered_runs = np.isfinite(qoi_info['VAF change']['values'])
else:
filtered_runs = np.ones((self.end_run + 1,))
for run_num in range(self.start_run, self.end_run + 1):
run_name = f'run{run_num:03}'
if (filtered_runs[run_num] and
os.path.isfile(os.path.join(spinup_test_dir, run_name,
f'rst.{branch_year}-01-01.nc'))):
if os.path.exists(os.path.join(self.work_dir, run_name)):
print(f"WARNING: {run_name} path already exists; "
"skipping. ")
else:
print(f"Adding {run_name}")
# use this run
self.add_step(BranchRun(test_case=self, run_num=run_num))
# Note: do not add to steps_to_run; ensemble_manager
# will handle submitting and running the runs
# Have compass run only run the run_manager but not any actual runs.
# This is because the individual runs will be submitted as jobs
# by the ensemble manager.
self.steps_to_run = ['ensemble_manager',]
# no run() method is needed
# no validate() method is needed