#!/usr/bin/python
"""
A module to calculate the current, the conductance and the TMR from
a set of rate arrays.
The rate arrays are supposed to be stored in a h5 file in the job directory.
The result is stored in a h5 file. The name of the dataset contains all
parameters. They are also stored as attributes in the dataset.
The conductance in the two lead configurations (parallel/anti-parallel)
are stored in arrays in the dataset.

Usage:
  ./tmr.py <jobname>
"""

import numpy as np
from numpy import linalg

import time
import sys
import getopt
import h5py
import os

# We are picky about possible floating point overflows
# to avoid calculating NaNs
np.seterr(divide="raise")
np.seterr(invalid="raise")

# A helper module to calculate the populations.
import pop

# The configuration module
import cfg

# path to the dat directory
datpath = "dat/"
# name of the temporary file where the rates are stored
ratefile = "running_calc.h5"
# name of the h5 file to store the conductance for the two configuration
# and the configuraion parameters.
hdffile = "simdata_new.h5"

def save_hdf5(fname,G_P,G_AP):
    """
    Store the conductance and the configuration to the h5 file.

    Args:
      fname: filename of the h5 file
      G_P: the conductance for leads with parallel magnetization
      G_AP: the conductance for leads with anti-parallel magnetization
    """
    print "Shape of GP {}".format(G_P.shape)

    fileh = h5py.File(fname,"a")

    # Note that the selection of parameters to construct the name of the
    # dataset should be chosen such that this string is unique!
    # That is, it should contain all running parameters.
    dset_name = "G={}_kbT={}_Ec={}_E0={}_Pol={}_PolOrb={}_SO={}_tau={}_DS={}_B_P={}_B_AP={}_B_ORB_P={}_B_ORB_AP={}_W_e={}_W_0={}".format(cfg.conf['G_scale'],cfg.conf['kBT'],cfg.conf['E_C'],cfg.conf['E_0'],cfg.conf['Pol'],cfg.conf['OrbPol'],cfg.conf['SO'],cfg.conf['tau_r'],cfg.conf['D_S_factor'],cfg.conf['B_P'],cfg.conf['B_AP'],cfg.conf['B_ORB_P'],cfg.conf['B_ORB_AP'],cfg.conf['W_E'],cfg.conf['W_0'])

    try:
        # we create the dataset
        dset = fileh.create_dataset(dset_name,data=np.vstack((G_P,G_AP)))

        # and store the config attributes
        dset.attrs['alpha'] = cfg.conf['ALPHA']
        dset.attrs['temperature'] = cfg.conf['kBT']
        dset.attrs['coupling'] = cfg.conf['G_scale']
        dset.attrs['electron_number'] = cfg.conf['N_0']
        dset.attrs['charging_energy'] = cfg.conf['E_C']
        dset.attrs['level_spacing'] = cfg.conf['E_0']
        dset.attrs['polarization_spin'] = cfg.conf['Pol']
        dset.attrs['polarization_orbit'] = cfg.conf['OrbPol']
        dset.attrs['spinorbit'] = cfg.conf['SO']
        dset.attrs['stonershift'] = cfg.conf['D_S_factor']
        dset.attrs['tau_r'] = cfg.conf['tau_r']
        dset.attrs['vg_min'] = cfg.conf['V_g_min']
        dset.attrs['vg_max'] = cfg.conf['V_g_max']
        dset.attrs['b_p'] = cfg.conf['B_P']
        dset.attrs['b_ap'] = cfg.conf['B_AP']
        dset.attrs['b_orb_p'] = cfg.conf['B_ORB_P']
        dset.attrs['b_orb_ap'] = cfg.conf['B_ORB_AP']
        dset.attrs['w_0'] = cfg.conf['W_0']
        dset.attrs['w_e'] = cfg.conf['W_E']
        dset.attrs['timestamp'] = time.time()
    except KeyError:
        # If the choice was not unique we complain but continue.
        print "Dataset exists."

    fileh.close()

def eval_DENKER(GM,GP,configuration):
    """
    Evaluate the density matrix kernel using the in- and out-tunneling rates.

    Args:
      GM,GP: numpy arrays containing in- and out-tunneling rates
             in the order of cfg.TLIST.
      configuration: integer determining parallel (0) or anti-parallel(1)
                     configuration

    Returns:
      the density matrix as a square 2-d numpy array that is NP**2 in size,
      where NP is the number of states in the groundstatespace.
    """

    # we get a view on the transition list and, for simplicity, its transpose
    TLIST = cfg.TLIST[configuration]
    TLIST_T = np.transpose(TLIST)

    # from all transitions we extract all groundstates in the statespace
    # this is probably a complicated way to do it
    PLIST = list(set(TLIST_T[0]).union(TLIST_T[1]))
    # ... and sort it by index
    PLIST.sort()

    # the number of groundstates
    NP = len(PLIST)

    # let's create an empty density matrix
    ME = np.zeros((NP,NP))

    # we create a version of the transition list that does not contain
    # the indices in terms of the energy array (see cfg.py), but
    # in terms of the number in the state list (plist)
    # (the transition list can then be used to denote non-zero matrix elements)
    TMP = np.copy(TLIST)
    for idx,val in enumerate(PLIST):
        TMP[TLIST == val] = idx

    # We calculate diagonal elements of the density matrix:
    # TLIST_T[1] == num selects the correct in-tunneling rates for the
    # state with label num
    # have a look at numpy.where to understand this line

    for idx,num in enumerate(PLIST):
        ME[idx,idx] = -np.sum(np.where(TLIST_T[1] == num,GP,0.)) - np.sum(np.where(TLIST_T[0] == num,GM,0.))

    # for the off diagonal elements we can directly use the generated TMP
    # transition list

    for k,tup in enumerate(TMP):
        ME[tup[0],tup[1]] = GP[k]
        ME[tup[1],tup[0]] = GM[k]
