# @auto-fold regex /^\s*if/ /^\s*else/ /^\s*def/
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# version 0.7.1
# date 17 jan 2023

__version__ = '0.7.1'
__name__ = 'astroemperor'

# my coding convention
# **EVAL : evaluate the performance of this method
# **RED  : redo this
# **DEB  : debugging needed in this part
# **DEL  : DELETE AT SOME POINT
# **FIN  : Finish this

# sourcery skip: remove-redundant-if
if True:
    import numpy as np
    import pandas as pd
    
    import os
    import pickle

    import itertools

    from tabulate import tabulate
    from termcolor import colored
    from tqdm import tqdm


    from .utils import *
    from .canvas import *
    from .block import ReddModel
    from .block_repo import *

    try:
        terminal_width = os.get_terminal_size().columns
    except:
        print('I couldnt grab the terminal size! Trying with pandas...')
        terminal_width = pd.get_option('display.width')

stat_names_ = ['chi2', 'chi2_red', 'AIC', 'BIC',
               'DIC', 'HQIC', 'RMSE', 'post_max',
               'like_max', 'BayesFactor']




class ModelSelectionObj:
    def __init__(self, crit):
        self._current_criteria = crit
        self._tolerance = 5
        self.compare_f = self.foobarmin
        self.dict = {'chi2':None, 'chi2_red':None, 'AIC':self.foobarmin, 'BIC':self.foobarmin,
                     'DIC':self.foobarmin, 'HQIC':self.foobarmin, 'RMSE':None, 'post_max':None,
                     'like_max':None, 'BayesFactor':self.foobarmax}
        self.msg = ''
        self.update()

    @property
    def criteria(self):
        return self._current_criteria

    @criteria.setter
    def set_criteria(self, val):
        self._current_criteria = val
        self.update()

    @property
    def tolerance(self):
        return self._tolerance

    @tolerance.setter
    def set_tolerance(self, val):
        self._tolerance = val


    def foobarmin(self, foo, bar):
        foo_d = np.round(foo, 3)
        bar_d = np.round(bar, 3)
        self.msg = f'{foo_d} < {bar_d} - {self._tolerance}'

        return foo < bar - self._tolerance

    def foobarmax(self, foo, bar):
        foo_d = np.round(foo, 3)
        bar_d = np.round(bar, 3)
        self.msg = f'{foo_d} > {bar_d} + {self._tolerance}'

        return foo > bar + self._tolerance

    def compare(self, foo, bar):
        return self.compare_f(foo, bar)

    def update(self):
        self.compare_f = self.dict[self._current_criteria]


