//  [python]
def calibratemmmpd(self,mmmpd,size,t):
        """
        This version computes the exact model probabilities for the 1D 2D gaussian mixture example.
        """
        global ep, dp, m1prob, PLOT_PROGRESS
        self.within_model_proposal.calibratemmmpd(mmmpd,size,t)
        mks = self.pmodel.getModelKeys() # get all keys
        # set up transforms
        self.flows = {}
        self.mk_logZhat = {}
        #mks = self.getModel().getModelKeys(theta)
        orig_theta,orig_theta_w = mmmpd.getOriginalParticleDensityForTemperature(t,resample=True,resample_max_size=1000)
        orig_mkdict,rev = self.pmodel.enumerateModels(orig_theta)

        #mk1cov = 1./t
        #mk2cov = torch.tensor([[1.,.99],[.99,1.]]) * 1./t

        var_h = 25.
        var_h_inv = 1./var_h
        mk1sig = 1
        log_mk1sig = 0
        mk1cov_t = 1./((1.-var_h_inv)*t+var_h_inv)
        #log_mk1cov_t = -np.log((1.-var_h_inv)*t+var_h_inv)
        log_mk1cov_t = -np.log((1./mk1sig)*t+var_h_inv*(1-t))

        def make_mk2cov_t(t,var_h,mk2cov):
            var_h_inv = 1./var_h
            mk2L, mk2Q = torch.symeig(mk2cov)
            return torch.mm(mk2Q,torch.mm(torch.diag(1./(var_h_inv+t*((1./mk2L)-var_h_inv))),mk2Q.T))

        mk2cov = torch.tensor([[1.,.99],[.99,1.]]) 
        mk2cov_t = make_mk2cov_t(t,var_h,mk2cov)
        print("mk2cov_t",mk2cov_t)
        print("test t=1 mk2cov",make_mk2cov_t(0,var_h,mk2cov))

        # compute normalising constants.
        mk1sig_t = np.sqrt(mk1cov_t)
        log_mk1sig_t = 0.5 * log_mk1cov_t
        mk2detcov_t = torch.det(mk2cov_t)
        sign,log_mk2detcov_t = torch.logdet(mk2cov_t)
        mk1sig_h_1t = np.sqrt(var_h) ** (1-t)
        log_mk1sig_h_1t = np.log(var_h) * (1-t) * 0.5
        mk2detcov_h_1t = (var_h * var_h) ** (1-t)
        log_mk2detcov_h_1t = (1-t) * 2 * np.log(var_h)
        mk2detcov = torch.det(mk2cov)
        sign,log_mk2detcov = torch.logdet(mk2cov)
        mk1_inc = (m1prob ** t) * mk1sig_t / ((mk1sig ** t) * mk1sig_h_1t)# inverse normalising constant I think
        mk2_inc = np.sqrt(((1-m1prob) ** t) * mk2detcov_t / ((mk2detcov ** t) * mk2detcov_h_1t))
        log_mk1_inc = np.log(m1prob) * t + log_mk1sig_t - ((log_mk1sig * t) + log_mk1sig_h_1t) # inverse normalising constant I think
        log_mk2_inc = (np.log(1-m1prob) * t) + 0.5*(log_mk2detcov_t - ((log_mk2detcov * t) + log_mk2detcov_h_1t))
        print("t=",t,"log_mk2detcov_t",log_mk2detcov_t,"log_mk2detcov",log_mk2detcov,"log_mk2detcov_h_1t",log_mk2detcov_h_1t)
        print("t=",t,"mk1_inc=",np.exp(log_mk1_inc),"mk2_inc=",torch.exp(log_mk2_inc))

        #self.mk_logZhat[(0,)] = np.log(mk1_inc / (mk1_inc + mk2_inc))
        #self.mk_logZhat[(1,)] = np.log(mk2_inc / (mk1_inc + mk2_inc))
        self.mk_logZhat[(0,)] = log_mk1_inc - torch.log(np.exp(log_mk1_inc) + torch.exp(log_mk2_inc))
        self.mk_logZhat[(1,)] = log_mk2_inc - torch.log(np.exp(log_mk1_inc) + torch.exp(log_mk2_inc))
        # hack to show forward proposal
        self.mk_logZhat[(0,)] = np.NINF
        self.mk_logZhat[(1,)] = 1.

        if False:
            for mk in mks:
                mk_theta,mk_theta_w = mmmpd.getParticleDensityForModelAndTemperature(mk,t,resample=True,resample_max_size=2000)
                #self.mk_logZhat[mk] = np.log(orig_mkdict[mk].shape[0]*1./1000)
                #self.mk_logZhat[mk] = 0 
                if self.getModelInt(mk)==0:
                    tf1  = n.transforms.InverseTransform(SinArcSinhTransform(ep[0],dp[0]))
                    #tf1  = n.transforms.InverseTransform(L1DTransform(np.sqrt(mk1cov_t)))
                    self.flows[mk] = Flow(tf1,StandardNormal((1,)))
                elif self.getModelInt(mk)==1:
                    tf2  = n.transforms.InverseTransform(n.transforms.CompositeTransform([LTransform(torch.linalg.cholesky(torch.tensor([[1.,.99],[.99,1.]]))),SAS2DTransform([ep[1],ep[2]],[dp[1],dp[2]])]))
                    #tf2  = n.transforms.InverseTransform(LTransform(torch.linalg.cholesky(mk2cov_t)))
                    self.flows[mk] = Flow(tf2,StandardNormal((2,)))
                X = self.extractModelConcatCols(self.concatParameters(mk_theta,mk),mk)
                if PLOT_PROGRESS:
                    tmp1 = self.flows[mk].sample(1000)
                    tmp1=tmp1.detach().numpy()
                    f,ax = plt.subplots(nrows=1,ncols=2)
                    if self.getModelInt(mk)==0:
                        ax[0].hist(X,bins=50,color='red')
                        ax[1].hist(tmp1,bins=50)
                        plt.show()
                    elif self.getModelInt(mk)==1:
                        ax[0].scatter(X[:,0],X[:,1],color='red')
                        ax[1].scatter(tmp1[:,0],tmp1[:,1])
                        plt.show()
            print("MK log Z",self.mk_logZhat)
            print("MK Z",[np.exp(z) for i,z in self.mk_logZhat.items()])
            return

        else:
            for mk in mks:
                mk_theta,mk_theta_w = mmmpd.getParticleDensityForModelAndTemperature(mk,t,resample=True,resample_max_size=2000)
                #mk_theta = orig_theta[orig_mkdict[mk]]
                #self.mk_logZhat[mk] = mmmpd.getlogZForModelAndTemperature(mk,t)
                #self.mk_logZhat[mk] = np.log(orig_mkdict[mk].shape[0]*1./1000)
                #self.mk_logZhat[mk] = mmmpd.getlogZForModelAndTemperature(mk,t)
    
                if self.getModelInt(mk)==0:
                    #b = Uniform(low=torch.Tensor([-100.]),high=torch.Tensor([100.]))
                    #ls = LinearSquish(torch.Tensor([-100.]),torch.Tensor([100.]))
                    ls = n.transforms.Sigmoid()
                    bnorm = StandardNormal((1,))
                    #tf1 = SinArcSinhTransform(ep[0],dp[0])
                    #self.flows[mk] = n.transforms.InverseTransform(tf1)
                    #tf = SinArcSinhTransform(-2,1.0)
                    #self.flows[mk] = tf
                elif self.getModelInt(mk)==1:
                    #b = Uniform(low=torch.Tensor([-100.,-100.]),high=torch.Tensor([100.,100.]))
                    #ls = LinearSquish(torch.Tensor([-100.,-100]),torch.Tensor([100.,100.]))
                    ls = n.transforms.Sigmoid()
                    bnorm = StandardNormal((2,))
                    #tf = n.transforms.CompositeTransform([LTransform(torch.linalg.cholesky(torch.tensor([[1.,.99],[.99,1.]]))),SAS2DTransform([1.5,-2],[1,1.5])])
                    #tf2 = n.transforms.CompositeTransform([LTransform(torch.linalg.cholesky(torch.tensor([[1.,.99],[.99,1.]]))),SAS2DTransform([ep[1],ep[2]],[dp[1],dp[2]])])
                    #tf2 = n.transforms.CompositeTransform([SAS2DTransform([ep[1],ep[2]],[dp[1],dp[2]])])
                    #self.flows[mk] = n.transforms.InverseTransform(tf2)
                    #self.flows[mk] = tf
                    # test it
                    #a,b=tf.inverse(torch.tensor([[1.,1.]]))
                    #print("test out",a,b)
                X = self.extractModelConcatCols(self.concatParameters(mk_theta,mk),mk)
                # Fit betamix to marginals
                #fn = n.transforms.IdentityTransform()
                #bmmt = BetaMixtureMarginalTransform(XX)
                bmmt = n.transforms.IdentityTransform()
                cbmmt = n.transforms.CompositeCDFTransform(n.transforms.Sigmoid(),bmmt)
                if self.proptype=='affine':
                    fn = n.transforms.InverseTransform(NaiveGaussianTransform(torch.Tensor(X)))
                    self.flows[mk] = Flow(fn,bnorm)
                elif self.proptype=='nf':
                    fn = FixedNorm(torch.Tensor(X))
                    #fn = n.transforms.InverseTransform(NaiveGaussianTransform(torch.Tensor(X)))
                    X_,_ = fn.forward(torch.Tensor(X))
                    XX,__ = ls.forward(X_)
                    if PLOT_PROGRESS:
                        #tmp1,tmp1ld = bmmt.forward(XX)
                        tmp1 = XX
                        tmp1=tmp1.detach().numpy()
                        if self.getModelInt(mk)==0:
                            plt.hist(tmp1,bins=50)
                            plt.show()
                        elif self.getModelInt(mk)==1:
                            plt.scatter(tmp1[:,0],tmp1[:,1])
                            plt.show()
                    self.flows[mk] = RationalQuadraticFlow.factory(X,bnorm,bmmt,ls,fn)
                else:
                    #perfect
                    if self.getModelInt(mk)==0:
                        tf  = n.transforms.InverseTransform(SinArcSinhTransform(ep[0],dp[0]))
                    else:
                        tf  = n.transforms.InverseTransform(n.transforms.CompositeTransform([LTransform(torch.linalg.cholesky(torch.tensor([[1.,.99],[.99,1.]]))),SAS2DTransform([ep[1],ep[2]],[dp[1],dp[2]])]))
                    self.flows[mk] = Flow(tf,bnorm)
                if PLOT_PROGRESS:
                    tmp1 = self.flows[mk].sample(1000)
                    tmp1=tmp1.detach().numpy()
                    f,ax = plt.subplots(nrows=1,ncols=2)
                    if self.getModelInt(mk)==0:
                        ax[0].hist(X,bins=50,color='red')
                        ax[1].hist(tmp1,bins=50)
                        plt.show()
                    elif self.getModelInt(mk)==1:
                        ax[0].scatter(X[:,0],X[:,1],color='red')
                        ax[1].scatter(tmp1[:,0],tmp1[:,1])
                        plt.show()
            print("MK Z",self.mk_logZhat)
            print("MK Z",[np.exp(z) for i,z in self.mk_logZhat.items()])