#        print "tup: {} and matrix element {}".format(tup,ME[tuple(tup)])

    return ME

def eval_CURKER(GM,GP,configuration):
    """
    Evaluate the current kernel using the in- and out-tunneling rates.

    Args:
      GM,GP: numpy arrays containing in- and out-tunneling rates
             in the order of cfg.TLIST.
      configuration: integer determining parallel (0) or anti-parallel(1)
                     configuration

    Returns:
      the current kernel as a 1-d numpy array.
    """

    # We get a view on the transition list and its transpose
    TLIST = cfg.TLIST[configuration]
    TLIST_T = np.transpose(TLIST)

    # ... and extract the list of groundstates (see also eval_DENKER)
    PLIST = list(set(TLIST_T[0]).union(TLIST_T[1]))
    PLIST.sort()

    # this determines the size of the statespace
    NP = len(PLIST)
    CUR = np.zeros(NP)

    # Note that the current kernel can be calculated by summing the diagonal elements
    # of the density matrix with opposite sign
    # compare eval_DENKER

    for idx,num in enumerate(PLIST):

        CUR[idx] = np.sum(np.where(TLIST_T[1] == num,GP,0.)) - np.sum(np.where(TLIST_T[0] == num,GM,0.))
    return CUR

def current(GP,GM,POP,configuration):
    """
    Calculate the current using the rates and populations.

    Args:
      GP, GM: np-arrays containing in- and out-tunneling rates.
      POP: np-array for the populations
      configuration: integer determining parallel (0) or anti-parallel(1)
                     configuration

    Returns:
      current as a float.
    """

    # We calculate the current kernel
    CURKER = eval_CURKER(GM,GP,configuration)

    # and vector-multiply it with the population vector
    I = -np.sum(cfg.conf["ELE"]*np.dot( CURKER, POP))

    return I

def eval_tmr(fname,plotname,pop):
    """
    Calculates the TMR by evaluating conductance through
    parallel and anti-parallel polarized contacts.

    Args:
      fname: the h5 file to load the rates from.
      plotname: A name for the pdf output to produce.
      pop: If True, we plot the populations, too.

    """

    # We prepare the current and conductance vectors for different
    # values of gate and bias voltage

    C_p = np.zeros((cfg.conf['NV'],cfg.conf['NVb']))
    C_ap = np.zeros((cfg.conf['NV'],cfg.conf['NVb']))
    G_p =  np.zeros((cfg.conf['NV'],cfg.conf['NVb']-1))
    G_ap = np.zeros((cfg.conf['NV'],cfg.conf['NVb']-1))
    dVb = cfg.conf['Vb_range'][1]- cfg.conf['Vb_range'][0]

    # the population vectors, for all values of gate and bias
    POP_p =  np.zeros((cfg.conf['NVb'],cfg.conf['NV'],cfg.N_GS[0]))
    POP_ap = np.zeros((cfg.conf['NVb'],cfg.conf['NV'],cfg.N_GS[1]))

    # We iterate over two bias values first
    for nV,Vb in enumerate(cfg.conf["Vb_range"]):
        # now the rates are loaded from the h5 file
        # note that the label of the specific rate arrays are fixed
        with h5py.File(fname) as file:
            GP0_p = np.array(file['par_P0_V{}'.format(Vb)])
            GP0_ap = np.array(file['apa_P0_V{}'.format(Vb)])
            GP1_p = np.array(file['par_P1_V{}'.format(Vb)])
            GP1_ap = np.array(file['apa_P1_V{}'.format(Vb)])
            GM0_p = np.array(file['par_M0_V{}'.format(Vb)])
            GM0_ap = np.array(file['apa_M0_V{}'.format(Vb)])
            GM1_p = np.array(file['par_M1_V{}'.format(Vb)])
            GM1_ap = np.array(file['apa_M1_V{}'.format(Vb)])

        # for the density kernel, we sum all rates over both leads
        DENKER_p = np.array([eval_DENKER(GM0_p[n]+GM1_p[n],GP0_p[n]+GP1_p[n],0)for n in range(cfg.conf["NV"])])

        DENKER_ap = np.array([eval_DENKER(GM0_ap[n]+GM1_ap[n],GP0_ap[n]+GP1_ap[n],1)for n in range(cfg.conf["NV"])])

        # the populations are calculated from the density kernel by an asymptotic
        # approximation scheme
        POP_ap[nV] = np.array([pop.asymptotic_ssp(DENKER_ap[n]) for n in range(cfg.conf["NV"])])
        POP_p[nV] = np.array([pop.asymptotic_ssp(DENKER_p[n]) for n in range(cfg.conf["NV"])])

        # note that the current is calculated from the rates in one of the leads only
        C_p[:,nV] = np.array([ current(GP0_p[n],GM0_p[n],POP_p[nV,n],0) for n in np.arange(cfg.conf["NV"]) ])
        C_ap[:,nV] = np.array([ current(GP0_ap[n],GM0_ap[n],POP_ap[nV,n],1) for n in np.arange(cfg.conf["NV"]) ])

    # the numerical derivative gives the conductance
    G_p = np.diff(C_p).flatten()/dVb
    G_ap = np.diff(C_ap).flatten()/dVb

    # we save the conductance traces to a h5 file specified as a global variable
    # hdffile in the path datpath
    # It is possible that the dataset already exists. In this case, we issue a warning.
    try:
        save_hdf5("{}{}".format(datpath,hdffile),G_p,G_ap)
    except RuntimeError:
        print "Unable to save to {}, maybe there is already a dataset with similar parameters...".format(hdffile)

    # the tmr and conductance graphs are plotted to a pdf file for review.
    plot_tmr_pdf(G_p,G_ap,plotname)

    # if the pop flag is set, we also plot the population for one bias value
    if pop:
        plot_population([POP_p[0],POP_ap[0]],os.path.splitext(plotname)[0]+"_POP.pdf")