class Simulation(object):
    def __init__(self, setup=None):
        if setup is None:
            setup = []
        # LOAD ATTRIBUTES
        self.blocks__ = []
        self.ndim__ = None
        self.model = []

        self.kplanets__ = 0
        self.nins__ = 0

        self.logger = reddlog()
        self.cores__ = multiprocessing.cpu_count() - 1

        self.save_loc = ''
        self.read_loc = ''

        self.starmass = 1.
        Nonethings = ['starname', 'betas', 'saveplace']
        for c in Nonethings:
            setattr(self, c, None)

        switches = ['switch_first', 'switch_RV', 'switch_SA', 'switch_constrain',
                    'switch_dynamics', 'dynamics_already_included']
        for switch in switches:
            setattr(self, switch, False)

        switches_T = ['switch_evidence', 'gaussian_mixtures_fit']
        for switch in switches_T:
            setattr(self, switch, True)


        self.conds = []

        self.eccentricity_limits = [0, 1]
        self.eccentricity_prargs = [0, 0.1]

        self.jitter_limits = [0, 1]
        self.jitter_prargs = [5, 5]


        self.multiprocess_method = 1

        # constrain
        self.constrain_sigma = 3
        self.constrain_method = 'sigma'  # 'sigma', 'GM'

        # posterior
        self.posterior_fit_method = 'GM'  # KDE*soon

        self.posterior_dict = {'GM': 'Gaussian Mixtures',
                               'KDE': 'Kernel Density Estimation'}
        # stats
        stats_names_posi = ['chi2', 'chi2_red', 'AIC', 'BIC',
                            'DIC', 'HQIC', 'RMSE']
        for stat in stats_names_posi:
            setattr(self, stat, np.inf)

        stats_names_nega = ['post_max', 'like_max', 'BayesFactor']
        for stat in stats_names_nega:
            setattr(self, stat, -np.inf)


        # Writing stuff
        self.general_dependencies = []
        self.dynesty_config = {'dlogz_init':0.05,
                                }
        self.reddemcee_config = {'burnin':'half',
                                'thinby':1,
                                }

        #self.ModelSelection = 'BIC'
        self.ModelSelection = ModelSelectionObj('BIC')
        self.evidence = 0, 0


        self.save_all = False
        self.save_plots = False
        self.save_log = True
        self.save_plots_fmt = 'png'

        # plots
        self.instrument_names = None


        self.plot_gaussian_mixtures = {'plot':True,
                                        'sig_factor':4,
                                        'plot_title':None,
                                        'plot_ylabel':None}
        #self.plot_gaussian_mixtures = True
        self.plot_keplerian_model = {'plot':True,
                                     'hist':True,
                                     'uncertain':True,
                                     'errors':False,
                                     'format':'png',
                                     'logger_level':'ERROR',
                                     'gC':0}

        self.plot_trace = {'plot':True,
                           'modes':[0, 1, 2, 3],
                           'temp':0}

        self.parameter_histograms = False
        self.corner = (np.array(self.plot_trace['modes']) == 3).any()

        self.save_chains = [0]
        self.save_likelihoods = [0]
        self.save_posteriors = [0]
        self.logger('   ', center=True, save=False, c='green', attrs=['bold', 'reverse'])
        self.logger('~~ Simulation Successfully Initialized ~~', center=True, save=False, c='green', attrs=['bold', 'reverse'])
        self.logger('   ', center=True, save=False, c='green', attrs=['bold', 'reverse'])


    def set_engine(self, eng):
        setattr(self, f'{eng}_config', {'name':eng})

        if eng == 'emcee':
            import emcee
            self.engine__ = emcee
        elif eng == 'dynesty':
            import dynesty
            self.engine__ = dynesty

        elif eng == 'dynesty_dynamic':
            import dynesty
            self.engine__ = dynesty
            self.engine__args = 'dynamic'
            self.general_dependencies.append('dynesty')

            self.dynesty_config['dlogz_init'] = 0.05

        elif eng == 'pymc3':
            import pymc3 as pm
            self.engine__ = pm
        elif eng == 'reddemcee':
            import reddemcee
            self.engine__ = reddemcee
            self.general_dependencies.append('reddemcee')
            self.general_dependencies.append('emcee')

            self.reddemcee_config['burnin'] = 'half'
            self.reddemcee_config['thinby'] = 1
        else:
            raise Exception(self.logger('Failed to set engine properly. Try a string!', center=True, c='red'))


    def load_data(self, folder_name):
        self.starname = folder_name
        self.data_wrapper = DataWrapper(folder_name, read_loc=self.read_loc)
        self.logger('\n')
        self.logger(self.data_wrapper.add_all__(), center=True, c='blue')
        self.logger('\n')

        if self.instrument_names is None:
            self.instrument_names = self.data_wrapper.RV_labels
        self.my_data = self.data_wrapper.get_data__()

        self.my_data_reduc = self.my_data.values[:, 0:3].T
        if len(self.data_wrapper.RV_labels) > 0:
            self.nins__ = len(self.data_wrapper.RV_labels)
            self.switch_RV = True


    def add_keplerian_block(self, parameterisation=0):
        self.kplanets__ += 1
        kb = mk_KeplerianBlock(self.my_data, parameterisation=parameterisation,
                                  number=self.kplanets__)

        prargs = [self.eccentricity_limits, self.eccentricity_prargs]
        kw = {'prargs':prargs, 'dynamics':self.switch_dynamics,
              'kplan':self.kplanets__, 'starmass':self.starmass,
              'dynamics_already_included':self.dynamics_already_included}
        SmartLimits(self.my_data, kb, **kw)  # sets limits and returns <extra_priors>

        #if parameterisation == 1 or parameterisation == 3:
        #    br.add_additional_priors(extra_priors)

        kb.signal_number = self.kplanets__

        kb.slice = slice((self.kplanets__ - 1)*kb.ndim_, self.kplanets__*kb.ndim_)

        self.blocks__.insert((self.kplanets__ - 1), kb)

        msg = '{} {}, {}'.format(colored(kb.type_, 'green', attrs=['bold']),
                                 colored('block added', 'green'),
                                 colored(kb.name_, 'green'))
        msg = f'                              {msg}'
        self.logger(msg, center=True)
        self.logger('\n')


    def add_instrumental_blocks(self, moav=0, offset=True):
        for i in range(self.nins__):
            ib = mk_InstrumentBlock(self.my_data, number=i+1, moav=moav)

            jitter_args = [self.jitter_limits, self.jitter_prargs]
            SmartLimits(self.my_data, ib, *jitter_args)

            ib.ins_no = int(i+1)
            ib.slice = slice(self.kplanets__ * 5 + (i) * ib.ndim_,
                             self.kplanets__ * 5 + (i+1) * ib.ndim_)

            ib.instrument_label = self.instrument_names[i]
            self.blocks__.append(ib)

            msg = '{} {}, {}'.format(colored(ib.type_, 'green', attrs=['bold']),
                                     colored('block added', 'green'),
                                     colored(ib.name_, 'green'))
            msg = f'                              {msg}'
            self.logger(msg, center=True)
            self.logger('\n')


    def add_acceleration_block(self, accel=1):
        ab = mk_AccelerationBlock(self.my_data, n=accel)
        self.blocks__.append(ab)

        msg = '{} {}, {}'.format(colored(ab.type_, 'green', attrs=['bold']),
                                 colored('block added', 'green'),
                                 colored(ab.name_, 'green'))
        msg = f'                              {msg}'
        self.logger(msg, center=True)
        self.logger('\n')


    def update_model(self):
        self.model = ReddModel(self.my_data, self)
        #if self.model.update_additional_priors():
        #    self.update_additional_priors_block()
        self.model.refresh__()


    def run(self, setup, progress=True):
        ### assert errors!
        ##
        if self.constrain_method == 'GM':
            if not self.gaussian_mixtures_fit:
                msg = 'Invalid constrain_method = GM with .gaussian_mixtures_fit = False'
                raise SyntaxError(msg)

        self.apply_conditions()
        self.saveplace = ensure_dir(self.starname, loc=self.save_loc)
        #self.temp_script = self.saveplace+'/temp/temp_script.py'
        self.temp_script = 'temp_script.py'

        if not self.switch_first:
            self.logger('\n')
            self.logger('~~ Setup Info ~~', center=True, c='blue', attrs=['reverse'])
            self.logger('\nCurrent Engine is  '+colored(self.engine__.__name__+' '+self.engine__.__version__, attrs=['bold']), c='blue')
            self.logger('Number of cores is '+colored(self.cores__, attrs=['bold']), c='blue')
            self.logger('Save location is   '+colored(self.saveplace, attrs=['bold']), c='blue')

            if self.switch_dynamics:
                dyn_crit = 'Hill Stability'
            else:
                dyn_crit = 'None'
            self.logger('Dynamical Criteria is      '+colored(dyn_crit, attrs=['bold']), c='blue')
            self.logger('Posterior fit method is    '+colored(self.posterior_dict[self.posterior_fit_method], attrs=['bold']), c='blue')
            self.logger('Limits constrain method is '+colored(self.constrain_method, attrs=['bold']), c='blue')
            self.logger('Model Selection method is  '+colored(self.ModelSelection.criteria, attrs=['bold']), c='blue')

            self.logger('\n')
            self.logger('~~ Automatically Saving ~~', center=True, c='blue', attrs=['reverse'])

            saving_ = ['save_log', 'save_chains', 'save_posteriors',
                       'save_likelihoods', 'plot_gaussian_mixtures',
                       'plot_keplerian_model', 'parameter_histograms',
                       'corner']
            saving0_ = ['Logger       ',
                        'Samples      ',
                        'Posteriors   ',
                        'Likelihoods  ',
                        'Plots: Gaussian Mixture     ',
                        'Plots: Keplerian Model      ',
                        'Plots: Parameter Histograms ',
                        'Plots: Corner               ']
            checks_ = []
            for thing in saving_:
                self_attr = getattr(self, thing)
                if type(self_attr) == dict:
                    if self_attr['plot']:
                        checks_.append(colored('✔ ', attrs=['reverse'], color='green'))
                    else:
                        checks_.append(colored('✘ ', attrs=['reverse'], color='red'))
                    pass
                else:
                    if self_attr:
                        checks_.append(colored('✔ ', attrs=['reverse'], color='green'))
                    else:
                        checks_.append(colored('✘ ', attrs=['reverse'], color='red'))

            self.logger('')
            for i in range(4):
                self.logger('{}: {}'.format(saving0_[i], checks_[i]), c='blue')
            self.logger('')
            for i in range(4, 8):
                self.logger('{}: {}'.format(saving0_[i], checks_[i]), c='blue')


            self.switch_first = True

        self.update_model()

        # Print Pre-Run
        if True:
            self.logger('\n\n')
            self.logger('~~ Pre-Run Info ~~', center=True, c='yellow', attrs=['bold', 'reverse'])
            self.logger('\n\n')

            tab_3 = np.array([])
            switch_title = True

            for b in self:
                to_tab0 = b.get_attr(['name', 'display_prior', 'limits'])
                to_tab0[2] = np.round(to_tab0[2], 3)
                to_tab = list(zip(*to_tab0))

                if switch_title:
                    self.logger(tabulate(to_tab,
                                          headers=['Parameter       ',
                                                   'Prior   ',
                                                   'Limits      ',
                                                   ]))
                    switch_title = False

                else:
                    self.logger(tabulate(to_tab,
                                          headers=['                ',
                                                   '        ',
                                                   '            ',
                                                   ]))

            self.logger('\n')
            for b in self:
                self.logger('Math for {}:\n'.format(b.name_), c='yellow')
                self.logger('{}'.format(b.math_display_), center=True, c='yellow')

            self.logger('\n')


        if self.engine__.__name__ == 'reddemcee':
            from emcee.backends import HDFBackend
            ntemps, nwalkers, nsteps = setup

            self.write_model()

            os.system('ipython {}'.format(self.temp_script))

            self.sampler = self.engine__.PTSampler(nwalkers, self.model.ndim__,
                                         self.model.evaluate_loglikelihood,
                                         self.model.evaluate_logprior,
                                         logl_args=[], logl_kwargs={},
                                         logp_args=[], logp_kwargs={},
                                         ntemps=ntemps, pool=None)

            #self.sampler = [None for _ in range(ntemps)]
            with open('sampler_pickle.pkl', 'rb') as sampler_metadata:
                self.sampler_metadata_dict = pickle.load(sampler_metadata)

            for t in range(ntemps):
                loc_t = '{}emperor_backend_{}.h5'.format(self.saveplace+'/temp/', t)
                self.sampler[t] = HDFBackend(loc_t)

        if self.engine__.__name__ == 'dynesty':
            # TRANSFORM TO PTFORMARGS
            # This is missing additional_parameters ! !

            self.ptformargs0 = []
            for b in self:
                for p in b:
                    if p.fixed == None:
                        if p.ptformargs == None:
                            l, h = p.limits
                            p.ptformargs = [(h-l)/2., (h+l)/2.]
                            if b.parameterisation == 1:
                                if p.name[:3] == 'Ecc' and p.ptformargs[0] > 0.707:
                                    p.ptformargs[0] = 0.707
                            if b.parameterisation == 3:
                                if p.name[:3] == 'Ecc' and p.ptformargs[0] > 0.707:
                                    p.ptformargs[0] = 0.707
                        else:
                            s, c = p.ptformargs
                            p.limits = [c-s, c+s]
                        self.ptformargs0.append(p.ptformargs)


            if self.engine__args == 'dynamic':
                # SET SETUP
                nlive0, nlive_batch0 = setup
                # SET SAMPLER
                self.write_model()

                # RUN SAMPLER
                os.system('ipython {}'.format(self.temp_script))

                with open('sampler_pickle.pkl', 'rb') as sampler_metadata:
                    self.sampler_metadata_dict = pickle.load(sampler_metadata)
                pass
            else:
                # SET SETUP
                # SET SAMPLER
                # RUN SAMPLER
                pass


    def run_auto(self, setup, k_start=0, k_end=10, parameterisation=1, moav=0, accel=0, progress=True):
        self.auto_setup = setup
        if self.engine__.__name__ in ['emcee', 'dynesty', 'pymc3', 'reddemcee']:

            if self.switch_RV and not self.switch_SA:
                self.add_instrumental_blocks(moav=moav)
            if accel:
                self.add_acceleration_block(accel=accel)

            while k_start <= k_end:
                if not self.switch_first and k_start > 0 and self.switch_RV:
                    for _ in range(k_start):
                        self.add_keplerian_block(parameterisation=parameterisation)


                oldlike_max = self.like_max
                oldpost_max = self.post_max
                oldchi2 = self.chi2
                oldAIC = self.AIC
                oldBIC = self.BIC
                oldDIC = self.DIC
                oldHQIC = self.HQIC
                oldRMSE = self.RMSE
                oldBayesFactor = self.BayesFactor


                self.run(self.auto_setup, progress=progress)
                self.postprocess(self.auto_setup)  # change values

                k_start += 1


                if self.switch_constrain:
                    if self.constrain_method == 'sigma':
                        for b in self:
                            if b.type_ == 'Keplerian':
                                for p in b:
                                    if p.fixed is None:
                                        pval = p.value
                                        psig = p.sigma

                                        limf, limc = pval - self.constrain_sigma*psig, pval + self.constrain_sigma*psig

                                        if limc > p.limits[1]:
                                            limc = p.limits[1]

                                        if psig / abs(pval) < 1e-5:
                                            self.add_condition([p.name, 'fixed', pval])
                                        elif (limf > p.limits[0] and limc < p.limits[1]):
                                            self.add_condition([p.name, 'limits', [limf, limc]])
                                        elif limf > p.limits[0]:
                                            self.add_condition([p.name, 'limits', [limf, p.limits[1]]])
                                        elif limc < p.limits[1]:
                                            self.add_condition([p.name, 'limits', [p.limits[0], limc]])
                    if self.constrain_method == 'GM':
                        count = 0
                        for b in self:
                            if b.type_ == 'Keplerian':
                                for p in b[b.C_]:
                                    if p.GM_parameter.n_components == 1:
                                        prarg0 = [p.GM_parameter.means[0], p.GM_parameter.sigmas[0]]

                                        self.add_condition([p.name, 'prior', 'Normal'])
                                        self.add_condition([p.name, 'prargs', prarg0])

                                    elif p.GM_parameter.n_components > 1:
                                        self.add_condition([p.name, 'prior', 'GaussianMixture'])
                                        self.add_condition([p.name, 'prargs', [self.model.C_[count]]])
                                    count += 1
                # if not continue, model selec
                if self.ModelSelection.compare(self.BIC, oldBIC):
                    oldbic_display = np.round(oldBIC, 3)
                    newbic_display = np.round(self.BIC, 3)
                    self.logger('\nBIC condition met!!', c='blue', attrs=['bold'])
                    self.logger('present BIC < past BIC - 5', c='blue')
                    self.logger(self.ModelSelection.msg, c='blue')
                else:
                    self.logger('\nBIC condition not met', c='blue')
                    self.logger('present BIC < past BIC - 5', c='blue')
                    self.logger(self.ModelSelection.msg, c='blue')

                    self.logger('\n')
                    self.logger('   ', center=True, c='magenta', attrs=['bold', 'reverse'])
                    self.logger('~~ Ending the run ~~', center=True, c='magenta', attrs=['bold', 'reverse'])
                    self.logger('   ', center=True, c='magenta', attrs=['bold', 'reverse'])
                    self.logger('\n', center=True, c='magenta')
                    break

                if k_start > k_end:
                    self.logger('\n')
                    self.logger('   ', center=True, c='magenta', attrs=['bold', 'reverse'])
                    self.logger('~~ Run came to an end ~~', center=True, c='magenta', attrs=['bold', 'reverse'])
                    self.logger('   ', center=True, c='magenta', attrs=['bold', 'reverse'])
                    self.logger('\n', center=True, c='magenta')
                    break

                # if passes:
                self.logger('\n\n')
                self.logger('   ', center=True, c='magenta', attrs=['bold', 'reverse'])
                self.logger('~~ Proceeding with the next run ! ~~', center=True, c='magenta', attrs=['bold', 'reverse'])
                self.logger('   ', center=True, c='magenta', attrs=['bold', 'reverse'])
                self.logger('\n')
                if self.switch_RV:
                    self.add_keplerian_block(parameterisation=parameterisation)
                self.update_model()


    def postprocess(self, setup=[]):
        if self.engine__.__name__ == 'reddemcee':
            ntemps, nwalkers, nsteps = setup

            self.acceptance_fraction = self.sampler_metadata_dict['acceptance_fraction']
            self.autocorr_time = self.sampler_metadata_dict['get_autocorr_time']

            self.sampler.betas = self.sampler_metadata_dict['betas']
            self.sampler.ratios = self.sampler_metadata_dict['ratios']


            if True:
                if type(self.reddemcee_config['burnin']) == str:
                    if self.reddemcee_config['burnin'] == 'half':
                        self.reddemcee_discard = nsteps // 2
                    elif self.reddemcee_config['burnin'] == 'auto':
                        print('method not yet implemented!! CODE 26')
                        self.reddemcee_discard = 0
                    else:
                        self.reddemcee_discard = 0
                elif type(self.reddemcee_config['burnin']) == int:
                    self.reddemcee_discard = self.reddemcee_config['burnin']

                elif type(self.reddemcee_config['burnin']) == float:
                    self.reddemcee_discard = int(self.reddemcee_config['burnin'] * nsteps)

                else:
                    print('method not understood!! CODE 27')
                    self.reddemcee_discard = 0
            if True:
                if type(self.reddemcee_config['thinby']) == str:
                    if self.reddemcee_config['thinby'] == 'half':
                        self.reddemcee_thin = 2

                    elif self.reddemcee_config['thinby'] == 'auto':
                        print('method not yet implemented!! CODE 28')
                        self.reddemcee_thin = 1
                    else:
                        self.reddemcee_thin = 1
                elif type(self.reddemcee_config['thinby']) == int:
                    self.reddemcee_thin = self.reddemcee_config['thinby']

                else:
                    print('method not understood!! CODE 29')
                    self.reddemcee_thin = 1

            reddemcee_dict = {'discard':self.reddemcee_discard,
                              'thin':self.reddemcee_thin,
                              'flat':True}

            raw_chain = self.sampler.get_func('get_chain', kwargs=reddemcee_dict)
            raw_posts = self.sampler.get_func('get_log_prob', kwargs=reddemcee_dict)
            raw_likes = self.sampler.get_func('get_blobs', kwargs=reddemcee_dict)

            setup_info = 'Temperatures, Walkers, Steps   : '
            size_info = [len(raw_chain[t]) for t in range(ntemps)]


            if self.switch_evidence:
                self.evidence = self.sampler_metadata_dict['thermodynamic_integration']

            best_loc = np.argmax(raw_posts[0])

            self.post_max = raw_posts[0][best_loc]
            self.like_max = raw_likes[0][best_loc]
            self.prior_max = self.post_max - self.like_max

            self.ajuste = raw_chain[0][best_loc]
            self.sigmas = np.std(raw_chain, axis=1)[0]

            self.fit_max = raw_chain[0][best_loc]
            self.fit_mean = np.mean(raw_chain[0], axis=0)
            self.fit_median = np.median(raw_chain[0], axis=0)

        if self.engine__.__name__ == 'dynesty':
            '''
            needs to save likes
            '''
            results = self.sampler_metadata_dict['results']
            self.sampler = [results]
            setup_info = '\nLive Points                       : '
            size_info = results['niter']

            raw_chain = np.array([results['samples']])
            raw_likes = [results['logl']]
            if self.switch_evidence:
                self.evidence = (results['logz'][-1], results['logzerr'][-1])

            raw_posts = raw_likes - self.evidence[0]

            ## FIN
            best_loc = -1

            self.post_max = raw_posts[0][best_loc]
            self.like_max = raw_likes[0][best_loc]
            self.prior_max = 0

            self.ajuste = raw_chain[0][best_loc]
            self.sigmas = np.std(raw_chain[0], axis=0)

            self.fit_max = raw_chain[0][best_loc]
            self.fit_mean = raw_chain[0][best_loc]
            self.fit_median = raw_chain[0][best_loc]

            print('\n\n------------ Dynesty Summary -----------\n\n')
            print(str(results.summary()))


        chains = raw_chain
        posts = raw_posts
        likes = raw_likes


        ###########################################
        ###########################################
        # GET STATS
        if True:
            if self.switch_RV:
                ymod, err2 = self.model.evaluate_model(self.ajuste)
                ferr2 = err2 + self.my_data['eRV'].values ** 2
                residuals = self.my_data['RV'].values - ymod

                ndim = self.model.ndim__
                ndat = self.model.ndata

                rss = np.sum(residuals**2)

                self.dof = ndat - ndim
                self.chi2 = rss / self.dof
                self.chi2_red = np.sum(residuals**2 / ferr2) / self.dof
                self.RMSE = np.sqrt(np.sum(residuals ** 2) / len(residuals))

                self.AIC = 2 * ndim - 2 * self.like_max
                self.BIC = np.log(ndat) * ndim - 2 * self.like_max

                tm = np.mean(raw_chain[0], axis=0)
                self.DIC = -2 * self.model.evaluate_loglikelihood(tm) + np.var(-2 * likes[0])

                self.post_true = self.post_max - self.evidence[0]
                self.BayesFactor = self.like_max - self.evidence[0]

                self.HQIC = 2 * ndim * np.log(np.log(ndat)) - 2 * self.like_max

        ## SET P.VALUES P.SIGMA
        if True:
            ## **RED w/ set_attr
            j = 0  # delete this ap1
            for b in self:
                for p in b:
                    if p.fixed == None:
                        p.value = self.ajuste[j]
                        p.sigma = self.sigmas[j]
                        p.sigma_frac_mean = 0

                        p.value_max = self.fit_max[j]
                        p.value_mean = self.fit_mean[j]
                        p.value_median = self.fit_median[j]
                        j += 1
                    else:
                        p.sigma = np.nan
                        p.value_max = p.value
                        p.value_mean = p.value
                        p.value_median = p.value

        # Get extra info. Parameter transformation and planet signatures
        if True:
            self.sma = []
            self.mm = []

            self.sma_sig = []
            self.mm_sig = []

            self.extra_names = []
            self.extra_chains = []


            # Get extra chains
            uptothisdim = 0
            for b in self:
                chain_counter = 0
                ## PLANET SIGNATURES
                if b.type_ == 'Keplerian':
                    my_params = [None, None, None, None, None]

                    for i in b.C_:
                        my_params[i] = chains[0].T[uptothisdim + chain_counter]
                        chain_counter += 1

                    for i in b.A_:
                        my_params[i] = b[i].fixed * np.ones(len(chains[0]))


                    if True:
                        if b.parameterisation == 0:
                            per, A, phase, ecc, w = b.get_attr('value')
                            per_, A_, phase_, ecc_, w_ = my_params

                        elif b.parameterisation == 1:
                            P, As, Ac, S, C = b.get_attr('value')
                            P_, As_, Ac_, S_, C_ = my_params

                            per = np.exp(P)
                            per_ = np.exp(P_)

                            A, phase = delinearize(As, Ac)
                            ecc, w = delinearize(S, C)

                            A_, phase_ = adelinearize(As_, Ac_)
                            ecc_, w_ = adelinearize(S_, C_)

                            for thingy in ['Period', 'Amplitude', 'Phase', 'Eccentricity', 'Longitude_Periastron']:
                                self.extra_names.append(thingy+'_{}'.format(b.number_))

                            for thingy in [per_, A_, phase_, ecc_, w_]:
                                self.extra_chains.append(thingy)

                        elif b.parameterisation == 2:
                            per, A, t0, ecc, w = b.get_attr('value')
                            per_, A_, t0_, ecc_, w_ = my_params

                        elif b.parameterisation == 3:
                            per, A, t0, S, C = b.get_attr('value')
                            per_, A_, t0_, S_, C_ = my_params

                            ecc, w = delinearize(S, C)
                            ecc_, w_ = adelinearize(S_, C_)

                            for thingy in ['Eccentricity', 'Longitude_Periastron']:
                                self.extra_names.append(thingy)
                            for thingy in [ecc_, w_]:
                                self.extra_chains.append(thingy)

                        if self.starmass:
                            sma, mm = cps(per, A, ecc, self.starmass)
                            sma_, mm_ = cps(per_, A_, ecc_, self.starmass)

                            self.sma_sig.append(sma)
                            self.mm_sig.append(mm)

                            self.sma_sig.append(np.std(sma_))
                            self.mm_sig.append(np.std(mm_))

                            self.extra_names.append('Semi-Major Axis [AU]')
                            self.extra_names.append('Minimum Mass [M_J]')
                            self.extra_chains.append(sma_)
                            self.extra_chains.append(mm_)

                uptothisdim += b.ndim_
            ## Set p.values and sigma for extra params
            if True:
                ## **RED w/ set_attr\
                jj = 0
                for b in self:
                    for p in b.additional_parameters:
                        if p.has_posterior:
                            ch = self.extra_chains[jj]
                            p.value = ch[best_loc]
                            p.sigma = np.std(ch)
                            p.sigma_frac_mean = 0

                            p.value_max = ch[best_loc]
                            p.value_mean = np.mean(ch)
                            p.value_median = np.median(ch)
                            jj += 1

        # SAVE STUFF??
        if True:
            if self.save_chains is not None:
                self.save_chain(chains)
                self.save_posterior(posts)
                self.save_loglikelihood(likes)

            self.chains = chains[0]
            self.posts = posts[0]
            self.likes = likes[0]

            self.update_model()

        # SET GM
        if True:
            # REGULAR PARAMETERS
            if self.gaussian_mixtures_fit:
                self.model.get_GMEstimates(self.chains)

            # ADDITIONAL PARAMETERS
            for b in self:
                jj = 0
                for p in b.additional_parameters:
                    if p.has_posterior:
                        ch = self.extra_chains[jj]
                        p.GM_parameter = GM_Estimator().estimate(ch, p.display_name, p.unit)
            pass

        # SET POSTERIORS
        if True:
            if self.posterior_fit_method == 'GM':
                for b in self:
                    for p in b[b.C_]:
                        p.posterior = p.GM_parameter
                        if p.GM_parameter.n_components == 1:
                            mu = np.round(p.GM_parameter.mixture_mean, 3)
                            sig = np.round(p.GM_parameter.mixture_sigma, 3)
                            p.display_posterior = '~𝓝 ({}, {})'.format(mu, sig)
                        elif p.GM_parameter.n_components > 1:
                            subscript_nums = ['', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']
                            mu = np.round(p.GM_parameter.mixture_mean, 3)
                            sig = np.round(p.GM_parameter.mixture_sigma, 3)

                            p.display_posterior = '𝛴{}~~𝓝 ({}, {})'.format(subscript_nums[p.GM_parameter.n_components],
                                                                    mu, sig)
                        else:
                            print('Something really weird is going on! Error 110.')
                    for p in b[b.A_]:
                        p.posterior = p.GM_parameter
                        p.display_posterior = '~𝛿 (x - {})'.format(p.value)

                    jj = 0
                    for p in b.additional_parameters:
                        if p.has_posterior:
                            p.posterior = p.GM_parameter

                            if p.GM_parameter.n_components == 1:
                                mu = np.round(p.GM_parameter.mixture_mean, 3)
                                sig = np.round(p.GM_parameter.mixture_sigma, 3)
                                p.display_posterior = '~𝓝 ({}, {})'.format(mu, sig)
                            elif p.GM_parameter.n_components > 1:
                                subscript_nums = ['', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']
                                mu = np.round(p.GM_parameter.mixture_mean, 3)
                                sig = np.round(p.GM_parameter.mixture_sigma, 3)

                                p.display_posterior = '𝛴{}~~𝓝 ({}, {})'.format(subscript_nums[p.GM_parameter.n_components],
                                                                        mu, sig)
                            else:
                                print('Something really weird is going on! Error 110.')

                        pass

        # PRINT POSTERIORS
        if True:
            self.logger('\n\n')
            self.logger('~~ Best Fit ~~', center=True, c='yellow', attrs=['bold', 'reverse'])
            self.logger('\n\n')


            tab_3 = np.array([])
            switch_title = True

            for b in self:
                to_tab0 = b.get_attr(['name', 'display_posterior', 'value_max',
                                      'value_mean', 'sigma', 'limits'])

                to_tab0[2] = np.round(to_tab0[2], 3)
                to_tab0[3] = np.round(to_tab0[3], 3)
                to_tab0[4] = np.round(to_tab0[4], 3)
                to_tab0[5] = np.round(to_tab0[5], 3)


                to_tab = list(zip(*to_tab0))
                if switch_title:
                    self.logger(tabulate(to_tab,
                                          headers=['Parameter       ',
                                                   'Posterior       ',
                                                   'Value (max)',
                                                   'Value (mean)',
                                                   'Sigma',
                                                   'Limits      ',
                                                   ]))
                    switch_title = False
                else:
                    self.logger(tabulate(to_tab,
                                          headers=['                ',
                                                   '                ',
                                                   '           ',
                                                   '           ',
                                                   '     ',
                                                   '           ',
                                                   ]))

                if len(b.additional_parameters):
                    mask = [x.has_posterior for x in b.additional_parameters]

                    pnames = [p.display_name for p in np.array(b.additional_parameters)[mask]]
                    #pdisp = [p.limits for p in np.array(b.additional_parameters)[mask]]
                    pdisp = [p.display_posterior for p in np.array(b.additional_parameters)[mask]]
                    pvalmax = [p.value_max for p in np.array(b.additional_parameters)[mask]]
                    pvalmean = [p.value_mean for p in np.array(b.additional_parameters)[mask]]
                    psig = [p.sigma for p in np.array(b.additional_parameters)[mask]]
                    plims = [p.limits for p in np.array(b.additional_parameters)[mask]]

                    to_tab1 = [pnames, pdisp, pvalmax, pvalmean, psig, plims]

                    to_tab1[2] = np.round(to_tab1[2], 3)
                    to_tab1[3] = np.round(to_tab1[3], 3)
                    to_tab1[4] = np.round(to_tab1[4], 3)
                    to_tab1[5] = np.round(to_tab1[5], 3)

                    to_tab = list(zip(*to_tab1))
                    self.logger(tabulate(to_tab,
                                          headers=['                ',
                                                   '                ',
                                                   '           ',
                                                   '           ',
                                                   '     ',
                                                   '           ',
                                                   ]))

        # PRINT STATS
        if True:
            self.logger('\n\n')
            self.logger('~~ Run Info ~~', center=True, c='yellow', attrs=['bold', 'reverse'])
            self.logger('\n\n')

            tabh_1 = ['Info                             ', 'Value                       ']

            tab_1 =    [['Star Name                      : ', self.starname],
                        ['The sample sizes are           : ', size_info],
                        [setup_info, setup],
                        ['Model used is                  : ', str(self)],
                        ['N data                         : ', self.model.ndata],
                        ['Number of Dimensions           : ', len(self)],
                        ['Degrees of Freedom             : ', self.dof]
                        ]

            self.logger('\n\n')
            self.logger(tabulate(tab_1, headers=tabh_1))
            self.logger('\n')
            self.logger('---------------------------------------------------', center=True)
            self.logger('\n')


            tabh_2 = ['Statistic                        ', 'Value']

            tab_2 = [['The maximum posterior is    :    ', '{:.3f}'.format(self.post_max)],
                     ['The maximum likelihood is   :    ', '{:.3f}'.format(self.like_max)],
                     ['The chi2 is                 :    ', '{:.3f}'.format(self.chi2)],
                     ['The reduced chi2 is         :    ', '{:.3f}'.format(self.chi2_red)],
                     ['The AIC is                  :    ', '{:.3f}'.format(self.AIC)],
                     ['The BIC is                  :    ', '{:.3f}'.format(self.BIC)],
                     ['The DIC is                  :    ', '{:.3f}'.format(self.DIC)],
                     ['The HQIC is                 :    ', '{:.3f}'.format(self.HQIC)],
                     ['The Bayes Factor is         :    ', '{:.3f}'.format(self.BayesFactor)],
                     ['The RMSE is                 :    ', '{:.3f}'.format(self.RMSE)]
                     ]

            if self.engine__.__name__ == 'reddemcee':
                self.logger('Beta Detail                     :   ' + str(['{:.3f}'.format(x) for x in self.sampler.betas]))
                self.logger('Temperature Swap                :   ' + str(['{:.3f}'.format(x) for x in self.sampler.ratios]))
                self.logger('Mean Acceptance Fraction        :   ' + str(['{:.3f}'.format(x) for x in np.mean(self.acceptance_fraction, axis=1)]))
                if self.switch_evidence:
                    x = [['The evidence is             :    ', '%.3f +- %.3f' % self.evidence]]
                    tab_2 = np.vstack([x, tab_2])

            if self.engine__.__name__ == 'dynesty':
                if self.switch_evidence:
                    x = [['The evidence is             :    ', '%.3f +- %.3f' % self.evidence]]
                    tab_2 = np.vstack([x, tab_2])

            self.logger('\n\n')
            self.logger('~~ Statistical Details ~~', center=True, c='yellow', attrs=['bold', 'reverse'])
            self.logger('\n\n')
            self.logger(tabulate(tab_2, headers=tabh_2))
            self.logger('\n\n')

        #######################
        # PLOT GM PER PARAMETER
        if self.gaussian_mixtures_fit:
            if self.plot_gaussian_mixtures['plot']:
                self.logger('Plotting Gaussian Mixtures', center=True, c='green')
                pbar_tot = self.model.ndim__
                pbar = tqdm(total=pbar_tot)
                for b in self:
                    for p in b[b.C_]:
                        plot_GM_Estimator(p.GM_parameter,
                                        saveloc=self.saveplace,
                                        fmt=self.save_plots_fmt,
                                        sig_factor=self.plot_gaussian_mixtures['sig_factor'],
                                        fill_cor=b.bnumber_-1,
                                        plot_name='{} '.format(b.bnumber_) + p.GM_parameter.name,
                                        plot_title=self.plot_gaussian_mixtures['plot_title'],
                                        plot_ylabel=self.plot_gaussian_mixtures['plot_ylabel'])
                        pbar.update(1)
                    for p in b.additional_parameters:
                        if p.has_posterior:
                            plot_GM_Estimator(p.GM_parameter,
                                            saveloc=self.saveplace,
                                            fmt=self.save_plots_fmt,
                                            sig_factor=self.plot_gaussian_mixtures['sig_factor'],
                                            fill_cor=b.bnumber_-1,
                                            plot_name='{} '.format(b.bnumber_) + p.GM_parameter.name,
                                            plot_title=self.plot_gaussian_mixtures['plot_title'],
                                            plot_ylabel=self.plot_gaussian_mixtures['plot_ylabel'])
                pbar.close()

        # PLOT Keplerian Model and uncertainties
        if self.kplanets__ > 0:
            if self.plot_keplerian_model['plot']:
                res_max = flatten(self.get_attr_param('value_max'))
                self.logger('Plotting Keplerian Models', center=True, c='green')
                if True:
                    plot_KeplerianModel(self.my_data, self.model,
                                        res_max, saveloc=self.saveplace,
                                        options = self.plot_keplerian_model)
                else:
                    print('Model plot failed miserably :(\n')

        # PLOT stuff with arviz, including corner!!

        if self.plot_trace['plot']:
            self.logger('Plotting Trace', center=True, c='green')

            plot_traces(self.sampler[self.plot_trace['temp']],
                                self.engine__.__name__,
                                self.model, saveloc=self.saveplace,
                                trace_modes=self.plot_trace['modes'], fmt='png')

        # SAVE LOG
        if self.save_log:
            self.logger.saveto(self.saveplace)


    def get_attr_param(self, call, flat=False, asarray=False):
        ret = [b.get_attr(call) for b in self]
        if flat:
            ret = flatten(ret)
        if asarray:
            ret = np.array(ret)
        return ret


    def get_attr_block(self, call, flat=False, asarray=False):
        ret = [getattr(b, call) for b in self]
        if flat:
            ret = flatten(ret)
        if asarray:
            ret = np.array(ret)
        return ret


    def save_chain(self, chains):
        temps = self.save_chains
        if self.engine__.__name__ == 'reddemcee':
            for temp in temps:
                np.savez_compressed(f'{self.saveplace}/chains/chain_{str(temp)}', chains[temp])


    def save_posterior(self, posts):
        temps = self.save_posteriors
        if self.engine__.__name__ == 'reddemcee':
            for temp in temps:
                np.savez_compressed(
                    f'{self.saveplace}/posteriors/posterior_{str(temp)}',
                    posts[temp],
                )


    def save_loglikelihood(self, likes):
        temps = self.save_likelihoods
        if self.engine__.__name__ == 'reddemcee':
            for temp in temps:
                np.savez_compressed(self.saveplace + '/likelihoods/likelihood_'+str(temp), likes[temp])


    def apply_conditions(self):
        applied = []
        for b in self:
            for p in b:
                for c in self.conds:
                    if p.name == c[0]:
                        setattr(p, c[1], c[2])
                        if c not in applied:
                            applied.append(c)

                            msg = '\nCondition applied: Parameter {} attribute {} set to {}'.format(
                                        colored(c[0], attrs=['underline']),
                                        colored(c[1], attrs=['underline']),
                                        colored(c[2], attrs=['underline']))

                            self.logger(msg)

                            #toprint = [colored(x, attrs=['bold', 'underline']) for x in c]
                            #print('\nCondition applied: Parameter {} attribute {} set to {}'.format(*toprint))

        applied.sort()
        applied = [applied for applied,_ in itertools.groupby(applied)]

        for ap in applied[::-1]:
            self.conds.remove(ap)


    def add_condition(self, cond):
        self.conds.append(cond)


    def write_model(self):

        self.dir_work = os.path.dirname(os.path.realpath(__file__))
        self.dir_save = self.saveplace

        self.script_pool_opt = get_support(f'pools/0{self.multiprocess_method}.pool')

        if self.engine__.__name__ == 'reddemcee':


            ntemps, nwalkers, nsteps = self.auto_setup
            #self.my_data.to_csv('{}/temp/temp_data.csv'.format(self.saveplace))
            with open(self.temp_script, 'w') as f:
                f.write(open(get_support('init.scr')).read())

                # DEPENDENCIES
                for d in self.general_dependencies:
                    f.write('''
import {}
'''.format(d))

                f.write('''
import kepler
''')
                # CONSTANTS
                f.write('''
nan = np.nan
A_ = {}
mod_fixed_ = {}
gaussian_mixture_objects = dict()

'''.format(self.model.A_, self.model.mod_fixed))

                # MODEL
                f.write(open(self.model.write_model_(loc=self.saveplace)).read())

                # LIKELIHOOD
                f.write(open(get_support('likelihoods/00.like')).read())

                # PRIOR
                for prior_script in os.listdir(get_support('priors')):
                    f.write(open(get_support(f'priors/{prior_script}')).read())
                    f.write('''
''')
                count = 0
                for b in self:
                    for p in b[b.C_]:
                        first = True
                        attributes = ['weights_',
                                      'means_',
                                      'covariances_',
                                      'precisions_',
                                      'precisions_cholesky_',
                                      'converged_',
                                      'n_iter_',
                                      'lower_bound_',
                                      'n_features_in_',
                                      ]
                        if p.prior == 'GaussianMixture':
                            if first:
                                f.write('''

from sklearn.mixture import GaussianMixture as skl_gm

''')
                            first = False
                            f.write('''
{0} = skl_gm()
gaussian_mixture_objects[{1}] = {0}
'''.format('gaussian_mixture_{}'.format(self.model.C_[count]), self.model.C_[count]))

                            for at in attributes:
                                coso = getattr(p.GM_parameter, at)
                                if type(coso) == np.ndarray:
                                    coso = coso.tolist()
                                    f.write('''
setattr(gaussian_mixture_objects[{0}], '{1}', np.array({2}))'''.format(self.model.C_[count], at, coso))

                                else:
                                    f.write('''
setattr(gaussian_mixture_objects[{0}], '{1}', {2})'''.format(self.model.C_[count], at, coso))
                        count += 1
                f.write('''

def my_prior(theta):
    for a in A_:
        theta = np.insert(theta, a, mod_fixed_[a])
    lp = 0.
''')
                count = 0
                for b in self:
                    for p in b[b.C_]:
                        f.write('''
    lp += {}(theta[{}], {}, {})
'''.format(p.prior, self.model.C_[count], p.limits, p.prargs))
                        count += 1


                    f.write('''
    if lp == -np.inf:
        return lp

''')
                    if len(b.additional_parameters):
                        for p in b.additional_parameters:
                            if p.has_prior:
                                if p.name == 'Amplitude':
                                    f.write('''
    x = theta[{0}][1]**2 + theta[{0}][2]**2
    '''.format(b.slice))

                                elif p.name == 'Eccentricity':
                                    f.write('''
        x = theta[{0}][3]**2 + theta[{0}][4]**2
    '''.format(b.slice))

                                elif p.name == 'Hill' and p.prargs[0] > 1:
                                    f.write('''
    b_len = {}
    kplanets = {}
    '''.format(len(b)   , p.prargs[0]))
                                    f.write(open(get_support(f'PAE/0{b.parameterisation}.pae')).read())

                                else:
                                    continue

                                f.write('''
    lp += {}(x, {}, {})
'''.format(p.prior, p.limits, p.prargs))

                        f.write('''
    if lp == -np.inf:
        return lp

''')

                f.write('''

    return lp


''')

                # MULTIPROCESSING
                f.write(open(self.script_pool_opt).read())

                # SETUP CONSTS
                f.write('''

ntemps, nwalkers, nsteps = {0}, {1}, {2}
setup = ntemps, nwalkers, nsteps
ndim = {3}
'''.format(ntemps, nwalkers, nsteps, self.model.ndim__))

                # BACKENDS
                f.write('''
backends = [None for _ in range(ntemps)]
for t in range(ntemps):
    filename = '{}emperor_backend_' +str(t)+'.h5'
    backends[t] = emcee.backends.HDFBackend(filename)
    backends[t].reset(nwalkers, ndim)

sampler = reddemcee.PTSampler(nwalkers, ndim,
                             my_likelihood,
                             my_prior,
                             ntemps=ntemps, pool=mypool,
                             backend=backends)
'''.format(self.saveplace+'/temp/'))

                # POS 0
                f.write('''
def set_init():
    pos = np.zeros((ntemps, nwalkers, ndim))

    for t in range(ntemps):
        j = 0
''')

                for b in self.model:
                    for p in b:
                        if p.fixed == None:
                            r = 1
                            if p.is_hou:
                                r = 0.707
                            f.write('''
        m = ({0} + {1}) / 2
        r = ({0} - {1}) / 2 * {2}
        dist = np.sort(np.random.uniform(0, 1, nwalkers))
        pos[t][:, j] = r * (2 * dist - 1) + m
        np.random.shuffle(pos[t, :, j])
        j += 1

'''.format(p.limits[1], p.limits[0], r))


                f.write('''
    return list(pos)


''')

                f.write('''
def test_init(max_repeats={0}):
    p0 = set_init()

    is_bad_position = True
    repeat_number = 0

    while is_bad_position and repeat_number < max_repeats:
        is_bad_position = False
        for t in range(ntemps):
            for n in range(nwalkers):
                position_evaluated = p0[t][n]
                if my_prior(position_evaluated) == -np.inf:
                    is_bad_position = True
                    p0[t][n] = set_init()[t][n]
        repeat_number += 1
    return p0

'''.format(100))
            # RUN
                f.write('''

p1 = test_init()

''')
                f.write(open(get_support('endit.scr')).read())

        if self.engine__.__name__ == 'dynesty':
            if self.engine__args == 'dynamic':
                nlive, nlive_batch = self.auto_setup
                with open(self.temp_script, 'w') as f:
                    f.write(open(get_support('init.scr')).read())

                    # DEPENDENCIES
                    for d in self.general_dependencies:
                        f.write('''
import {}
    '''.format(d))

                    f.write('''
import kepler
    ''')
                    # CONSTANTS
                    f.write('''
nan = np.nan
A_ = {}
mod_fixed_ = {}
    '''.format(self.model.A_, self.model.mod_fixed))

                    # MODEL
                    f.write(open(self.model.write_model_(loc=self.saveplace)).read())

                    # LIKELIHOOD
                    f.write(open(get_support('likelihoods/00.like')).read())

                    # PTFORMARGS
                    f.write('''
ptformargs = {}
'''.format(self.ptformargs0))
                    # PRIOR


                    f.write('''
def my_prior(theta):
#    for a in A_:
#        theta = np.insert(theta, a, mod_fixed_[a])
    x = np.array(theta)
    for i in range(len(x)):
        a, b = ptformargs[i]
        x[i] =  a * (2. * x[i] - 1) + b
    return x

''')
                    # SETUP CONSTS
                    f.write('''

nlive, nlive_batch = {}, {}
ndim = {}
'''.format(nlive, nlive_batch, self.model.ndim__))

                    # SAMPLER /BACKENDS?

                    # END
                    pool_bool = False
                    if self.multiprocess_method:
                        pool_bool = True
                    nested_dict = self.dynesty_config
                    nested_args = ''
                    for key in [*nested_dict]:
                        nested_args += f'{key} = {nested_dict[key]}, '

                    f.write(open(get_support('endit_dyn.scr')).read().format(pool_bool, self.cores__, nested_args))

        pass


    def __getitem__(self, n):
        return self.blocks__[n]


    def __repr__(self):
        #return self.model
        return str([self.blocks__[i].name_ for i in range(len(self.blocks__))])


    def __len__(self):
        return np.sum([len(b) for b in self])






#
