import CoolProp.CoolProp as CP
import CoolProp
import textwrap
import os
from parse_bib import BibTeXerClass

def PropertyConsistency(Fluid):

    Tmax = CP.Props(Fluid,"Tcrit")-1 if Fluid == 'SES36' else CP.Props(Fluid,"Tcrit")-0.01

    return textwrap.dedent(
    """
    Check of p,h and p,s as inputs (X: Failure .: Success)
    =================================================================
    .. plot::

        from CoolProp.Plots.Plots import Ph,Ps
        from CoolProp.CoolProp import Props
        from matplotlib import pyplot as plt
        import numpy as np

        Ref = "{Fluid:s}"
        fig = plt.figure(figsize=(10,5))
        ax1 = fig.add_subplot(121)
        ax2 = fig.add_subplot(122)

        Tmin = Props(Ref,'Tmin')+3
        pmin = Props('P','T',Tmin,'Q',0,Ref)
        pmax = Props(Ref,'pcrit')*2
        hmin = Props('H','T',Tmin,'Q',0,Ref)
        hmax = 2*Props('H','T',Props(Ref,'Tcrit')-1,'Q',1,Ref)-hmin
        smin = Props('S','T',Tmin,'Q',0,Ref)
        smax = 2*Props('S','T',Props(Ref,'Tcrit')-1,'Q',1,Ref)-smin

        Ph(Ref, axis = ax1, Tmin = Tmin, Tmax = {Tmax:f})
        Ps(Ref, axis = ax2, Tmin = Tmin, Tmax = {Tmax:f})

        for p in np.linspace(pmin,pmax,10):
            for h in np.linspace(hmin,hmax):
                _bad = False
                try:
                    T = Props('T','H',h,'P',p,Ref)
                    rho = Props('D','H',h,'P',p,Ref)
                    hEOS = Props('H','T',T,'D',rho,Ref)
                except ValueError:
                    _bad = True
                if _bad or abs(hEOS/h-1)>1e-6:
                    ax1.plot(h,p,'x',ms = 10)
                else:
                    ax1.plot(h,p,'k.', ms = 1)

        for p in np.linspace(pmin,pmax,10):
            for s in np.linspace(smin,smax):
                _bad = False
                try:
                    T = Props('T','S',s,'P',p,Ref)
                    rho = Props('D','S',s,'P',p,Ref)
                    sEOS = Props('S','T',T,'D',rho,Ref)
                except ValueError:
                    _bad = True
                if _bad or abs(sEOS/s-1)>1e-6:
                    ax2.plot(s,p,'x',ms = 10)
                else:
                    ax2.plot(s,p,'k.', ms = 1)

        plt.tight_layout()
    """.format(Fluid=Fluid,Tmax = Tmax))

def CriticalIsotherm(Fluid):

    return textwrap.dedent(
    """
    Along the critical isotherm where T=T\ :sub:`c`
    ================================================
    .. plot::

        Fluid = "{Fluid:s}"
        RPFluid = "{RPFluid:s}"

        #Critical isotherm
        from CoolProp.CoolProp import Props
        from numpy import linspace,array,abs
        import matplotlib.pyplot as plt

        Tc = Props(Fluid,'Tcrit')
        rhoc = Props(Fluid,'rhocrit')
        rhov = linspace(1e-12,2*rhoc)

        #All the CoolProp calculations
        p = array([Props('P','T',Tc,'D',D,Fluid) for D in rhov])
        rho = array([Props('D','T',Tc,'D',D,Fluid) for D in rhov])
        cp = array([Props('C','T',Tc,'D',D,Fluid) for D in rhov])
        cv = array([Props('O','T',Tc,'D',D,Fluid) for D in rhov])
        h0 = Props('H','T',0.95*Tc,'Q',1,Fluid)
        h = array([Props('H','T',Tc,'D',D,Fluid)-h0 for D in rhov])
        s0 = Props('S','T',0.95*Tc,'Q',1,Fluid)
        s = array([Props('S','T',Tc,'D',D,Fluid)-s0 for D in rhov])
        visc = array([Props('V','T',Tc,'D',D,Fluid) for D in rhov])
        cond = array([Props('L','T',Tc,'D',D,Fluid) for D in rhov])

        Rp = array([Props('P','T',Tc,'D',D,RPFluid) for D in rhov])
        Rrho = array([Props('D','T',Tc,'D',D,RPFluid) for D in rhov])
        Rcp = array([Props('C','T',Tc,'D',D,RPFluid) for D in rhov])
        Rcv = array([Props('O','T',Tc,'D',D,RPFluid) for D in rhov])
        Rh0 = Props('H','T',0.95*Tc,'Q',1,RPFluid)
        Rh = array([Props('H','T',Tc,'D',D,RPFluid)-Rh0 for D in rhov])
        Rs0 = Props('S','T',0.95*Tc,'Q',1,RPFluid)
        Rs = array([Props('S','T',Tc,'D',D,RPFluid)-Rs0 for D in rhov])
        Rvisc = array([Props('V','T',Tc,'D',D,RPFluid) for D in rhov])
        Rcond = array([Props('L','T',Tc,'D',D,RPFluid) for D in rhov])

        fig = plt.figure()

        ax = fig.add_axes((0.15,0.15,0.8,0.8))
        ax.semilogy(rhov/rhoc,abs(p/Rp-1)*100,'o',label='Pressure')
        ax.semilogy(rhov/rhoc,abs(cp/Rcp-1)*100,'o',label='Specific heat (cp)')
        ax.semilogy(rhov/rhoc,abs(cv/Rcv-1)*100,'o',label='Specific heat (cv)')
        ax.semilogy(rhov/rhoc,abs(h/Rh-1)*100,'o',label='Enthalpy')
        ax.semilogy(rhov/rhoc,abs(s/Rs-1)*100,'o',label='Entropy')
        ax.semilogy(rhov/rhoc,abs(visc/Rvisc-1)*100,'^',label='Viscosity')
        ax.semilogy(rhov/rhoc,abs(cond/Rcond-1)*100,'s',label='Conductivity')
        ax.set_ylim(1e-16,100)
        ax.set_title('Critical isotherm Deviations from REFPROP 9.1')
        ax.set_xlabel(r'Reduced density $\\rho/\\rho_c$')
        ax.set_ylabel('Absolute deviation [%]')
        ax.legend(numpoints=1,loc='best')
        plt.show()
    """.format(Fluid=Fluid,RPFluid = 'REFPROP-'+CP.get_REFPROPname(Fluid)))

