def run_fit(self):
    "\n        Perform a fit (as described in Paper I) to a set of prepared data.\n\n        Results are outputted as two dictionaries\n        results = {'comps':best_fit, (list of components)\n                   'med_and_spans':median and spans of model parameters,\n                   'memb_probs': membership probability array (the standard one)}\n        scores  = {'bic': the bic,\n                   'lnlike': log likelihood of that run,\n                   'lnpost': log posterior of that run}\n        "
    log_message('Beginning Chronostar run', symbol='_', surround=True)
    if self.fit_pars['store_burnin_chains']:
        log_message(msg='Storing burnin chains', symbol='-')
    if ((self.fit_pars['init_comps'] is None) and (self.fit_pars['init_memb_probs'] is None)):
        assert (self.ncomps == 1), 'If no initialisation set, can only accept ncomp==1'
        init_memb_probs = np.zeros((len(self.data_dict['means']), (self.ncomps + self.fit_pars['use_background'])))
        init_memb_probs[:, 0] = 1.0
    else:
        log_message(msg=('Initialising with init_comps or init_memb_probs with%i components' % self.ncomps), symbol='*', surround=True)
        pass
    log_message(msg='FITTING {} COMPONENT'.format(self.ncomps), symbol='*', surround=True)
    run_dir = (self.rdir + '{}/'.format(self.ncomps))
    prev_result = self.run_em_unless_loadable(run_dir)
    prev_score = self.calc_score(prev_result['comps'], prev_result['memb_probs'])
    self.ncomps += 1
    while (self.ncomps <= self.fit_pars['max_comp_count']):
        log_message(msg='FITTING {} COMPONENT'.format(self.ncomps), symbol='*', surround=True)
        all_results = []
        all_scores = []
        for (i, target_comp) in enumerate(prev_result['comps']):
            div_label = chr((ord('A') + i))
            run_dir = (self.rdir + '{}/{}/'.format(self.ncomps, div_label))
            log_message(msg='Subdividing stage {}'.format(div_label), symbol='+', surround=True)
            mkpath(run_dir)
            self.fit_pars['init_comps'] = self.build_init_comps(prev_result['comps'], split_comp_ix=i, prev_med_and_spans=prev_result['med_and_spans'], memb_probs=prev_result['memb_probs'])
            result = self.run_em_unless_loadable(run_dir)
            all_results.append(result)
            score = self.calc_score(result['comps'], result['memb_probs'])
            all_scores.append(score)
            logging.info('Decomposition {} finished with \nBIC: {}\nlnlike: {}\nlnpost: {}'.format(div_label, all_scores[(- 1)]['bic'], all_scores[(- 1)]['lnlike'], all_scores[(- 1)]['lnpost']))
        all_bics = [score['bic'] for score in all_scores]
        best_split_ix = np.nanargmin(all_bics)
        new_result = all_results[best_split_ix]
        new_score = all_scores[best_split_ix]
        self.iter_end_log(best_split_ix, prev_result=prev_result, new_result=new_result)
        self.log_score_comparison(new=new_score, prev=prev_score)
        if (new_score['bic'] < prev_score['bic']):
            prev_score = new_score
            prev_result = new_result
            self.ncomps += 1
            log_message(msg='Commencing {} component fit on {}{}'.format(self.ncomps, (self.ncomps - 1), chr((ord('A') + best_split_ix))), symbol='+')
        else:
            logging.info('... saving previous fit as best fit to data')
            self.Component.store_raw_components((self.rdir + self.final_comps_file), prev_result['comps'])
            np.save((self.rdir + self.final_med_and_spans_file), prev_result['med_and_spans'])
            np.save((self.rdir + self.final_memb_probs_file), prev_result['memb_probs'])
            np.save((self.rdir + 'final_likelihood_post_and_bic'), prev_score)
            tabcomps = self.Component.convert_components_array_into_astropy_table(prev_result['comps'])
            if self.fit_pars['overwrite_fits']:
                tabcomps.write(os.path.join(self.rdir, ('final_comps_%d.fits' % len(prev_result['comps']))), overwrite=self.fit_pars['overwrite_fits'])
            else:
                filename_comps_fits_random = os.path.join(self.rdir, ('final_comps_%d_%s.fits' % (len(prev_result['comps']), str(uuid.uuid4().hex))))
                tabcomps.write(filename_comps_fits_random, overwrite=self.fit_pars['overwrite_fits'])
            try:
                if self.fit_pars['overwrite_fits']:
                    tabletool.construct_an_astropy_table_with_gaia_ids_and_membership_probabilities(self.fit_pars['data_table'], prev_result['memb_probs'], prev_result['comps'], os.path.join(self.rdir, ('final_memberships_%d.fits' % len(prev_result['comps']))), get_background_overlaps=True, stellar_id_colname=self.fit_pars['stellar_id_colname'], overwrite_fits=self.fit_pars['overwrite_fits'])
                else:
                    filename_memb_probs_fits_random = os.path.join(self.rdir, ('final_memberships_%d_%s.fits' % (len(prev_result['comps']), str(uuid.uuid4().hex))))
                    tabletool.construct_an_astropy_table_with_gaia_ids_and_membership_probabilities(self.fit_pars['data_table'], prev_result['memb_probs'], prev_result['comps'], filename_memb_probs_fits_random, get_background_overlaps=True, stellar_id_colname=self.fit_pars['stellar_id_colname'], overwrite_fits=self.fit_pars['overwrite_fits'])
            except:
                logging.info("[WARNING] Couldn't print membership.fits file. Check column id.")
            self.log_final_log(prev_result, prev_score)
            break
        logging.info('Best fit:\n{}'.format([group.get_pars() for group in prev_result['comps']]))
    if (self.ncomps >= self.fit_pars['max_comp_count']):
        log_message(msg='REACHED MAX COMP LIMIT', symbol='+', surround=True)
    return (prev_result, prev_score)