def plot_tmr_pdf(C_p,C_ap,fname):
    """
    A helper routine to plot the conductance and TMR to a pdf file in the datpath.

    Args:
      C_p, C_ap: the parallel and anti-parallel conductance.
      fname: the filename to plot to
    """
    import matplotlib as mpl
    mpl.use('Agg')
    import matplotlib.pyplot as plt

    # we plot the conductance graph on top, p and ap with different colors
    Axes1 = plt.subplot(2,1,1)

    Axes1.set_xticklabels([])
    plt.ylabel("Conductance (e^2/h)")

    plt.title("Conductance at zero bias")

    # parallel is plotted in red, and anti-parallel as blue dashed line
    plt.plot( cfg.conf["V_g"],C_p,'r',cfg.conf["V_g"], C_ap, 'b--')

    # on the second panel, the TMR is plotted
    Axes2 = plt.subplot(2,1,2)

    plt.xlabel("gate voltage (V)")
    plt.ylabel("TMR")
    plt.title("TMR")

    plt.ylim((-0.3,1.5))

    TMR = np.zeros(cfg.conf["NV"])

    for i in range(cfg.conf["NV"]):
        try:
            TMR[i] = C_p[i]/C_ap[i]-1.
        except ZeroDivisionError:
            print "Zero Division, returning null."
            TMR[i] = 0.
    plt.plot( cfg.conf["V_g"], TMR)
    plt.savefig(fname, bbox_inches='tight')

def plot_population(POP, fname):
    """
    Calculates and plots selected populations of the quantum dot
    with gate voltage. The edge states N=-1 and 5 are neglected.

    Args:
      POP: a list with the two population vectors
           for parallel and anti-parallel configurations
      fname: the filename to plot to

    """
    import matplotlib.pyplot as plt

    NV = cfg.conf["NV"]

    print "Calculating populations..."

    # We plot the populations for both configurations
    # the parallel populations on top
    # the anti-parallel on bottom
    Ax = [plt.subplot(2,1,1),plt.subplot(2,1,2)]

    cm = plt.get_cmap('gist_rainbow')

    PopPlots = [1,4,8,12,17,18]
    NP = len(PopPlots)

    for gamidx in range(2):
        TLIST = cfg.TLIST[gamidx]
        TLIST_T = np.transpose(TLIST)

        PLIST = list(set(TLIST_T[0]).union(TLIST_T[1]))
        PLIST.sort()

        # we cycle through the linecolors to distinguish the different
        # groundstates
        Ax[gamidx].set_color_cycle([cm(1.*k/NP) for k in range(NP)])

        for i in PopPlots:
            color = cm(1.*i/NP)
            LABEL = "P_{}".format(cfg.int_to_state(PLIST[i]))
            Ax[gamidx].plot( cfg.conf["V_g"], POP[gamidx][:,i],label=LABEL)

        lines =Ax[gamidx].get_lines()
        labels = [l.get_label() for l in lines]
        leg = plt.figlegend(lines,labels,loc='upper right')

    plt.savefig(fname)
    plt.show()

class Usage(Exception):
    def __init__(self, msg):
        self.msg = msg