def SatVaporParity(Fluid):

    return textwrap.dedent(
    """
    Saturated Vapor Deviations
    ==========================

    .. plot::

        Fluid = "{Fluid:s}"
        RPFluid = "{RPFluid:s}"

        #Saturated Vapor
        from CoolProp.CoolProp import Props
        from numpy import linspace,array,abs
        import matplotlib.pyplot as plt

        Tt = Props(Fluid,'Tmin')
        Tc = Props(Fluid,'Tcrit')
        Tv = linspace(Tt+0.01,0.95*Tc,20)

        #All the CoolProp calculations
        p = array([Props('P','T',T,'Q',1,Fluid) for T in Tv])
        rho = array([Props('D','T',T,'Q',1,Fluid) for T in Tv])
        cp = array([Props('C','T',T,'Q',1,Fluid) for T in Tv])
        cv = array([Props('O','T',T,'Q',1,Fluid) for T in Tv])
        h0 = Props('H','T',(Tt+Tc)/2.0,'Q',1,Fluid)
        h = array([Props('H','T',T,'Q',1,Fluid)-h0 for T in Tv])
        s0 = Props('S','T',(Tt+Tc)/2.0,'Q',1,Fluid)
        s = array([Props('S','T',T,'Q',1,Fluid)-s0 for T in Tv])
        sigma = array([Props('I','T',T,'Q',1,Fluid) for T in Tv])
        visc = array([Props('V','T',T,'Q',1,Fluid) for T in Tv])
        cond = array([Props('L','T',T,'Q',1,Fluid) for T in Tv])

        Rp = array([Props('P','T',T,'Q',1,RPFluid) for T in Tv])
        Rrho = array([Props('D','T',T,'Q',1,RPFluid) for T in Tv])
        Rcp = array([Props('C','T',T,'Q',1,RPFluid) for T in Tv])
        Rcv = array([Props('O','T',T,'Q',1,RPFluid) for T in Tv])
        Rh0 = Props('H','T',(Tt+Tc)/2.0,'Q',1,RPFluid)
        Rh = array([Props('H','T',T,'Q',1,RPFluid)-Rh0 for T in Tv])
        Rs0 = Props('S','T',(Tt+Tc)/2.0,'Q',1,RPFluid)
        Rs = array([Props('S','T',T,'Q',1,RPFluid)-Rs0 for T in Tv])
        Rsigma = array([Props('I','T',T,'Q',1,RPFluid) for T in Tv])
        Rvisc = array([Props('V','T',T,'Q',1,RPFluid) for T in Tv])
        Rcond = array([Props('L','T',T,'Q',1,RPFluid) for T in Tv])

        fig = plt.figure()

        ax = fig.add_axes((0.15,0.15,0.8,0.8))
        ax.semilogy(Tv/Tc,abs(p/Rp-1)*100,'o',label='Pressure')
        ax.semilogy(Tv/Tc,abs(rho/Rrho-1)*100,'o',label='Density')
        ax.semilogy(Tv/Tc,abs(cp/Rcp-1)*100,'o',label='Specific heat (cp)')
        ax.semilogy(Tv/Tc,abs(cv/Rcv-1)*100,'o',label='Specific heat (cv)')
        ax.semilogy(Tv/Tc,abs(h/Rh-1)*100,'o',label='Enthalpy')
        ax.semilogy(Tv/Tc,abs(s/Rs-1)*100,'o',label='Entropy')
        ax.semilogy(Tv/Tc,abs(visc/Rvisc-1)*100,'^',label='Viscosity')
        ax.semilogy(Tv/Tc,abs(cond/Rcond-1)*100,'s',label='Conductivity')
        ax.semilogy(Tv/Tc,abs(sigma/Rsigma-1)*100,'p',label='Surface tension')
        ax.set_ylim(1e-16,100)
        ax.set_title('Saturated Vapor Deviations from REFPROP 9.1')
        ax.set_xlabel('Reduced temperature T/Tc')
        ax.set_ylabel('Absolute deviation [%]')
        ax.legend(numpoints=1,loc='best')
        plt.show()
    """.format(Fluid=Fluid,RPFluid = 'REFPROP-'+CP.get_REFPROPname(Fluid)))

def SatLiquidParity(Fluid):

    return textwrap.dedent(
    """
    Saturated Liquid Deviations
    ===========================

    .. plot::

        Fluid = "{Fluid:s}"
        RPFluid = "{RPFluid:s}"

        #Saturated Liquid
        from CoolProp.CoolProp import Props
        from numpy import linspace,array,abs
        import matplotlib.pyplot as plt

        Tt = Props(Fluid,'Tmin')
        Tc = Props(Fluid,'Tcrit')
        Tv = linspace(Tt+0.01,0.95*Tc,20)

        #All the CoolProp calculations
        p = array([Props('P','T',T,'Q',0,Fluid) for T in Tv])
        rho = array([Props('D','T',T,'Q',0,Fluid) for T in Tv])
        cp = array([Props('C','T',T,'Q',0,Fluid) for T in Tv])
        cv = array([Props('O','T',T,'Q',0,Fluid) for T in Tv])
        h0 = Props('H','T',(Tt+Tc)/2.0,'Q',0,Fluid)
        h = array([Props('H','T',T,'Q',0,Fluid)-h0 for T in Tv])
        s0 = Props('S','T',(Tt+Tc)/2.0,'Q',0,Fluid)
        s = array([Props('S','T',T,'Q',0,Fluid)-s0 for T in Tv])
        visc = array([Props('V','T',T,'Q',0,Fluid) for T in Tv])
        cond = array([Props('L','T',T,'Q',0,Fluid) for T in Tv])
        sigma = array([Props('I','T',T,'Q',0,Fluid) for T in Tv])

        Rp = array([Props('P','T',T,'Q',0,RPFluid) for T in Tv])
        Rrho = array([Props('D','T',T,'Q',0,RPFluid) for T in Tv])
        Rcp = array([Props('C','T',T,'Q',0,RPFluid) for T in Tv])
        Rcv = array([Props('O','T',T,'Q',0,RPFluid) for T in Tv])
        Rh0 = Props('H','T',(Tt+Tc)/2.0,'Q',0,RPFluid)
        Rh = array([Props('H','T',T,'Q',0,RPFluid)-Rh0 for T in Tv])
        Rs0 = Props('S','T',(Tt+Tc)/2.0,'Q',0,RPFluid)
        Rs = array([Props('S','T',T,'Q',0,RPFluid)-Rs0 for T in Tv])
        Rvisc = array([Props('V','T',T,'Q',0,RPFluid) for T in Tv])
        Rcond = array([Props('L','T',T,'Q',0,RPFluid) for T in Tv])
        Rsigma = array([Props('I','T',T,'Q',0,RPFluid) for T in Tv])

        fig = plt.figure()

        ax = fig.add_axes((0.15,0.15,0.8,0.8))
        ax.semilogy(Tv/Tc,abs(p/Rp-1)*100,'o',label='Pressure')
        ax.semilogy(Tv/Tc,abs(rho/Rrho-1)*100,'o',label='Density')
        ax.semilogy(Tv/Tc,abs(cp/Rcp-1)*100,'o',label='Specific heat (cp)')
        ax.semilogy(Tv/Tc,abs(cv/Rcv-1)*100,'o',label='Specific heat (cv)')
        ax.semilogy(Tv/Tc,abs(h/Rh-1)*100,'o',label='Enthalpy')
        ax.semilogy(Tv/Tc,abs(s/Rs-1)*100,'o',label='Entropy')
        ax.semilogy(Tv/Tc,abs(visc/Rvisc-1)*100,'^',label='Viscosity')
        ax.semilogy(Tv/Tc,abs(cond/Rcond-1)*100,'s',label='Conductivity')
        ax.semilogy(Tv/Tc,abs(sigma/Rsigma-1)*100,'p',label='Surface tension')
        ax.set_ylim(1e-16,100)
        ax.set_title('Saturated Liquid Deviations from REFPROP 9.1')
        ax.set_xlabel('Reduced temperature T/Tc')
        ax.set_ylabel('Absolute deviation [%]')
        ax.legend(numpoints=1,loc='best')
        plt.show()
    """.format(Fluid=Fluid,RPFluid = 'REFPROP-'+CP.get_REFPROPname(Fluid)))

def params_table(Fluid):
    params = dict(mm = CP.Props(Fluid,'molemass'),
                  Tt = CP.Props(Fluid,'Ttriple'),
                  pt = CP.Props(Fluid,'ptriple'),
                  Tmin = CP.Props(Fluid,'Tmin'),
                  CAS = CP.get_CAS_code(Fluid),
                  ASHRAE = CP.get_ASHRAE34(Fluid)
                  )

    return textwrap.dedent(
    """
    Fluid Data
    ==========

    Fluid Parameters

    =========================  ==============================
    Mole Mass [kg/kmol]        {mm:0.5f}
    Triple Point Temp. [K]     {Tt:0.3f}
    Triple Point Press. [kPa]  {pt:0.10g}
    Minimum temperature [K]    {Tmin:0.3f}
    CAS number                 {CAS:s}
    ASHRAE classification      {ASHRAE:s}
    =========================  ==============================
    """.format(**params))

