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