def test_verify(self): """Verifies that the config.json file is created in the correct directory, then removes the created files.""" da = DataStore() dsa = DataStoreAnalyser(self.c, da, "concentration") bds = BatchDataStore() bds.add_run(self.c) bdsw = BatchResultsWriter( self.c, self.space, {self.c: dsa}, self.out_dir, "concentration" ) try: bdsw.write() except BatchDataStoreIDError as e: pass self.assertIn( "batch_run_summary.txt", os.listdir(f"{self.out_dir}") ) with open(os.path.join(self.this_dir, "st14/run/batch_run_summary.txt")) as f: txt = f.read() self.assertIn( "Computational space dimensions: 1 x", txt )
class TestBatchDataStore(unittest.TestCase): "Unit tests for the :class:`~.BatchDataStore` class." "" def setUp(self) -> None: """setUp method which instantiates the :class:`~.RIDTConfig` class, and the :class:`~.BatchDataStore` class.""" this_dir = os.path.dirname(os.path.abspath(__file__)) path = os.path.join(this_dir, "../../default/config.json") with open(path) as f: loaded_json = json.load(f) self.config = RIDTConfig(loaded_json) self.bds = BatchDataStore() def test_add_run(self): """Adds a run to the batch data store then checks to make sure the new items match the type of the ones added.""" self.bds.add_run(self.config) self.assertEqual(type(self.bds.store), dict) for key, val in self.bds.store.items(): self.assertEqual(type(key), RIDTConfig) self.assertEqual(type(val), DataStore)
def setUp(self) -> None: """setUp method which instantiates the :class:`~.RIDTConfig` class, and the :class:`~.BatchDataStore` class.""" this_dir = os.path.dirname(os.path.abspath(__file__)) path = os.path.join(this_dir, "../../default/config.json") with open(path) as f: loaded_json = json.load(f) self.config = RIDTConfig(loaded_json) self.bds = BatchDataStore()
def evaluate(self, data_store: Union[DataStore, BatchDataStore])\ -> Union[DataStore, BatchDataStore]: """Iterates over all geometries and computes exposures. Parameters ---------- data_store : Union[:class:`~.DataStore`, :class:`~.BatchDataStore`] The data store or batch data store to be analysed. Returns ------- Union[:class:`~.DataStore`, :class:`~.BatchDataStore`] The computed exposures. Raises ------ :obj:`TypeError` If the `data_store` is not a :class:`~.DataStore` or :class:`~.BatchDataStore`. """ if isinstance(data_store, DataStore): rv = DataStore() for geometry in self.geometries: for name, data in getattr(data_store, geometry).items(): rv.add(geometry, name, self.compute(data)) return rv elif isinstance(data_store, BatchDataStore): rv = BatchDataStore() for setting, store in data_store.items(): rv.add_run(setting) rv[setting] = self.evaluate(data_store[setting]) return rv else: raise TypeError(f"Expecting {DataStore} or {BatchDataStore}.")
def test_verify(self): """Verifies that the config.json file is created in the correct directory, then removes the created files.""" bds = BatchDataStore() for space in self.space.space: bds.add_run(space) try: BatchDataStoreWriter( self.c, bds, self.space, self.directory, "concentration") except BatchDataStoreIDError as e: pass self.assertIn( "batch_config.json", os.listdir(f"{self.directory}") )
def setUp(self) -> None: this_dir = os.path.dirname(os.path.abspath(__file__)) with ConfigFileParser(join(this_dir, "st23/config.json")) as cfp: self.c = cfp self.bds = BatchDataStore() self.domain = Domain(self.c) self.output_dir = join(this_dir, "st23/data") Path(self.output_dir).mkdir(parents=True, exist_ok=True) self.edr = EddyDiffusionRun(self.c, self.output_dir)
def __init__(self, settings: RIDTConfig, outdir: str): """The constructor for the :class:`EddyDiffusionRun` class. Parameters ---------- settings : :class:`~.RIDTConfig` The settings for the run in question. outdir : :obj:`str` The path to the output directory for the run. """ self.settings = settings self.outdir = outdir self.data_store = BatchDataStore() self.exposure_store = None self.space = self.prepare() self.evaluate() self.compute_exposure() self.write() self.plot() self.analyse()
class EddyDiffusionRun: """The class which orchestrates an Eddy Diffusion model run. Attributes ---------- setting : :class:`~.RIDTConfig` The settings for the run in question. data_store : :class:`~.BatchDataStore` The batch run data store for concentration values. outdir: :obj:`str` The path to the output directory for the run. space : :class:`~.ComputationalSpace` The :class:`~.ComputationalSpace` instance corresponding to the :attr:`settings` attribute. exposure_store : :obj:`Union`[:class:`~.BatchDataStore`, None] The batch run data store for exposure values. """ def __init__(self, settings: RIDTConfig, outdir: str): """The constructor for the :class:`EddyDiffusionRun` class. Parameters ---------- settings : :class:`~.RIDTConfig` The settings for the run in question. outdir : :obj:`str` The path to the output directory for the run. """ self.settings = settings self.outdir = outdir self.data_store = BatchDataStore() self.exposure_store = None self.space = self.prepare() self.evaluate() self.compute_exposure() self.write() self.plot() self.analyse() @property def geometries(self): """:obj:`list` [:obj:`str`] : the list of geometries selected for evaluation in :attr:`settings`. """ locations = self.settings.models.eddy_diffusion.monitor_locations return [g for g, e in locations.evaluate.items() if e] def prepare(self) -> ComputationalSpace: """Instantiates :class:`~.ComputationalSpace` instance. Generates a :class:`~.ComputationalSpace` instance from :attr:`settings`. Returns ------- :class:`~.ComputationalSpace` The Computational Space created from :attr:`settings`. """ print("Preparing Eddy Diffusion run...") restrict = {"models": "eddy_diffusion"} return ComputationalSpace(self.settings, restrict) def evaluate(self) -> None: """Loops over all elements in :attr:`space` and evaluates the model. Returns ------- None """ for setting in self.space.space: count = f"{self.space.linear_index(setting) + 1}/{len(self.space)}" print(f"Evaluating computational space element {count}") self.run(setting) def run(self, setting: RIDTConfig) -> None: """Evaluates the model for a set of parameters, for all geometries. Loops over all monitor locations that have been selected for evaluation and evaluates them over their respective domains. Writes output to :attr:`data_store`. Parameters ---------- settings : :class:`~.RIDTConfig` The settings for the run in question. Returns ------- None """ self.data_store.add_run(setting) domain = Domain(setting) solver = EddyDiffusion(setting) locations = setting.models.eddy_diffusion.monitor_locations for geometry in self.geometries: print(f"Evaluating {geometry} monitor locations...") for name, item in getattr(locations, geometry).items(): print(f"Evaluating {name}...") space = getattr(domain, geometry)(item) output = solver(*getattr(domain, geometry)(item), domain.time) self.data_store[setting].add(geometry, name, squeeze(output)) def compute_exposure(self) -> None: """Computes the exposure from the concentration data. Saves the result to a new data store :attr:`exposure_store` Returns ------- None """ if self.settings.compute_exposure: print("\nComputing exposure...") self.exposure_store = Exposure(self.settings, self.data_store) def args(self, data_store: BatchDataStore, quantity: str) -> tuple: """A helper function that returns a tuple of some values. Parameters ---------- data_store : :class:`~.BatchDataStore` A batch data store. quantity : :obj:`str` The name of the quantity in the data store. Returns ------- :obj:`tuple` The various quantites as a tuple. """ return self.settings, data_store, self.space, self.outdir, quantity def write(self) -> None: """Writes all data stores to disk. Returns ------- None """ print("\nWriting data to disk... ") BatchDataStoreWriter(*self.args(self.data_store, "concentration")) if self.settings.compute_exposure: BatchDataStoreWriter(*self.args(self.exposure_store, "exposure")) def plot(self) -> None: """Plots all requested data and writes it to disk. Returns ------- None """ print("\nProducing plots... ") BatchDataStorePlotter(*self.args(self.data_store, "concentration")) if self.settings.compute_exposure: BatchDataStorePlotter(*self.args(self.exposure_store, "exposure")) def analyse(self) -> None: """Performs all relevant analysis and writes it to disk. Returns ------- None """ if not self.settings.models.eddy_diffusion.analysis.perform_analysis: return print("\nPerforming data analysis...") BatchDataStoreAnalyser(*self.args(self.data_store, "concentration")) if self.settings.compute_exposure: BatchDataStoreAnalyser(*self.args(self.exposure_store, "exposure"))
class WellMixedRun: """The class which orchestrates an Well Mixed model run. Attributes ---------- setting : :class:`~.RIDTConfig` The settings for the run in question. data_store : :class:`~.BatchDataStore` The batch run data store for concentration values. outdir: :obj:`str` The path to the output directory for the run. space : :class:`~.ComputationalSpace` The :class:`~.ComputationalSpace` instance corresponding to the :attr:`settings` attribute. exposure_store : :obj:`Union`[:class:`~.BatchDataStore`, None] The batch run data store for exposure values. """ def __init__(self, settings: RIDTConfig, output_dir: str): """The constructor for the :class:`EddyDiffusion` class. Parameters ---------- settings : :class:`~.RIDTConfig` The settings for the run in question. outdir : :obj:`str` The path to the output directory for the run. """ self.settings = settings self.outdir = output_dir self.data_store = BatchDataStore() self.exposure_store = None self.space = self.prepare() self.evaluate() self.compute_exposure() self.write() self.plot() print("\n") def prepare(self) -> ComputationalSpace: """Instantiates :class:`~.ComputationalSpace` instance. Generates a :class:`~.ComputationalSpace` instance from :attr:`settings`. Returns ------- :class:`~.ComputationalSpace` The Computational Space created from :attr:`settings`. """ print("Preparing Well Mixed run... ") restrict = {"models": "well_mixed"} return ComputationalSpace(self.settings, restrict) def evaluate(self) -> None: """Loops over all elements in :attr:`space` and evaluates the model. Returns ------- None """ print("Evaluating model over domain... ") for setting in self.space.space: count = f"{self.space.linear_index(setting) + 1}/{len(self.space)}" print(f"Evaluating computational space element {count}") self.run(setting) def run(self, setting: RIDTConfig) -> None: """Evaluates the model for a set of parameters. Writes output to :attr:`data_store`. Parameters ---------- settings : :class:`~.RIDTConfig` The settings for the run in question. Returns ------- None """ self.data_store.add_run(setting) domain = Domain(setting) solver = WellMixed(setting) output = solver(domain.time) self.data_store[setting].add("points", "well_mixed", output) def compute_exposure(self): """Computes the exposure from the concentration data. Saves the result to a new data store :attr:`exposure_store` Returns ------- None """ if self.settings.compute_exposure: print("Computing exposure...") self.exposure_store = Exposure(self.settings, self.data_store) def args(self, data_store: BatchDataStore, quantity: str) -> tuple: """A helper function that returns a tuple of some values. Parameters ---------- data_store : :class:`~.BatchDataStore` A batch data store. quantity : :obj:`str` The name of the quantity in the data store. Returns ------- :obj:`tuple` The various quantities as a tuple. """ return self.settings, data_store, self.space, self.outdir, quantity def write(self) -> None: """Writes all data stores to disk. Returns ------- None """ print("\nWriting data to disk... ") BatchDataStoreWriter(*self.args(self.data_store, "concentration")) if self.settings.compute_exposure: BatchDataStoreWriter(*self.args(self.exposure_store, "exposure")) def plot(self) -> None: """Plots all requested data and writes it to disk. Returns ------- None """ print("\nProducing plots... ") BatchDataStorePlotter(*self.args(self.data_store, "concentration")) if self.settings.compute_exposure: BatchDataStorePlotter(*self.args(self.exposure_store, "exposure"))