def main(argv=None):
    """
    Interface routine to call the tmr module.
    Example:
      ./tmr.py <jobname>

    In principle, there were routines to plot rates, populations,
    conductances etc. but apart from the population plotting,
    none of the use cases was needed anymore.

    """
    POP = False

    # The default config file is called cnt.conf
    cfile = "cnt.conf"
    rlist = [0.,]

    if argv is None:
        argv = sys.argv
    try:
        try:
            opts, args = getopt.getopt(argv[1:], "hc:P", ["help","config=","pop"])
        except getopt.error, msg:
             raise Usage(msg)
        for o,a in opts:
            if o in ('-h','--help'):
                usage()
                exit()
            elif o in ('-c','--config'):
                cfile = a
            elif o in ('-P','--pop'):
                POP = True
            else:
                raise Usage('Invalid argument.')

        # we parse the config and initialize it
        cfg.parse_conf("dat/{0}/{1}".format(args[0],cfile))
        cfg.init()

        h5file = "{}{}/{}".format(datpath,args[0],ratefile)
        pdffile = "{}{}.pdf".format(datpath,args[0])
        print "Try to open {}".format(h5file)
        eval_tmr(h5file,pdffile,POP)

    except Usage, err:
        print >>sys.stderr, err.msg
        print >>sys.stderr, "for help use --help"
        return 2

def usage():
    print "This is a tool to process rate files.\n\
    \n\
    usage: tmr.py [-hP] [--pop] jobname\n\
    \n\
    --pop or -P: Plot the populations.\n\
    \n\
    jobname: The name of the directory for the rate files.\n\
    \n\
    The script searches for files dat/jobname/running_calc.h5\n\
    and dat/jobname/cnt.conf"

if __name__ == "__main__":
    sys.exit(main())


"""Style Net w/ tests for Video Style Net.

Video Style Net requires OpenCV 3.0.0+ w/ Contrib for Python to be installed.

Creative Applications of Deep Learning w/ Tensorflow.
Kadenze, Inc.
Copyright Parag K. Mital, June 2016.
"""
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import os
from . import vgg16
from . import gif

def make_4d(img):
    """Create a 4-dimensional N x H x W x C image.

    Parameters
    ----------
    img : np.ndarray
        Given image as H x W x C or H x W.

    Returns
    -------
    img : np.ndarray
        N x H x W x C image.

    Raises
    ------
    ValueError
        Unexpected number of dimensions.
    """
    if img.ndim == 2:
        img = np.expand_dims(img[np.newaxis], 3)
    elif img.ndim == 3:
        img = img[np.newaxis]
    elif img.ndim == 4:
        return img
    else:
        raise ValueError('Incorrect dimensions for image!')
    return img

def stylize(content_img, style_img, base_img=None, saveto=None, gif_step=5,
            n_iterations=100, style_weight=1.0, content_weight=1.0):
    """Stylization w/ the given content and style images.

    Follows the approach in Leon Gatys et al.

    Parameters
    ----------
    content_img : np.ndarray
        Image to use for finding the content features.
    style_img : TYPE
        Image to use for finding the style features.
    base_img : None, optional
        Image to use for the base content.  Can be noise or an existing image.
        If None, the content image will be used.
    saveto : str, optional
        Name of GIF image to write to, e.g. "stylization.gif"
    gif_step : int, optional
        Modulo of iterations to save the current stylization.
    n_iterations : int, optional
        Number of iterations to run for.
    style_weight : float, optional
        Weighting on the style features.
    content_weight : float, optional
        Weighting on the content features.

    Returns
    -------
    stylization : np.ndarray
        Final iteration of the stylization.
    """
    # Preprocess both content and style images
    content_img = make_4d(content_img)
    style_img = make_4d(style_img)
    if base_img is None:
        base_img = content_img
    else:
        base_img = make_4d(base_img)

    # Get Content and Style features
    net = vgg16.get_vgg_model()
    g = tf.Graph()
    with tf.Session(graph=g) as sess:
        tf.import_graph_def(net['graph_def'], name='vgg')
        names = [op.name for op in g.get_operations()]
        x = g.get_tensor_by_name(names[0] + ':0')
        content_layer = 'vgg/conv3_2/conv3_2:0'
        content_features = g.get_tensor_by_name(
            content_layer).eval(feed_dict={
                x: content_img,
                'vgg/dropout_1/random_uniform:0': [[1.0]],
                'vgg/dropout/random_uniform:0': [[1.0]]})
        style_layers = ['vgg/conv1_1/conv1_1:0',
                        'vgg/conv2_1/conv2_1:0',
                        'vgg/conv3_1/conv3_1:0',
                        'vgg/conv4_1/conv4_1:0',
                        'vgg/conv5_1/conv5_1:0']
        style_activations = []
        for style_i in style_layers:
            style_activation_i = g.get_tensor_by_name(style_i).eval(
                feed_dict={
                    x: style_img,
                    'vgg/dropout_1/random_uniform:0': [[1.0]],
                    'vgg/dropout/random_uniform:0': [[1.0]]})
            style_activations.append(style_activation_i)
        style_features = []
        for style_activation_i in style_activations:
            s_i = np.reshape(style_activation_i,
                             [-1, style_activation_i.shape[-1]])
            gram_matrix = np.matmul(s_i.T, s_i) / s_i.size
            style_features.append(gram_matrix.astype(np.float32))

    # Optimize both
    g = tf.Graph()
    with tf.Session(graph=g) as sess:
        net_input = tf.Variable(base_img)
        tf.import_graph_def(
            net['graph_def'],
            name='vgg',
            input_map={'images:0': net_input})

        content_loss = tf.nn.l2_loss((g.get_tensor_by_name(content_layer) -
                                      content_features) /
                                     content_features.size)
        style_loss = np.float32(0.0)
        for style_layer_i, style_gram_i in zip(style_layers, style_features):
            layer_i = g.get_tensor_by_name(style_layer_i)
            layer_shape = layer_i.get_shape().as_list()
            layer_size = layer_shape[1] * layer_shape[2] * layer_shape[3]
            layer_flat = tf.reshape(layer_i, [-1, layer_shape[3]])
            gram_matrix = tf.matmul(
                tf.transpose(layer_flat), layer_flat) / layer_size
            style_loss = tf.add(
                style_loss, tf.nn.l2_loss(
                    (gram_matrix - style_gram_i) /
                    np.float32(style_gram_i.size)))
        loss = content_weight * content_loss + style_weight * style_loss
        optimizer = tf.train.AdamOptimizer(0.01).minimize(loss)

        sess.run(tf.initialize_all_variables())
        imgs = []
        for it_i in range(n_iterations):
            _, this_loss, synth = sess.run(
                [optimizer, loss, net_input],
                feed_dict={
                    'vgg/dropout_1/random_uniform:0': np.ones(
                        g.get_tensor_by_name(
                            'vgg/dropout_1/random_uniform:0'
                        ).get_shape().as_list()),
                    'vgg/dropout/random_uniform:0': np.ones(
                        g.get_tensor_by_name(
                            'vgg/dropout/random_uniform:0'
                        ).get_shape().as_list())
                })
            print("iteration %d, loss: %f, range: (%f - %f)" %
                  (it_i, this_loss, np.min(synth), np.max(synth)), end='\r')
            if it_i % gif_step == 0:
                imgs.append(np.clip(synth[0], 0, 1))
        if saveto is not None:
            gif.build_gif(imgs, saveto=saveto)
    return np.clip(synth[0], 0, 1)