def critical_table(Fluid):
    params = dict(Tc = CP.Props(Fluid,'Tcrit'),
                  rhoc = CP.Props(Fluid,'rhocrit'),
                  pc = CP.Props(Fluid,'pcrit'),
                  )

    return textwrap.dedent(
    """
    Critical Parameters

    ==============================  ==============================
    Temperature [K]                 {Tc:0.3f}
    Density [kg/m\ :sup:`3`\ ]      {rhoc:0.6f}
    Pressure [kPa]                  {pc:0.5f}
    ==============================  ==============================

    """.format(**params))

def buildrst(Fluid):
    pass

def index_file(Fluids):
    Fluids=[Fluid+'.rst' for Fluid in Fluids]
    FluidList = '\n    '.join(Fluids)
    return textwrap.dedent(
"""
.. toctree::
    :maxdepth: 1

    {:s}
""".format(FluidList))

def fluid_header(Fluid):
    aliases = CP.get_aliases(str(Fluid))
    aliases = ', '.join(['``'+a.strip()+'``' for a in aliases])

    BTC = BibTeXerClass()

    EOSkey = CP.get_BibTeXKey(Fluid, "EOS")
    CP0key = CP.get_BibTeXKey(Fluid, "CP0")
    SURFACE_TENSIONkey = CP.get_BibTeXKey(Fluid, "SURFACE_TENSION")
    VISCOSITYkey = CP.get_BibTeXKey(Fluid, "VISCOSITY")
    CONDUCTIVITYkey = CP.get_BibTeXKey(Fluid, "CONDUCTIVITY")
    ECS_LENNARD_JONESkey = CP.get_BibTeXKey(Fluid, "ECS_LENNARD_JONES")
    ECS_FITSkey = CP.get_BibTeXKey(Fluid, "ECS_FITS")

    BibInfo = ''
    if EOSkey:
        BibInfo += '**Equation of State**: ' + BTC.entry2rst(EOSkey) + '\n\n'
    if CP0key:
        BibInfo += '**Ideal-Gas Specific Heat**: ' + BTC.entry2rst(CP0key) + '\n\n'
    if SURFACE_TENSIONkey:
        BibInfo += '**Surface Tension**: ' + BTC.entry2rst(SURFACE_TENSIONkey) + '\n\n'
    if VISCOSITYkey:
        BibInfo += '**Viscosity**: ' + BTC.entry2rst(VISCOSITYkey) + '\n\n'
    if CONDUCTIVITYkey:
        BibInfo += '**Conductivity**: ' + BTC.entry2rst(CONDUCTIVITYkey) + '\n\n'
    if ECS_LENNARD_JONESkey:
        BibInfo += '**Lennard-Jones Parameters for ECS**: ' + BTC.entry2rst(ECS_LENNARD_JONESkey) + '\n\n'
    if ECS_FITSkey:
        BibInfo += '**ECS Correction Fit**: ' + BTC.entry2rst(ECS_FITSkey) + '\n\n'

    return textwrap.dedent(
"""
********************
{Fluid:s}
********************

Aliases
================================================================================
{Aliases:s}

Bibliographic Information
=========================
{Reference:s}
""".format(Fluid=Fluid,
           Aliases = aliases,
           Reference = BibInfo,
           )
           )

