def __init__(self,  paramtree=None, measuretree=None,
                 paramfile=PARAMFILE, measurefile=MEASUREFILE,
                 initial_plug='random', reduce_p=True,
                 verbose=False):

        """
        Metaphase instanciation method


        :param duration: The duration of the mitosis in seconds (defaults to 900)
        :type duration: float

        :param paramtree: The paramtree contains the parameters for the simulation
            if paramtree is None, the parameters are read
            from the file paramfile. Defaults to None.
        :type paramtree: ParamTree instance or None

        :param measuretree: The measuretree contains the observed characteristics
            of the mitosis e.g. metaphase spindle elongation rate, etc.
            if measuretree is None, the measures are read from the file
            indicated by the measurefile argument. Defaults to None.
        :type measuretree: ParamTree instance or None

        :param paramfile: Path to a xml file to read the parameters from. Defaults to the
            file params.xml in the module's default directory. Other parameter
            files can be produced by editing and changing the default one.
            If the paramtree argument is not None,  paramfile is ignored
        :type paramfile: string

        :param measurefile: Path to a xml file to read the measures from. Defaults to the
            file measures.xml in the module's default directory.
            Other measure files can be produced by editing and changing
            the default one. If the measuretree argument is not None, measurefile
            is ignored
        :type measurefile: string

        :param initial_plug: Defines globally the initial attachment states.
            This argument can have the following values:
                * 'null': all kinetochores are detached
                * 'amphitelic': all chromosmes are amphitelic
                * 'random': all attachement site can be bound to
                        either pole or deteched with equal prob.
                * 'monotelic': right kinetochores are attached to the same pole,
                           left ones are detached
                * 'syntelic' : all kinetochores are attached to the same pole
        :type initial_plug: string or None

        :param reduce_p: If True, changes the parameters according to the measures
            so that the simulation average behaviour complies with
            the data in the measures dictionary
        :type reduce_p: bool

        """

        # Enable or disable log console
        self.verbose = verbose
        logger = logging.getLogger(__name__)
        if not self.verbose:
            logger.disabled = True
        else:
            logger.disabled = False

        if paramtree is None:
            self.paramtree = ParamTree(paramfile)
        else:
            self.paramtree = paramtree
        if measuretree is None:
            self.measuretree = ParamTree(measurefile, adimentionalized=False)
        else:
            self.measuretree = measuretree

        if reduce_p:
            parameters.reduce_params(self.paramtree, self.measuretree)

        logger.info('Parameters loaded')

        params = self.paramtree.relative_dic
        # Reset explicitely the unit parameters to their
        # dimentionalized value
        params['Vk'] = self.paramtree.absolute_dic['Vk']
        params['Fk'] = self.paramtree.absolute_dic['Fk']
        params['dt'] = self.paramtree.absolute_dic['dt']

        self.KD = KinetoDynamics(params, initial_plug=initial_plug)
        dt = self.paramtree.absolute_dic['dt']
        duration = self.paramtree.absolute_dic['span']
        self.num_steps = int(duration / dt)
        self.KD.anaphase = False
        self.timelapse = np.arange(0, duration, dt)
        self.report = []
        self.delay = -1
        self.observations = {}

        logger.info('Simulation initialized')
        logger.disabled = False