def warp_img(img, dx, dy):
    """Apply the motion vectors to the given image.

    Parameters
    ----------
    img : np.ndarray
        Input image to apply motion to.
    dx : np.ndarray
        H x W matrix defining the magnitude of the X vector
    dy : np.ndarray
        H x W matrix defining the magnitude of the Y vector

    Returns
    -------
    img : np.ndarray
        Image with pixels warped according to dx, dy.
    """
    warped = img.copy()
    for row_i in range(img.shape[0]):
        for col_i in range(img.shape[1]):
            dx_i = int(np.round(dx[row_i, col_i]))
            dy_i = int(np.round(dy[row_i, col_i]))
            sample_dx = np.clip(dx_i + col_i, 0, img.shape[0] - 1)
            sample_dy = np.clip(dy_i + row_i, 0, img.shape[1] - 1)
            warped[sample_dy, sample_dx, :] = img[row_i, col_i, :]
    return warped

def test_video(style_img='arles.jpg', videodir='kurosawa'):
    r"""Test for artistic stylization using video.

    This requires the python installation of OpenCV for the Deep Flow algorithm.
    If cv2 is not found, then there will be reduced "temporal coherence".

    Unfortunately, installing opencv for python3 is not the easiest thing to do.
    OSX users can install this using:

    $ brew install opencv --with-python3 --with-contrib

    then will have to symlink the libraries.  I think you can do this w/:

    $ brew link --force opencv3

    But the problems start to arise depending on which python you have
    installed, and it is always a mess w/ homebrew.  Sorry!

    Your best bet is installing from source.  Something along
    these lines should get you there:

    $ cd ~
    $ git clone https://github.com/Itseez/opencv.git
    $ cd opencv
    $ git checkout 3.1.0
    $ cd ~
    $ git clone https://github.com/Itseez/opencv_contrib.git
    $ cd opencv_contrib
    $ git checkout 3.1.0
    $ cd ~/opencv
    $ mkdir build
    $ cd build
    $ cmake -D CMAKE_BUILD_TYPE=RELEASE \
        -D CMAKE_INSTALL_PREFIX=/usr/local \
        -D INSTALL_C_EXAMPLES=OFF \
        -D INSTALL_PYTHON_EXAMPLES=OFF \
        -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \
        -D BUILD_EXAMPLES=OFF ..

    Parameters
    ----------
    style_img : str, optional
        Location to style image
    videodir : str, optional
        Location to directory containing images of each frame to stylize.

    Returns
    -------
    imgs : list of np.ndarray
        Stylized images for each frame.
    """
    has_cv2 = True
    try:
        import cv2
        has_cv2 = True
        optflow = cv2.optflow.createOptFlow_DeepFlow()
    except ImportError:
        has_cv2 = False

    style_img = plt.imread(style_img)
    content_files = [os.path.join(videodir, f)
                     for f in os.listdir(videodir) if f.endswith('.png')]
    content_img = plt.imread(content_files[0])
    from scipy.misc import imresize
    style_img = imresize(style_img, (448, 448)).astype(np.float32) / 255.0
    content_img = imresize(content_img, (448, 448)).astype(np.float32) / 255.0
    if has_cv2:
        prev_lum = cv2.cvtColor(content_img, cv2.COLOR_RGB2HSV)[:, :, 2]
    else:
        prev_lum = (content_img[..., 0] * 0.3 +
                    content_img[..., 1] * 0.59 +
                    content_img[..., 2] * 0.11)
    imgs = []
    stylized = stylize(content_img, style_img, content_weight=5.0,
                       style_weight=0.5, n_iterations=50)
    plt.imsave(fname=content_files[0] + 'stylized.png', arr=stylized)
    imgs.append(stylized)
    for f in content_files[1:]:
        content_img = plt.imread(f)
        content_img = imresize(content_img, (448, 448)).astype(np.float32) / 255.0
        if has_cv2:
            lum = cv2.cvtColor(content_img, cv2.COLOR_RGB2HSV)[:, :, 2]
            flow = optflow.calc(prev_lum, lum, None)
            warped = warp_img(stylized, flow[..., 0], flow[..., 1])
            stylized = stylize(content_img, style_img, content_weight=5.0,
                               style_weight=0.5, base_img=warped, n_iterations=50)
        else:
            lum = (content_img[..., 0] * 0.3 +
                   content_img[..., 1] * 0.59 +
                   content_img[..., 2] * 0.11)
            stylized = stylize(content_img, style_img, content_weight=5.0,
                               style_weight=0.5, base_img=None, n_iterations=50)
        imgs.append(stylized)
        plt.imsave(fname=f + 'stylized.png', arr=stylized)
        prev_lum = lum
    return imgs