fp=open(os.path.join('Fluids','FluidInformation.rst'),'w')
fp.write('###########################\nFluid Information\n###########################\n')
fp.write(
"""
CoolProp Fluid Information
==========================
.. toctree::
    :maxdepth: 1

    PseudoPureFluids.rst
    PureFluids.rst

There are 4 basic classes of fluids that can be used in CoolProp, an example is provided for each one.

Pure Fluids, Pseudo-Pure Fluids
-------------------------------
All the fluids listed in Pure-Fluids and Pseudo-Pure-Fluids sections above can be used.  To use one of these fluids, do something like

.. ipython::

    In [1]: from CoolProp.CoolProp import Props

    #Density of dry air at 1 atm. and 25C
    In [1]: Props('D','T',298,'P',101.325,'Air')

You can also use any of the aliases of the fluids that are the listed on the fluid page.  For instance, R717 is the refrigerant number for ammonia

.. ipython::

    In [1]: from CoolProp.CoolProp import Props

    #Density of saturated ammonia vapor at 1 atm.
    In [1]: Props('D','Q',1,'P',101.325,'R717')

    #Density of saturated ammonia vapor at 1 atm.
    In [1]: Props('D','Q',1,'P',101.325,'Ammonia')

REFPROP Fluids and Mixtures
---------------------------
If you are on Windows and have REFPROP installed, you can use it with CoolProp.  REFPROP needs to be installed in c:\\\\Program Files\\\\REFPROP.  If it is somewhere else, just copy it to this location.

It is also possible to use REFPROP on Linux.  Please follow the instructions from https://github.com/jowr/librefprop.so to install the library from Fortran sources.  Additionally, you also need to copy the fluid and mixture files to /opt/refprop.

All the pure fluids in REFPROP are used just like the CoolProp fluids except that "REFPROP-" is added at the beginning of the fluid name.  You can use any fluid that is included in REFPROP, but you must use the REFPROP fluid file name.  For CoolProp Fluids, you can use the ``get_REFPROPName()`` function to get the REFPROP name for the fluid.

.. ipython::

    In [1]: from CoolProp.CoolProp import Props

    #Saturated isobutane vapor density at 1 atmosphere
    In [1]: Props('D','Q',1,'P',101.325,'REFPROP-ISOBUTAN')

You can also use mixtures in REFPROP, there is a special format for the fluid name.  The fluid name is set up like this: ``"REFPROP-MIX:R32[0.697615]&R125[0.302385]"`` -  this is R410A.  The numbers within the brackets are the mole fractions of the components.  They must add up to 1.0

.. ipython::

    In [1]: from CoolProp.CoolProp import Props

    #Saturated R410 vapor density at 1 atmosphere using the mixture properties
    In [1]: Props('D','Q',1,'P',101.325,'REFPROP-MIX:R32[0.697615]&R125[0.302385]')

Incompressible Liquids
----------------------
There is also a selection of incompressible liquids implemented.  These only allow for calls with
temperature and pressure as input and provide only a subset of thermophysical properties, namely:
density, heat capacity, internal energy, enthalpy, entropy, viscosity and thermal conductivity.
Hence, the available output keys for the ``Props`` function are: "D", "C", "U", "H", "S", "V", "L",
"Tmin", Tmax" and "Psat". An internal iteration allows us to use enthalpy and pressure as inputs,
but be aware of the reduced computational efficiency.

.. ipython::

    In [1]: from CoolProp.CoolProp import Props

    #Density of HFE-7100 at 300 K and 1 atm.
    In [1]: Props('D','T',300,'P',101.325,'HFE')

For refrigeration applications, 8 fluids were implemented from Aake Melinder "Properties of
Secondary Working Fluids for Indirect Systems" published in 2010 by IIR and coefficients are
obtained from a fit between -80 and +100 degrees Celsius.

==========================   ===================================================
Fluid Name                   Description
==========================   ===================================================
``DEB``                      Diethyl Benzene
``HCM``                      Hydrocarbon Mixture (Therminol D12 Solutia)
``HFE``                      Hydrofluoroether HFE-7100
``PMS1``                     Polydimethylsiloxan 1.
``PMS2``                     Polydimethylsiloxan 2.
``SAB``                      Synthetic alkyl benzene
``HCB``                      Hydrocarbon blend (Dynalene MV)
``TCO``                      Terpene from citrus oils
==========================   ===================================================

Some additional secondary cooling fluids are based on data compiled by Morten Juel Skovrup in
his `SecCool software <http://en.ipu.dk/Indhold/refrigeration-and-energy-technology/seccool.aspx>`_
provided by his employer `IPU <http://en.ipu.dk>`_. Fits have been made according to the manufacturer
data stored in the sodtware. The Aspen Temper fluids are a blend of potassium formate and sodiumpropionate
and the Zitrec S group consists mainly of potassium acetate and potassium formate.

==========================   ===================================================
Fluid Name                   Description
==========================   ===================================================
``AS10``                     Aspen Temper -10 (-10 to +27.5 C)
``AS20``                     Aspen Temper -20 (-20 to +27.5 C)
``AS30``                     Aspen Temper -30 (-30 to +27.5 C)
``AS40``                     Aspen Temper -40 (-40 to +27.5 C)
``AS55``                     Aspen Temper -55 (-55 to +27.5 C)
``ZS10``                     Zitrec S -10 (-10 to +85 C)
``ZS25``                     Zitrec S -25 (-25 to +85 C)
``ZS40``                     Zitrec S -40 (-40 to +85 C)
``ZS45``                     Zitrec S -45 (-45 to +85 C)
``ZS55``                     Zitrec S -55 (-55 to +85 C)
==========================   ===================================================

There are also a few high temperature heat transfer fluids with individual temperature ranges. Please
refer to the file IncompLiquid.h for a complete overview. For these fluids, information from commercial
data sheets was used to obtain coefficients.

==========================   ===================================================
Fluid Name                   Description
==========================   ===================================================
``TD12``                     Therminol D12 (-85 to +230 C)
``TVP1``                     Therminol VP-1 (+12 to +397 C)
``T72``                      Therminol 72 (-10 to +380 C)
``T66``                      Therminol 66 (0 to +345 C)
``DowJ``                     Dowtherm J (-80 to +345 C)
``DowQ``                     Dowtherm Q (-35 to +360 C)
``TX22``                     Texatherm 22 (0 to +350 C)
``NaK``                      Nitrate Salt Blend (+300 to +600 C)
``XLT``                      Syltherm XLT (-100 to +260 C)
``HC10``                     Dynalene HC-10 (-10 to +218 C)
``HC20``                     Dynalene HC-20 (-20 to +210 C)
``HC30``                     Dynalene HC-30 (-30 to +210 C)
``HC40``                     Dynalene HC-40 (-40 to +200 C)
``HC50``                     Dynalene HC-50 (-50 to +210 C)
==========================   ===================================================

All fluids are implemented with polynomials for density and heat capacity with typically 4 coefficients
and hence a third order polynomial. Thermal conductivity is a second order polynomial and viscosity and
vapour pressure are exponential functions.

.. math::

    \\rho    &= \\sum_{i=0}^n C_{\\rho}[i] \\cdot T^i \\\\
    c        &= \\sum_{i=0}^n C_{c}[i] \\cdot T^i \\\\
    u        &= \\int_{0}^{1} c\\left( T \\right) dT
              = \\sum_{i=0}^n \\frac{1}{i+1} \\cdot C_{c}[i]
                \\cdot \\left( T_1^{i+1} - T_0^{i+1} \\right) \\\\
    s        &= \\int_{0}^{1} \\frac{c\\left( T \\right)}{T} dT
              = C_{c}[0] \\cdot \\ln\\left(\\frac{T_1}{T_0}\\right)
                + \\sum_{i=0}^{n-1} \\frac{1}{i+1} \\cdot C_{c}[i+1]
                \\cdot \\left( T_1^{i+1} - T_0^{i+1} \\right) \\\\
    \\lambda &= \\sum_{i=0}^n C_{\\lambda}[i] \\cdot T^i \\\\
    \\mu     &= \\exp\\left( \\frac{C_{\\mu}[0]}{T+C_{\\mu}[1]} - C_{\\mu}[2] \\right) \\\\
    p_{sat}  &= \\exp\\left( \\frac{C_{sat}[0]}{T+C_{sat}[1]} - C_{sat}[2] \\right) \\\\

Brines and Solutions
--------------------
All the brines and solutions can be accessed through the Props function. To use them, the fluid name
is something like ``"MEG-20%"`` which is a 20% by mass ethylene glycol solution. Note that these fluids
have an arbitrary reference state: Be careful with enthalpy and entropy calculations. Again, only
temperature and pressure inputs are supported directly to calculate the same subset of thermophysical
properties as above , namely: density, heat capacity, internal energy, enthalpy, entropy, viscosity
and thermal conductivity. Hence, the available output keys for the ``Props`` function are: "D", "C",
"U", "H", "S", "V", "L", "Tmin", Tmax" and "Tfreeze". An internal iteration allows us to use enthalpy
and pressure as inputs, but be aware of the reduced computational efficiency.

.. ipython::

    In [1]: from CoolProp.CoolProp import Props

    #Specific heat 20% mass ethylene glycol solution at 300 K and 1 atm.
    In [1]: Props('C','T',300,'P',101.325,'MEG-20%')

For Lithium-Bromide, the publication by Patek and Klomfar from 2005 was implemented based on the
source code provided by the authors. The `paper <http://dx.doi.org/10.1016/j.ijrefrig.2005.10.007>`_
covering the equations can be found in the
`International Journal of Refrigeration <http://dx.doi.org/10.1016/j.ijrefrig.2005.10.007>`_. Data is
available for temperatures from 0 C to 225 C and for the full composition range. Use ``LiBr`` to acccess
the functions.

A number of aqueous solutions are implemented using the coefficients from Aake Melinder "Properties of
Secondary Working Fluids for Indirect Systems" published in 2010 by IIR.  According to the book, 2D
polynomials are given in a form that satisfies :math:`0 \\leq i \\leq 5`, :math:`0 \\leq j \\leq 3`
and :math:`i + j \\leq 5` yielding a triangular matrix of coefficients. It is only for the freezing
temperature calculation that the implemented procedures differ from what is presented in Melinder's
book the dependency on the current temperature is removed. In CoolProp, :math:`T_{freeze}` only depends
on concentration.

==========================   ===================================================   =================   =================
Melinder Fluids              Description                                           max. T              max. x
==========================   ===================================================   =================   =================
``MEG``                      Ethylene Glycol (C2H6O2)                              +100 C              60 %
``MPG``                      Propylene Glycol (C3H8O2)                             +100 C              60 %
``MEA``                      Ethyl Alcohol, Ethanol (C2H6O)                        +40 C               60 %
``MMA``                      Methyl Alcohol, Methanol (CH4O)                       +40 C               60 %
``MGL``                      Glycerol (C3H8O3)                                     +40 C               60 %
``MAM``                      Ammonia (NH3)                                         +30 C               30 %
``MKC``                      Potassium Carbonate (K2CO3)                           +40 C               40 %
``MCA``                      Calcium Chloride (CaCl2)                              +40 C               30 %
``MMG``                      Magnesium Chloride (MgCl2)                            +40 C               30 %
``MNA``                      Sodium Chloride (NaCl)                                +40 C               23 %
``MKA``                      Potassium Acetate (CH3CO2K)                           +40 C               45 %
``MKF``                      Potassium Formate (CHKO2)                             +40 C               48 %
``MLI``                      Lithium Chloride (LiCl)                               +40 C               24 %
==========================   ===================================================   =================   =================

Furthermore, there is a number of other secondary fluids that can be accessed in the same way. Most
information is based on the data compiled by Morten Juel Skovrup in his `SecCool software <http://en.ipu.dk/Indhold/refrigeration-and-energy-technology/seccool.aspx>`_
provided by his employer `IPU <http://en.ipu.dk>`_. The coefficient matrix of the SecCool-based fluids
has the same structure as mentioned above.

For slurry ice, the concentration :math:`x` refers to the solid content and the heat capacity includes the heat of fusion.
It might be necessary to adjust the solid content during heat transfer. The implementation is based on the data available
in SecCool, which was originally recorded at the `Danish Technological Institute (DTI) <http://www.dti.dk/>`_.

==========================   ===================================================   =================   =================
SecCool Fluids               Description                                           max. T              max. x
==========================   ===================================================   =================   =================
``ZiAC``                     ZitrecAC (corrosion inhibitor)                        +100 C              50 %
``IceEA``                    Ethanol-water mixture with slurry ice                 -10 C               35 %
``IcePG``                    Propylene glycol-water mixture with slurry ice        -10 C               35 %
``IceNA``                    Sodium chloride-water mixture with slurry ice         -5 C                35 %
``PK2000``                   Pekasol 2000 (Potassium acetate and formate)          +100 C              100 %
==========================   ===================================================   =================   =================

In both of the above cases, :math:`i` is the exponent for the concentration :math:`x` and :math:`j`
is used with the temperature :math:`T`. Properties are modelled with the following polynomials:

.. math::

    \\rho      &= \\sum_{i=0}^n x^i  \\cdot \\sum_{j=0}^m C_{\\rho}[i,j] \\cdot T^j \\\\
    c          &= \\sum_{i=0}^n x^i  \\cdot \\sum_{j=0}^m C_{c}[i,j] \\cdot T^j \\\\
    u          &= \\int_{0}^{1} c\\left( x,T \\right) dT
                = \\sum_{i=0}^n x^i \\cdot \\sum_{j=0}^m \\frac{1}{j+1} \\cdot C_{c}[i,j]
                  \\cdot \\left( T_1^{j+1} - T_0^{j+1} \\right) \\\\
    s          &= \\int_{0}^{1} \\frac{c\\left( x,T \\right)}{T} dT
                = \\sum_{i=0}^n x^i \\cdot \\left(
                  C_{c}[i,0] \\cdot \\ln\\left(\\frac{T_1}{T_0}\\right)
                  + \\sum_{j=0}^{m-1} \\frac{1}{j+1} \\cdot C_{c}[i,j+1] \\cdot \\left( T_1^{j+1} - T_0^{j+1} \\right)
                  \\right) \\\\
    \\lambda   &= \\sum_{i=0}^n x^i  \\cdot \\sum_{j=0}^m C_{\\lambda}[i,j] \\cdot T^j \\\\
    \\mu       &= \\exp \\left( \\sum_{i=0}^n x^i  \\cdot \\sum_{j=0}^m C_{\\mu}[i,j] \\cdot T^j \\right) \\\\
    T_{freeze} &= \\sum_{i=0}^n C_{freeze}[i] \\cdot x^i \\\\

Using a centered approach for the independent variables,
the fit quality can be enhanced. Therefore, all solutions have a reference temperature and concentration
in the original work by Melinder and Skovrup as well as in CoolProp: :math:`x = x_{real} - x_{ref}`
and :math:`T = T_{real} - T_{ref}`, this technique does not affect the calculation
of the derived quantity internal energy since the formula contains temperature differences.
However, integrating :math:`c(x,T)T^{-1}dT` for the entropy requires some changes due to
the logarithm. To structure the problem, we introduce a variable :math:`d(j,T_{real})`, which will be expressed by a third sum.
As a first step for simplification, one has to expand the the binomial :math:`(T_{real}-T_{ref})^n` to a series.
Only containing :math:`j` and :math:`T_{real}`, :math:`d` is independent from :math:`x` and can be
computed outside the loop for enhanced computational efficiency. An integration of the expanded binomial
then yields the final factor :math:`D` to be multiplied with the other coefficients and the concentration.

.. math::

    s          &= \\int_{0}^{1} \\frac{c\\left( x,T \\right)}{T} dT = \\sum_{i=0}^n x^i \\cdot \\sum_{j=0}^m C_{c}[i,j] \\cdot D(j,T_0,T_1) \\\\
    D          &= (-1)^j \\cdot \\ln \\left( \\frac{T_1}{T_0} \\right) \\cdot T_{ref}^j + \\sum_{k=0}^{j-1} \\binom{j}{k} \\cdot \\frac{(-1)^k}{j-k} \\cdot \\left( T_1^{j-k} - T_0^{j-k} \\right) \\cdot T_{ref}^k

"""
)
fp.close()

