aegis_sim.recording.recordingmanager

Data recorder

Records data generated by the simulation.

When thinking about recording additional data, consider that there are three recording methods: I. Snapshots (record data from the population at a specific step) II. Flushes (collect data over time then flush) III. One-time records IV. Other: TE records

  1"""Data recorder
  2
  3Records data generated by the simulation.
  4
  5When thinking about recording additional data, consider that there are three recording methods:
  6    I. Snapshots (record data from the population at a specific step)
  7    II. Flushes (collect data over time then flush)
  8    III. One-time records
  9    IV. Other: TE records
 10"""
 11
 12import pathlib
 13import shutil
 14import logging
 15
 16from aegis_sim import variables
 17
 18from .terecorder import TERecorder
 19from .picklerecorder import PickleRecorder
 20from .popgenstatsrecorder import PopgenStatsRecorder
 21from .intervalrecorder import IntervalRecorder
 22from .flushrecorder import FlushRecorder
 23from .featherrecorder import FeatherRecorder
 24from .phenomaprecorder import PhenomapRecorder
 25from .summaryrecorder import SummaryRecorder
 26from .progressrecorder import ProgressRecorder
 27from .simpleprogressrecorder import SimpleProgressRecorder
 28from .popsizerecorder import PopsizeRecorder
 29from .resourcerecorder import ResourcesRecorder
 30from .ticker import Ticker
 31from .configrecorder import ConfigRecorder
 32from .envdriftmaprecorder import Envdriftmaprecorder
 33
 34# TODO write tests
 35
 36
 37class RecordingManager:
 38    """
 39    Container class for various recorders.
 40    Each recorder records a certain type of data.
 41    Most recorders record data as tables, except SummaryRecorder and PickleRecorder which record JSON files and pickles (a binary python format).
 42    Headers and indexes of all tabular files are explicitly recorded.
 43
 44    -----
 45    GUI
 46    AEGIS records a lot of different data.
 47    In brief, AEGIS records
 48    genomic data (population-level allele frequencies and individual-level binary sequences) and
 49    phenotypic data (observed population-level phenotypes and intrinsic individual-level phenotypes),
 50    as well as
 51    derived demographic data (life, death and birth tables),
 52    population genetic data (e.g. effective population size, theta), and
 53    survival analysis data (TE / time-event tables).
 54    Furthermore, it records metadata (e.g. simulation log, processed configuration files) and python pickle files.
 55
 56    Recorded data is distributed in multiple files.
 57    Almost all data are tabular, so each file is a table to which rows are appended as the simulation is running.
 58    The recording rates are frequencies at which rows are added; they are expressed in simulation steps.
 59    """
 60
 61    def init(self, custom_config_path, overwrite):
 62        self.odir = self.make_odir(custom_config_path=custom_config_path, overwrite=overwrite)
 63        # TODO make subfolders
 64
 65    def initialize_recorders(self, TICKER_RATE):
 66        self.terecorder = TERecorder(odir=self.odir)
 67        self.picklerecorder = PickleRecorder(odir=self.odir)
 68        self.popgenstatsrecorder = PopgenStatsRecorder(odir=self.odir)
 69        self.guirecorder = IntervalRecorder(odir=self.odir)
 70        self.flushrecorder = FlushRecorder(odir=self.odir)
 71        self.featherrecorder = FeatherRecorder(odir=self.odir)
 72        self.phenomaprecorder = PhenomapRecorder(odir=self.odir)
 73        self.summaryrecorder = SummaryRecorder(odir=self.odir)
 74        self.progressrecorder = ProgressRecorder(odir=self.odir)
 75        self.simpleprogressrecorder = SimpleProgressRecorder(odir=self.odir)
 76        self.ticker = Ticker(odir=self.odir, TICKER_RATE=TICKER_RATE)
 77        self.popsizerecorder = PopsizeRecorder(odir=self.odir)
 78        self.resourcerecorder = ResourcesRecorder(odir=self.odir)
 79        self.configrecorder = ConfigRecorder(odir=self.odir)
 80        self.envdriftmaprecorder = Envdriftmaprecorder(odir=self.odir)
 81
 82    #############
 83    # UTILITIES #
 84    #############
 85
 86    @staticmethod
 87    def make_odir(custom_config_path, overwrite) -> pathlib.Path:
 88        output_path = custom_config_path.parent / custom_config_path.stem  # remove .yml
 89        is_occupied = output_path.exists() and output_path.is_dir()
 90        if is_occupied:
 91            if overwrite:
 92                shutil.rmtree(output_path)
 93            else:
 94                raise Exception(f"{output_path} already exists. To overwrite, add flag --overwrite or -o.")
 95        return output_path
 96
 97    @staticmethod
 98    def make_subfolders(paths):
 99        # TODO relink paths that are now in classes