def test():
    """Test for artistic stylization."""
    from six.moves import urllib
    f = ('https://upload.wikimedia.org/wikipedia/commons/thumb/5/54/' +
         'Claude_Monet%2C_Impression%2C_soleil_levant.jpg/617px-Claude_Monet' +
         '%2C_Impression%2C_soleil_levant.jpg?download')
    filepath, _ = urllib.request.urlretrieve(f, f.split('/')[-1], None)
    style = plt.imread(filepath)

    f = ('https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/' +
         'El_jard%C3%ADn_de_las_Delicias%2C_de_El_Bosco.jpg/640px-El_jard' +
         '%C3%ADn_de_las_Delicias%2C_de_El_Bosco.jpg')
    filepath, _ = urllib.request.urlretrieve(f, f.split('/')[-1], None)
    content = plt.imread(filepath)

    stylize(content, style)

if __name__ == '__main__':
    test_video()


import numpy as np

try:
    isclose = np.isclose
except AttributeError:
    def isclose(*args, **kwargs):
        raise RuntimeError("You need numpy version 1.7 or greater to use "
                           "isclose.")

try:
    full = np.full
except AttributeError:
    def full(shape, fill_value, dtype=None, order=None):
        """Our implementation of numpy.full because your numpy is old."""
        if order is not None:
            raise NotImplementedError("`order` kwarg is not supported upgrade "
                                      "to Numpy 1.8 or greater for support.")
        return np.multiply(fill_value, np.ones(shape, dtype=dtype),
                           dtype=dtype)

# Taken from scikit-learn:
# https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/utils/fixes.py#L84
try:
    if (not np.allclose(np.divide(.4, 1, casting="unsafe"),
                        np.divide(.4, 1, casting="unsafe", dtype=np.float))
            or not np.allclose(np.divide(.4, 1), .4)):
        raise TypeError('Divide not working with dtype: '
                        'https://github.com/numpy/numpy/issues/3484')
    divide = np.divide

except TypeError:
    # Divide with dtype doesn't work on Python 3
    def divide(x1, x2, out=None, dtype=None):
        """Implementation of numpy.divide that works with dtype kwarg.

        Temporary compatibility fix for a bug in numpy's version. See
        https://github.com/numpy/numpy/issues/3484 for the relevant issue."""
        x = np.divide(x1, x2, out)
        if dtype is not None:
            x = x.astype(dtype)
        return x


"""
Laconic plot functions to replace some of the matplotlibs verbosity
"""
from matplotlib import pyplot as plt
import numpy as np
import seaborn as sns

# -- File I/O ------------------------------------------------------------ -- #
def lsave(data,fileName):
  np.savetxt(fileName, data, delimiter=',',fmt='%1.2e')

def lload(fileName):
  return np.loadtxt(fileName, delimiter=',')