pseudo_pure_fluids = ['Air','R404A','R410A','R407C','R507A','SES36','R407F']
with open(os.path.join('Fluids','PseudoPureFluids.rst'),'w') as fp:
    fp.write('#######################\nPseudo-Pure Fluids\n#######################\n')
    fp.write(index_file(pseudo_pure_fluids))

for Fluid in pseudo_pure_fluids:
    fp=open(os.path.join('Fluids',Fluid+'.rst'),'w')
    s = fluid_header(Fluid) + params_table(Fluid) + critical_table(Fluid) + SatVaporParity(Fluid) + SatLiquidParity(Fluid) + CriticalIsotherm(Fluid) + PropertyConsistency(Fluid)
    fp.write(s)
    fp.close()

pure_fluids = sorted([fluid for fluid in CoolProp.__fluids__ if fluid not in pseudo_pure_fluids])
with open(os.path.join('Fluids','PureFluids.rst'),'w') as fp:
    fp.write('#######################\nPure Fluids\n#######################\n')
    fp.write(index_file(sorted(pure_fluids)))

for Fluid in sorted(pure_fluids):
    fp=open(os.path.join('Fluids',Fluid+'.rst'),'w')
    s = fluid_header(Fluid) + params_table(Fluid) + critical_table(Fluid) + SatVaporParity(Fluid) + SatLiquidParity(Fluid) + CriticalIsotherm(Fluid) + PropertyConsistency(Fluid)
    fp.write(s)
    fp.close()


from wand.image import Image
import os
from needle.engines.base import EngineBase

class Engine(EngineBase):

    def assertSameFiles(self, output_file, baseline_file, threshold=0):

        diff_file = output_file.replace('.png', '.diff.png')

        img_base = Image(filename=os.path.abspath(baseline_file))
        img_out =  Image(filename=os.path.abspath(output_file))

        img_base.normalize()
        img_out.normalize()

        comparison, difference = img_base.compare(img_out, metric='root_mean_square')

        if difference <= threshold:
            return
        else:
            comparison.save(filename=diff_file)

        raise AssertionError("The new screenshot '{new}' did not match "
                             "the baseline '{baseline}' (See {diff}):\n"
                             .format(new=output_file,
                                     baseline=baseline_file,
                                     diff=diff_file))


# -*- coding: utf-8 -*-
import time
import logging

from .asyncache import Defer, REGET, CancelledError
from .base import BaseCacheClient, NONE

from chorde.mq import coherence