100        for path in paths:
101            path.mkdir(exist_ok=True, parents=True)
102
103    def is_extinct(self) -> bool:
104        if self.summaryrecorder.extinct:
105            logging.info(f"Population went extinct (at step {variables.steps}).")
106            return True
107        return False
class RecordingManager:
 38class RecordingManager:
 39    """
 40    Container class for various recorders.
 41    Each recorder records a certain type of data.
 42    Most recorders record data as tables, except SummaryRecorder and PickleRecorder which record JSON files and pickles (a binary python format).
 43    Headers and indexes of all tabular files are explicitly recorded.
 44
 45    -----
 46    GUI
 47    AEGIS records a lot of different data.
 48    In brief, AEGIS records
 49    genomic data (population-level allele frequencies and individual-level binary sequences) and
 50    phenotypic data (observed population-level phenotypes and intrinsic individual-level phenotypes),
 51    as well as
 52    derived demographic data (life, death and birth tables),
 53    population genetic data (e.g. effective population size, theta), and
 54    survival analysis data (TE / time-event tables).
 55    Furthermore, it records metadata (e.g. simulation log, processed configuration files) and python pickle files.
 56
 57    Recorded data is distributed in multiple files.
 58    Almost all data are tabular, so each file is a table to which rows are appended as the simulation is running.
 59    The recording rates are frequencies at which rows are added; they are expressed in simulation steps.
 60    """
 61
 62    def init(self, custom_config_path, overwrite):
 63        self.odir = self.make_odir(custom_config_path=custom_config_path, overwrite=overwrite)
 64        # TODO make subfolders
 65
 66    def initialize_recorders(self, TICKER_RATE):
 67        self.terecorder = TERecorder(odir=self.odir)
 68        self.picklerecorder = PickleRecorder(odir=self.odir)
 69        self.popgenstatsrecorder = PopgenStatsRecorder(odir=self.odir)
 70        self.guirecorder = IntervalRecorder(odir=self.odir)
 71        self.flushrecorder = FlushRecorder(odir=self.odir)
 72        self.featherrecorder = FeatherRecorder(odir=self.odir)
 73        self.phenomaprecorder = PhenomapRecorder(odir=self.odir)
 74        self.summaryrecorder = SummaryRecorder(odir=self.odir)
 75        self.progressrecorder = ProgressRecorder(odir=self.odir)
 76        self.simpleprogressrecorder = SimpleProgressRecorder(odir=self.odir)
 77        self.ticker = Ticker(odir=self.odir, TICKER_RATE=TICKER_RATE)
 78        self.popsizerecorder = PopsizeRecorder(odir=self.odir)
 79        self.resourcerecorder = ResourcesRecorder(odir=self.odir)
 80        self.configrecorder = ConfigRecorder(odir=self.odir)
 81        self.envdriftmaprecorder = Envdriftmaprecorder(odir=self.odir)
 82
 83    #############
 84    # UTILITIES #
 85    #############
 86
 87    @staticmethod
 88    def make_odir(custom_config_path, overwrite) -> pathlib.Path:
 89        output_path = custom_config_path.parent / custom_config_path.stem  # remove .yml
 90        is_occupied = output_path.exists() and output_path.is_dir()
 91        if is_occupied:
 92            if overwrite:
 93                shutil.rmtree(output_path)
 94            else:
 95                raise Exception(f"{output_path} already exists. To overwrite, add flag --overwrite or -o.")
 96        return output_path
 97
 98    @staticmethod
 99    def make_subfolders(paths):