# -- Basic Plotting ------------------------------------------------------ -- #
def lplot(*args,label=[],axis=False):
  """Plots an vector, a set of vectors, with or without an x scale
  """
  fig, ax = getAxis(axis)

  if len(args) == 1: # No xscale
    x = np.arange(np.shape(args)[1])
    y = args[0]
  if len(args) == 2: # xscale given
    x = args[0]
    y = args[1]

  if np.ndim(y) == 2:
    for i in range(np.shape(y)[1]):
      ax.plot(x,y[:,i],'-')
      if len(label) > 0:
        ax.legend((label))
  else:
    ax.plot(x,y,'o-')

  if axis is False:
    return fig, ax
  else:
    return ax

def ldist(x, axis=False):
  """Plots histogram with estimated distribution
  """
  fig, ax = getAxis(axis)

  if isinstance(x, str):
    vals = lload(x)
  else:
    vals = x
  sns.distplot(vals.flatten(),ax=ax,bins=10)
  #sns.distplot(vals.flatten(),ax=ax,hist_kws={"histtype": "step", "linewidth": 3, "alpha": 1, "color": "g"})
  return ax

def lquart(x,y,label=[],axis=False):
  """Plots quartiles, x is a vector, y is a matrix with same length as x
  """
  if axis is not False:
    ax = axis
    fig = ax.figure.canvas
  else:
    fig, ax = plt.subplots()

  q = np.percentile(y,[25,50,75],axis=1)
  plt.plot(x,q[1,:],label=label) # median
  plt.plot(x,q[0,:],'k:',alpha=0.5)
  plt.plot(x,q[2,:],'k:',alpha=0.5)
  plt.fill_between(x,q[0,:],q[2,:],alpha=0.25)

  return ax

def getAxis(axis):
  if axis is not False:
    ax = axis
    fig = ax.figure.canvas
  else:
    fig, ax = plt.subplots()

  return fig,ax
# -- --------------- -- --------------------------------------------#


from ..greengraph import Greengraph
from ..map import Map
import geopy
from nose.tools import assert_equal, assert_almost_equal
import numpy.testing as np_test
from mock import Mock, patch
import requests
from matplotlib import image
import yaml
import os
import numpy as np

#@patch.object(Greengraph, 'location_sequence')
#@patch.object(Map, 'count_green')
def test_map_constructor():
    mock_image= open(os.path.join(os.path.dirname(__file__),'fixtures','NY_2.png'),'rb') #as mock_imgfile:
    with patch.object(requests,'get',return_value=Mock(content=mock_image.read())) as mock_get:
        with patch.object(image,'imread') as mock_img:
            #default
            Map(40.7127837, -74.0059413) # New York
            #Longon Map(51.5073509,-0.1277583)
            mock_get.assert_called_with(
                "http://maps.googleapis.com/maps/api/staticmap?",
                params={
                    'sensor':'false',
                    'zoom':10,
                    'size':'400x400',
                    'center':'40.7127837,-74.0059413',
                    'style':'feature:all|element:labels|visibility:off',
                    'maptype': 'satellite'
                    }
            )
                #changing parameters
            Map(41.8781136, -87.6297982,satellite=False,zoom=15,size=(500,350),sensor=True) # New York
            mock_get.assert_called_with(
                "http://maps.googleapis.com/maps/api/staticmap?",
                params={
                    'sensor':'true',
                    'zoom':15,
                    'size':'500x350',
                    'center':'41.8781136,-87.6297982',
                    'style':'feature:all|element:labels|visibility:off',
                    #'maptype': 'satellite'
                    }
                )

def test_green():
    mock_image= open(os.path.join(os.path.dirname(__file__),'fixtures','NY_2.png'),'rb')
    fixture_green = np.load(os.path.join(os.path.dirname(__file__),'fixtures','ny_green.npy'))
    threshold = 1.1
    with patch('requests.get', return_value=Mock(content=mock_image.read())) as mock_get:
        testMap = Map(41.8781136, -87.6297982) # New York
        assert_equal(fixture_green.shape,testMap.green(threshold).shape)
        assert (testMap.green(threshold) == fixture_green).all() == True
        assert (testMap.green(1.5) == fixture_green).all() == False

def test_count_green():
    mock_image= open(os.path.join(os.path.dirname(__file__),'fixtures','NY_2.png'),'rb')
    fixture_green = np.load(os.path.join(os.path.dirname(__file__),'fixtures','ny_green.npy'))
    threshold = 1.1
    with patch('requests.get', return_value=Mock(content=mock_image.read())) as mock_get:
        testMap = Map(41.8781136, -87.6297982) # New York
        count_from_fixture=np.sum(fixture_green)
        assert (testMap.count_green() == count_from_fixture)
        assert (testMap.count_green(1.5) != count_from_fixture)


import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler, StandardScaler

