Beispiel #1
0
 def _construct(self):
     # We create the database on the analysis path --- oooh! Clever.
     if not self.path.exists():
         self._create_path(self.path)
         if self.path != self.analysis_path:
             if not self.analysis_path.exists():
                 self._create_path(self.analysis_path)
     self.database = Database(self.analysis_path)
     self.database.create()
     self._init_db()
Beispiel #2
0
class Experiment(object):
    def __init__(self, path, treatments, name=None, seed=1, analysis_path=None, full=True):
        logtools.set_logging()

        if name is None:
            name = _make_name_from_program()

        self.path = _construct_path(path, name)
        if analysis_path:
            self.analysis_path = _construct_path(analysis_path, name)
        else:
            self.analysis_path = self.path

        self.next_treatment_seq = 0
        if full:
            self.lineage_class = FullLineage
        else:
            self.lineage_class = SnapshotLineage

        self.seed = seed
        self.rng = random.Random(seed)

        self.user_interrupt = False

        self.treatments = []
        for t in treatments:
            assert isinstance(t, Treatment)
            self.treatments.append(t)
            t._bind(self)

        self._construct()

    def _construct(self):
        # We create the database on the analysis path --- oooh! Clever.
        if not self.path.exists():
            self._create_path(self.path)
            if self.path != self.analysis_path:
                if not self.analysis_path.exists():
                    self._create_path(self.analysis_path)
        self.database = Database(self.analysis_path)
        self.database.create()
        self._init_db()

    def get_replicate(self, t_id, r_id):
        t_idx = t_id - 1
        r_idx = r_id - 1
        if t_id < 1 or t_id > len(self.treatments):
            raise ExperimentError("No treatment {}".format(str(t_id)))

        tr = self.treatments[t_idx]
        assert isinstance(tr, Treatment)
        assert tr.seq == t_id

        if r_id < 1 or r_id > len(tr.replicates):
            raise ExperimentError("No Replicate {}".format(str(r_id)))

        rep = tr.replicates[r_idx]
        assert isinstance(rep, Replicate)
        assert rep.seq == r_id

        return rep

    def get_next_treatment_seq(self):
        self.next_treatment_seq += 1
        return self.next_treatment_seq

    def _create_path(self, path):
        if not path.parent.exists():
            raise ExperimentError("No parent path: {}".format(str(path.parent)))

        log.info("Creating path {}".format(str(path)))
        path.mkdir(parents=True)

    def _remove_paths(self):
        if self.path.exists():
            _remove_folder(self.path)
        if self.path is not self.analysis_path:
            if self.analysis_path.exists():
                _remove_folder(self.analysis_path)
            self.analysis_path.mkdir(parents=True)

    def _init_db(self):
        # Use merge to allow for nice things to happen
        # TODO: We don't deal with the deletion of old records if the
        # replicate number are changed
        for t in self.treatments:
            self.database.session.merge(TreatmentRecord(t))
            for r in t.replicates:
                self.database.session.merge(ReplicateRecord(r))

        # TODO: we should really update the status of this stuff too?
        self.database.session.commit()

    def iter_lineages(self, readonly=False, skip_errors=True):
        for t in self.treatments:
            for r in t.replicates:
                with r.get_lineage(readonly=readonly) as lin:
                    yield r, lin

    def run(self, overwrite=False, verbose=False, dry=False,
            only_treatment=None, only_replicate=None):
        """Run the experiment."""
        if overwrite:
            self._remove_paths()
            self._construct()

        if dry:
            log.info("Dry run -- exiting without simulating")
            return

        # Now run
        log.info("Beginning experiment in {}".format(str(self.path)))
        for treat in self.treatments:
            if only_treatment is not None and treat != only_treatment:
                continue
            if not self.user_interrupt:
                treat.run(only_replicate)

        if self.user_interrupt:
            log.info("User interrupted --- quitting")

    def visit_lineages(self, visitor,
                       only_treatment=None,
                       only_replicate=None):

        for treat in self.treatments:
            if only_treatment is not None and treat != only_treatment:
                continue

            for rep in treat.replicates:
                if only_replicate is not None and rep != only_replicate:
                    continue

                with rep.get_lineage() as lin:
                    visitor.visit_lineage(rep, lin)

    def visit_generations(self, visitor, every=1, only=None,
                          only_treatment=None,
                          only_replicate=None):
        """Try and visit everything with the least amount of loading"""

        for treat in self.treatments:
            if only_treatment is not None and treat != only_treatment:
                continue

            for rep in treat.replicates:
                if only_replicate is not None and rep != only_replicate:
                    continue

                with rep.get_lineage() as lin:
                    visitor.visit_lineage(rep, lin)

                    if only is not None:
                        only = int(only)
                        if visitor.wants_generation(only):
                            pop = lin.get_generation(only)
                            visitor.visit_generation(only, pop)
                    else:
                        # Now iterate through the generations
                        gen_num = 0
                        while gen_num <= lin.generation:
                            # Check if the visitor wants this generation (as loading is
                            # expensive)
                            if visitor.wants_generation(gen_num):
                                pop = lin.get_generation(gen_num)
                                visitor.visit_generation(gen_num, pop)
                            gen_num += every

                    if hasattr(visitor, 'leave_lineage'):
                        visitor.leave_lineage(rep, lin)

    def find_matching(self, text, repnum):
        # Default to ALL
        matching_treatment = None
        matches = []

        if text == "":
            # If they've selected a replicate too, then we need a treatment.
            if repnum >= 1:
                if len(self.treatments) > 1:
                    raise ExperimentError("No treatment supplied and more than one is possible.")
                    # If they've supplied a replicate...
                else:
                    # Otherwise just match the only treament
                    matches.append(self.treatments[0])
            else:
                matches = [None]
        else:
            look = text.lower()
            len_look = len(text)
            for t in self.treatments:
                current = t.name.lower()
                if len_look <= len(current):
                    if look == current[:len_look]:
                        if len(current) == len_look:
                            matches = [t]
                            break
                        else:
                            matches.append(t)

            if not matches:
                raise ExperimentError("No match for {}.".format(text))

            if len(matches) > 1:
                raise Experiment("More than one match for {}.".format(text))

        # Ok. Grab the match. It may be None.
        matching_treatment = matches[0]

        if repnum >= 1:
            matching_replicate = matching_treatment.with_replicate_id(repnum)
        else:
            matching_replicate = None

        return matching_treatment, matching_replicate