class CoherentDefer(Defer):
    """
    Wrap a callable in this, and pass it as a value to an AsyncWriteCacheClient,
    and the evaluation of the given callable will happen asynchronously. The cache
    will return stale entries until the callable is finished computing a new value.
    Computation will be aborted if the coherence protocol shows someone else already
    computing, or if the shared cache is re-validated somehow when this method is
    called.
    """

    def __init__(self, callable_, *args, **kwargs):
        """
        Params
            callable_, args, kwargs: see Defer. All others must be passed by keyword.

            manager: A CoherenceManager instance that coordinates the corresponding cache clients.

            expired: A callable of the sort CoherenceManager takes, to re-check expiration status
                against the shared cache.

            expire_private: An optional callable that will be called with the given key (see below)
                right before receiving an OOB update. It should mark any privately held value for
                that key as expired, since a fresher one will be coming OOB. Usually the expire
                method of the private cache client works for this purpose.

            key: The key associated with this computation, to be provided to the CoherenceManager.

            timeout: Coherence protocol timeout, in ms, if the peers don't answer in this time,
                detached operation will be assumed and computation will proceed.
                Default: whatever the heartbeat timeout is on the underlying IPSub channel

            wait_time: Whether and how long to wait for other node's computation to be done.
                Normally, the default value of 0, which means "no wait", is preferrable so as not
                to stall deferred computation workers. However, in quick computations, it may be
                beneficial to provide a small wait time, to decrease latency in case some node
                goes down. This deferred would then take it upon him to start computing, and the
                whole group could be spared a whole cycle (versus just waiting for the value to
                be needed again), trading thoughput for latency. A value of None will cause
                infinite waits.
        """
        self.manager = kwargs.pop('manager')
        self.expired = kwargs.pop('expired')
        self.expire_private = kwargs.pop('expire_private', None)
        self.fetch = kwargs.pop('fetch', None)
        self.key = kwargs.pop('key')
        self.timeout = kwargs.pop('timeout', None)
        if self.timeout is None:
            self.timeout = self.manager.ipsub.heartbeat_push_timeout
        self.wait_time = kwargs.pop('wait_time', 0)
        self.computed = False
        self.aborted = False
        super(CoherentDefer, self).__init__(callable_, *args, **kwargs)

    def undefer(self):
        logger = logging.getLogger('chorde.coherence')
        while True:
            if not self.expired():
                logger.debug("Not computing because already fresh, key=%r", self.key)
                if hasattr(self, 'future'):
                    if self.expire_private is not None:
                        self.expire_private(self.key)
                    return REGET
                else:
                    return NONE
            else:
                computer = self.manager.query_pending(self.key, self.expired, self.timeout, True)
                if computer is None:
                    # My turn
                    logger.debug("Acquired computer duty on key=%r", self.key)
                    try:
                        rv = super(CoherentDefer, self).undefer()
                        if rv is not NONE:
                            logger.debug("Computing done on key=%r", self.key)
                            self.computed = True
                        else:
                            logger.debug("Computing skipped on key=%r", self.key)
                            self.aborted = True
                    except:
                        logger.debug("Computing aborted on key=%r due to exception", self.key, exc_info=True)
                        self.aborted = True
                        raise
                    return rv
                elif computer is coherence.OOB_UPDATE and not self.expired():
                    # Skip, tiered caches will read it from the shared cache and push it downstream
                    logger.debug("Fresh value available OOB on key=%r", self.key)
                    if hasattr(self, 'future'):
                        if self.expire_private is not None:
                            self.expire_private(self.key)
                        return REGET
                    else:
                        return NONE
                elif self.wait_time != 0:
                    logger.debug("Waiting for computation on node %r on key=%r", computer, self.key)
                    if self.manager.wait_done(self.key, timeout = self.wait_time):
                        logger.debug("Computation done (was waiting on node %r) on key=%r", computer, self.key)
                        if hasattr(self, 'future'):
                            if self.expire_private is not None:
                                self.expire_private(self.key)
                            return REGET
                        else:
                            return NONE
                    else:
                        # retry
                        logger.debug("Computation still in progress (waiting on node %r) on key=%r", computer, self.key)
                        continue
                else:
                    logger.debug("Computation in progress on node %r key=%r, not waiting", computer, self.key)
                    if hasattr(self, 'future'):
                        # Must cancel it if we're not going to wait
                        self.future.cancel()
                        self.future.set_exception(CancelledError())
                    return NONE

    def done(self):
        if self.computed:
            self.manager.mark_done(self.key)
        elif self.aborted:
            self.manager.mark_aborted(self.key)
        super(CoherentDefer, self).done()

class CoherentWrapperClient(BaseCacheClient):
    """
    Client wrapper that publishes cache activity with the coherence protocol.
    Given a manager, it will invoke its methods to make sure other instances
    on that manager are notified of invalidations.

    It adds another method of putting, put_coherently, that will additionally
    ensure that only one node is working on computing the result (thust taking
    a callable rather than a value, as defers do).

    The regular put method will publish being done, if the manager is configured
    in quick refresh mode, but will not attempt to obtain a computation lock,
    resulting in less overhead, decent consistency, but some duplication of
    effort. Therefore, put_coherently should be applied to expensive computations.

    If the underlying client isn't asynchronous, put_coherently will implicitly
    undefer the values, executing the coherence protocol in the calling thread.
    """

    def __init__(self, client, manager, timeout = 2000):
        self.client = client
        self.manager = manager
        self.timeout = timeout

    @property
    def is_async(self):
        return self.client.is_async

    @property
    def capacity(self):
        return self.client.capacity

    @property
    def usage(self):
        return self.client.usage

    def wait(self, key, timeout = None):
        # Hey, look at that. Since locally it it all happens on a Defer,
        # we can just wait on the wrapped client first to wait for ourselves
        if timeout is not None:
            deadline = time.time() + timeout
        else:
            deadline = None
        self.client.wait(key, timeout)

        # But in the end we'll have to ask the manager to talk to the other nodes
        if deadline is not None:
            timeout = int(max(0, deadline - time().time()) * 1000)
        else:
            timeout = None
        self.manager.wait_done(key, timeout=timeout)

    def put(self, key, value, ttl, coherence_timeout = None, **kw):
        manager = self.manager
        if manager.quick_refresh:
            # In quick refresh mode, we publish all puts
            if self.is_async and isinstance(value, Defer) and not isinstance(value, CoherentDefer):
                callable_ = value.callable_
                def done_after(*p, **kw):
                    rv = callable_(*p, **kw)
                    if rv is not NONE:
                        manager.fire_done([key])
                    return rv
                value.callable_ = done_after
                self.client.put(key, value, ttl, **kw)
            else:
                self.client.put(key, value, ttl, **kw)
                manager.fire_done([key], timeout = coherence_timeout)
        else:
            self.client.put(key, value, ttl, **kw)

    def put_coherently(self, key, ttl, expired, future, callable_, *args, **kwargs):
        """
        Another method of putting, that will additionally ensure that only one node
        is working on computing the result. As such, it takes  a callable rather
        than a value, as defers do.

        If the underlying client isn't asynchronous, put_coherently will implicitly
        undefer the value, executing the coherence protocol in the calling thread.

        Params
            key, ttl: See put
            expired: A callable that will re-check expiration status of the key on
                a shared cache. If this function returns False at mid-execution of
                the coherence protocol, the protocol and the computation will be
                aborted (assuming the underlying client will now instead fetch
                values from the shared cache).
            future: (optional) A future to be associated with the deferred
                computation.
            callable_, args, kwargs: See Defer. In contrast to normal puts, the
                callable may not be invoked if some other node has the computation
                lock.
        """
        wait_time = kwargs.pop('wait_time', 0)
        put_kwargs = kwargs.pop('put_kwargs', None) or None
        value = CoherentDefer(
            callable_,
            key = key,
            manager = self.manager,
            expired = expired,
            timeout = self.timeout,
            wait_time = wait_time,
            *args, **kwargs )
        if future is not None:
            value.future = future
        deferred = None
        try:
            if not self.is_async:
                # cannot put Defer s, so undefer right now
                deferred = value
                value = value.undefer()
                if value is NONE:
                    # Abort
                    return
            self.client.put(key, value, ttl, **(put_kwargs or {}))
        finally:
            if deferred is not None:
                deferred.done()

    def renew(self, key, ttl):
        self.client.renew(key, ttl)

    def delete(self, key, coherence_timeout = None):
        self.client.delete(key)

        # Warn others
        self.manager.fire_deletion(key, timeout = coherence_timeout)

    def expire(self, key):
        self.client.expire(key)

    def clear(self, coherence_timeout = None):
        self.client.clear()

        # Warn others
        self.manager.fire_deletion(coherence.CLEAR, timeout = coherence_timeout)

    def purge(self, *p, **kw):
        self.client.purge(*p, **kw)

    def getTtl(self, key, default = NONE, **kw):
        return self.client.getTtl(key, default, **kw)

    def get(self, key, default = NONE, **kw):
        return self.client.get(key, default, **kw)

    def getTtlMulti(self, keys, default = NONE, **kw):
        return self.client.getTtlMulti(keys, default, **kw)

    def getMulti(self, keys, default = NONE, **kw):
        return self.client.getMulti(keys, default, **kw)

    def contains(self, key, ttl = None, **kw):
        return self.client.contains(key, ttl, **kw)

    def promote(self, key, *p, **kw):
        return self.client.promote(key, *p, **kw)


from konlpy.tag import Okt
from textblob.classifiers import NaiveBayesClassifier
import nltk
# nltk.download('punkt')
from konlpy.tag import Komoran
import re

okt = Okt()
komoran = Komoran()