class data_scaler(object):
    def __init__(self):
        self.norm = None
        self.norm_1 = None
        self.std = None
        self.case = None
        self.scale = 1
        self.bias = 1e-20
        #         self.bias = 1

        self.switcher = {
            'min_std': 'min_std',
            'std2': 'std2',
            'std_min': 'std_min',
            'min': 'min',
            'no': 'no',
            'log': 'log',
            'log_min': 'log_min',
            'log2': 'log2',
            'tan': 'tan'
        }

    def fit_transform(self, input_data, case):
        self.case = case
        if self.switcher.get(self.case) == 'min_std':
            self.norm = MinMaxScaler()
            self.std = StandardScaler()
            out = self.norm.fit_transform(input_data)
            out = self.std.fit_transform(out)

        if self.switcher.get(self.case) == 'std2':
            self.std = StandardScaler()
            out = self.std.fit_transform(input_data)

        if self.switcher.get(self.case) == 'std_min':
            self.norm = MinMaxScaler()
            self.std = StandardScaler()
            out = self.std.fit_transform(input_data)
            out = self.norm.fit_transform(out)

        if self.switcher.get(self.case) == 'min':
            self.norm = MinMaxScaler()
            out = self.norm.fit_transform(input_data)

        if self.switcher.get(self.case) == 'no':
            self.norm = MinMaxScaler()
            self.std = StandardScaler()
            out = input_data

        if self.switcher.get(self.case) == 'log':
            out = - np.log(np.asarray(input_data / self.scale) + self.bias)
            self.std = StandardScaler()
            out = self.std.fit_transform(out)

        if self.switcher.get(self.case) == 'log_min':
            out = - np.log(np.asarray(input_data / self.scale) + self.bias)
            self.norm = MinMaxScaler()
            out = self.norm.fit_transform(out)

        if self.switcher.get(self.case) == 'log2':
            self.norm = MinMaxScaler()
            self.norm_1 = MinMaxScaler()
            out = self.norm.fit_transform(input_data)
            out = np.log(np.asarray(out) + self.bias)
            out = self.norm_1.fit_transform(out)

        if self.switcher.get(self.case) == 'tan':
            self.norm = MaxAbsScaler()
            self.std = StandardScaler()
            out = self.std.fit_transform(input_data)
            out = self.norm.fit_transform(out)
            out = np.tan(out / (2 * np.pi + self.bias))

        return out

    def transform(self, input_data):
        if self.switcher.get(self.case) == 'min_std':
            out = self.norm.transform(input_data)
            out = self.std.transform(out)

        if self.switcher.get(self.case) == 'std2':
            out = self.std.transform(input_data)

        if self.switcher.get(self.case) == 'std_min':
            out = self.std.transform(input_data)
            out = self.norm.transform(out)

        if self.switcher.get(self.case) == 'min':
            out = self.norm.transform(input_data)

        if self.switcher.get(self.case) == 'no':
            out = input_data

        if self.switcher.get(self.case) == 'log':
            out = - np.log(np.asarray(input_data / self.scale) + self.bias)
            out = self.std.transform(out)

        if self.switcher.get(self.case) == 'log_min':
            out = - np.log(np.asarray(input_data / self.scale) + self.bias)
            out = self.norm.transform(out)

        if self.switcher.get(self.case) == 'log2':
            out = self.norm.transform(input_data)
            out = np.log(np.asarray(out) + self.bias)
            out = self.norm_1.transform(out)

        if self.switcher.get(self.case) == 'tan':
            out = self.std.transform(input_data)
            out = self.norm.transform(out)
            out = np.tan(out / (2 * np.pi + self.bias))

        return out

    def inverse_transform(self, input_data):

        if self.switcher.get(self.case) == 'min_std':
            out = self.std.inverse_transform(input_data)
            out = self.norm.inverse_transform(out)

        if self.switcher.get(self.case) == 'std2':
            out = self.std.inverse_transform(input_data)

        if self.switcher.get(self.case) == 'std_min':
            out = self.norm.inverse_transform(input_data)
            out = self.std.inverse_transform(out)

        if self.switcher.get(self.case) == 'min':
            out = self.norm.inverse_transform(input_data)

        if self.switcher.get(self.case) == 'no':
            out = input_data

        if self.switcher.get(self.case) == 'log':
            out = self.std.inverse_transform(input_data)
            out = (np.exp(-out) - self.bias) * self.scale

        if self.switcher.get(self.case) == 'log_min':
            out = self.norm.inverse_transform(input_data)
            out = (np.exp(-out) - self.bias) * self.scale

        if self.switcher.get(self.case) == 'log2':
            out = self.norm_1.inverse_transform(input_data)
            out = np.exp(out) - self.bias
            out = self.norm.inverse_transform(out)

        if self.switcher.get(self.case) == 'tan':
            out = (2 * np.pi + self.bias) * np.arctan(input_data)
            out = self.norm.inverse_transform(out)
            out = self.std.inverse_transform(out)

        return out

def read_h5_data(fileName, input_features, labels):
    df = pd.read_hdf(fileName)
    df = df[df['f'] < 0.45]

    input_df = df[input_features]
    in_scaler = data_scaler()
    input_np = in_scaler.fit_transform(input_df.values, 'no')

    label_df = df[labels].clip(0)
    #     if 'PVs' in labels:
    #       label_df['PVs']=np.log(label_df['PVs']+1)
    out_scaler = data_scaler()
    label_np = out_scaler.fit_transform(label_df.values, 'std2')

    return input_np, label_np, df, in_scaler, out_scaler