from data.Full_Heart.predict import predict, save_results_full_hearts
from data.data import sample_outer_surface_in_voxel
from utils.registration_utils import shift_2d_replace
from utils.utils_common import Modes, blend_cpu3, gaussian_filter, hist_normalize, mkdir, blend, crop_indices, blend_cpu, append_line, val2str, write_lines, blend_cpu2
from utils.utils_voxel2mesh.file_handle import get_slice_mesh, save_to_obj, save_to_texture_obj
from torch.utils.data import DataLoader
import numpy as np
import torch
from skimage import io
import itertools
import torch.nn.functional as F
import os
from scipy import ndimage
from IPython import embed
import wandb
# from utils.rasterize.rasterize import Rasterize
# from utils import stns
from pytorch3d.structures import Meshes
from utils.rasterize.rasterize2 import rasterize_vol
import cv2 as cv
from data.CHUV.load_stack import resacle, resacle_z
from torchmcubes import marching_cubes
from collect_env import run
import trimesh
import csv
import igl
import pyvista as pv
from pytorch3d.ops import sample_points_from_meshes
from pyremesh import remesh_botsch
from skimage import measure
import torch.nn as nn

class Structure(object):

    def __init__(self,
                voxel=None,
                mesh=None,
                contours2d=None,
                contours3d=None,
                slices=None,
                name=None,
                surface_points=None,
                center=None,
                center_map=None,
                distance_map=None,
                scar_mesh=None,
                scar_map=None,
                myocardium=None,
                mu_scar=None,
                std_scar=None):
        self.voxel = voxel
        self.mesh = mesh
        self.contours2d = contours2d
        self.contours3d = contours3d
        self.surface_points = surface_points
        self.name = name
        self.slices = slices
        self.center = center
        self.center_map = center_map
        self.distance_map = distance_map
        self.scar_map = scar_map
        self.scar_mesh = scar_mesh
        self.myocardium = myocardium
        self.mu_scar = mu_scar
        self.std_scar = std_scar

def write_to_wandb(split, performences):
    log_vals = {}
    for key, value in performences[split].items():
        log_vals[split + '_' + key + '/mean'] = np.mean(performences[split][key])
        num_classes = performences[split][key].shape[-1]
        for i in range(num_classes):
            log_vals[split + '_' + key + '/class_' + str(i+1)] = np.mean(performences[split][key][:, i])
    try:
        wandb.log(log_vals)
    except:
        print('')