with open('../text-mining-data/positive-words-ko-v2.txt', encoding='UTF8') as positiveTextFile, open('../text-mining-data/negative-words-ko-v2.txt', encoding='UTF8') as negativeWordFile:
    train = []
    for text in positiveTextFile.readlines():
        refinedText = re.sub(r'\n', '', text)
        posTagTokens = ['/'.join(token) for token in komoran.pos(refinedText)]
        train.append((posTagTokens, 'pos'))
    for negativeWord in negativeWordFile.readlines():
        refinedText = re.sub(r'\n', '', negativeWord)
        posTagTokens = ['/'.join(token) for token in komoran.pos(refinedText)]
        train.append((posTagTokens, 'neg'))
    # print(train)

    cl = NaiveBayesClassifier(train)

    # print(cl.classify("당신을 좋아해요"))
    # print(cl.classify("대통령님은 나라를 건설적으로 만드셨다. 친밀감 있게 다가가셨고 항상 책임감과 참을성을 가지고 계셨다."))

    # sentence = "영웅들이여 양질의 업적을 달성하기 위해 씩씩하게 압도하는 길을 가자."
    # [(['/'.join(token) for token in komoran.pos(sentence)], result)
    #              for [sentence, result] in test]

    testText = "봉사하시는 분들을 위해 칭찬과 격려 부탁드립니다."
    testDatum = (['/'.join(token) for token in komoran.pos(testText)])
    prob_dist = cl.prob_classify(testDatum)
    print(round(prob_dist.prob("pos"), 2))
    print(round(prob_dist.prob("neg"), 2))


import argparse
import os

import tensorflow as tf
from tqdm import tqdm

from lpr.dataset import get_train_dataset, get_val_dataset
from lpr.model import DeepLPR

@tf.function
def train_step(image, label, model, loss_fn, optim):
    with tf.GradientTape() as tape:
        predict = model(image, training=True)
        loss = loss_fn(label, predict)
    grads = tape.gradient(loss, model.trainable_variables)
    optim.apply_gradients(zip(grads, model.trainable_variables))
    return loss, predict

def main(args):
    train_dataset = get_train_dataset()
    train_dataset = train_dataset.shuffle(1024, reshuffle_each_iteration=True)
    train_dataset = train_dataset.batch(args.batch_size)
    train_total = tf.data.experimental.cardinality(train_dataset).numpy()
    val_dataset = get_val_dataset()
    val_dataset = val_dataset.batch(args.batch_size)
    val_total = tf.data.experimental.cardinality(val_dataset).numpy()

    model = DeepLPR()
    loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
    optim = tf.keras.optimizers.Adam(lr=args.learning_rate)
    model.summary()

    avg_loss = tf.keras.metrics.Mean('loss', dtype=tf.float32)
    avg_acc = tf.keras.metrics.SparseCategoricalAccuracy('acc')
    avg_val_loss = tf.keras.metrics.Mean('val_loss', dtype=tf.float32)
    avg_val_acc = tf.keras.metrics.SparseCategoricalAccuracy('val_acc')

    train_writer = tf.summary.create_file_writer(
        os.path.join(args.log_dir, 'train'))
    val_writer = tf.summary.create_file_writer(
        os.path.join(args.log_dir, 'val'))
    for epoch in range(args.epochs):
        avg_loss.reset_states()
        avg_val_loss.reset_states()
        with tqdm(total=train_total, dynamic_ncols=True) as pbar:
            pbar.set_description(
                '[Train] Epoch %2d/%2d' % (epoch + 1, args.epochs))
            for image, label in train_dataset:
                loss, predict = train_step(image, label, model, loss_fn, optim)
                avg_loss.update_state(loss)
                avg_acc.update_state(label, predict)
                pbar.set_postfix(loss='%.4f' % loss.numpy())
                pbar.update(1)
        with train_writer.as_default():
            tf.summary.scalar('loss', loss, step=epoch)

        with tqdm(total=val_total, dynamic_ncols=True) as pbar:
            pbar.set_description(
                '[Val  ] Epoch %2d/%2d' % (epoch + 1, args.epochs))
            for image, label in val_dataset:
                predict = model(image, training=False)
                loss = loss_fn(label, predict)
                avg_val_loss.update_state(loss)
                avg_val_acc.update_state(label, predict)
                pbar.set_postfix(total_val_loss='%.4f' % loss.numpy())
                pbar.update(1)
        print('Epoch %2d/%2d: train_loss: %.4f, val_loss: %.4f, '
              'train_acc: %.4f, val_acc: %.4f' % (
                epoch + 1, args.epochs,
                avg_loss.result().numpy(),
                avg_val_loss.result().numpy(),
                avg_acc.result().numpy(),
                avg_val_acc.result().numpy()))
        with val_writer.as_default():
            tf.summary.scalar('loss', loss, step=epoch)
        if epoch == 0 or (epoch + 1) % args.checkpoint_period == 0:
            model.save_weights(os.path.join(
                args.checkpoint_dir, 'lpr_train_%d.tf' % (epoch + 1)))

if __name__ == '__main__':
    parser = argparse.ArgumentParser('License Plate Recognition')
    parser.add_argument('--epochs', type=int, default=100)
    parser.add_argument('--batch-size', type=int, default=64)
    parser.add_argument('--learning-rate', type=float, default=0.001)
    parser.add_argument('--checkpoint-period', type=int, default=5)
    parser.add_argument('--checkpoint-dir', type=str, default="./checkpoints")
    parser.add_argument('--log-dir', type=str, default="./logs")
    args = parser.parse_args()

    main(args)


__author__ = "Adrien Leger"
__copyright__ = "Copyright 2019, Adrien Leger"
__email__ = "aleg@ebi.ac.uk"
__license__ = "MIT"
__version__ = "0.0.2"

# Imports
from pyBioTools import Fasta
from pyfaidx import Faidx

# Shortcuts
ref_input = str(snakemake.input.ref)
ref_output = snakemake.output.ref

# Parse fasta file save transcript info in tabulated report and simplify transcript ids
with open(ref_output, "w") as fa_out:
    for rec in Fasta.Reader(ref_input):
        fa_out.write(">{}\n{}\n".format(rec.short_name, rec.seq))

# Index fasta file
with Faidx(ref_output) as fa_out:
    fa_out.build_index()


import pandas as pd
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

dataset = pd.read_csv("50_Startups.csv")

X = dataset.iloc[:, :-1].values
Y = dataset.iloc[:, -1:].values

# encode categorical type column (Country)
label_encoder = LabelEncoder()
X[:, -1] = label_encoder.fit_transform(X[:, -1])

# hot encode for categorical type column
one_hot_encoder = OneHotEncoder(categorical_features=[-1])
X = one_hot_encoder.fit_transform(X).toarray()

# split data to train and test set
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2, random_state=0)

# make small model
linear_regression = LinearRegression()

# train out model
linear_regression.fit(X_train, Y_train)

# test accuracy
y_pred = linear_regression.predict(X_test)


# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function

from marshmallow import fields

from polyaxon_deploy.schemas.base import BaseConfig, BaseSchema

class IngressSchema(BaseSchema):
    enabled = fields.Bool(allow_none=True)
    hostName = fields.Str(allow_none=True)
    path = fields.Str(allow_none=True)
    tls = fields.List(fields.Dict(allow_none=True), allow_none=True)
    annotations = fields.Dict(allow_none=True)

    @staticmethod
    def schema_config():
        return IngressConfig

class IngressConfig(BaseConfig):
    SCHEMA = IngressSchema
    REDUCED_ATTRIBUTES = ['enabled', 'hostName', 'tls', 'annotations', 'path']

    def __init__(self,  # noqa
                 enabled=None,
                 hostName=None,
                 path=None,
                 tls=None,
                 annotations=None,):
        self.enabled = enabled
        self.hostName = hostName
        self.path = path
        self.tls = tls
        self.annotations = annotations


from http.server import HTTPServer, BaseHTTPRequestHandler
import json