100        # TODO relink paths that are now in classes
101        for path in paths:
102            path.mkdir(exist_ok=True, parents=True)
103
104    def is_extinct(self) -> bool:
105        if self.summaryrecorder.extinct:
106            logging.info(f"Population went extinct (at step {variables.steps}).")
107            return True
108        return False

Container class for various recorders. Each recorder records a certain type of data. Most recorders record data as tables, except SummaryRecorder and PickleRecorder which record JSON files and pickles (a binary python format). Headers and indexes of all tabular files are explicitly recorded.


GUI AEGIS records a lot of different data. In brief, AEGIS records genomic data (population-level allele frequencies and individual-level binary sequences) and phenotypic data (observed population-level phenotypes and intrinsic individual-level phenotypes), as well as derived demographic data (life, death and birth tables), population genetic data (e.g. effective population size, theta), and survival analysis data (TE / time-event tables). Furthermore, it records metadata (e.g. simulation log, processed configuration files) and python pickle files.

Recorded data is distributed in multiple files. Almost all data are tabular, so each file is a table to which rows are appended as the simulation is running. The recording rates are frequencies at which rows are added; they are expressed in simulation steps.

def init(self, custom_config_path, overwrite):
62    def init(self, custom_config_path, overwrite):
63        self.odir = self.make_odir(custom_config_path=custom_config_path, overwrite=overwrite)
64        # TODO make subfolders
def initialize_recorders(self, TICKER_RATE):
66    def initialize_recorders(self, TICKER_RATE):
67        self.terecorder = TERecorder(odir=self.odir)
68        self.picklerecorder = PickleRecorder(odir=self.odir)
69        self.popgenstatsrecorder = PopgenStatsRecorder(odir=self.odir)
70        self.guirecorder = IntervalRecorder(odir=self.odir)
71        self.flushrecorder = FlushRecorder(odir=self.odir)
72        self.featherrecorder = FeatherRecorder(odir=self.odir)
73        self.phenomaprecorder = PhenomapRecorder(odir=self.odir)
74        self.summaryrecorder = SummaryRecorder(odir=self.odir)
75        self.progressrecorder = ProgressRecorder(odir=self.odir)
76        self.simpleprogressrecorder = SimpleProgressRecorder(odir=self.odir)
77        self.ticker = Ticker(odir=self.odir, TICKER_RATE=TICKER_RATE)
78        self.popsizerecorder = PopsizeRecorder(odir=self.odir)
79        self.resourcerecorder = ResourcesRecorder(odir=self.odir)
80        self.configrecorder = ConfigRecorder(odir=self.odir)
81        self.envdriftmaprecorder = Envdriftmaprecorder(odir=self.odir)
@staticmethod
def make_odir(custom_config_path, overwrite) -> pathlib.Path:
87    @staticmethod
88    def make_odir(custom_config_path, overwrite) -> pathlib.Path:
89        output_path = custom_config_path.parent / custom_config_path.stem  # remove .yml
90        is_occupied = output_path.exists() and output_path.is_dir()
91        if is_occupied:
92            if overwrite:
93                shutil.rmtree(output_path)
94            else:
95                raise Exception(f"{output_path} already exists. To overwrite, add flag --overwrite or -o.")
96        return output_path
@staticmethod
def make_subfolders(paths):
 98    @staticmethod
 99    def make_subfolders(paths):
100        # TODO relink paths that are now in classes
101        for path in paths:
102            path.mkdir(exist_ok=True, parents=True)
def is_extinct(self) -> bool:
104    def is_extinct(self) -> bool:
105        if self.summaryrecorder.extinct:
106            logging.info(f"Population went extinct (at step {variables.steps}).")
107            return True
108        return False