Perform a fit (as described in Paper I) to a set of prepared data.

Results are outputted as two dictionaries
results = {'comps':best_fit, (list of components)
           'med_and_spans':median and spans of model parameters,
           'memb_probs': membership probability array (the standard one)}
scores  = {'bic': the bic,
           'lnlike': log likelihood of that run,
           'lnpost': log posterior of that run}
def run_fit(self):
    "\n        Perform a fit (as described in Paper I) to a set of prepared data.\n\n        Results are outputted as two dictionaries\n        results = {'comps':best_fit, (list of components)\n                   'med_and_spans':median and spans of model parameters,\n                   'memb_probs': membership probability array (the standard one)}\n        scores  = {'bic': the bic,\n                   'lnlike': log likelihood of that run,\n                   'lnpost': log posterior of that run}\n        "
    log_message('Beginning Chronostar run', symbol='_', surround=True)
    if self.fit_pars['store_burnin_chains']:
        log_message(msg='Storing burnin chains', symbol='-')
    if ((self.fit_pars['init_comps'] is None) and (self.fit_pars['init_memb_probs'] is None)):
        assert (self.ncomps == 1), 'If no initialisation set, can only accept ncomp==1'
        init_memb_probs = np.zeros((len(self.data_dict['means']), (self.ncomps + self.fit_pars['use_background'])))
        init_memb_probs[:, 0] = 1.0
    else:
        log_message(msg=('Initialising with init_comps or init_memb_probs with%i components' % self.ncomps), symbol='*', surround=True)
        pass
    log_message(msg='FITTING {} COMPONENT'.format(self.ncomps), symbol='*', surround=True)
    run_dir = (self.rdir + '{}/'.format(self.ncomps))
    prev_result = self.run_em_unless_loadable(run_dir)
    prev_score = self.calc_score(prev_result['comps'], prev_result['memb_probs'])
    self.ncomps += 1
    while (self.ncomps <= self.fit_pars['max_comp_count']):
        log_message(msg='FITTING {} COMPONENT'.format(self.ncomps), symbol='*', surround=True)
        all_results = []
        all_scores = []
        for (i, target_comp) in enumerate(prev_result['comps']):
            div_label = chr((ord('A') + i))
            run_dir = (self.rdir + '{}/{}/'.format(self.ncomps, div_label))
            log_message(msg='Subdividing stage {}'.format(div_label), symbol='+', surround=True)
            mkpath(run_dir)
            self.fit_pars['init_comps'] = self.build_init_comps(prev_result['comps'], split_comp_ix=i, prev_med_and_spans=prev_result['med_and_spans'], memb_probs=prev_result['memb_probs'])
            result = self.run_em_unless_loadable(run_dir)
            all_results.append(result)
            score = self.calc_score(result['comps'], result['memb_probs'])
            all_scores.append(score)
            logging.info('Decomposition {} finished with \nBIC: {}\nlnlike: {}\nlnpost: {}'.format(div_label, all_scores[(- 1)]['bic'], all_scores[(- 1)]['lnlike'], all_scores[(- 1)]['lnpost']))
        all_bics = [score['bic'] for score in all_scores]
        best_split_ix = np.nanargmin(all_bics)
        new_result = all_results[best_split_ix]
        new_score = all_scores[best_split_ix]
        self.iter_end_log(best_split_ix, prev_result=prev_result, new_result=new_result)
        self.log_score_comparison(new=new_score, prev=prev_score)
        if (new_score['bic'] < prev_score['bic']):
            prev_score = new_score
            prev_result = new_result
            self.ncomps += 1
            log_message(msg='Commencing {} component fit on {}{}'.format(self.ncomps, (self.ncomps - 1), chr((ord('A') + best_split_ix))), symbol='+')
        else:
            logging.info('... saving previous fit as best fit to data')
            self.Component.store_raw_components((self.rdir + self.final_comps_file), prev_result['comps'])
            np.save((self.rdir + self.final_med_and_spans_file), prev_result['med_and_spans'])
            np.save((self.rdir + self.final_memb_probs_file), prev_result['memb_probs'])
            np.save((self.rdir + 'final_likelihood_post_and_bic'), prev_score)
            tabcomps = self.Component.convert_components_array_into_astropy_table(prev_result['comps'])
            if self.fit_pars['overwrite_fits']:
                tabcomps.write(os.path.join(self.rdir, ('final_comps_%d.fits' % len(prev_result['comps']))), overwrite=self.fit_pars['overwrite_fits'])
            else:
                filename_comps_fits_random = os.path.join(self.rdir, ('final_comps_%d_%s.fits' % (len(prev_result['comps']), str(uuid.uuid4().hex))))
                tabcomps.write(filename_comps_fits_random, overwrite=self.fit_pars['overwrite_fits'])
            try:
                if self.fit_pars['overwrite_fits']:
                    tabletool.construct_an_astropy_table_with_gaia_ids_and_membership_probabilities(self.fit_pars['data_table'], prev_result['memb_probs'], prev_result['comps'], os.path.join(self.rdir, ('final_memberships_%d.fits' % len(prev_result['comps']))), get_background_overlaps=True, stellar_id_colname=self.fit_pars['stellar_id_colname'], overwrite_fits=self.fit_pars['overwrite_fits'])
                else:
                    filename_memb_probs_fits_random = os.path.join(self.rdir, ('final_memberships_%d_%s.fits' % (len(prev_result['comps']), str(uuid.uuid4().hex))))
                    tabletool.construct_an_astropy_table_with_gaia_ids_and_membership_probabilities(self.fit_pars['data_table'], prev_result['memb_probs'], prev_result['comps'], filename_memb_probs_fits_random, get_background_overlaps=True, stellar_id_colname=self.fit_pars['stellar_id_colname'], overwrite_fits=self.fit_pars['overwrite_fits'])
            except:
                logging.info("[WARNING] Couldn't print membership.fits file. Check column id.")
            self.log_final_log(prev_result, prev_score)
            break
        logging.info('Best fit:\n{}'.format([group.get_pars() for group in prev_result['comps']]))
    if (self.ncomps >= self.fit_pars['max_comp_count']):
        log_message(msg='REACHED MAX COMP LIMIT', symbol='+', surround=True)
    return (prev_result, prev_score)