class TelegramActivityHandler(BaseHTTPRequestHandler):

    start_command_message = "Hi! I'm smart bot and I'll help you to stay tuned for your Trello board. \
    \n\rJust type '/register' and specify user filter to receive notifications from me. I can notife you about: \
    \n\t1) Updating tickets\
    \n\t2) Moving tickets\
    \n\t3) ...all other functions will be created later"

    def do_POST(self):
        print("[INFO] Received POST request on {path}".format(path = self.path))
        if self.path != str("/" + self.server.telegram_token):
            self.send_response(401)
            self.send_header('Content-type','text/html')
            self.end_headers()
            return

        telegram_payload_info = json.loads(self.rfile.read(int(self.headers['Content-Length'])))
        chat_id = str(telegram_payload_info['message']['chat']['id'])
        incoming_msg = str(telegram_payload_info['message']['text'])
        print("[DEBUG] Received the next JSON payload: \n{}".format(json.dumps(telegram_payload_info, indent = 2)))

        isItCommandReceived = False
        for field in telegram_payload_info['message']:
            if field == 'entities' and telegram_payload_info['message']['entities'][0]['type'] == 'bot_command':
                isItCommandReceived = True
                self.process_message(chat_id, incoming_msg)

        if not isItCommandReceived:
            self.process_command(chat_id, incoming_msg)

        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        return

    def process_message(self, chat_id, incoming_msg):
        if incoming_msg == '/subscribe' and self.is_current_user_active(chat_id):
            self.server.telegram_api_utils.send_message(chat_id, "Enter usernames for the things you want to follow on the board "
                + "(or write 'ALL' to keep track of everything): ")
            self.upsert_telegram_user_activity_log(chat_id, incoming_msg)
        elif incoming_msg == '/register':
            self.server.telegram_api_utils.send_message(chat_id, "Please, provide your invite token here: ")
            self.upsert_telegram_user_activity_log(chat_id, incoming_msg)
        elif incoming_msg == '/start':
            self.server.telegram_api_utils.send_message(chat_id, TelegramActivityHandler.start_command_message)
            self.reset_last_user_command(chat_id)
        return

    def process_command(self, chat_id, incoming_msg):
        telegram_users_activity_log = self.server.mongodb_utils.findTelegramUserActivityLogByChatId(chat_id)
        # collect data for /register command and substeps
        if telegram_users_activity_log['last_event'] == '/register':
            if incoming_msg == self.server.telegram_bot_invite_token:
                self.server.telegram_api_utils.send_message(
                    chat_id,
                    "Thank you, you have successfully logged in!\nPlease, enter your trello username:"
                )
                self.upsert_telegram_user_activity_log(chat_id, '/register_step2')
                self.upsert_user_telegram_trello_assignment(chat_id, None, [], True)
            else:
                self.server.telegram_api_utils.send_message(
                    chat_id,
                    "<b>You shall not pass !!!</b> " + u'\U0001F6B7'
                    "\nSorry, but you entered the wrong invite token. If you repeat often, I will have to ban you " + u'\U0001F609'
                )
                self.upsert_user_telegram_trello_assignment(chat_id, None, [], False)
                self.reset_last_user_command(chat_id)
        elif telegram_users_activity_log['last_event'] == '/register_step2' and self.is_current_user_active(chat_id):
            self.upsert_user_telegram_trello_assignment(chat_id, incoming_msg, [], True)
            self.server.telegram_api_utils.send_message(chat_id, u'\U0001F44D' + " Now, you can use /subscribe !")
            self.reset_last_user_command(chat_id)
        # collect data for /subscribe command
        elif telegram_users_activity_log['last_event'] == '/subscribe' and self.is_current_user_active(chat_id):
            self.server.telegram_api_utils.send_message(chat_id, "The subscription was successful. "
                + "Now I will automatically notify you about changes in accordance with your settings " + u'\U0001F916')
            # TODO: should be refactored here
            trello_username = self.server.mongodb_utils.findUserTelegramTrelloAssignmentByChatId(chat_id)['trello_username']
            result_subscription = 'ALL' if incoming_msg.lower() == 'all' else incoming_msg
            self.upsert_user_telegram_trello_assignment(chat_id, trello_username, [result_subscription], True)
            self.reset_last_user_command(chat_id)
        return

    def upsert_telegram_user_activity_log(self, chat_id, command):
        user_event = {
            "last_event": command,
            "chat_id": chat_id
        }
        self.server.mongodb_utils.upsertTelegramUserActivityLog(user_event)
        return

    def reset_last_user_command(self, chat_id):
        user_event = {
            "last_event": 'N/A',
            "chat_id": chat_id
        }
        self.server.mongodb_utils.upsertTelegramUserActivityLog(user_event)
        return

    def is_current_user_active(self, chat_id) -> bool:
        active_result = self.server.mongodb_utils.findUserTelegramTrelloAssignmentByChatId(chat_id)
        if active_result == None:
            return False
        return bool(active_result['active'])

    def upsert_user_telegram_trello_assignment(self, chat_id, trello_username, subscription, active: bool):
        self.server.mongodb_utils.upsertUserTelegramTrelloAssignment(
            { "trello_username": trello_username, "telegram_chat_id": chat_id, "subscription_list": subscription, "active": active }
        )
        return


from django.urls import path
from .views import LoginView, RegisterView, logout_user

app_name = 'userauth'

urlpatterns = [
    path('login/', LoginView.as_view(), name="login"),
    path('register/', RegisterView.as_view(), name='register'),
    path('logout/', logout_user, name='logout')
]


from repository.menuItemScoreRepo import MenuItemScoreRepo
from utils.logger import Logger

logger = Logger('menuItemScoreService')

class MenuItemScoreService:
    def __init__(self):
        self.repo = MenuItemScoreRepo()

    def insertScore(self, id_item_menu, id_usuario, score):
      logger.debug('insertScore')
      logger.debug(id_item_menu)
      logger.debug(id_usuario)
      logger.debug(score)
      result = self.repo.insertScore(id_item_menu, id_usuario, score)
      return result


#setup matplotlib, pyplot
import matplotlib
#make it so that it doesn't use X for rendering
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import string
from subprocess import Popen, PIPE

if __name__ == '__main__':
    import argparse
    import glob
    parser = argparse.ArgumentParser()
    parser.add_argument('--trace', default='/scratch/cluster/msbrenan/champsim_traces_with_data/400.perlbench.gz')
    parser.add_argument('--out-dir', default='/u/jyoustra/Documents/compressed_cache/scripts')
    parser.add_argument('--program-path', default='/u/jyoustra/Documents/compressed_cache/build/ccachesim')
    parser.add_argument('--plot-types', nargs='*', default=['hist', 'violin'])
    parser.add_argument('--instructions', type=int, default=50000000)
    args = parser.parse_args()
    trace_file = args.trace
    print('processing %s', trace_file)
    p = Popen([args.program_path, '-q', '-t', trace_file, '-i', str(args.instructions)],
            stdin=PIPE, stdout=PIPE)
    output, err = p.communicate(b"stdin")
    print('done')
    if isinstance(output, bytes):
        output = str(output, 'utf-8')
    output = output.splitlines()
    print('generating data')
    data = list(map(int, filter(lambda w: len(w) > 0 and all(c in string.digits for c in w), next(filter(lambda x: len(x) > 10000, output)).split(','))))
    if isinstance(args.plot_types, str):
        args.plot_types = pargs.plot_types
    for plot_type in args.plot_types:
        fig, ax = plt.subplots()
        print('plotting data')
        if plot_type == 'hist':
            print('histogram')
            ax.hist(data, bins=np.logspace(np.log10(1.0),np.log10(1000000000.0), 50))
            ax.set_xscale("log")
        else:
            print('violin')
            ax.violinplot(data, showmeans=False, showextrema=False, showmedians=False) #, pos, points=20, widths=0.3, showmeans=True, showextrema=True, showmedians=True)
        try:
            import os.path
            fn = "%s/interval_sizes_%s_%s.png" % (args.out_dir, plot_type, os.path.basename(trace_file))
            print('saving data to %s' % fn)
            fig.savefig(fn)
        except Exception as e:
            import sys
            sys.stderr.write('there was an error:\n')
            sys.stderr.write(str(e) + '\n')
            print(e)
            pass
        plt.clf()
            #plt.show()