class Evaluator(object):
    def __init__(self, net, optimizer, data, save_path, config, support):
        self.data = data
        self.net = net
        self.current_best = None
        self.save_path = save_path + '/best_performance3'
        self.latest = save_path + '/latest'
        self.optimizer = optimizer
        self.config = config
        self.support = support
        self.count = 0

    def save_model(self, epoch):

        torch.save({
            'epoch': epoch,
            'model_state_dict': self.net.state_dict(),
            'optimizer_state_dict': self.optimizer.state_dict()
        }, self.save_path + '/model.pth')

    def evaluate(self, epoch, writer=None, backup_writer=None):
        # self.net.eval()

        performences = {}
        predictions = {}

        modes_to_eval = [Modes.TESTING]
        for split in modes_to_eval:
            dataloader = DataLoader(self.data[split], batch_size=1, shuffle=False)
            performences[split], predictions[split] = self.evaluate_set(dataloader)

            write_to_wandb(split, performences)

        if self.support.update_checkpoint(best_so_far=self.current_best, new_value=performences, metric=self.config.eval_metric):
        # if True:
            print('updating checkpoint...')
            if self.config.trial_id is None:
                mkdir(self.save_path)
                mkdir(self.save_path + '/mesh')
                mkdir(self.save_path + '/points')
                mkdir(self.save_path + '/voxels')
                self.save_model(epoch)
                for mode in modes_to_eval:
                    self.save_results(predictions[mode], epoch, performences[mode], self.save_path, f'/{mode}_', self.config)
                self.current_best = performences
            else:
                mkdir(self.save_path + '_')
                mkdir(self.save_path + '_/mesh')
                mkdir(self.save_path + '_/points')
                mkdir(self.save_path + '_/voxels')
                for mode in modes_to_eval:
                    self.save_results(predictions[mode], epoch, performences[mode], self.save_path + '_', f'/{mode}_', self.config)
            print('Saving complete!')
        print('Eval done!')
        self.net.eval()
        self.net.train()

    def predict(self, data, config):
        name = config.name
        if name == 'unet':
            self.save_results = self.save_results_unet
            name = data['name']
            y_hat, _ = self.net(data)
            y_hat = torch.argmax(y_hat, dim=1).cpu()

            x = data['x'].cpu()
            y = Structure(voxel=data['y_scar'].cpu(), name=name)
            y_hat = Structure(voxel=y_hat)

        elif name == 'full_heart':
            self.save_results = save_results_full_hearts
            x, y, y_hat = predict(self.net, data, config)

        elif name == 'voxel2mesh':
            self.save_results = self.save_results_v2m
            scale_factor = config.scale_factor
            x = data['x']
            # x = data['x_high_res']
            # y_ = data['y_voxels']
            name = data['name']
            resolution = data['resolution'].cpu()

            pred, data = self.net(data, mode=Modes.TESTING)
            pred_localizer = pred['register']
            pred_voxel2mesh = pred['voxel2mesh']
            pred_scarnet = pred['scarnet']

            x = data['x']
            y = data['y_voxels']

            pred_meshes = []
            true_meshes = []
            true_contours2d = []
            pred_contours2d = []
            true_contours3d = []
            pred_contours3d = []
            pred_scar_meshes = []
            true_scar_meshes = []

            nonzero = y.cpu().sum(dim=[2,3]).nonzero()[:,1]
            clip_min = nonzero.min() if y.sum() > 0 else 0
            clip_max = (nonzero.max() + 1) if y.sum() > 0 else y.shape[1]

            shape = torch.tensor(x.shape)
            shape = shape[2:].flip([0]) # flip() because we flip the ijk values in data laoder
            # shape = torch.tensor(x.shape[2:]).flip(0)[None, None].float().cuda()

            x_original = x.clone()
            x = torch.from_numpy(hist_normalize(x[0, 0].cpu().numpy())).cuda().float()
            # x = torch.from_numpy(x[0, 0].cpu().numpy()).cuda().float()
            x = (x-x.min())/(x.max()-x.min())
            x = resacle(x, scale_factor=scale_factor)[None, None].cpu()

            slice_grid, slice_grid_uv, grid_faces = get_slice_mesh(x, scale_factor)

            slices = {}
            for slice_id in range(clip_min, clip_max):
                z = slice_id * torch.ones(slice_grid.shape[0])[:, None]
                grid = torch.cat([slice_grid, z], dim=1)[None]
                grid = grid * resolution
                slices[slice_id] = {'slice_vertices':grid, 'slice_uv':slice_grid_uv, 'slice_faces': grid_faces, 'image':x[0, 0, slice_id]}

            pred_voxels_rasterized_all = []
            true_voxels_all = []

            surface_points_all = []

            for c in range(self.config.lv_num_classes-1):
                # embed()

                pred_vertices = pred_voxel2mesh[c][-1][0].detach().data.cpu()
                pred_faces = pred_voxel2mesh[c][-1][1].detach().data.cpu()
                pred_probs = pred_voxel2mesh[c][-1][3].detach().data.cpu()
                pred_meshes += [{'vertices': (pred_vertices/2 + 0.5) * (shape-1) * resolution, 'faces':pred_faces, 'normals':None}]

                if len(data['true_verts']) > 0:
                    true_vertices = data['true_verts'][c].data.cpu()
                    true_faces = data['true_faces'][c].data.cpu()
                    true_contour2d = data['true_contours'][c]  # True contour is in non-scaled x coordinates
                    surface_points = data['surface_points'][c]
                    surface_points_all += [(surface_points.cpu()/2 + 0.5) * (shape-1) * resolution]
                    true_meshes += [{'vertices': (true_vertices/2 + 0.5) * (shape-1) * resolution, 'faces':true_faces, 'normals':None}]

                    true_contours2d += [true_contour2d]

                    true_voxels_ = np.uint8(torch.zeros_like(x[0, 0]).numpy())
                    true_contour3d = []
                    for slice_id, contour in true_contour2d.items():
                        contour = contour.numpy()[0]
                        true_voxels_[slice_id] = cv.fillPoly(true_voxels_[slice_id], [np.int64(scale_factor * contour)], (1, 0, 0))
                        # true_voxels_[z] = cv.drawContours(true_voxels_[z], [scale_factor * contour], -1, (1, 0, 0), 1)

                        z = slice_id * np.ones(contour.shape[0])[:, None]
                        contour_3d = np.concatenate([contour, z], axis=1)
                        contour_3d = contour_3d[None] * resolution.numpy()
                        true_contour3d += [contour_3d]
                    true_voxels_all += [torch.from_numpy(true_voxels_)[None].long()]

                    true_contour3d = torch.from_numpy(np.concatenate(true_contour3d, axis=1))
                    N = true_contour3d.shape[1]
                    indices = torch.arange(N)[:, None]
                    true_contour3d_faces = torch.cat([indices, indices, torch.roll(indices, dims=0, shifts=[1])], dim=1)[None]
                    true_contours3d += [{'vertices': true_contour3d, 'faces':true_contour3d_faces, 'normals':None}]

                else:
                    true_vertices = true_faces = true_contour2d = surface_points = true_contour3d = true_voxels_all = true_contours2d = true_meshes = true_contours3d = None
                    # true_meshes += [{'vertices': None, 'faces':None, 'normals':None}]
                    # true_contours3d += [{'vertices': None, 'faces':None, 'normals':None}]

                verts = torch.flip(pred_vertices, [2])
                faces = pred_faces
                mesh = Meshes(verts=verts.detach(), faces=faces.detach().long())
                pred_voxels_rasterized = rasterize_vol(mesh, x.shape[2:])
                pred_voxels_rasterized_all += [pred_voxels_rasterized[None].cpu()]

                # Pred contour is in non-scaled x coordinates
                pred_contour2d = {}
                pred_contour3d = []
                for slice_id, slice in enumerate(pred_voxels_rasterized.numpy()):
                    _, contours, _ = cv.findContours(np.uint8(slice>0), cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
                    for k, ctrs in enumerate(contours):
                        if k == 0:
                            pred_contour2d[slice_id] = []
                        ctrs = np.squeeze(ctrs)/scale_factor
                        pred_contour2d[slice_id] += [ctrs]

                        if len(ctrs.shape) == 1:
                            z = slice_id * np.ones(1)[:, None]
                            ctrs = ctrs[None]
                        else:
                            z = slice_id * np.ones(ctrs.shape[0])[:, None]

                        contour_3d = np.concatenate([ctrs, z], axis=1)
                        contour_3d = contour_3d[None] * resolution.numpy()
                        pred_contour3d += [contour_3d]
                        # canvas[z] = cv.drawContours(slice, [ctrs], -1, (128, 128, 0), 1)

                pred_contours2d += [pred_contour2d]

                pred_contour3d = torch.from_numpy(np.concatenate(pred_contour3d, axis=1))
                N = pred_contour3d.shape[1]
                indices = torch.arange(N)[:, None]
                pred_contour3d_faces = torch.cat([indices, indices, torch.roll(indices, dims=0, shifts=[1])], dim=1)[None]
                pred_contours3d += [{'vertices': pred_contour3d, 'faces':pred_contour3d_faces, 'normals':None}]

                # scar extraction

            pred_voxels = torch.zeros_like(x)[:,0].long()
            pred_voxels[pred_voxels_rasterized_all[1]==1] = 2 # outer
            pred_voxels[pred_voxels_rasterized_all[0]==1] = 1 # inner
            pred_voxels = pred_voxels.cpu()

            true_voxels = torch.zeros_like(x)[:,0].long()
            if y.sum() > 0:
                true_voxels[true_voxels_all[1]==1] = 2 # outer
                true_voxels[true_voxels_all[0]==1] = 1 # inner

            # -----------------------
            # Scar extraction
            # -----------------------

            yhat_scars = torch.argmax(pred_scarnet, dim=1)
            # yhat_scars = torch.zeros_like(data['y_scar'])
            # for i in range(1, self.config.nu m_classes):
            #     yhat_scars[pred_scarnet[:,i]>0] = i+1
            y_scars = data['y_scar']

            x_scar = x_original.clone()[0,0]
            x_scar[yhat_scars[0]!=1] = 0

            mu_scar = torch.sum(x_scar, dim=[1,2])/torch.sum(yhat_scars[0]==1, dim=[1,2])

            std_scar = (x_original.clone()[0,0]-mu_scar[:, None, None]) ** 2
            std_scar[yhat_scars[0]!=1] = 0
            std_scar = torch.sqrt(torch.sum(std_scar, dim=[1,2])/(torch.sum(yhat_scars[0]==1, dim=[1,2])-1))

            y_myocardium = data['y_myocardium']

            val = 1
            valz = 9
            # val = 3
            # valz = 3
            filter_dim = (valz,val,val)
            filter_pad = (valz//2, val//2, val//2)
            # filter = gaussian_filter(filter_dim, sigma=1)
            # filter_op = nn.Conv3d(in_channels=1, out_channels=1, kernel_size=filter_dim, padding=filter_pad)
            # filter_op.weight.data = filter[None, None]
            # filter_op.bias.data.fill_(0.0)
            # filter_op.cuda()
            # pred_contours2d = []
            # pred_contours3d = []

            for sc in [1, 2, 3]:
                # if sc == 1:
                #     yhat_scars_ = (yhat_scars>0).float()[0]
                # else:
                #     yhat_scars_ = (yhat_scars==sc).float()[0]

                # # io.imsave('/cvlabdata2/cvlab/datasets_udaranga/outputs/before.tif', yhat_scars_.cpu().numpy())
                # yhat_scars_ = resacle_z(yhat_scars_.float(), scale_factor=5.9)
                # # io.imsave('/cvlabdata2/cvlab/datasets_udaranga/outputs/after.tif', yhat_scars_.float().cpu().numpy())

                # yhat_scars_ = filter_op(yhat_scars_[None, None].float())[0,0].detach()
                # # io.imsave('/cvlabdata2/cvlab/datasets_udaranga/outputs/after.tif', a.cpu().numpy())
                # level = (yhat_scars_.max() + yhat_scars_.min())/2
                # # level = (0.25*yhat_scars_.max() + 0.75*yhat_scars_.min())

                # try:
                #     scar_verts_, scar_faces_, _, _ = measure.marching_cubes(yhat_scars_.cpu().numpy(), level=level.item(), allow_degenerate=False)
                # except:
                #     embed()
                # scar_verts_ = np.ascontiguousarray(scar_verts_)
                # scar_faces_ = np.ascontiguousarray(scar_faces_)
                # # scar_verts = torch.flip(torch.from_numpy(scar_verts_), dims=[1]) * resolution[0]
                # scar_verts = torch.flip(torch.from_numpy(scar_verts_), dims=[1])
                # scar_faces = torch.from_numpy(scar_faces_)

                # yhat_scars__ = resacle_z(yhat_scars_.float(), scale_factor=1/5.87)
                # yhat_scars__ = resacle(yhat_scars__, scale_factor=scale_factor, mode='bilinear')
                # pred_voxels_rasterized =  (yhat_scars__ > 0.5).long().detach().cpu()

                # # Pred contour is in non-scaled x coordinates
                # if sc == 1:
                #     pred_contour2d = {}
                #     pred_contour3d = []
                #     for slice_id, slice in enumerate(pred_voxels_rasterized.cpu().numpy()):
                #         _, contours, _ = cv.findContours(np.uint8(slice>0), cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

                #         for k, ctrs in enumerate(contours):
                #             # embed()
                #             # a = np.uint8(slice>0)
                #             # io.imsave('/cvlabdata2/cvlab/datasets_udaranga/outputs/pred_voxels.tif', 255*a)
                #             if k == 0:
                #                 pred_contour2d[slice_id] = []
                #             ctrs = np.squeeze(ctrs)/scale_factor
                #             pred_contour2d[slice_id] += [ctrs]

                #             if len(ctrs.shape) == 1:
                #                 z = slice_id * np.ones(1)[:, None]
                #                 ctrs = ctrs[None]
                #             else:
                #                 z = slice_id * np.ones(ctrs.shape[0])[:, None]

                #             contour_3d = np.concatenate([ctrs, z], axis=1)
                #             contour_3d = contour_3d[None] * resolution.numpy()
                #             pred_contour3d += [contour_3d]
                #             # canvas[z] = cv.drawContours(slice, [ctrs], -1, (128, 128, 0), 1)

                #     pred_contours2d += [pred_contour2d]
                #     pred_contour3d = torch.from_numpy(np.concatenate(pred_contour3d, axis=1))
                #     N = pred_contour3d.shape[1]
                #     indices = torch.arange(N)[:, None]
                #     pred_contour3d_faces = torch.cat([indices, indices, torch.roll(indices, dims=0, shifts=[1])], dim=1)[None]
                #     pred_contours3d += [{'vertices': pred_contour3d, 'faces':pred_contour3d_faces, 'normals':None}]

                # scar_verts, scar_faces = trimesh.remesh.subdivide(scar_verts.numpy(), scar_faces.numpy())
                # scar_verts = torch.from_numpy(scar_verts)
                # scar_faces = torch.from_numpy(scar_faces)

                # pred_scar_meshes += [{'vertices': scar_verts[None], 'faces':scar_faces[None], 'normals':None}]
                # save_to_obj('/cvlabdata2/cvlab/datasets_udaranga/outputs/mesh.obj', scar_verts[None], scar_faces[None], None)

                if sc == 1:
                    y_scars_ = (data['y_scar']>0).float()[0]
                else:
                    y_scars_ = (data['y_scar']==sc).float()[0]
                scar_verts, scar_faces = marching_cubes(y_scars_, 0.5)
                scar_verts = scar_verts.cpu() * resolution[0]
                scar_faces = scar_faces.cpu()
                true_scar_meshes += [{'vertices': scar_verts[None], 'faces':scar_faces[None], 'normals':None}]
                pred_scar_meshes += [{'vertices': scar_verts[None], 'faces':scar_faces[None], 'normals':None}]
                # break

            yhat_scars = resacle(yhat_scars[0].float(), scale_factor=scale_factor)[None].detach().cpu()
            y_scars = resacle(y_scars[0].float(), scale_factor=scale_factor)[None].detach().cpu()
            y_myocardium = resacle(y_myocardium[0].float(), scale_factor=scale_factor)[None].cpu().long()
            yhat_myocardium = (pred_voxels == 2).long()

            yhat_scars = yhat_scars.long()
            y_scars = y_scars.long()

            # -----------------------
            # io.imsave('/cvlabdata2/cvlab/datasets_udaranga/outputs/pred_voxels.tif', np.uint8(255 * y_scars_1.cpu().numpy()))
            # save_to_obj('/cvlabdata2/cvlab/datasets_udaranga/outputs/mesh.obj', scar_verts[None], scar_faces[None], None)
            # -----------------------
            _, _, yhat_center_seg, yhat_center_ = pred_localizer
            y_dist = data['y_dist']
            yhat_center_seg = 0 * torch.argmax(yhat_center_seg, dim=1).cpu()

            y_centers = torch.amax(y_dist[0], dim=(1,2))
            y_centers = torch.logical_and(y_dist[0]==y_centers[:, None, None], y_dist[0] > 0.5)
            y_centers_coords_ = torch.nonzero(y_centers)
            y_centers_coords = {}

            for p in y_centers_coords_:
                y_centers_coords[p[0].item()] = p[1:][None]
            y_center = y_centers_coords

            y_center_seg = 0 * data['y_voxels']
            # y_center_seg[y_center_seg>1] = 1

            for k, v in y_center.items():
                y_center_seg[:, k, v[0, 0].long().item(), (v[0, 1].long().item()-5):(v[0, 1].long().item()+5)] = 3
                y_center_seg[:, k, (v[0, 0].long().item()-5):(v[0, 0].long().item()+5), v[0, 1].long().item()] = 3

            yhat_center = {}
            for k, v in enumerate(yhat_center_[0]):
                yhat_center[k] = v[None]
                yhat_center_seg[:, k, (v[0].long().item()-5):(v[0].long().item()+5), v[1].long().item()] = 2
                yhat_center_seg[:, k, v[0].long().item(), (v[1].long().item()-5):(v[1].long().item()+5)] = 2

                if k in y_center.keys():
                    v = y_center[k].cpu()
                    yhat_center_seg[:, k, v[0, 0].long().item(), (v[0, 1].long().item()-5):(v[0, 1].long().item()+5)] = 3
                    yhat_center_seg[:, k, (v[0, 0].long().item()-5):(v[0, 0].long().item()+5), v[0, 1].long().item()] = 3

            yhat_center_seg = resacle(yhat_center_seg[0].float().cuda(), scale_factor=scale_factor)[None].long().cpu()
            y_center_seg = resacle(y_center_seg[0].float().cuda(), scale_factor=scale_factor)[None].long().cpu()

            # -----------------------

            x = x.detach().data.cpu()
            y = Structure(mesh=true_meshes,
                            contours2d=true_contours2d,
                            voxel=true_voxels,
                            contours3d=true_contours3d,
                            name=name,
                            slices=slices,
                            surface_points=surface_points_all,
                            scar_mesh=true_scar_meshes,
                            scar_map=y_scars,
                            myocardium=y_myocardium,
                            center_map=y_center_seg,
                            mu_scar=data['mu_scar'],
                            std_scar=data['std_scar'])

            y_hat = Structure(mesh=pred_meshes,
                            contours2d=pred_contours2d,
                            voxel=pred_voxels,
                            contours3d=pred_contours3d,
                            scar_mesh=pred_scar_meshes,
                            myocardium=yhat_myocardium,
                            scar_map=yhat_scars,
                            center_map=yhat_center_seg,
                            mu_scar=mu_scar,
                            std_scar=std_scar)

        x = (x - torch.min(x)) / (torch.max(x) - torch.min(x))
        return x, y, y_hat

    def evaluate_set(self, dataloader):
        performance = {}
        predictions = []

        for i, data in enumerate(dataloader):
            # a = run('nvidia-smi')
            # mem = int(a[1].split('\n')[9][35:40])
            # print(f'{i}:  {mem}')

            x, y, y_hat = self.predict(data, self.config)
            result = self.support.evaluate(y, y_hat, self.config)

            predictions.append((x, y, y_hat))

            for key, value in result.items():
                if key not in performance:
                    performance[key] = []
                performance[key].append(result[key])

        for key, value in performance.items():
            performance[key] = np.array(performance[key])
        return performance, predictions

    def drawContours(self, y_voxel_z, contour, color, line_width):
        try:
            y_voxel_z = cv.drawContours(y_voxel_z, [contour], -1, color, line_width)
        except:
            print('cv drawContours error')
        return y_voxel_z

    def fillPoly(self, y_voxel_z, contour):
        try:
            y_voxel_z = cv.fillPoly(y_voxel_z, [contour], (1, 0, 0))
        except:
            print('cv fillPoly error')
        return y_voxel_z

    def scar_dist2mask(self, scarmap, mask):
        yhat_scars = torch.zeros_like(scarmap).long()
        # yhat_scars[scarmap<=2] = 1
        yhat_scars[scarmap>2] = 2
        yhat_scars[scarmap>5] = 3

        yhat_scarmap = mask * yhat_scars

        return yhat_scarmap

        # yhat_scarmap = yhat_scarmap.cuda()
        # yhat_scarmap_ = torch.zeros_like(yhat_scarmap)

        # for k_scar in range(1, 4):
        #     k_scarmap = sample_outer_surface_in_voxel((yhat_scarmap==k_scar).long())
        #     yhat_scarmap_[k_scarmap] = k_scar
        # return yhat_scarmap_.cpu()

    def save_results_v2m(self, predictions, epoch, performence, save_path, mode, config):

        xs = []
        ys_voxels = []
        y_hats_voxels = []
        overlays = []
        names = []

        scar_stats = []
        scarhat_stats = []

        stacks = []
        colors= [(0, 0, 255), (0, 255, 0), (0, 0, 192), (0, 192, 0), (0, 255, 255)]

        line_width = 2 if config.scale_factor >1 else 1
        fontScale = 1 if config.scale_factor >1 else 0.3
        color = (255, 0, 0)
        thickness = 2 if config.scale_factor >1 else 1
        font = cv.FONT_HERSHEY_SIMPLEX
        for i_main, data in enumerate(predictions):

            x, y, y_hat = data

            nonzero = torch.nonzero(x.sum(dim=[3,4]))[:,2]
            clip_min, clip_max = (nonzero.min(), nonzero.max()+1)

            names += [y.name[0]]
            # embed()

            xs_ = []
            for x_ in x[0, 0]:
                x_ = np.uint8(255*np.repeat(x_[..., None].clone().numpy(), 3, axis=2))
                # x_ = cv.putText(x_, y.name[0][7:], (5, 8*self.config.scale_factor) , font, fontScale, color, thickness, cv.LINE_AA)
                x_ = cv.putText(x_, y.name[0], (5, 8*config.scale_factor) , font, fontScale, color, thickness, cv.LINE_AA)

                k = 0
                for _, (key, value) in enumerate(performence.items()):
                    if len(value.shape) == 2:
                        # str_ = f'{key[:7]}: '+', '.join(['{:.2f}' for _ in range(config.num_classes-1)]).format(*100*value[i_main])
                        str_ = f'{key}: ' + ', '.join(map(val2str, 100*value[i_main]))
                        # x_ = cv.putText(x_, str_, (5, 16*config.scale_factor + k*8*config.scale_factor) , font, fontScale, color, thickness, cv.LINE_AA)
                        k += 1
                xs_ += [x_[None]]
            xs_ = np.concatenate(xs_, axis=0)
            xs__ = np.copy(xs_)

            if y_hat.contours3d is not None:
                save_path_i = f'{save_path}/mesh/{i_main}'
                mkdir(save_path_i)
                for p, (true_points, pred_points) in enumerate(zip(y.contours3d, y_hat.contours3d)):
                    save_to_obj(save_path_i + '/' + mode + 'true_' + str(i_main) + '_part_' + str(p) + '_contour.obj', true_points['vertices'], true_points['faces'])
                    save_to_obj(save_path_i + '/' + mode + 'pred_' + str(i_main) + '_part_' + str(p) + '_contour.obj', pred_points['vertices'], pred_points['faces'])

            if y.mesh is not None:
                save_path_i = f'{save_path}/mesh/{i_main}'
                mkdir(save_path_i)
                for p, true_mesh in enumerate(y.mesh):
                    save_to_obj(save_path_i + '/' + mode + 'true_' + str(i_main) + '_part_' + str(p) + '_mesh.obj', true_mesh['vertices'], true_mesh['faces'], true_mesh['normals'])

            if y_hat.mesh is not None:
                save_path_i = f'{save_path}/mesh/{i_main}'
                mkdir(save_path_i)
                for p, pred_mesh in enumerate(y_hat.mesh):
                    save_to_obj(save_path_i + '/' + mode + 'pred_' + str(i_main) + '_part_' + str(p) + '_mesh.obj', pred_mesh['vertices'], pred_mesh['faces'], pred_mesh['normals'])

            # if y.surface_points is not None:
            #     save_path_i = f'{save_path}/mesh/{i}'
            #     mkdir(save_path_i)
            #      for p, true_surface_points in enumerate(y.surface_points):
            #         save_to_obj(save_path_i + '/' + mode + 'true_' + str(i) + '_part_' + str(p) + '_surface_points.obj', true_surface_points, None, None)

            if y.scar_mesh is not None:
                for p, true_mesh in enumerate(y.scar_mesh):
                    save_to_obj(save_path_i + '/' + mode + 'true_scar_' + str(i_main) + '_region_' + str(p) + '_mesh.obj', true_mesh['vertices'], true_mesh['faces'], true_mesh['normals'])

            if y_hat.scar_mesh is not None:
                for p, pred_mesh in enumerate(y_hat.scar_mesh):
                    save_to_obj(save_path_i + '/' + mode + 'pred_scar_' + str(i_main) + '_region_' + str(p) + '_mesh.obj', pred_mesh['vertices'], pred_mesh['faces'], pred_mesh['normals'])

            y_hat_voxel = np.copy(xs_)
            y_hat_voxels_ = []
            if y_hat.contours2d is not None:
                for k, y_hat_ in enumerate(y_hat.contours2d):
                    y_hat_voxel_ = np.uint8(np.zeros_like(xs_[:,:,:,0]))
                    for z, contours in y_hat_.items():
                        for contour in contours:
                            contour = np.int64(config.scale_factor * contour)
                            y_hat_voxel[z] = self.drawContours(y_hat_voxel[z], contour, colors[k], line_width) # --------------------
                            y_hat_voxel_[z] = self.fillPoly(y_hat_voxel_[z], contour)
                    y_hat_voxels_ += [y_hat_voxel_]

            y_voxel = np.copy(xs_)
            overlap = np.copy(xs_)
            if y.contours2d is not None:
                y_voxel_ = np.uint8(np.zeros_like(xs_[:,:,:,0]))
                overlap = np.uint8(np.zeros_like(xs_[:,:,:,0]))
                for k, y_ in enumerate(y.contours2d):
                    for z, contour in y_.items():
                        contour = np.int64(config.scale_factor * contour.numpy())[0]
                        y_voxel[z] = self.drawContours(y_voxel[z], contour, colors[0], line_width) # --------------------
                        y_voxel_[z] = self.fillPoly(y_voxel_[z], contour)
                    # overlap += np.uint8(np.logical_xor(y_voxel_, y_hat_voxels_[k]))
                overlap = np.uint8(255*np.repeat(overlap[..., None], 3, axis=3))
                overlap = blend_cpu2(torch.from_numpy(xs_).float(), torch.from_numpy(np.uint8(overlap[:,:,:,0]>0))*2, 3, factor=0.5) # *2 is hack to get the overlay the color red

                for k, y_hat_ in enumerate(y_hat.contours2d):
                    for z, contours in y_hat_.items():
                        for contour in contours:
                            contour = np.int64(config.scale_factor * contour)
                            overlap[z] = self.drawContours(overlap[z], contour, colors[k], line_width)

            if y_hat.scar_map is not None and y_hat.scar_map.sum() > 0:

                # y_hat_voxel = blend_cpu3(torch.from_numpy(y_hat_voxel).float(), y_hat.scar_map[0], y_hat.myocardium[0], factor=0.65) # *2 is hack to get the overlay the color red
                if config.regress_scar:
                    yhat_scarmap = self.scar_dist2mask(y_hat.scar_map[0], y_hat.myocardium[0])
                    y_hat_voxel = blend_cpu2(torch.from_numpy(y_hat_voxel).float(), yhat_scarmap, config.scar_num_classes, factor=0.6) # *2 is hack to get the overlay the color red
                else:
                    yhat_scarmap = y_hat.scar_map[0]
                    y_hat_voxel = blend_cpu2(torch.from_numpy(y_hat_voxel).float(), yhat_scarmap, config.scar_num_classes, factor=0.6) # *2 is hack to get the overlay the color red

            if y.scar_map is not None and y.scar_map.sum() > 0:
                # y_voxel = blend_cpu3(torch.from_numpy(y_voxel).float(), y.scar_map[0], y.myocardium[0], factor=0.65) # *2 is hack to get the overlay the color red
                if config.regress_scar:
                    y_scarmap = self.scar_dist2mask(y.scar_map[0], y.myocardium[0])
                    y_voxel = blend_cpu2(torch.from_numpy(y_voxel).float(), y_scarmap, config.scar_num_classes, factor=0.6) # *2 is hack to get the overlay the color red
                else:
                    y_scarmap = y.scar_map[0]
                    y_voxel = blend_cpu2(torch.from_numpy(y_voxel).float(), y_scarmap, config.scar_num_classes, factor=0.6) # *2 is hack to get the overlay the color red

            # if y_hat.center_map is not None and y_hat.center_map.sum() > 0:
            #     # overlap = blend_cpu2(torch.from_numpy(overlap).float(), y_hat.center_map[0], 4, factor=0.3) # *2 is hack to get the overlay the color red
            #     y_hat_voxel = blend_cpu(torch.from_numpy(y_hat_voxel).float(), y_hat.center_map[0], 4, factor=0) # *2 is hack to get the overlay the color red
            # if y.center_map is not None and y.center_map.sum() > 0:
            #     # overlap = blend_cpu2(torch.from_numpy(overlap).float(), y.center_map[0], 4, factor=0.3) # *2 is hack to get the overlay the color red
            #     y_voxel = blend_cpu(torch.from_numpy(y_voxel).float(), y.center_map[0], 4, factor=0) # *2 is hack to get the overlay the color red
            # embed()
            xs_ = []
            for p, x_ in enumerate(y_voxel):
                # x_ = cv.putText(x_, 'Image', (260, 620) , font, fontScale, color, thickness, cv.LINE_AA)
                x_ = cv.putText(x_, 'Image + Ground truth', (140, 620) , font, fontScale, color, thickness, cv.LINE_AA)
                value = performence['y_N']
                th1, th2, lv = value[i_main][p]/(config.scale_factor**2)
                x_ = cv.putText(x_, f'Th1<Voxels<=Th2: {th1}[N], {th1 * 1 * 1 * 6 / 1000:.2f}[ml]', (5, 16*config.scale_factor + 0*8*config.scale_factor) , font, fontScale, color, thickness, cv.LINE_AA)
                x_ = cv.putText(x_, f'Voxels>Th2: {th2}[N], {th2 * 1 * 1 * 6 / 1000:.2f}[ml]', (5, 16*config.scale_factor + 1*8*config.scale_factor) , font, fontScale, color, thickness, cv.LINE_AA)
                x_ = cv.putText(x_, f'LV: {lv}[N], {lv * 1 * 1 * 6 / 1000:.2f}[ml] ', (5, 16*config.scale_factor + 2*8*config.scale_factor) , font, fontScale, color, thickness, cv.LINE_AA)

                xs_ += [x_[None]]
            y_voxel = np.concatenate(xs_, axis=0)

            xs_ = []
            for p, x_ in enumerate(y_hat_voxel):
                x_ = cv.putText(x_, 'Image + HEARTS output', (140, 620) , font, fontScale, color, thickness, cv.LINE_AA)
                value = performence['yhat_N']
                yhatth1, yhatth2, yhatlv = value[i_main][p]/(config.scale_factor**2)
                # yth1, yth2, ylv = performence['y_N'][i_main][p]/(config.scale_factor**2)
                x_ = cv.putText(x_, f'Th1<Voxels<=Th2: {yhatth1}[N], {yhatth1 * 1 * 1 * 6 / 1000:.2f}[ml]', (5, 16*config.scale_factor + 0*8*config.scale_factor) , font, fontScale, color, thickness, cv.LINE_AA)
                x_ = cv.putText(x_, f'Voxels>Th2: {yhatth2}[N], {yhatth2 * 1 * 1 * 6 / 1000:.2f}[ml]', (5, 16*config.scale_factor + 1*8*config.scale_factor) , font, fontScale, color, thickness, cv.LINE_AA)
                x_ = cv.putText(x_, f'LV: {yhatlv}[N], {yhatlv * 1 * 1 * 6 / 1000:.2f}[ml]', (5, 16*config.scale_factor + 2*8*config.scale_factor) , font, fontScale, color, thickness, cv.LINE_AA)

                xs_ += [x_[None]]
            y_hat_voxel = np.concatenate(xs_, axis=0)

            xs.append(xs__[clip_min:clip_max])
            ys_voxels.append(y_voxel[clip_min:clip_max])
            y_hats_voxels.append(y_hat_voxel[clip_min:clip_max])
            overlays.append(overlap[clip_min:clip_max])

            if y.slices is not None:
                stacks += [y.slices]
                # for slice_id, slice in y.slices.items():
                #     file_name = f'slice_{slice_id}'
                #     save_path_i = f'{save_path}/mesh/{i_main}'

                #     # print(save_path_i)
                #     # print(slice_id)
                #     # save_to_texture_obj(save_path_i, file_name, slice['slice_vertices'], slice['slice_faces'], slice['slice_uv'], slice['image'])
                #     img = torch.from_numpy(y_hat_voxel[slice_id]).float()
                #     img = torch.flip(img, dims=[0])
                #     save_to_texture_obj(save_path_i, file_name, slice['slice_vertices'], slice['slice_faces'], slice['slice_uv'], img)

        xs = np.concatenate(xs, axis=0)
        overlays = np.concatenate(overlays, axis=0)
        ys_voxels = np.concatenate(ys_voxels, axis=0)
        y_hats_voxels = np.concatenate(y_hats_voxels, axis=0)

        overlay = np.concatenate([xs, ys_voxels, y_hats_voxels], axis=2)
        io.imsave(save_path + mode + 'overlay_y_hat.tif', overlay)

        if performence is not None:
            for key in ['jaccard_lv', 'jaccard_scar']:
            # for key, value in performence.items():
                performence_mean = np.mean(performence[key], axis=0)
                summary = f'{key}-{epoch}: ' + ', '.join(map(val2str, 100*performence_mean)) + ' | mu: ' + val2str(100*np.mean(performence_mean))
                append_line(save_path + mode + 'summary' + key + '.txt', summary)
                print(summary)
                # all_results = [('{}: ' + ', '.join(['{:.8f}' for _ in range(config.num_classes-1)])).format(*((i+1,) + tuple(vals))) for i, vals in enumerate(performence[key])]
                # print(all_results)

            write_lines(save_path + mode + 'scar_volume' + '.txt', '')
            y_N = performence['y_N']
            yhat_N = performence['yhat_N']

            scar_error = []
            f = open(save_path + mode + 'scar_volume_per_slice.csv', 'w')
            writer = csv.writer(f)
            writer.writerow(['file name',
                            'LV[ml] - Gt',
                            'LV[ml] - HeARTS',
                            'Th1 < Voxels <= Th2[ml] - Gt',
                            'Th1 < Voxels <= Th2[ml] - HeARTS',
                            'Volume > Thr2[ml] - Gt',
                            'Volume > Thr2[ml] - HeARTS'])
            f2 = open(save_path + mode + 'scar_volume_total.csv', 'w')
            writer2 = csv.writer(f2)
            writer2.writerow(['file name',
                            'LV[ml] - Gt',
                            'LV[ml] - HeARTS',
                            'Th1 < Voxels <= Th2[ml] - Gt',
                            'Th1 < Voxels <= Th2[ml] - HeARTS',
                            'Volume > Thr2[ml] - Gt',
                            'Volume > Thr2[ml] - HeARTS'])

            for fileID, (y_N_i, yhat_N_i) in enumerate(zip(y_N, yhat_N)):
                name = names[fileID]

                y_N_volume = 0
                yhat_N_volume = 0
                for y_N_ij, yhat_N_ij in zip(y_N_i, yhat_N_i):
                    if y_N_ij.sum() > 0:
                        y_N_ij = y_N_ij/(config.scale_factor**2)
                        yhat_N_ij = yhat_N_ij/(config.scale_factor**2)

                        y_N_ij_volume = y_N_ij * 1 * 1 * 6 / 1000
                        yhat_N_ij_volume = yhat_N_ij * 1 * 1 * 6 / 1000

                        y_N_volume += y_N_ij_volume
                        yhat_N_volume += yhat_N_ij_volume
                        writer.writerow([name,
                                        f'{y_N_ij_volume[2]:.2f}',
                                        f'{yhat_N_ij_volume[2]:.2f}',
                                        f'{y_N_ij_volume[0]:.2f}',
                                        f'{yhat_N_ij_volume[0]:.2f}',
                                        f'{y_N_ij_volume[1]:.2f}',
                                        f'{yhat_N_ij_volume[1]:.2f}'])

                        values = ', '.join(map(val2str, y_N_ij)) + ', ' + ', '.join(map(val2str, yhat_N_ij))
                        append_line(save_path + mode + 'scar_volume_per_slice' + '.txt',values)

                        error = np.abs(y_N_ij - yhat_N_ij)
                        scar_error += [error[None]]
                writer.writerow([''])
                writer2.writerow([name,
                                f'{y_N_volume[2]:.2f}',
                                f'{yhat_N_volume[2]:.2f}',
                                f'{y_N_volume[0]:.2f}',
                                f'{yhat_N_volume[0]:.2f}',
                                f'{y_N_volume[1]:.2f}',
                                f'{yhat_N_volume[1]:.2f}'])
            f.close()
            f2.close()
            scar_error = np.concatenate(scar_error, axis=0)
            mean_scar_error = np.mean(scar_error,axis=0)
            std_scar_error = np.std(scar_error,axis=0)
            summary = f'scar-[error-mean]-{epoch}: ' + ', '.join(map(val2str, mean_scar_error)) + ' | mu: ' + val2str(np.mean(mean_scar_error))
            print(summary)
            summary = f'scar[error-std]-{epoch}: ' + ', '.join(map(val2str, std_scar_error)) + ' | mu: ' + val2str(np.mean(std_scar_error))
            print(summary)

            # # embed()
            # yscar_myocardium = y_scars > 0

            # surf1 = Meshes(verts=list(pred_meshes[0]['vertices']), faces=list(pred_meshes[0]['faces'])) # inner
            # surf2 = Meshes(verts=list(pred_meshes[1]['vertices']), faces=list(pred_meshes[1]['faces'])) # outer
            # surf_points = [sample_points_from_meshes(surf2, 6000), sample_points_from_meshes(surf1, 6000)]

            # pred_contour3d = {}
            # pred_contour3d[0] = []
            # pred_contour3d[1] = []
            # scenters = {}
            # scenters[0] = []
            # scenters[1] = []

            # shifts = {}
            # k = 0 # k = 0 outer, k = 1 inner
            # gap = 6
            # for slice_id, slice in enumerate(yscar_myocardium[0].numpy()):
            #     _, contours, _ = cv.findContours(np.uint8(slice>0), cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
            #     # for k, ctrs in enumerate(contours):
            #     if len(contours) >= k+1:
            #         ctrs = contours[k]
            #         # Center from scarnet
            #         ctrs = np.squeeze(ctrs)/scale_factor

            #         if len(ctrs.shape) == 1:
            #             z = slice_id * np.ones(1)[:, None]
            #             ctrs = ctrs[None]
            #         else:
            #             z = slice_id * np.ones(ctrs.shape[0])[:, None]

            #         contour_3d = np.concatenate([ctrs, z], axis=1)
            #         contour_3d = contour_3d[None] * resolution.numpy()
            #         scar_center = np.mean(contour_3d, axis=1)[None]

            #         # Center from V2M
            #         surf_z_levels = surf_points[k][0, :, 2]
            #         dist = np.abs(surf_z_levels - np.unique(contour_3d[0,:,2]))
            #         points_on_level = surf_points[k][:, dist < gap]
            #         v2m_center = torch.mean(points_on_level, dim=1)[None].numpy()

            #         shifts[slice_id] = (v2m_center[:,:,:2] - scar_center[:,:,:2]) * scale_factor

            #         scenters[k] += [scar_center]
            #         pred_contour3d[k] += [contour_3d]

            # # pred_contour3d[0] = np.concatenate(pred_contour3d[0], axis=1)
            # # pred_contour3d[1] = np.concatenate(pred_contour3d[1], axis=1)
            # # scenters[0] = np.concatenate(scenters[0], axis=1)
            # # scenters[1] = np.concatenate(scenters[1], axis=1)
            # # save_to_obj('/cvlabdata2/cvlab/datasets_udaranga/outputs/contour3d1.obj', torch.from_numpy(pred_contour3d[0]), None, None)
            # # save_to_obj('/cvlabdata2/cvlab/datasets_udaranga/outputs/contour3d2.obj', torch.from_numpy(pred_contour3d[1]), None, None)

            # # save_to_obj('/cvlabdata2/cvlab/datasets_udaranga/outputs/centers3d1.obj', torch.from_numpy(scenters[0]), None, None)
            # # save_to_obj('/cvlabdata2/cvlab/datasets_udaranga/outputs/centers3d2.obj', torch.from_numpy(scenters[1]), None, None)

            # print('shifted')
            # embed()
            # for slice_id in shifts.keys():
            #         x[0, 0, slice_id] = shift_2d_replace(data=x[0, 0, slice_id],
            #                                             dx=round(shifts[slice_id][0, 1].detach().item()),
            #                                             dy=round(shifts[slice_id][0, 0].detach().item()))

            #         true_voxels[0, slice_id] = shift_2d_replace(data=true_voxels[0, slice_id],
            #                                             dx=round(shifts[slice_id][0, 1].detach().item()),
            #                                             dy=round(shifts[slice_id][0, 0].detach().item()))

            #         y_scars[0, slice_id] = shift_2d_replace(data=y_scars[0, slice_id],
            #                                             dx=round(shifts[slice_id][0, 1].detach().item()),
            #                                             dy=round(shifts[slice_id][0, 0].detach().item()))

            #         yhat_scars[0, slice_id] = shift_2d_replace(data=yhat_scars[0, slice_id],
            #                                             dx=round(shifts[slice_id][0, 1].detach().item()),
            #                                             dy=round(shifts[slice_id][0, 0].detach().item()))

            #         y_myocardium[0, slice_id] = shift_2d_replace(data=y_myocardium[0, slice_id],
            #                                             dx=round(shifts[slice_id][0, 1].detach().item()),
            #                                             dy=round(shifts[slice_id][0, 0].detach().item()))

            #         yhat_myocardium[0, slice_id] = shift_2d_replace(yhat_myocardium=y_dist[0, slice_id],
            #                                             dx=round(shifts[slice_id][0, 1].detach().item()),
            #                                             dy=round(shifts[slice_id][0, 0].detach().item()))


def string_match_brute(A , P):
  for i in range(len(A)-len(P) + 1 ):
    for j in range(len(P)):
      if P[j] == A[i+j]:
         pass
      else:
        break
    if j+1 == len(P) and A[i+j] == P[j]:
      print(f"se encontro en la pocicion: {i}")
arch=open('el_quijote_ii.txt', encoding="utf8")
f=arch.read()
p=int(input("que deceas buscar hidalfo preciona ;1 ,molino preciona; 2,merced preciona 3  ;"))
if p==1:
    patron="hidalfo"
    entrada=f
    S=string_match_brute(entrada,patron)
if p==2:
    patron="molino"
    entrada=f
    S=string_match_brute(entrada,patron)
if p==3:
    patron="merced"
    entrada=f
    S=string_match_brute(entrada,patron)


import sys
from PyQt5 import QtWidgets
import sqlite3

class pencere(QtWidgets.QWidget):

	def __init__(self):

		super().__init__()

		self.init_ui()

	def init_ui(self):

		self.kullanıcı_Adı = QtWidgets.QLineEdit()
		self.parola = QtWidgets.QLineEdit()
		self.parola.setEchoMode(QtWidgets.QLineEdit.Password)
		self.yazı_alanı = QtWidgets.QLabel()
		self.giriş = QtWidgets.QPushButton("giriş")
		self.yeni = QtWidgets.QPushButton("kullanıcı oluştur")

		vbox = QtWidgets.QVBoxLayout()
		vbox.addWidget(self.kullanıcı_Adı)
		vbox.addWidget(self.parola)
		vbox.addWidget(self.yazı_alanı)
		vbox.addStretch()
		vbox.addWidget(self.giriş)
		vbox.addWidget(self.yeni)
		hbox = QtWidgets.QHBoxLayout()
		hbox.addStretch()
		hbox.addLayout(vbox)
		hbox.addStretch()

		self.setLayout(hbox)

		self.veritaban()

		self.giriş.clicked.connect(self.login)
		self.yeni.clicked.connect(self.yenik)

		self.show()

	def veritaban(self):

		bağlantı = sqlite3.connect("merhaba.db")
		self.cursor = bağlantı.cursor()
		self.cursor.execute("CREATE TABLE IF NOT EXISTS uyeler (kullanıcı TEXT , parola TEXT)")

		bağlantı.commit()

	def login(self):

		ad = self.kullanıcı_Adı.text()
		parola = self.parola.text()

		self.cursor.execute("SELECT * FROM uyeler WHERE kullanıcı = ? AND parola = ?",(ad,parola))

		data = self.cursor.fetchall()

		if len(data) == 0:

			self.yazı_alanı.setText("böyle bir kullanıcı bulunamadı")

		else:

			self.yazı_alanı.setText("hoşgeldin " + str(ad))

	def yenik(self):

		bağlantı = sqlite3.connect("merhaba.db")
		self.cursor = bağlantı.cursor()

		ad = self.kullanıcı_Adı.text()
		paro = self.parola.text()

		self.cursor.execute("INSERT INTO uyeler VALUES (?,?)",(ad,paro))
		bağlantı.commit()

		self.cursor.execute("SELECT * FROM uyeler WHERE kullanıcı = ? AND parola = ?",(ad,paro))
		data = self.cursor.fetchall()
		if len(data) == 0:

			self.yazı_alanı.setText("kullanıcı oluşturulurken hata oluştu")

		else:

			self.yazı_alanı.setText("kullanıcı oluşturuldu. oturum açabilirsiniz.")

app = QtWidgets.QApplication(sys.argv)

pencere = pencere()

sys.exit(app.exec_())


import click
import numpy as np
import time

from panda3d_visu import panda3d_draw_landscape

def parse_point(line_data, n_points):
    data = line_data.replace("\n", "").split(' ')
    if len(data) == 3:
        try:
            int_data = list(map(int, data))
            # check for borders values -> z = 0
            for idx in range(3):
                if idx < 2 and (int_data[idx] == 0 or int_data[idx] == n_points-1):
                    int_data[2] = 0
                    print("Border point %s flatened" % data)
                if int_data[idx] > n_points or int_data[idx] < 0:
                    print("Invalid data : %s Ignored Point" % data, flush=True)
                    return None
        except:
            print("Invalid data : %s Ignored Point" % data, flush=True)
            return None
    else:
        print("Incomplete data : %s Ignored Point" % data, flush=True)
        return None
    return int_data

def parse_file(filename, n_points):
    data_list = []
    with open(filename) as f:
        for line in f:
            clean_data = parse_point(line, n_points)
            if clean_data and clean_data not in data_list:
                data_list.append(clean_data)
    return data_list

# Build flat land
def build_landscape(n_points):
    xi = range(n_points)
    yi = range(n_points)
    xi, yi = np.meshgrid(xi, yi)
    xi, yi = xi.flatten(), yi.flatten()
    return xi, yi

def euclidean_distance(xa, ya, xb, yb):
    # substract over x
    dx = np.subtract.outer(xa, xb)
    # substract over y
    dy = np.subtract.outer(ya, yb)
    # euclidean dist
    return np.sqrt((dx)**2 + (dy)**2)

# Interpolation
def simple_idw(x, y, z, xi, yi):
    # Compute distance matrix
    dist = euclidean_distance(x, y, xi, yi)
    # In IDW, weights are 1 / distance !! TWEAKED !!
    weights = 1.0 / (dist + 1e-12)**3
    # Make weights sum to one
    weights /= weights.sum(axis=0)
    # Multiply the weights for each interpolated point by all observed Z-values
    zi = np.dot(weights.T, z)
    return zi

@click.command()
@click.argument("filename", default="maps/map0.mod1", type=click.Path(exists=True))
def main(filename):
    n_points = 100
    # read input
    points_list = parse_file(filename, n_points)
    x = np.array([point[0] for point in points_list])
    y = np.array([point[1] for point in points_list])
    z = np.array([point[2] for point in points_list])
    # append border's null values
    for j in range(n_points):
        for i in range(n_points):
            if j == 0 or j == n_points - 1 or i == 0 or i == n_points - 1:
                x = np.append(x, i)
                y = np.append(y, j)
                z = np.append(z, 0)
    # init landscape
    xi, yi = build_landscape(n_points)
    # IDW interpolation
    zi = simple_idw(x, y, z, xi, yi)
    final_shape = (n_points, n_points)

    panda3d_draw_landscape((xi.reshape(final_shape),
                           yi.reshape(final_shape),
                           zi.reshape(final_shape)), n_points)

if __name__ == "__main__":
    main()


from PyQt6.QtWidgets import *

class RunConfigDlg(QDialog):
    def __init__(self, myapp):
        super().__init__()
        self.setWindowTitle("View Config")
        self.resize(400, 400)
        self.myapp = myapp

        self.query_file_list = QListWidget()
        for file in self.myapp.filenames:
            self.query_file_list.addItem(file)

        self.initUI()

    def initUI(self):
        self.outer_layout = QVBoxLayout()

        # file config
        file_layout = QVBoxLayout()
        file_layout.addWidget(QLabel('Query Files:'))
        self.query_file_list.setMaximumHeight(200)
        file_layout.addWidget(self.query_file_list)

        # library config
        library_layout = QVBoxLayout()
        library_layout.addWidget(QLabel('Target lib: ' + str(self.myapp.target_lib_file)))
        library_layout.addWidget(QLabel('Decoy lib: ' + str(self.myapp.decoy_lib_file)))

        # peptide tol config
        peptide_tol_layout = QHBoxLayout()
        peptide_tol_layout.addWidget(QLabel('Peptide Tolerance(ppm): ' + str(self.myapp.peptide_tol)))

        # fragment tol config
        fragment_tol_layout = QHBoxLayout()
        fragment_tol_layout.addWidget(QLabel('Fragment Tolerance(Da): ' + str(round(self.myapp.frag_tol, 2))))

        # C13 isotope tol config
        c13_isotope_tol_layout = QHBoxLayout()
        c13_isotope_tol_layout.addWidget(QLabel('C13 Isotope Tolerance: ' + str(round(self.myapp.c13_isotope_tol_min, 2)) + ', ' + str(round(self.myapp.c13_isotope_tol_max, 2))))

        self.outer_layout.addLayout(file_layout)
        self.outer_layout.addStretch(1)
        self.outer_layout.addLayout(library_layout)
        self.outer_layout.addStretch(1)
        self.outer_layout.addLayout(peptide_tol_layout)
        self.outer_layout.addStretch(1)
        self.outer_layout.addLayout(fragment_tol_layout)
        self.outer_layout.addStretch(1)
        self.outer_layout.addLayout(c13_isotope_tol_layout)
        self.outer_layout.addStretch(1)
        self.setLayout(self.outer_layout)


"""SWF domain management."""

import datetime
import functools
import dataclasses
import typing as t

from . import _common

if t.TYPE_CHECKING:
    import botocore.client

@dataclasses.dataclass
class DomainInfo(_common.Deserialisable):
    """Domain details."""

    name: str
    """Domain name."""

    is_deprecated: bool
    """Domain is deprecated and not active."""

    arn: str
    """Domain ARN."""

    description: str = None
    """Domain description."""

    @classmethod
    def from_api(cls, data) -> "DomainInfo":
        return cls(
            name=data["name"],
            is_deprecated=_common.is_deprecated_by_registration_status[data["status"]],
            arn=data["arn"],
            description=data.get("description"),
        )

@dataclasses.dataclass
class DomainConfiguration(_common.Deserialisable):
    """Domain configuration."""

    execution_retention: datetime.timedelta
    """Maximum age of retained executions."""

    @classmethod
    def from_api(cls, data) -> "DomainConfiguration":
        execution_retention_data = data["workflowExecutionRetentionPeriodInDays"]
        return cls(
            execution_retention=datetime.timedelta(days=int(execution_retention_data)),
        )

@dataclasses.dataclass
class DomainDetails(_common.Deserialisable):
    """Domain details and configuration."""

    info: DomainInfo
    """Domain details."""

    configuration: DomainConfiguration
    """Domain configuration."""

    @classmethod
    def from_api(cls, data) -> "DomainDetails":
        return cls(
            info=DomainInfo.from_api(data["domainInfo"]),
            configuration=DomainConfiguration.from_api(data["configuration"]),
        )

def deprecate_domain(
    domain: str,
    client: "botocore.client.BaseClient" = None,
) -> None:
    """Deprecate (deactivate) a domain.

    Args:
        domain: domain to deprecate
        client: SWF client
    """

    client = _common.ensure_client(client)
    client.deprecate_domain(name=domain)

def describe_domain(
    domain: str,
    client: "botocore.client.BaseClient" = None,
) -> DomainDetails:
    """Describe a domain.

    Args:
        domain: domain to describe
        client: SWF client

    Returns:
        domain details and configuration
    """

    client = _common.ensure_client(client)
    response = client.describe_domain(name=domain)
    return DomainDetails.from_api(response)

def list_domains(
    deprecated: bool = False,
    reverse: bool = False,
    client: "botocore.client.BaseClient" = None,
) -> t.Generator[DomainInfo, None, None]:
    """List domains; retrieved semi-lazily.

    Args:
        deprecated: list deprecated domains instead of non-deprecated
        reverse: return results in reverse alphabetical order
        client: SWF client

    Returns:
        domains
    """

    client = _common.ensure_client(client)
    call = functools.partial(
        client.list_domains,
        registrationStatus=_common.registration_status_by_is_deprecated[deprecated],
        reverseOrder=reverse,
    )
    return _common.iter_paged(call, DomainInfo.from_api, "domainInfos")

def get_domain_tags(
    domain_arn: str,
    client: "botocore.client.BaseClient" = None,
) -> t.Dict[str, str]:
    """Get a domain's tags.

    Args:
        domain_arn: domain AWS ARN
        client: SWF client

    Returns:
        domain's resource tags
    """

    client = _common.ensure_client(client)
    response = client.list_tags_for_resource(resourceArn=domain_arn)
    return {tag["key"]: tag["value"] for tag in response["tags"]}

def register_domain(
    domain: str,
    configuration: DomainConfiguration,
    description: str = None,
    tags: t.Dict[str, str] = None,
    client: "botocore.client.BaseClient" = None,
) -> None:
    """Register a new domain.

    Args:
        domain: domain name
        configuration: configuration
        description: domain description
        tags: domain's resource tags
        client: SWF client
    """

    client = _common.ensure_client(client)
    kw = {}
    if description or description == "":
        kw["description"] = description
    if tags:
        kw["tags"] = [dict(key=k, value=v) for k, v in tags.items()]
    execution_retention_data = str(configuration.execution_retention.days)
    client.register_domain(
        name=domain,
        workflowExecutionRetentionPeriodInDays=execution_retention_data,
        **kw,
    )

def tag_domain(
    domain_arn: str,
    tags: t.Dict[str, str],
    client: "botocore.client.BaseClient" = None,
) -> None:
    """Add tags to domain.

    Args:
        domain_arn: domain AWS ARN
        tags: tags to add
        client: SWF client
    """

    client = _common.ensure_client(client)
    tags = [dict(key=k, value=v) for k, v in tags.items()]
    client.tag_resource(resourceArn=domain_arn, tags=tags)

def undeprecate_domain(
    domain: str,
    client: "botocore.client.BaseClient" = None,
) -> None:
    """Undeprecate (reactivate) a domain.

    Args:
        domain: domain to undeprecate
        client: SWF client
    """

    client = _common.ensure_client(client)
    client.undeprecate_domain(name=domain)

def untag_domain(
    domain_arn: str,
    tags: t.List[str],
    client: "botocore.client.BaseClient" = None,
) -> None:
    """Remove tags from a domain.

    Args:
        domain_arn: domain AWS ARN
        tags: tags (keys) to remove
        client: SWF client
    """

    client = _common.ensure_client(client)
    client.untag_resource(resourceArn=domain_arn, tagKeys=tags)


import requests
import json
import matplotlib.pyplot as plt
from datetime import datetime
from datetime import timedelta

# Realize a solicitação GET como você fez antes
url = "http://46.17.108.113:8666/STH/v1/contextEntities/type/sensorAlert/id/urn:ngsi-ld:sensorAlert:9/attributes/gas?lastN=20"
headers = {
  'fiware-service': 'smart',
  'fiware-servicepath': '/'
}
response = requests.get(url, headers=headers)

# Verifique se a solicitação foi bem-sucedida
if response.status_code == 200:
    data = json.loads(response.text)

    gas_data = data['contextResponses'][0]['contextElement']['attributes'][0]['values']

    gas_values = [entry['attrValue'] for entry in gas_data]
    recv_times = [datetime.fromisoformat(entry['recvTime'][:-1]) for entry in gas_data]

    # Filtre os dados para os últimos 5 minutos
    now = datetime.now()
    last_5_minutes = now - timedelta(minutes=5)
    filtered_gas_values = []
    filtered_recv_times = []
    for i in range(len(gas_values)):
        if recv_times[i] >= last_5_minutes:
            filtered_gas_values.append(gas_values[i])
            filtered_recv_times.append(recv_times[i])

    # Crie o gráfico
    plt.plot(filtered_recv_times, filtered_gas_values)
    plt.xlabel('Tempo')
    plt.ylabel('Quantidade de Gás')
    plt.title('Últimos 40 segundos de dados de Gás')
    plt.xticks(rotation=45)
    plt.grid(True)
    plt.tight_layout()

    plt.show()
else:
    print(f"A solicitação retornou o código de status: {response.status_code}")


import pyautogui as pag
import time

class Button:
    def __init__(self, name):
        self.name = name
        self.location = None  # should be center of the Button box
        self.box = None

    def find_location(self):
        if not self.location:
            self.location = pag.locateCenterOnScreen(f'img/{self.name}.png', confidence=0.9)
            if self.location:
                print(f"{self.name} has been found!")
            else:
                print(f"Warning! {self. name} can't be found")

    def convert_location(self):
        self.location = self.location/2

    def click(self):  # strategy to avoid robot-detection should be added here
        if self.location:
            pag.mouseDown(*self.location, duration=0.2)
            pag.mouseUp(*self.location, duration=0.2)
            pag.moveTo(500, 1, duration=0.2)

if __name__ == "__main__":
    time.sleep(3)
    test_button = Button('test')
    test_button.find_location()
    test_button.click()


#!/usr/bin/env python
# -*- encoding: utf8 -*-

import re
from StringTableInfo import StringTableInfo
from JPChecker import hasJP
from BaseProcessor import BaseProcessor

class FormProcessor(BaseProcessor):
    '''
    the processor for processing the controllers information
    in the frm files
    '''

    PCTRL = re.compile(r'\s*Begin VB\.(\w+) (\w+)\s*') # the pattern for VB Control definition line in frm file.
    PPROP = re.compile(r'\s*(\w+)\s*=\s*("[^"]+"|\d+)(?:\'.*)?') # the pattern for VB Control Properties definition line
    PBPROP = re.compile(r'\s*BeginProperty\s+(\w+)\s*')

    BEFORE_ATTR = 1
    IN_ATTR = 2
    AFTER_ATTR = 3

    def __init__(self, stg):
        '''
        class contructor

        arguments:
        stg -- StringTableGenerator
        '''
        self.__ctrls = []
        self.__ctrl = None
        self.__ctrlStack = []
        self.__pos = FormProcessor.BEFORE_ATTR
        self.__propname = ''
        self.__form_load = []
        self.__stg = stg

    @property
    def formLoad(self):
        return self.__form_load;

    def procProp(self, line):
        '''
        process the cascaded property informatin, which begins
        with 'BeginProperty'

        arguments:
        line -- the target line
        '''
        if (len(self.__propname) > 0):
            mo = FormProcessor.PPROP.match(line)
            if mo == None:
                if line.strip() == u'EndProperty':
                    self.__propname = u''
            else:
                #logging.warning(u'control[%s][%s] = %s', propname, mo.group(1), mo.group(2))
                self.__ctrl[self.__propname][mo.group(1)] = mo.group(2)
        else:
            if line.strip() == 'End':
                self.__ctrls.append(self.__ctrl)
                if len(self.__ctrlStack) > 0:
                    self.__ctrl = self.__ctrlStack.pop()
                else:
                    self.__ctrl = None
            else:
                mo = FormProcessor.PPROP.match(line) # match control property 'Caption = "Form1"'
                if mo != None:
                    self.__ctrl[mo.group(1)] = mo.group(2)
                else:
                    mo = FormProcessor.PBPROP.match(line) # match control cascade property 'BeginProperty Font'
                    if mo != None:
                        self.__propname = mo.group(1)
                        self.__ctrl[self.__propname] = {}

    def process(self, line):
        '''
        process the frm files, and gather the controllers informations

        arguments:
        line -- the target line

        return:
        the current position in the frm file
        '''

        line = self.removeComments(line)
        if self.__pos == FormProcessor.BEFORE_ATTR and line.startswith('Attribute '):
            self.__pos = FormProcessor.IN_ATTR
        elif self.__pos == FormProcessor.IN_ATTR and not line.startswith('Attribute '):
            self.__pos = FormProcessor.AFTER_ATTR

        if self.__pos == FormProcessor.BEFORE_ATTR:
            mo = FormProcessor.PCTRL.match(line) # match control definition begin "Begin VB.TYPE NAME"
            if mo == None: # not matched
                if self.__ctrl != None:
                    self.procProp(line)
            else:
                if self.__ctrl != None:
                    self.__ctrlStack.append(self.__ctrl) # save the out level control

                self.__ctrl = {'Type': mo.group(1), 'Name': mo.group(2)}
        return self.__pos

    def generateControllerInfo(self):
        '''
        analyze the controls info to generate the Japanese strings
        return:
        lines: the generated initialization code for form load
        start: the start index for next process
        '''
        lines = []
        for ctrl in self.__ctrls:

            lines.append('    %s%s.Font.Name = LoadResString(%d)' % (ctrl['Name'],
                    #if there is 'Index' property, then it is a member of controller array
                    '('+ctrl['Index'] + ')' if u'Index' in ctrl else '', self.__stg.index))
            info = StringTableInfo(u'ＭＳ ゴシック', None, None, '%s%s.Font.Name' % (ctrl['Name'],
                '('+ctrl['Index'] + ')' if u'Index' in ctrl else ''))

            self.__stg.putInfo(info)

            lines.append('    %s%s.Font.Charset = LoadResString(%d)' % (ctrl['Name'],
                    #if there is 'Index' property, then it is a member of controller array
                    '('+ctrl['Index'] + ')' if u'Index' in ctrl else '', self.__stg.index))
            info = StringTableInfo('128', None, None, '%s%s.Font.Charset: 128 for JP, 134 for CN' % (ctrl['Name'],
                '('+ctrl['Index'] + ')' if u'Index' in ctrl else ''))
            self.__stg.putInfo(info)

            for prop in ctrl:
                # 'Name' and 'Type' are not real control's properties
                # 'Font' need to be processed specially
                if prop in ('Name', 'Type', u'Font'):
                    continue

                if type(ctrl[prop]) == dict:
                    for propname in ctrl[prop]:
                        if hasJP(ctrl[prop][propname]):
                            info = StringTableInfo(ctrl[prop][propname][1:-1], None, None, u'%s.%s.%s = "%s"'
                                % (ctrl['Name'], prop, propname, ctrl[prop][propname][1:-1]))
                            line = u'    %s%s.%s.%s = LoadResString(%d)' % (ctrl['Name'],
                                    #if there is 'Index' property, then it is a member of controller array
                                    '('+ctrl['Index'] + ')' if u'Index' in ctrl else '',
                                    prop, propname, self.__stg.index)
                            self.__stg.putInfo(info)
                            lines.append(line)

                elif hasJP(ctrl[prop]):
                    info = StringTableInfo(ctrl[prop][1:-1], None, None, u'%s%s.%s = %s'
                            % (ctrl['Name'], '('+ctrl['Index'] + ')' if u'Index' in ctrl else '',
                            prop, ctrl[prop][1:-1]) )
                    line = u'    %s%s.%s = LoadResString(%d)' % (ctrl['Name'],
                            #if there is 'Index' property, then it is a member of controller array
                            '('+ctrl['Index'] + ')' if u'Index' in ctrl else '',
                            prop, self.__stg.index)
                    self.__stg.putInfo(info)
                    lines.append(line)

            lines.append('\r\n')

        self.__form_load = lines


def knapsack(arr,sum,n,t):
    if n == 0 or sum == 0:
        return 0
    for i in range(1,n+1):
        for j in range(1,sum+1):
            if arr[i-1]<=j:
                t[i][j]=t[i-1][j-arr[i-1]]+t[i-1][j]
            else:
                t[i][j]=t[i-1][j]
    return t[n][sum]
if __name__ == "__main__":
    n=int(input())
    arr=list(map(int,input().split()))
    diff=int(input())
    sum=sum(arr)
    t=[[-1 for i in range(sum+1)]for j in range(n+1)]
    for i in range(n+1):
        for j in range(sum+1):
            if i==0:
                t[i][j]=0
            if j == 0:
                t[i][j]=1

    sum_p1=(diff+sum)//2
    print(knapsack(arr,sum_p1,n,t))

Count of subsets with diff or target sum.py


import torch
import torch.nn as nn
import torch.nn.init as init

class L2Norm(nn.Module):
    def __init__(self,in_ch=512, scale=20):
        super(L2Norm,self).__init__()
        self.in_ch = in_ch
        self.gamma = scale or None
        self.eps = 1e-10
        self.weight = nn.Parameter(torch.Tensor(1, self.in_ch, 1, 1))
        self.init_params()

    def init_params(self):
        init.constant_(self.weight,self.gamma)

    def forward(self, x):
        norm = x.pow(2).sum(dim=1, keepdim=True).sqrt()+self.eps
        x = torch.div(x,norm)
        out = x * self.weight
        return out

if __name__ == '__main__':
    x = torch.randn([1, 512, 38, 38])
    l2norm = L2Norm(512, 20)(x)


import logging

import config.default as default

# class Logging:

def create_logger(log_name, logger_name):
    logger = logging.getLogger(logger_name)
    logger.setLevel(logging.DEBUG)
    fh = logging.FileHandler(default.base_path + '/log/{log_name}.log'.format(log_name=log_name))
    fh.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
    fh.setFormatter(formatter)
    if not logger.hasHandlers():
        logger.addHandler(fh)
    return logger

# utility function to use to avoid writing out two lines
def log_it_info(logger, msg):
    logger.info(msg)
    print(msg)


import numpy as np
from scipy.spatial.distance import cdist

import free_energy_clustering.GMM as GMM
from sklearn.mixture import GaussianMixture
import free_energy_clustering.cross_validation as CV
import free_energy_clustering as FEC

import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

class FreeEnergyClustering(object):

	def __init__(self, data, min_n_components=8, max_n_components=None, n_components_step=1, x_lims=None, temperature=300.0,
				 n_grids=50, n_splits=1, shuffle_data=False, n_iterations=1, convergence_tol=1e-4, stack_landscapes=False,
				 verbose=True, test_set_perc=0.0, data_weights=None, bias_factors=None):
		"""
		Class for computing free energy landscape in [kcal/mol].
		- observed_data has dimensionality [N x d].
		"""
		self.data_ = data
		self.shuffle_data = shuffle_data
		self.n_splits_ = n_splits
		self.n_iterations_ = n_iterations
		self.convergence_tol_ = convergence_tol
		self.stack_landscapes_ = stack_landscapes

		self.min_n_components = min_n_components
		self.max_n_components = max_n_components
		self.n_components_step = n_components_step

		self.FE_points_ = None
		self.FE_landscape_ = None
		self.coords_ = None
		self.min_FE_ = None

		self.cl_ = None # Clustering object
		self.labels_ = None
		self.core_labels_ = None
		self.cluster_centers_ = None
		self.pathways_ = None
		self.state_populations_ = None

		if x_lims is not None:
			self.x_lims_ = x_lims
			self.n_dims_ = len(self.x_lims_)
		else:
			if len(data.shape) > 1:
				self.x_lims_ = []
				for i in range(data.shape[1]):
					self.x_lims_.append([data[:,i].min(),data[:,i].max()])
				self.n_dims_ = len(self.x_lims_)
			else:
				self.x_lims_ = [[data.min(),data.max()]]
				self.n_dims_ = 1

		self.temperature_ = temperature # [K]
		self.boltzmann_constant_ = 0.0019872041 # [kcal/(mol K)]
		self.density_est_ = None
		self.standard_error_FE_ = None
		self.nx_ = n_grids
		self.n_grids_ = [self.nx_]*self.n_dims_
		self.test_set_perc_ = test_set_perc
		self.verbose_ = verbose
		self.data_weights_ = data_weights
		self.bias_factors_ = bias_factors

		self.BICs_ = []

		if data_weights is not None or bias_factors is not None:
			use_data_weights = True
			# Convert data weights to the right format
			self.data_weights_ /= self.data_weights_.sum()
			self.data_weights_ *= self.data_weights_.shape[0]
		else:
			use_data_weights = False

		self.test_set_loglikelihood = None
		if verbose:
			print('*----------------Gaussian mixture model free energy estimator----------------*')
			print('   n_splits = '+str(n_splits))
			print('   shuffle_data = ' + str(shuffle_data))
			print('   n_iterations = ' + str(n_iterations))
			print('   n_grids = ' + str(n_grids))
			print('   covergence_tol = ' + str(convergence_tol))
			print('   stack_landscapes = ' + str(stack_landscapes))
			print('   x_lims (axes limits) = ' + str(self.x_lims_))
			print('   temperature = ' + str(temperature))
			print('   min_n_components = ' + str(min_n_components))
			print('   max_n_components = ' + str(max_n_components))
			print('   n_components_step = ' + str(n_components_step))
			print('   Using weighted data: ' + str(use_data_weights))
			print('*----------------------------------------------------------------------------*')
		return

	def _get_grid_coords(self):
		if self.n_dims_ < 4:
			x = []
			self.n_grids_ = []
			for i_dim in range(self.n_dims_):
				self.n_grids_.append(self.nx_)
				x.append(np.linspace(self.x_lims_[i_dim][0], self.x_lims_[i_dim][1], self.nx_))

			if self.n_dims_ == 1:
				return x
			coords = np.meshgrid(*x)
		else:
			# Do not discretize
			print('Note: # features > 3 => density not evaluated on grid.')
			coords = None

		return coords

	def _density_landscape(self, density_est):
		"""
		Evaluate density model at the grid points.
		"""
		if self.coords_ is None:
			coords = self._get_grid_coords()
		else:
			coords = self.coords_

		if self.n_dims_ == 1:
			densities = density_est.density(coords[0][:,np.newaxis])
			return coords, densities

		if coords is not None:
			print('Density grid shape: '+str(self.n_grids_))
			grid_points_flatten = []
			for x in coords:
				grid_points_flatten.append(np.ravel(x))
			points = np.asarray(grid_points_flatten).T
			densities = density_est.density(points)
			densities = np.reshape(densities, self.n_grids_)
		else:
			densities = density_est.density(self.data_)

		return coords, densities

	def _free_energy(self,density):
		density[density < 1e-8] = 1e-8
		FE = -self.temperature_ * self.boltzmann_constant_ * np.log(density)
		return FE

	def standard_error(self, n_data_blocks=3):
		"""
		Estimating standard error.
		"""
		print('Estimating standard error.')
		n_points = self.data_.shape[0]
		n_data_points = int(n_points/n_data_blocks)

		free_energies = []

		for i in range(n_data_blocks):

			if i != n_data_blocks-1:
				data = np.copy(self.data_[i*n_data_points:(i+1)*n_data_points])
			else:
				data = np.copy(self.data_[i*n_data_points::])

			if self.n_dims_ == 1:
				data = data[:,np.newaxis]

			_, density_model = self._fit_FE(data, set_density_model=False)
			_, density = self._density_landscape(density_model)
			free_energies.append(self._free_energy(density))

		free_energies = np.asarray(free_energies)
		self.standard_error_FE_ = np.std(free_energies,axis=0)/np.sqrt(n_data_blocks-1)
		print('Standard error estimation done.')
		return self.standard_error_FE_

	def _train_GMM(self, data, n_components, train_inds=None, val_inds=None, loglikelihood=0):
		"""
		Perform one training of GMM.
		:param data:
		:param n_components:
		:return:
		"""

		if train_inds is not None and val_inds is not None:
			training_data, validation_data = CV.get_train_validation_set(data, train_inds, val_inds)
		else:
			training_data = np.copy(data)
			validation_data = np.copy(data)

		if self.data_weights_ is None and self.bias_factors_ is None:
			gmm = GaussianMixture(n_components=n_components, tol=self.convergence_tol_)

			# Train model on the current training data
			gmm.fit(training_data)

			# Check log-likelihood of validation data
			loglikelihood += gmm.score(validation_data)
		else:
			gmm = GMM.GaussianMixture(n_components=n_components, convergence_tol=self.convergence_tol_,verbose=self.verbose_)

			training_data_weights = self.data_weights_
			validation_data_weights = self.data_weights_
			training_bias_factors = self.bias_factors_

			if train_inds is not None and val_inds is not None:
				if self.data_weights_ is not None:
					training_data_weights, validation_data_weights = CV.get_train_validation_set(self.data_weights_,
																								 train_inds, val_inds)

				if self.bias_factors_ is not None:
					training_bias_factors, validation_bias_factors = CV.get_train_validation_set(self.bias_factors_,
																								 train_inds, val_inds)

			# Train model on the current training data
			gmm.fit(training_data, data_weights=training_data_weights, bias_factors=training_bias_factors)

			if training_bias_factors is not None and train_inds is not None and val_inds is not None:
				# Compute the weights of validation data using the validation data bias factors
				validation_data_weights = gmm.compute_data_weights(validation_data, validation_bias_factors)

			# Check log-likelihood of validation data
			loglikelihood += gmm.loglikelihood(validation_data, data_weights=validation_data_weights)

		return gmm, loglikelihood

	def _fit_FE(self, data, set_density_model=True):
		"""
		Fit density to data points.
		:param data: [n_samples x n_dims]
		:return: free energy of points
		"""

		best_n_components = self.min_n_components

		# Extract test set from the dataset
		n_points_test = int(self.test_set_perc_*data.shape[0])
		data_orig = np.copy(data)
		data_weights_orig = np.copy(self.data_weights_)

		if n_points_test > 0:
			test_data = data[-n_points_test::,:]
			data = np.copy(data[0:-n_points_test, :])
			if self.data_weights_ is not None:
				self.data_weights_ = np.copy(self.data_weights_[0:-n_points_test,:])
		else:
			test_data = np.zeros((0,self.n_dims_))

		if self.stack_landscapes_:
			print('Estimating density with stacked GMMs.')
		else:
			print('Estimating density with GMM.')

		if self.data_weights_ is not None:
			print('Using weighted data to estimate GMM.')

		best_loglikelihood = -np.inf
		list_of_GMMs = []
		list_of_validation_data = []
		ICs = []

		# Get indices of training and validation datasets
		if self.n_splits_ > 1:
			train_inds, val_inds = CV.split_train_validation(data, self.n_splits_, self.shuffle_data)

		# Determine number of components with k-fold cross-validation,
		# or store all estimated densities and then weight together.
		if self.max_n_components is not None:
			for n_components in range(self.min_n_components,self.max_n_components+1,self.n_components_step):
				if self.verbose_:
					print('# Components = '+str(n_components))

				if self.n_splits_ > 1 and not(self.stack_landscapes_):
					loglikelihood = 0
					for i_split in range(self.n_splits_):
						gmm, loglikelihood = self._train_GMM(data, n_components, train_inds[i_split], val_inds[i_split], loglikelihood)

					# Keep best model
					if loglikelihood > best_loglikelihood:
						best_loglikelihood = loglikelihood
						best_n_components = n_components
				else:
					best_loglikelihood = -np.inf
					for i_iter in range(self.n_iterations_):
						# Train GMM
						gmm, loglikelihood = self._train_GMM(data, n_components)

						if self.data_weights_ is not None:
							# Move over to new GMM object
							new_gmm = GaussianMixture(n_components=n_components,max_iter=1)
							new_gmm.fit(data)	# Fit is needed before calling aic or bic. Note that max_iter=1.
							new_gmm.means_ = gmm.means_
							new_gmm.covariances_ = gmm.covariances_
							new_gmm.weights_ = gmm.weights_
							gmm = new_gmm

						# Compute average AIC/BIC over iterations
						if i_iter == 0:
							if self.stack_landscapes_:
								ICs.append(gmm.aic(data))
							else:
								ICs.append(gmm.bic(data))

						# Keep best model
						if loglikelihood > best_loglikelihood:
							best_loglikelihood = loglikelihood
							if i_iter == 0:
								list_of_GMMs.append(GMM.GaussianMixture(n_components=n_components))

							if self.stack_landscapes_:
								ICs[-1] = gmm.aic(data)
							else:
								ICs[-1] = gmm.bic(data)

							list_of_GMMs[-1].weights_ = gmm.weights_
							list_of_GMMs[-1].means_ = gmm.means_
							list_of_GMMs[-1].covariances_ = gmm.covariances_

		if self.stack_landscapes_:
			if  self.max_n_components is None:
				gmm, _ = self._train_GMM(data, self.min_n_components)
				list_of_GMMs.append(gmm)

			ICs = np.asarray(ICs)
			model_weights = np.exp(-0.5 *(ICs-ICs.min()))
			model_weights /= model_weights.sum()

			# Fit mixture of density estimators using the validation data
			density_est = FEC.LandscapeStacker(data, list_of_validation_data, list_of_GMMs, n_splits=1,
														convergence_tol=self.convergence_tol_, n_iterations=self.n_iterations_,
														model_weights=model_weights)

			density = density_est.density(data_orig)
			if set_density_model:
					self.density_est_ = density_est
		else:
			# Estimate FE with best number of components (deduced from cross-validation)
			if self.n_splits_ > 1:
				print('Training final model with ' + str(best_n_components) + ' components.')
				best_loglikelihood = -np.inf
				density_est = GMM.GaussianMixture(n_components=best_n_components)
				# Fit multiple times to
				for i_iter in range(self.n_iterations_):
					gmm, loglikelihood = self._train_GMM(data, best_n_components)

					if  loglikelihood > best_loglikelihood:
						best_loglikelihood = loglikelihood
						density_est.weights_ = gmm.weights_
						density_est.means_ = gmm.means_
						density_est.covariances_ = gmm.covariances_
			else:
				ICs = np.asarray(ICs)
				self.BICs_ = np.copy(ICs)
				model_ind = ICs.argmin()
				gmm = list_of_GMMs[model_ind]
				best_n_components = gmm.weights_.shape[0]
				density_est = GMM.GaussianMixture(n_components=best_n_components)

				print('Identifying final model with ' + str(density_est.n_components_) + ' components.')

				density_est.weights_ = gmm.weights_
				density_est.means_ = gmm.means_
				density_est.covariances_ = gmm.covariances_

			density = density_est.density(data_orig)

			if set_density_model:
				self.density_est_ = density_est

		if set_density_model:
			# Compute test set loglikelihood on the test set if test set exists
			if n_points_test > 0:
				self.test_set_loglikelihood = self.density_est_.loglikelihood(test_data)
			return self._free_energy(density)
		else:
			return self._free_energy(density), density_est

	def landscape(self):
		"""
		Computing free energy landscape with
		G(x) = -kT*log(p(x|T))
		Returns the X,Y coordinate matrices (meshgrid) and
		their corresponding free energy.
		"""

		if len(self.data_.shape) == 1:
			FE_points = self._fit_FE(self.data_[:,np.newaxis])
		else:
			FE_points = self._fit_FE(self.data_)

		print('Evaluating density in landscape')
		coords, density = self._density_landscape(self.density_est_)

		FE_landscape = self._free_energy(density)

		# Shift to zero
		self.min_FE_ = np.min(FE_landscape)
		FE_landscape = FE_landscape-self.min_FE_
		FE_points = FE_points-self.min_FE_

		self.FE_points_ = FE_points
		self.FE_landscape_ = FE_landscape
		self.coords_ = coords

		return coords, FE_landscape, FE_points

	def evaluate_free_energy(self,data):
		"""
		Evaluate the free energy of given data in the current free energy model.
		"""
		density = self.density_est_.density(data)
		free_energy = self._free_energy(density)
		if self.min_FE_ is not None:
			free_energy -= self.min_FE_

		return free_energy

	def population_states(self, n_sampled_points=10000):
		"""
		Estimate the population of states (probability to be in a state) based on Mante-Carlo integration of
		the estimated density and state definitions.
		:param n_sampled_points:
		:return:
		"""

		if self.stack_landscapes_:
			state_populations = None
			print('TODO: Estimating population of states is not possible with stacked landscapes yet.')
		else:

			print('Sampling points from density.')
			# Sample points from estimated density
			points = self.density_est_.sample(n_sampled_points)

			# Assign cluster labels of sampled points
			cluster_labels = self.evaluate_clustering(points)

			print('Computing state populations.')
			# Monte-Carlo integration (histogramming)
			self.state_populations_, _ = np.histogram(cluster_labels, bins=int(self.labels_.max()+1), range=(self.labels_.min(),self.labels_.max()),density=False)

			#print(state_populations)
			self.state_populations_ = self.state_populations_/self.state_populations_.sum()

		return self.state_populations_

	def evaluate_clustering(self, points, assign_transition_points=False):
		"""
		Assign cluster indices to points based on precomputed density model clustering.
		"""
		print('Assigning cluster labels based on precomputed density model clustering.')
		if self.cl_ is not None and self.cl_.clusterer_ is not None:
			labels = self.cl_.clusterer_.data_cluster_indices(cdist(points, self.cl_.clusterer_.grid_points_), self.cl_.clusterer_.grid_cluster_inds_)

		if assign_transition_points:
				labels = self.cl_.assign_transition_points(labels, points, self.density_est_)

		return labels

	def cluster(self, points, free_energies, eval_points=None, return_center_coords=False, assign_transition_points=False,use_FE_landscape=False, unravel_grid=True, transition_matrix=None):
		"""
		Cluster points according to estimated density.
		"""

		self.transition_matrix_ = transition_matrix

		print('Clustering free energy landscape...')
		self.cl_ = FEC.LandscapeClustering(self.stack_landscapes_,verbose=self.verbose_)

		if eval_points is not None and unravel_grid:
			tmp_points = []
			for x in points:
				tmp_points.append(np.ravel(x))
			points = np.asarray(tmp_points).T

		if len(points.shape) == 1:
			points = points[:,np.newaxis]

		if eval_points is not None:
			if len(eval_points.shape) == 1:
				eval_points = eval_points[:,np.newaxis]

		self.labels_, self.is_FE_min = self.cl_.cluster(self.density_est_, points, eval_points=eval_points, use_FE_landscape=use_FE_landscape, transition_matrix=self.transition_matrix_)

		self.core_labels_ = np.copy(self.labels_)

		if eval_points is not None:
			self.cluster_centers_ = self.cl_.get_cluster_representative(eval_points, self.labels_, free_energies)
		else:
			self.cluster_centers_ = self.cl_.get_cluster_representative(points, self.labels_, free_energies)

		if assign_transition_points:
			if eval_points is not None:
				self.labels_ = self.cl_.assign_transition_points(self.labels_, eval_points, self.density_est_)
			else:
				self.labels_ = self.cl_.assign_transition_points(self.labels_, points, self.density_est_)

		print('Done clustering.')
		if return_center_coords:
			return self.labels_, eval_points[self.cluster_centers_,:]
		else:
			return self.labels_, self.cluster_centers_

	def pathways(self, states_from, states_to,n_points=10, convergence_tol=1e-1, step_size=1e-3, max_iter=100):
		"""
		Calculate minimum pathways between points (indices) in states_from and states_to.
		:param states_from:
		:param states_to:
		:param n_points:
		:param convergence_tol:
		:param step_size:
		:return:
		"""
		pathway_estimator = FEC.FreeEnergyPathways(self.density_est_, self.data_, self.temperature_,
													  n_points=n_points, convergence_tol=convergence_tol,
													  step_size=step_size, ensemble_of_GMMs=self.stack_landscapes_,
													  max_iter=max_iter)
		self.pathways_ = []
		for from_ind, to_ind in zip(states_from,states_to):
			self.pathways_.append(pathway_estimator.minimum_pathway(from_ind, to_ind))

		return

	def visualize(self,title="Free energy landscape", fontsize=30, savefig=True, xlabel='x', ylabel='y', zlabel='z', vmax=7.5,
				  n_contour_levels=15, show_data=False, figsize= [12, 10], filename='free_energy_landscape', dx=1, ax=None):

		if self.n_dims_ > 3:
			print('Plotting does not support > 3 dimensions')
			return

		# Set custom colormaps
		my_cmap = matplotlib.cm.get_cmap('jet')
		my_cmap.set_over('white')
		my_cmap_cont = matplotlib.colors.ListedColormap(['black'])
		my_cmap_cont.set_over('white')

		plt.rcParams['figure.figsize'] = figsize

		if ax is None:
			fig = plt.figure()
			if self.n_dims_ < 3:
				ax = fig.add_subplot(1, 1, 1)
			else:
				ax = fig.add_subplot(111, projection='3d')
		ax.tick_params(labelsize=fontsize - 2)

		plt.tick_params(axis='both', which='major', labelsize=fontsize-4)

		for tick in ax.get_xticklabels():
			tick.set_fontname("Serif")
			tick.set_fontweight('light')

		for tick in ax.get_yticklabels():
			tick.set_fontname("Serif")
			tick.set_fontweight('light')

		# Plot free energy landscape
		FE_landscape = np.copy(self.FE_landscape_)
		FE_landscape[self.FE_landscape_ > vmax+0.5] = vmax+0.5

		if self.n_dims_ == 2:
			ax.contourf(self.coords_[0], self.coords_[1], FE_landscape, n_contour_levels, cmap=my_cmap, vmin=0, vmax=vmax)
			cb=plt.colorbar(label='[kcal/mol]')
			text = cb.ax.yaxis.label
			font = matplotlib.font_manager.FontProperties(size=fontsize-3,family='serif',weight='light')
			text.set_font_properties(font)
			cb.ax.tick_params(labelsize=fontsize-2)

			for tick in cb.ax.get_yticklabels():
				tick.set_fontname("Serif")
				tick.set_fontweight('light')

			ax.set_ylim([self.coords_[1].min(), self.coords_[1].max()])
			ax.set_ylabel(ylabel, fontsize=fontsize - 2,fontname='serif',fontweight='light')
		elif self.n_dims_ == 1:
			if self.standard_error_FE_ is not None:
				ax.fill_between(self.coords_[0], FE_landscape - self.standard_error_FE_, FE_landscape + self.standard_error_FE_, color='k', alpha=0.2,zorder=2)
			ax.plot(self.coords_[0], FE_landscape, linewidth=3,color='k',zorder=1)
			ax.set_ylabel('Free energy [kcal/mol]',fontsize=fontsize-2,fontname='serif',fontweight='light')
		else:
			sc = ax.scatter(self.data_[::dx,0], self.data_[::dx,1], self.data_[::dx,2], s=30, c=self.FE_points_[::dx], alpha=0.8, cmap=my_cmap, vmin=0, vmax=vmax, edgecolor='k')

			ax.set_ylim([self.coords_[1].min(), self.coords_[1].max()])
			ax.set_zlim([self.coords_[2].min(), self.coords_[2].max()])

			cb=plt.colorbar(sc,label='[kcal/mol]')
			text = cb.ax.yaxis.label
			font = matplotlib.font_manager.FontProperties(size=fontsize-3,family='serif',weight='light')
			text.set_font_properties(font)
			cb.ax.tick_params(labelsize=fontsize-2)

			ax.set_ylabel(ylabel, fontsize=fontsize - 2,fontname='serif',fontweight='light')
			ax.set_zlabel(zlabel, fontsize=fontsize - 2,fontname='serif',fontweight='light')

		ax.set_xlim([self.coords_[0].min(), self.coords_[0].max()])

		# Plot projected data points
		if show_data and self.n_dims_ < 3:

			# Plot projected data points
			if self.labels_ is not None:
				if self.n_dims_ > 1:
					transition_points=self.data_[self.labels_==0]
					core_points = self.data_[self.labels_ > 0]
					core_labels = self.labels_[self.labels_>0]
					ax.scatter(transition_points[::dx, 0], transition_points[::dx, 1], s=30, c=0.67*np.ones((transition_points[::dx].shape[0],3)),alpha=0.5)
					ax.scatter(core_points[::dx, 0], core_points[::dx, 1], s=80, c=core_labels[::dx],
						   edgecolor='k', cmap=my_cmap, label='Intermediate state',alpha=0.8)
				else:
					ax.scatter(self.data_[self.labels_==0], self.FE_points_[self.labels_==0], s=30, c=[0.67, 0.67, 0.65],alpha=0.6,zorder=3)
					ax.scatter(self.data_[self.labels_>0], self.FE_points_[self.labels_>0], s=50, c=self.labels_[self.labels_>0],
						   edgecolor='k', cmap=my_cmap, label='Intermediate state',alpha=0.8,zorder=4)
				if fontsize > 18:
					plt.legend(fontsize=fontsize-10,facecolor=[0.9,0.9,0.92])
				else:
					plt.legend(fontsize=fontsize-4,facecolor=[0.9,0.9,0.92])
			else:
				if self.n_dims_ > 1:
					ax.scatter(self.data_[:, 0], self.data_[:, 1], s=30, c=[0.67, 0.67, 0.65],alpha=0.5)
				else:
					ax.scatter(self.data_, self.FE_points_[:, 1], s=30, c=[0.67, 0.67, 0.65],alpha=0.5)

			# Plot minimum pathways between states
			if self.pathways_ is not None and self.n_dims_ > 1:
				set_pathway_label = True
				for p in self.pathways_:
					if set_pathway_label:
						ax.plot(p[:, 0], p[:, 1], color=[43.0/256.0,46.0/256.0,60.0/256.0], linewidth=5, marker='', label='Pathway')
						set_pathway_label = False
					else:
						ax.plot(p[:, 0], p[:, 1], color=[43.0/256.0,46.0/256.0,60.0/256.0], linewidth=5, marker='')

				if fontsize > 18:
					plt.legend(fontsize=fontsize-10,facecolor=[0.9,0.9,0.92])
				else:
					plt.legend(fontsize=fontsize-4,facecolor=[0.9,0.9,0.92])

			# Plot cluster centers in landscape
			if self.cluster_centers_ is not None:
				if self.n_dims_ > 1:
					ax.scatter(self.data_[self.cluster_centers_,0], self.data_[self.cluster_centers_,1], marker='s', s=120,
						   linewidth=4, facecolor='',edgecolor='w', label='Cluster center')
				else:
					ax.scatter(self.data_[self.cluster_centers_], self.FE_points_[self.cluster_centers_], marker='s', s=120,
						   linewidth=4, facecolor='',edgecolor='w', label='Cluster center',zorder=5)
				if fontsize > 18:
					plt.legend(fontsize=fontsize-10,facecolor=[0.9,0.9,0.92])
				else:
					plt.legend(fontsize=fontsize-4,facecolor=[0.9,0.9,0.92])
		ax.set_title(title, fontsize=fontsize,fontname='serif',fontweight='light')
		ax.set_xlabel(xlabel, fontsize=fontsize - 2,fontname='serif',fontweight='light')
		plt.rc('xtick', labelsize=fontsize-2)
		plt.rc('ytick', labelsize=fontsize-2)
		matplotlib.rc('font',family='Serif')

		if savefig:
			plt.savefig(filename + '.svg')
			plt.savefig(filename + '.eps')
			plt.savefig(filename + '.png')

		return