class Metaphase(object):
    """
    An instance of the Metaphase class is a wrapper around
    the whole simulation.

    **Typical usage**

    >>> from kt_simul.simul_spindle import Metaphase
    >>> m = Metaphase()
    >>> m.simul()
    >>> m.show_trajs()
    >>> m.write_results('examples/docstring_results.xml',
                        'examples/docstring_data.npy')

    **From an already runned simulation**

    >>> from kt_simul.simul_spindle import Metaphase
    >>> m1 = get_fromfile('examples/docstring_results.xml')
    >>> m1.show_one(1) #This shows the trajactory of the chromosome 1
    >>> m2 = Metaphase(m1.paramtree, m1.measuretree) #A new simulation
    >>> m2.simul(ablat = 600) #this time with spindle ablation

    """

    def __init__(self,  paramtree=None, measuretree=None,
                 paramfile=PARAMFILE, measurefile=MEASUREFILE,
                 initial_plug='random', reduce_p=True,
                 verbose=False):

        """
        Metaphase instanciation method


        :param duration: The duration of the mitosis in seconds (defaults to 900)
        :type duration: float

        :param paramtree: The paramtree contains the parameters for the simulation
            if paramtree is None, the parameters are read
            from the file paramfile. Defaults to None.
        :type paramtree: ParamTree instance or None

        :param measuretree: The measuretree contains the observed characteristics
            of the mitosis e.g. metaphase spindle elongation rate, etc.
            if measuretree is None, the measures are read from the file
            indicated by the measurefile argument. Defaults to None.
        :type measuretree: ParamTree instance or None

        :param paramfile: Path to a xml file to read the parameters from. Defaults to the
            file params.xml in the module's default directory. Other parameter
            files can be produced by editing and changing the default one.
            If the paramtree argument is not None,  paramfile is ignored
        :type paramfile: string

        :param measurefile: Path to a xml file to read the measures from. Defaults to the
            file measures.xml in the module's default directory.
            Other measure files can be produced by editing and changing
            the default one. If the measuretree argument is not None, measurefile
            is ignored
        :type measurefile: string

        :param initial_plug: Defines globally the initial attachment states.
            This argument can have the following values:
                * 'null': all kinetochores are detached
                * 'amphitelic': all chromosmes are amphitelic
                * 'random': all attachement site can be bound to
                        either pole or deteched with equal prob.
                * 'monotelic': right kinetochores are attached to the same pole,
                           left ones are detached
                * 'syntelic' : all kinetochores are attached to the same pole
        :type initial_plug: string or None

        :param reduce_p: If True, changes the parameters according to the measures
            so that the simulation average behaviour complies with
            the data in the measures dictionary
        :type reduce_p: bool

        """

        # Enable or disable log console
        self.verbose = verbose
        logger = logging.getLogger(__name__)
        if not self.verbose:
            logger.disabled = True
        else:
            logger.disabled = False

        if paramtree is None:
            self.paramtree = ParamTree(paramfile)
        else:
            self.paramtree = paramtree
        if measuretree is None:
            self.measuretree = ParamTree(measurefile, adimentionalized=False)
        else:
            self.measuretree = measuretree

        if reduce_p:
            parameters.reduce_params(self.paramtree, self.measuretree)

        logger.info('Parameters loaded')

        params = self.paramtree.relative_dic
        # Reset explicitely the unit parameters to their
        # dimentionalized value
        params['Vk'] = self.paramtree.absolute_dic['Vk']
        params['Fk'] = self.paramtree.absolute_dic['Fk']
        params['dt'] = self.paramtree.absolute_dic['dt']

        self.KD = KinetoDynamics(params, initial_plug=initial_plug)
        dt = self.paramtree.absolute_dic['dt']
        duration = self.paramtree.absolute_dic['span']
        self.num_steps = int(duration / dt)
        self.KD.anaphase = False
        self.timelapse = np.arange(0, duration, dt)
        self.report = []
        self.delay = -1
        self.observations = {}

        logger.info('Simulation initialized')
        logger.disabled = False

    def __str__(self):
        lines = []
        lines.append('Metaphase class')
        try:
            lines.append('Parameters:')
            for line in str(self.paramtree.relative_dic).split(','):
                lines.append(line)
        except AttributeError:
            pass
        try:
            lines.append('Measures:')
            for line in str(self.measuretree.absolute_dic).split(','):
                lines.append(line)
        except AttributeError:
            pass
        lines.append('')
        lines.append('Observations:')
        if len(self.observations.keys()) > 0:
            for line in str(self.observations).split(','):
                lines.append(line)
        else:
            lines.append('Not yet evaluated')
        return '\n'.join(lines)

    def simul(self, ablat=None, ablat_pos=0.):
        """
        The simulation main loop.

        :param ablat: Timepoint at which ablation takes place. If None (default)
            no ablation is performed.
        :type ablat: float, optional

        """

        # Check is simulation has already be done
        if self.KD.simulation_done:
            raise SimulationAlreadyDone("""A simulation is already done on this
instance. Please create another Metaphase instance to launch a new simulation.""")

        kappa_c = self.KD.params['kappa_c']

        if self.verbose:
            logger.info('Running simulation')
        bef = 0
        log_anaphase_onset = False

        for time_point in range(1, self.num_steps):

            progress = int((time_point * 100.0) / self.num_steps)

            if self.verbose and progress != bef:
                print_progress(int(progress))
                bef = progress

            # Ablation test
            if ablat == time_point:
                if self.verbose:
                    logger.info("Performing ablation")
                self._ablation(time_point, pos=ablat_pos)

            # Anaphase transition ?
            if self._anaphase_test(time_point):
                if not log_anaphase_onset:
                    print_progress(-1)
                    if self.verbose:
                        logger.info("Anaphase onset at %i / %i" %
                                        (time_point, self.num_steps))
                    log_anaphase_onset = True

            self.KD.one_step(time_point)
            # if time_point % 100 == 0:
                # print self.KD.At_mat

        if self.verbose:
            print_progress(-1)

        if self.verbose:
            logger.info('Simulation done')
        self.KD.params['kappa_c'] = kappa_c
        delay_str = "delay = %2d seconds" % self.delay
        self.report.append(delay_str)

        for ch in self.KD.chromosomes:
            ch.calc_correct_history()
            ch.calc_erroneous_history()
            ch.cen_A.calc_toa()
            ch.cen_B.calc_toa()

    def evaluate(self, name=None, groups=[],
                 debug=False,
                 verbose=False,
                 draw=False,
                 run_all=False):
        """
        Passes all the evaluations in kt_simul.analysis.valuations module
        results are stored in the self.observations dictionnary

        TODO: most of the code of this method should be moved to
        kt_simul.analysis.evaluations.__init__
        """
        if not self.KD.simulation_done:
            logger.info("No simulation was runned")
            return False

        if not name and verbose:
            logger.info("Starting evaluations")
        all_evaluations = evaluations.find_evaluations(name=name, groups=groups, run_all=run_all)

        if not all_evaluations:
            if verbose:
                logger.info("No evaluations found")
            return False

        for evaluation in all_evaluations:
            if verbose:
                logger.info("Running %s" % evaluation.name)
            if debug:
                result = evaluation().run(self.KD, draw)
                if verbose:
                    logger.info("%s done" % evaluation.name)
            else:
                try:
                    result = evaluation().run(self.KD, draw)
                    if verbose:
                        logger.info("%s done" % evaluation.name)
                except Exception as e:
                    result = np.nan
                    if verbose:
                        logger.info("%s returns errors : %s" % (evaluation.name, e))

            if name and not run_all:
                return result
            else:
                current_name = evaluation.name.replace(" ", "_")
                self.observations[current_name] = result

        if verbose:
            logger.info("All evaluations processed")

        return self.observations

    def get_report(self, time = 0):
        """
        Print simulation state about a specific time point
        """
        params = self.paramtree.relative_dic

        report = collections.OrderedDict()

        report["Total time (span)"] = params["span"]
        report["Time precision (dt)"] = params["dt"]
        report["Chromosomes (N)"] = params["N"]
        report["Kinetochores (Mk)"] = params["Mk"]
        report["separate"] = ""

        report["Current time"] = "%i\n" % ((time + 1) * float(params["dt"]))

        report["separate"] = ""
        report["spbR pos"] = round(self.KD.spbR.traj[time], 3)
        report["spbL pos"] = round(self.KD.spbL.traj[time], 3)
        report["separate"] = ""

        for ch in self.KD.chromosomes:
            chdict = collections.OrderedDict()
            chdict["correct"] = ch.correct_history[time]
            chdict["erroneous"] = ch.erroneous_history[time]
            for cent in [ch.cen_A, ch.cen_B]:
                cen_dict = collections.OrderedDict()
                cen_dict["position"] = round(cent.traj[time], 3)
                for site in cent.plugsites:
                    site_dict = collections.OrderedDict()
                    site_dict['position'] = round(site.traj[time], 3)
                    site_dict['Plug state'] = site.state_hist[time]

                    cen_dict["PlugSite %i" % site.site_id] = site_dict

                chdict["Centromere %s" % cent.tag] = cen_dict

            report["Chromosome %i" % ch.ch_id] = chdict
            report["separate"] = ""

        return pretty_dict(report)

    def _anaphase_test(self, time_point):
        """
        Returns True if anaphase has been executed.
        At anaphase onset, set the cohesin spring constent to 0 and
        self.KD.anaphase to True.
        """

        t_A = int(self.KD.params['t_A'])
        dt = self.KD.params['dt']
        t = time_point * dt
        if self.KD.anaphase :
            return True
        if t >= t_A and self._plug_checkpoint():
            if self.delay == -1 :
                self.delay = t - t_A
                #Then we just get rid of cohesin
                self.KD.params['kappa_c'] = 0.
                self.KD.calc_B()
                nb_mero = self._mero_checkpoint()
                if nb_mero:
                    s = ("There were %d merotelic MT at anaphase onset"
                         % nb_mero)
                    self.report.append(s)
                self.KD.anaphase = True
                return True
        return False

    def _ablation(self, time_point, pos = None):
        """
        Simulates a laser ablation: detaches all the kinetochores
        and sets the midzone stall force Fmz to 0

        :param pos: Position of the laser beam within the spindle
        :type pos: float or None, optional

        """
        if pos == None: pos = self.KD.spbR.pos
        if not self.KD.spbL.pos <= pos <= self.KD.spbR.pos:
            logger.warning('Missed shot, same player play again!')
            return
        self.KD.params['Fmz'] = 0.
        self.KD.params['k_a'] = 0.
        self.KD.params['k_d0'] = 0.
        self.KD.A0_mat = self.KD.time_invariantA()

        for plugsite in self.KD.spindle.all_plugsites:
            if pos < plugsite.pos and plugsite.plug_state == - 1:
                plugsite.set_plug_state(0, time_point)
            elif pos > plugsite.pos and plugsite.plug_state == 1:
                plugsite.set_plug_state(0, time_point)

    def _plug_checkpoint(self):
        """
        If the spindle assembly checkpoint is active, returns True
        if all chromosomes are plugged by at least one kMT, False
        otherwise.
        """
        sac = self.KD.params['sac']
        if sac == 0:
            return True
        for ch in self.KD.chromosomes :
            if not ch.cen_A.is_attached() or not ch.cen_B.is_attached():
                return False
        return True

    def _mero_checkpoint(self):
        """
        :return: The total number of merotellic kT
        """
        nb_mero = 0
        for ch in self.KD.chromosomes :
            if np.any(ch.erroneous()) :
                nb_mero += sum(ch.erroneous())
                #print "active checkpoint"
        return nb_mero

    def _mplate_checkpoint(self):
        """
        :return: Returns True if each kinetochore is in the proper half
        of the spindle
        """
        for ch in self.KD.chromosomes:
            ktR = ch.cen_A.pos
            ktL = ch.cen_B.pos
            if min(ktR, ktL) <= 0 and max(ktR, ktL) >= 0:
                return True
        return True