# -*- coding: utf-8 -*-
"""
Created on Fri Mar 04 10:04:46 2016

@author: nfette

A single effect LiBr absorption chiller model.
"""
import numpy as np
import tabulate
from scipy.optimize import fsolve
from scipy.interpolate import PchipInterpolator
from collections import namedtuple
import CoolProp.CoolProp as CP
from hw2_1 import CelsiusToKelvin as C2K
from hw2_1 import KelvinToCelsius as K2C
import libr_props, libr_props2
import HRHX_integral_model

water = 'HEOS::Water'
librname = lambda x: 'INCOMP::LiBr[{}]'.format(x)
pwater = CP.AbstractState("HEOS","water")

pointType = np.dtype(dict(names="name m x T p Q h D C".split(),formats=['S32']+['d']*8))
class ProcessPoint(object):
    def __init__(self,row):
        self.row = row
def makeprop(i):
    def getx(self):
        return self.row[i]
    def setx(self,value):
        self.row[i]=value
    def delx(self):
        del self.row[i]
    return property(getx,setx,delx)
for i in pointType.names:
   setattr(ProcessPoint,i,makeprop(i))
class ProcessTable(object):
    pass
def makePointTable(names):
    table=np.zeros(len(names),dtype=pointType)
    points=ProcessTable()
    for i,name in enumerate(names):
        points.__setattr__(name,ProcessPoint(table[i]))
        table[i][0]=name
    return table,points

# Units in this file:
# temperature [C]
# enthalpy [J/kg]
# pressure [Pa]
# mass fraction [kg/kg total]
# effectiveness [K/K]

# The LiBr enthalpy is zero at 293.15 K, 1 atm, per
# http://www.coolprop.org/fluid_properties/Incompressibles.html#general-introduction
# We need to evaluate water enthalpy relative to that, but it is not built-in.
# http://www.coolprop.org/coolprop/HighLevelAPI.html#reference-states
T_ref = 20
P_ref = 101325

pwater.update(CP.PT_INPUTS,P_ref,C2K(T_ref))
h_w_ref = pwater.hmass()

class GeneratorLiBr(object):
    """Provide process heat canonical curve for generator in various forms.
        For purpose of external heat exchange,  generator process goes ...
        P_cond, T_gen_pre, x1  (subcooled)
        P_cond, T_gen_inlet, x1 (saturated liquid) + backwards flowing vapor
        P_cond, T_gen_outlet, x2 (saturated liquid)

        Args:
            P : Pressure (Pa)
                The process is assumed to occur at constant pressure level.
            m_in : Solution inlet mass flow rate (kg/s)
                The mass flow rate of the stream pumped up from low pressure.
            T_in : Solution inlet temperature (C)
                Needed to determine inlet state, which may be subcooled.
            x_in : Solution inlet mass fraction (kg/kg)
                The LiBr mass relative to total mass
            x_out : Solution outlet mass fraction (kg/kg)
                The outlet solution LiBr mass fraction
    """

    def __init__(self, P, m_in, T_in, x_in, x_out):
        self.update(P, m_in, T_in, x_in, x_out)
        # Create the functions ...
        self.q = np.vectorize(self._q)
        self.T = np.vectorize(self._T)
        # Create faster functions using splines ...

    def update(self, P, m_in, T_in, x_in, x_out):
        self.P = P
        self.m_in = m_in
        self.T_in = T_in
        self.x_in = x_in
        self.x_out = x_out

        # Find inlet enthalpy.
        # Find saturation point at inlet concentration.
        # Find ...
        self.T_sat = K2C(libr_props.temperature(self.P * 1e-5, self.x_in))
        self.T_out = K2C(libr_props.temperature(self.P * 1e-5, self.x_out))
        self.h_sat = libr_props.massSpecificEnthalpy(C2K(self.T_sat), self.x_in)
        self.h_out = libr_props.massSpecificEnthalpy(C2K(self.T_out),self.x_out)

        self.cp_in = libr_props.massSpecificHeat(C2K(self.T_in),self.x_in)
        # If h_in is an input:
        if False:
            preheat = (self.h_sat - self.h_in)/self.cp_in
            self.T_in = self.T_sat - preheat
        else:
            preheat = self.T_sat - self.T_in
            self.h_in = self.h_sat - preheat * self.cp_in

        pwater.update(CP.PT_INPUTS, self.P, C2K(self.T_sat))
        self.h_vapor_out = pwater.hmass() - h_w_ref

        # Mass balance on LiBr
        self.m_out = self.m_in * self.x_in / self.x_out
        # Mass balance on Water
        self.m_vapor_out = self.m_in - self.m_out
        self.m_total = self.m_out

        self.Q_preheat = self.m_in * (self.h_sat - self.h_in)
        self.Q_desorb = self.m_out * self.h_out \
                + self.m_vapor_out * self.h_vapor_out \
                - self.m_in * self.h_sat

        # Determine a reasonable limit for extending the domain.
        self.Tmax = K2C(libr_props.temperature(self.P*1e-5,libr_props.xmax))

    def __repr__(self):
        import tabulate
        names = """P
        x_in
        x_out
        T_in
        m_in
        T_sat
        T_out
        m_out
        m_vapor_out
        h_in
        h_sat
        h_out
        h_vapor_out
        Q_preheat
        Q_desorb
        Q_total""".split()
        vals = [self.P,
                self.x_in,
                self.x_out,
                self.T_in,
                self.m_in,
                self.T_sat,
                self.T_out,
                self.m_out,
                self.m_vapor_out,
                self.h_in,
                self.h_sat,
                self.h_out,
                self.h_vapor_out,
                self.Q_preheat,
                self.Q_desorb,
                self.Q_preheat+self.Q_desorb]
        units = """Pa
        kg/kg kg/kg
        C
        kg/s
        C C
        kg/s kg/s
        J/kg J/kg J/kg J/kg
        W W W""".split()
        return tabulate.tabulate(zip(names,vals,units))

    def _q_helper(self,T):
        x_local = libr_props.massFraction(C2K(T),self.P * 1e-5)
        # Could parametrize this by x, but libr_props.temperature also has an
        # implicit solve. Only P(T,x) is explicit.
        pwater.update(CP.PT_INPUTS, self.P, C2K(T))
        h_vapor_local = pwater.hmass() - h_w_ref
        h_solution_local = libr_props.massSpecificEnthalpy(C2K(T), x_local)
        # Mass balance on LiBr
        m_solution_local = self.m_in * self.x_in / x_local

        hlv1 = h_vapor_local - h_solution_local
        q1 = self.m_total * h_vapor_local - m_solution_local * hlv1
        return q1

    def _T_helper(self,q,Tguess):
        func = lambda T:self._q_helper(T)-q
        sol = fsolve(func, Tguess)
        return sol[0]

    def _q(self,T):
        """Provide process heat canonical curve for generator in various forms.
        Assumes that
        * inlet solution state is obtained from self,
        * generated vapor is flowing in reverse direction and
        * it is everywhere in local equilibrium with solution.

        Args
        ----
        T : Temperature (deg C)
            The local temperature

        Returns
        -------
        q : Local progress index
            Measured as cumulative heat flux (W).
        Q : Total heat flux (W)
            The total amount of heat transferred into the generator.
        """

        hlv0 = self.h_vapor_out - self.h_sat
        q0 = self.m_total * self.h_vapor_out - self.m_in * hlv0

        if T < self.T_in:
            raise "Generator outlet must be greater than pre-inlet temperature!"
        elif T < self.T_sat:
            # The state is either saturated or subcooled.
            # Use linear interpolation.
            q = self.m_in * self.cp_in * (T - self.T_in)
        else:
            x_local = libr_props.massFraction(C2K(T),self.P * 1e-5)
            pwater.update(CP.PT_INPUTS, self.P, C2K(T))
            h_vapor_local = pwater.hmass() - h_w_ref
            h_solution_local = libr_props.massSpecificEnthalpy(C2K(T), x_local)
            # Mass balance on LiBr
            m_solution_local = self.m_in * self.x_in / x_local

            hlv1 = h_vapor_local - h_solution_local
            q1 = self.m_total * h_vapor_local - m_solution_local * hlv1

            q = (q1 - q0) + self.Q_preheat
        # TODO
        # If q > Q (iff T > T_solution_outlet) then result is invalid.
        return q

    def _T(self,q):
        if q < 0:
            raise "Process index must be greater than 0!"
        elif q < self.Q_preheat:
            T = self.T_in + q / (self.m_in * self.cp_in)
        #elif q < self.Q_desorb + self.Q_preheat:
        else:
            hlv0 = self.h_vapor_out - self.h_sat
            q0 = self.m_total * self.h_vapor_out - self.m_in * hlv0
            q1 = q0 + (q - self.Q_preheat)
            alpha = (q - self.Q_preheat) / self.Q_desorb
            Tguess = alpha*self.T_sat+(1-alpha)*self.T_out
            T = self._T_helper(q1,Tguess)
        #else:
        #    raise "Process index extends past process
        return T

class GeneratorLiBrInterpolated(GeneratorLiBr):
    def __init__(self, P, m_in, T_in, x_in, x_out, debug=False):
        print("I am still alive!")
        self.update(P, m_in, T_in, x_in, x_out)
        TT = np.linspace(self.T_in,self.Tmax,100)
        qfunc = np.vectorize(self._q)
        qq = qfunc(TT)
        if np.isnan(qq).any():
            print("There is a problem with some nans")

        # Create extended domain such that interpolate saturates at endpoints.
        qq1 = np.resize(qq,qq.size+1)
        TT1 = np.resize(TT,TT.size+1)
        qq1[-1] = qq1[-2]
        TT1[-1] = TT1[-2] + 1
        if (np.diff(qq1) < 0).any():
            print("Captain, it's a non-monotonic function!")
        self.q = PchipInterpolator(TT1,qq1,extrapolate=True)

        # Need to use fresh arrays because they are referenced.
        qq2 = np.resize(qq,qq.size+1)
        TT2 = np.resize(TT,TT.size+1)
        qq2[-1] = qq2[-2] * 1.02
        TT2[-1] = TT2[-2]
        self.T = PchipInterpolator(qq2,TT2,extrapolate=True)

        # Show that it worked
        if debug:
            print(tabulate.tabulate(zip(TT1,qq1)))
            print(tabulate.tabulate(zip(TT2,qq2)))
            import matplotlib.pyplot as plt
            plt.figure()
            plt.plot(TT1,qq1,'.'); plt.title("qqmod vs TTmod for q()")
            plt.figure()
            plt.plot(qq2,TT2,'.'); plt.title("TTmod vs qqmod for T()")

class AbsorberLiBr1(object):
    """Provides a canonical heat (output) curve for a LiBr water vapor absorber.

    Assumes:
        Vapor comes into equilibrium with surface only where it is absorbed.

    Inputs
    ------
        P : number (Pa)
            Process pressure
        m_in : number (kg/s)
            Solution inlet mass flow rate
        h_in : number (J/kg)
            Solution inlet enthalpy
        x_in : number (kg/kg)
            Solution inlet mass fraction LiBr
        T_vapor_inlet : number (deg C)
            Vapor inlet temperature
    """
    def __init__(self,P,m_in,h_in,x_in,h_vapor_inlet,debug=False):
        self.P=P
        self.m_in=m_in
        self.h_in=h_in
        self.x_in=x_in
        self.h_vapor_inlet = h_vapor_inlet

        self.T_sat = K2C(libr_props.temperature(self.P * 1e-5,
                                                          self.x_in))
        self.h_sat = libr_props.massSpecificEnthalpy(C2K(self.T_sat),self.x_in)

        if self.h_in > self.h_sat:
            q,t,xl = libr_props.twoPhaseProps(self.h_in,self.P*1e-5,self.x_in)
            # Pre-cooling is required to reach saturation temperature
            self.Q_pre_cool = self.m_in * (self.h_sat - self.h_in)
            self.T_in = K2C(t)
            prepoints_x = np.linspace(xl,self.x_in,20,endpoint=False)
            prepoints_T = np.zeros_like(prepoints_x)
            prepoints_q = np.zeros_like(prepoints_x)

            for i,x in enumerate(prepoints_x):
                #q,t,xl = libr_props.twoPhaseProps(h,self.P*1e-5,self.x_in)
                t = libr_props.temperature(self.P * 1e-5, x)
                h = libr_props.massSpecificEnthalpy(t,x)
                prepoints_T[i] = K2C(t)
                prepoints_q[i] = self.m_in * (h - self.h_in)
                prepoints_x[i] = x
        else:
            self.Q_pre_cool = 0
            self.T_in = K2C(libr_props.temperature(self.P * 1e-5, self.x_in))
            prepoints_T = []
            prepoints_q = []
            prepoints_x = []

        # Set up bounds and points for interpolation.
        # Absorber limit is liquid water.
        pwater.update(CP.PQ_INPUTS,P,0)
        self.Tmin = pwater.T()
        x_points = np.linspace(x_in,0.1,100)
        T_points = np.zeros_like(x_points)
        q_points = np.zeros_like(x_points)
        #q_func = np.vectorize(self._q)
        #q_points = q_func(T_points)
        for i,x in enumerate(x_points):
            T_points[i],q_points[i] = self._qx(x)

        x_points = np.concatenate([prepoints_x,x_points])
        T_points = np.concatenate([prepoints_T,T_points])
        q_points = np.concatenate([prepoints_q,q_points])

        # Forward function
        T_points1 = np.resize(T_points,len(T_points)+1)
        q_points1 = np.resize(q_points,len(T_points)+1)
        T_points1[-1] = T_points[-1] - 5
        q_points1[-1] = q_points[-1]

        # Inverse function
        T_points2 = np.resize(T_points,len(T_points)+1)
        q_points2 = np.resize(q_points,len(T_points)+1)
        T_points2[-1] = T_points[-1]
        q_points2[-1] = q_points[-1] * 1.05

        if debug:
            import matplotlib.pyplot as plt
            import tabulate
            xmod = np.resize(x_points,len(x_points)+1)
            print(tabulate.tabulate(zip(xmod,T_points1,q_points1,
                                    T_points2,q_points2),
                                    headers=['x','T1','q1','T2','q2']))
            plt.figure(); plt.plot(T_points1,q_points1); plt.title("q(T)")
            plt.figure(); plt.plot(q_points2,T_points2); plt.title("T(q)")
        # Interpolate data must be in increasing order, so we reverse it
        # compared to reaction direction.
        self.q = PchipInterpolator(T_points1[::-1], q_points1[::-1])
        self.T = PchipInterpolator(q_points2[::-1], T_points2[::-1])

    def _q(self,T):
        # First, determine the mass fraction here.
        if T > self.T_sat:
            raise ValueError("This function is for subcooled LiBr...")
        else:
            x_local = libr_props.massFraction(C2K(T),self.P*1e-5)
        return self._qx(x_local)

    def _qx(self,x_local):
        T = K2C(libr_props.temperature(self.P*1e-5,x_local))
        dx = self.x_in - x_local
        # TODO
        h_local = libr_props.massSpecificEnthalpy(C2K(T),x_local)
        # And calculate
        m_vapor = self.m_in * dx / x_local
        m_out = self.m_in + m_vapor
        # Heat is inbound.
        result = -self.m_in * self.h_in - m_vapor * self.h_vapor_inlet \
            + m_out * h_local
        return T,result

    def __repr__(self):
        names = """P
        m_in
        x_in
        T_in
        h_in
        h_sat
        h_vapor_inlet""".split()
        vals = [self.P,
                self.m_in,
                self.x_in,
                self.T_in,
                self.h_in,
                self.h_sat,
                self.h_vapor_inlet]
        units = """Pa
        kg/kg kg/kg
        C
        kg/s
        C
        kg/s kg/s
        J/kg J/kg J/kg J/kg
        W W W""".split()
        return tabulate.tabulate(zip(names,vals,units))

class ChillerLiBr1(object):
    def __init__(self,
                 T_evap=1.5, T_cond=39.9,
                 x1=0.567, x2=0.624,
                 Eff_SHX=0.64, m_pump=0.05):
        """Args
        ----
            T_evap : float
                Evaporator saturation temperature (deg C)
            T_cond : float
                Condenser saturation temperature (deg C)
            x1 : float
                Pump side mass fraction of LiBr in stream (low) [kg/kg]
            x2 : float
                Return side mass fraction of LiBr in stream (high/concentrate)
            Eff_SHX : float
                Effectiveness of the solution heat exchanger (K/K), 0 to 1
            m_pump : float
                Mass flow rate through the solution pump (kg/s)
        """
        self.T_evap = T_evap
        self.T_cond = T_cond
        self.x1 = x1
        self.x2 = x2
        self.m_pump = m_pump
        self.Eff_SHX = Eff_SHX
        self.dx = x1 - x2

        pwater.update(CP.QT_INPUTS, 1, C2K(T_evap))
        self.P_evap = pwater.p()

        pwater.update(CP.QT_INPUTS, 1, C2K(T_cond))
        self.P_cond = pwater.p()

        self.stateLabels = """abs_outlet
pump_outlet
gen_inlet
gen_sat_liquid
gen_outlet
SHX_conc_outlet
abs_inlet
abs_sat_liquid
gen_vapor_outlet
cond_sat_vapor
cond_outlet
evap_inlet
evap_sat_liquid
evap_sat_vapor
evap_outlet""".split('\n')
        #self.states=dict((k, nullPP('LiBrH2O')) for k in self.stateLabels)
        self.stateTable,self.states=makePointTable(self.stateLabels)

        self.T_gen_inlet = 0
        self.T_gen_outlet = 0
        self.T_abs_inlet_max = 0
        self.T_abs_outlet_max = 0
        self.h_gen_inlet = 0
        self.h_gen_outlet = 0
        self.h_abs_inlet = 0
        self.h_abs_outlet = 0
        self.m_concentrate = 0
        self.m_refrig = 0
        self.T_SHX_concentrate_outlet = 0
        self.Q_SHX = 0
        self.T_abs_pre = np.nan
        self.h_abs_pre = np.nan
        self.Q_abs_pre_cool = 0
        self.P_abs_pre = np.nan
        self.Q_abs_main = 0
        self.Q_abs_total = 0
        self.T_gen_pre = np.nan
        self.Q_gen_pre_heat = 0
        self.Q_gen_main = 0
        self.Q_gen_total = 0
        self.Q_condenser_reject = 0
        self.Q_evap_heat = 0
        self.COP = 0
        self.W_pump = 0
        self.f = np.inf
        self.x_abs_pre = self.x2

    # These routines allow updating solution
    def setT_evap(self,T_evap):
        self.T_evap = T_evap
        pwater.update(CP.QT_INPUTS, 1, C2K(T_evap))
        self.P_evap = pwater.p()
    def setT_cond(self,T_cond):
        self.T_cond = T_cond
        pwater.update(CP.QT_INPUTS, 1, C2K(T_cond))
        self.P_cond = pwater.p()

    def ZeroCheck(self):
        return self.W_pump + self.Q_evap_heat + self.Q_gen_total - self.Q_condenser_reject - self.Q_abs_total

    def iterate1(self):
        """Update the internal parameters."""
        self.T_gen_inlet = K2C(libr_props.temperature(self.P_cond*1e-5,
                                                      self.x1))
        self.T_gen_outlet = K2C(libr_props.temperature(self.P_cond * 1e-5,
                                                   self.x2))
        self.T_abs_inlet_max = K2C(libr_props.temperature(self.P_evap * 1e-5,
                                                          self.x2))
        self.T_abs_outlet_max = K2C(libr_props.temperature(self.P_evap * 1e-5,
                                                           self.x1))

        self.h_gen_inlet = libr_props.massSpecificEnthalpy(
            C2K(self.T_gen_inlet), self.x1)
        self.h_gen_outlet = libr_props.massSpecificEnthalpy(
            C2K(self.T_gen_outlet), self.x2)
        self.h_abs_inlet = libr_props.massSpecificEnthalpy(
            C2K(self.T_abs_inlet_max), self.x2)
        self.h_abs_outlet = libr_props.massSpecificEnthalpy(
            C2K(self.T_abs_outlet_max), self.x1)

        # Mass balance on LiBr
        self.m_concentrate = self.m_pump * self.x1 / self.x2
        # Mass balance on Water
        self.m_refrig = self.m_pump - self.m_concentrate
        self.f = self.m_pump / self.m_refrig

        # Compute SHX outlets, assuming concentrate limits heat flow (C_min)
        # Neglect pump work for the present.
        DeltaT_max = self.T_gen_outlet - self.T_abs_outlet_max
        DeltaT_SHX_concentrate = self.Eff_SHX * DeltaT_max
        self.T_SHX_concentrate_outlet = self.T_gen_outlet \
            - DeltaT_SHX_concentrate
        self.h_SHX_concentrate_outlet = libr_props.massSpecificEnthalpy(
            C2K(self.T_SHX_concentrate_outlet), self.x2)
        self.Q_SHX = self.m_concentrate \
            * (self.h_gen_outlet - self.h_SHX_concentrate_outlet)

        # Expansion valve
        self.h_abs_pre = self.h_SHX_concentrate_outlet
        if self.h_abs_pre > self.h_abs_inlet:
            # Pre-cooling is required to reach saturation temperature
            self.Q_abs_pre_cool = self.m_concentrate \
                * (self.h_abs_pre - self.h_abs_inlet)
            q,t,xl = libr_props.twoPhaseProps(self.h_abs_pre,
                                              self.P_evap*1e-5,
                                              self.x2)
            self.T_abs_pre = K2C(t)
            self.x_abs_pre = xl
            # ignore vapor quality, q
            # Minimum vapor pressure for absorption to occur
            self.P_abs_pre = np.inf
        else:
            self.Q_abs_pre_cool = 0
            #self.T_abs_pre = K2C(CP.PropsSI('T',
            #    'H', self.h_abs_pre,
            #    'P', self.P_evap,
            #    librname(self.x2)))
            self.T_abs_pre = np.nan
            # Minimum vapor pressure for absorption to occur
#            self.P_abs_pre = CP.PropsSI('P',
#                'T', C2K(self.T_abs_pre),
#                'Q', 0,
#                librname(self.x2))
            self.P_abs_pre = np.nan

        # Heat rejection in absorber: energy balance
        pwater.update(CP.PQ_INPUTS, self.P_evap, 1)
        self.h_abs_vapor_inlet = pwater.hmass() - h_w_ref
        self.Q_abs_main = self.m_refrig * self.h_abs_vapor_inlet \
            + self.m_concentrate * self.h_abs_inlet \
            - self.m_pump * self.h_abs_outlet
        self.Q_abs_total = self.Q_abs_main + self.Q_abs_pre_cool

        # Energy balance in SHX, pump side
        D_in = CP.PropsSI('D',
            'T',C2K(self.T_abs_outlet_max),
            'Q',0,
            librname(self.x1))
        DeltaH_pump = (self.P_cond - self.P_evap) / D_in
        self.W_pump = self.m_pump * DeltaH_pump
        self.h_pump_outlet = self.h_abs_outlet + DeltaH_pump
        DeltaH_SHX_pumpside = self.Q_SHX / self.m_pump
        self.h_gen_pre = self.h_pump_outlet + DeltaH_SHX_pumpside
        if self.h_gen_pre > self.h_gen_inlet:
            # Flash steam
            self.T_gen_pre = np.nan
        else:
            # The state is either saturated or subcooled.
            # We need to calculate the temperature from specific heat.
            cp = libr_props.massSpecificHeat(C2K(self.T_gen_inlet),self.x1)
            deltaHsub = self.h_gen_inlet - self.h_gen_pre
            deltaT = deltaHsub / cp
            self.T_gen_pre = self.T_gen_inlet - deltaT

        self.Q_gen_pre_heat = self.m_pump * (self.h_gen_inlet - self.h_gen_pre)

        # Heat input to generator: energy balance
        pwater.update(CP.PT_INPUTS, self.P_cond, C2K(self.T_gen_inlet))
        self.h_gen_vapor_outlet = pwater.hmass() - h_w_ref
        self.vapor_superheat = self.T_gen_inlet - self.T_cond
        self.Q_gen_main = self.m_refrig * self.h_gen_vapor_outlet \
            + self.m_concentrate * self.h_gen_outlet \
            - self.m_pump * self.h_gen_inlet
        self.Q_gen_total = self.Q_gen_main + self.Q_gen_pre_heat

        # Condenser
        pwater.update(CP.PQ_INPUTS, self.P_cond, 0)
        self.h_condenser_outlet = pwater.hmass() - h_w_ref
        self.Q_condenser_reject = self.m_refrig * (self.h_gen_vapor_outlet
            - self.h_condenser_outlet)

        # Expansion valve
        self.h_evap_inlet = self.h_condenser_outlet

        # Evaporator
        self.h_evap_outlet = self.h_abs_vapor_inlet
        self.Q_evap_heat = self.m_refrig * (self.h_evap_outlet
            - self.h_evap_inlet)

        self.COP = self.Q_evap_heat / self.Q_gen_total

    def updateGenerator(self,Q_gen):
        genStream = self.getGeneratorStream()
        self.h_gen_inlet = genStream.h_sat
        self.T_gen_inlet = genStream.T_sat

        if Q_gen < genStream.Q_preheat:
            self.T_gen_outlet = genStream.T(Q_gen)
            self.x2 = self.x1
            # error?
        else:
            self.T_gen_outlet = genStream.T(Q_gen)
            self.x2 = libr_props.massFraction(C2K(self.T_gen_outlet),
                                              self.P_cond)
            genStream.update(self.P_cond, self.m_pump, self.T_gen_pre,
                             self.x1, self.x2)
            self.h_gen_outlet = genStream.h_out
            self.h_gen_vapor_outlet = genStream.h_vapor_out
        self.dx = self.x1 - self.x2
        # Mass balance on LiBr
        self.m_concentrate = self.m_pump * self.x1 / self.x2
        # Mass balance on Water
        self.m_refrig = self.m_pump - self.m_concentrate
        self.f = self.m_pump / self.m_refrig

    def updateSHX_hot_side(self):
        DeltaT_max = self.T_gen_outlet - self.T_abs_outlet_max
        DeltaT_SHX_concentrate = self.Eff_SHX * DeltaT_max
        self.T_SHX_concentrate_outlet = self.T_gen_outlet \
            - DeltaT_SHX_concentrate
        self.h_SHX_concentrate_outlet = libr_props.massSpecificEnthalpy(
            C2K(self.T_SHX_concentrate_outlet), self.x2)
        self.Q_SHX = self.m_concentrate \
            * (self.h_gen_outlet - self.h_SHX_concentrate_outlet)

    def getHeatCurve(self):
        """Returns (Heat,T), arrays showing progress of the process.
        Note: absorber heat input is negative.
        Learn this from (my revision to) example 3.3.
        """
        Q, result = 0, []
        # Starting coordinates
        result.append((0,self.T_abs_pre))
        # Heat input to reach a saturated state.
        Q += self.m_concentrate * (self.h_abs_inlet - self.h_abs_pre)
        result.append((Q,self.T_abs_inlet_max))
        # Heat input to reach outlet.
        Q += self.m_pump * self.h_abs_outlet \
            - self.m_concentrate * self.h_abs_inlet \
            - self.m_refrig * self.h_abs_vapor_inlet
        result.append((Q,self.T_abs_outlet_max))
        # Pump -- no heat, just work

        # Pump outlet to generator through SHX
        Q += self.m_pump * self.h_gen_pre - self.m_pump * self.h_abs_outlet
        result.append((Q,self.T_gen_pre))
        # Generator preheat
        Q += self.m_concentrate * self.h_gen_inlet \
                - self.m_concentrate * self.h_gen_pre
        result.append((Q,self.T_gen_inlet))
        # Generator proper
        Q += self.m_concentrate * self.h_gen_outlet \
                + self.m_refrig * self.h_gen_vapor_outlet \
                - self.m_pump * self.h_gen_inlet
        result.append((Q,self.T_gen_outlet))
        # SHX, concentrate side
        Q += self.m_concentrate * self.h_SHX_concentrate_outlet \
                - self.m_concentrate * self.h_gen_outlet
        result.append((Q,self.T_SHX_concentrate_outlet))
        # Solution expander
        result.append((Q,self.T_abs_pre))
        # Condenser cool to saturated
        result.append((Q,self.T_gen_inlet))
        pwater.update(CP.QT_INPUTS,0,C2K(self.T_cond))
        h_condenser_sat = pwater.hmass() - h_w_ref
        Q += self.m_refrig * h_condenser_sat \
                - self.m_refrig * self.h_gen_vapor_outlet
        result.append((Q,self.T_cond))
        # Real condense
        Q += self.m_refrig * (self.h_condenser_outlet - h_condenser_sat)
        result.append((Q,self.T_cond))
        # What if condenser subcools? Later.
        # Expander
        pwater.update(CP.HmassP_INPUTS,self.h_condenser_outlet + h_w_ref,
                      self.P_evap)
        T_into_evap = pwater.T()
        result.append((Q,T_into_evap))
        # Evaporator
        Q += self.m_refrig * (self.h_evap_outlet - self.h_evap_inlet)
        result.append((Q,self.T_evap))

        return zip(*result)

    def iterate2(self,T_gen_outlet,T_abs_outlet):
        """Resolve the concentrations. Not yet implemented."""
        pass

    def buildGeneratorHeatCurve(self):
        """Provide process heat canonical curve for generator in various forms.
        For purpose of external heat exchange,  generator process goes ...
        P_cond, T_gen_pre, x1  (subcooled)
        P_cond, T_gen_inlet, x1 (saturated liquid) + backwards flowing vapor
        P_cond, T_gen_outlet, x2 (saturated liquid)

        Returns
        -------
        T : callable
            Maps process progress in terms of heat flux (W) to local
            temperature T (deg C).
        q : callable
            Maps process local temperature T (deg C) and total heat flux Q (W)
            to the local progress index, cumulative heat flux q (W).
        """
        self.genpoints, Q = [], 0
        # 0, pre-inlet
        self.genpoints.append((Q,self.T_gen_pre))
        # 1, Generator preheat
        Q += self.m_concentrate * self.h_gen_inlet \
                - self.m_concentrate * self.h_gen_pre
        self.genpoints.append((Q,self.T_gen_inlet))
        # 2, Generator proper
        Q += self.m_concentrate * self.h_gen_outlet \
                + self.m_refrig * self.h_gen_vapor_outlet \
                - self.m_pump * self.h_gen_inlet
        self.genpoints.append((Q,self.T_gen_outlet))

    def generatorHeatCurveQ(self,T,x_out):
        """Provide process heat canonical curve for generator in various forms.
        Assumes that
        * inlet solution state is obtained from self,
        * generated vapor is flowing in reverse direction and
        * it is everywhere in local equilibrium with solution.

        Args
        ----
        T : Temperature (deg C)
            The local temperature
        x_out : Mass fraction (kg/kg)
            The outlet solution LiBr mass fraction

        Returns
        -------
        q : Local progress index
            Measured as cumulative heat flux (W).
        Q : Total heat flux (W)
            The total amount of heat transferred into the generator.
        """

        # We may need m_concentrate. It depends on Q -- solve from inlet.
        h_solution_inlet = self.h_gen_inlet
        h_vapor_outlet = self.h_gen_vapor_outlet
        T_solution_outlet = K2C(libr_props.temperature(self.P_cond * 1e-5,
                                               x_out))
        h_solution_outlet = libr_props.massSpecificEnthalpy(
            C2K(T_solution_outlet), x_out)
        # Mass balance on LiBr
        m_solution_outlet = self.m_pump * self.x1 / x_out
        # Mass balance on Water
        m_vapor_outlet = self.m_pump - m_solution_outlet
        m_total = m_solution_outlet

        hlv0 = h_vapor_outlet - h_solution_inlet
        q0 = m_total * h_vapor_outlet - self.m_pump * hlv0

        Q = m_solution_outlet * h_solution_outlet \
            + m_vapor_outlet * h_vapor_outlet \
            - self.m_pump * h_solution_inlet

        q = 0
        T0,T1,T2=self.genpoints[0][1],self.genpoints[1][1],self.genpoints[2][1]
        Q0,Q1,Q2=self.genpoints[0][0],self.genpoints[1][0],self.genpoints[2][0]
        if T < T0:
            raise "Generator outlet must be greater than pre-inlet temperature!"
        elif T < T1:
            # The state is either saturated or subcooled.
            # Use linear interpolation.
            q = (T - T0) / (T1 - T0) * (Q1 - Q0)
        else:
            x_local = libr_props.massFraction(C2K(T),self.P_cond * 1e-5)
            pwater.update(CP.PT_INPUTS, self.P_cond, C2K(T))
            h_vapor_local = pwater.hmass() - h_w_ref
            h_solution_local = libr_props.massSpecificEnthalpy(C2K(T), x_local)
            # Mass balance on LiBr
            m_solution_local = self.m_pump * self.x1 / x_local

            hlv1 = h_vapor_local - h_solution_local
            q1 = m_total * h_vapor_local - m_solution_local * hlv1

            q = (q1 - q0) + (Q1 - Q0)
        # TODO
        # If q > Q (iff T > T_solution_outlet) then result is invalid.
        return q, Q

    def generatorHeatCurveT(self,Q):
        """Provide process heat canonical curve for generator in various forms."""
        T = 0
        return T

    def getGeneratorStream(self):
        gen = GeneratorLiBrInterpolated(self.P_cond,self.m_pump,self.T_gen_pre,
                                        self.x1,self.x2)
        return gen

    def getAbsorberStream(self):
        absorber = AbsorberLiBr1(self.P_evap,
                                 self.m_concentrate,
                                 self.h_abs_pre,
                                 self.x_abs_pre,
                                 self.h_evap_outlet)
        return absorber

    def getCondenserStream(self):
        h_rel = self.h_gen_vapor_outlet + h_w_ref
        condenser = HRHX_integral_model.waterStreamInterpolated(
            self.P_cond, h_rel, self.m_refrig, -self.Q_condenser_reject)
        return condenser

    def getEvaporatorStream(self):
        h_rel = self.h_evap_inlet + h_w_ref
        evaporator = HRHX_integral_model.waterStreamInterpolated(
            self.P_evap, h_rel, self.m_refrig, self.Q_evap_heat)
        return evaporator

    def __repr__(self):
        names = """T_evap T_cond P_evap P_cond
        x1 x2
        T_gen_inlet T_gen_outlet T_abs_inlet_max T_abs_outlet_max
        h_gen_inlet h_gen_outlet h_abs_inlet h_abs_outlet
        m_pump m_concentrate m_refrig
        Eff_SHX
        T_SHX_concentrate_outlet Q_SHX
        T_abs_pre h_abs_pre x_abs_pre Q_abs_pre_cool P_abs_pre
        Q_abs_main Q_abs_total
        T_gen_pre
        Q_gen_pre_heat Q_gen_main Q_gen_total
        Q_condenser_reject Q_evap_heat COP
        W_pump
        self.f
        ZeroCheck
        string""".split()
        vals = [self.T_evap, self.T_cond, self.P_evap, self.P_cond,
            self.x1, self.x2,
            self.T_gen_inlet, self.T_gen_outlet, self.T_abs_inlet_max, self.T_abs_outlet_max,
            self.h_gen_inlet, self.h_gen_outlet, self.h_abs_inlet, self.h_abs_outlet,
            self.m_pump, self.m_concentrate, self.m_refrig,
            self.Eff_SHX,
            self.T_SHX_concentrate_outlet, self.Q_SHX,
            self.T_abs_pre, self.h_abs_pre, self.x_abs_pre,
            self.Q_abs_pre_cool, self.P_abs_pre,
            self.Q_abs_main, self.Q_abs_total,
            self.T_gen_pre,
            self.Q_gen_pre_heat, self.Q_gen_main, self.Q_gen_total,
            self.Q_condenser_reject, self.Q_evap_heat, self.COP,
            self.W_pump,
            self.f,
            self.ZeroCheck(),
            False]
        units = """C C Pa Pa
        kg/kg kg/kg
        C C C C
        J/kg J/kg J/kg J/kg
        kg/s kg/s kg/s
        K/K
        C W
        C J/kg kg/kg W Pa
        W W
        C
        W W W
        W W W/W
        W
        kg/kg
        W
        none""".split()
        vartable = tabulate.tabulate(zip(names,vals,units))
        statetable = tabulate.tabulate(self.stateTable,pointType.names)
        return vartable + "\nComing soon ...\n" + statetable

def main():
    if True:
        # Example 6.1 in the book
        P1,P2 = 673, 7445
        T1 = K2C(CP.PropsSI('T','P',P1,'Q',1,water))
        T2 = K2C(CP.PropsSI('T','P',P2,'Q',1,water))
        # Trying different inputs
        T1, T2 = 1, 35
        c = ChillerLiBr1(T1,T2,0.5,0.7)
        c.x2=libr_props2.Xsat(89.9,c.P_cond)
        c.x1=libr_props2.Xsat(32.7,c.P_evap)
        # Custom example
        c = ChillerLiBr1(T_evap=5,T_cond=45,x1=0.6026,x2=0.66)
        print("Initializing...")
        print(c)
        print("Iterating...")
        try:
            c.iterate1()
        finally:
            print(c)

    if True:
        # Figure 6.3 in the book
        Eff_SHX = np.linspace(0,1)
        COP = np.zeros_like(Eff_SHX)
        for i in range(len(Eff_SHX)):
            c = ChillerLiBr1(Eff_SHX=Eff_SHX[i])
            try:
                c.iterate1()
                COP[i] = c.COP
            except:
                pass
        if False:
            import matplotlib.pyplot as plt
            plt.plot(Eff_SHX, COP)
            plt.show()

    return c

if __name__ == "__main__":
    c=main()

{'plt': 'matplotlib.pyplot', 'tabulate': 'tabulate'}


#!/usr/local/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2018/7/10 PM4:59
# @Author  : L
# @Email   : L862608263@163.com
# @File    : google.py
# @Software: PyCharm

import json
import urllib
import urllib.request
import urllib.parse
import re

def url_open(url, data=None):
    request = urllib.request.Request(url)
    request.add_header('User-Agent',
                       'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/605.1.15 (KHTML, like Gecko) '
                       'Version/11.1 Safari/605.1.15')
    response = urllib.request.urlopen(request, data)
    return response.read()

class TranslateGoogle:
    _tkk_url = "http://translate.google.cn/"
    _translate_url = "https://translate.google.cn/translate_a/single"

    def translate_word(self, translate_string):

        tk = self.get_tk(translate_string)
        print('请求需要的tk参数 ', tk)
        # 这里的字典有很多个dt的key, 按理说请求前就会被覆盖, 不知道有什么用
        # 'dt': 'bd', 'dt': 'ex', 'dt': 'ld', 'dt': 'md', 'dt': 'qca', 'dt': 'rw', 'dt': 'rm', 'dt': 'ss', 'dt': 't'
        data = {'client': 't', 'sl': 'auto', 'tl': 'en', 'hl': 'zh - CN', 'dt': 'at',
                'ie': 'UTF - 8',
                'oe': 'UTF - 8', 'source': 'bh', 'ssel': '0', 'tsel': '0', 'kc': '1', 'tk': str(tk),
                'q': translate_string}
        data = urllib.parse.urlencode(data).encode('utf-8')

        result = url_open(self._translate_url, data).decode('utf-8')
        print('翻译结果: ', json.loads(result))

    def get_tk(self, input_str):

        a = 4211913557
        b = -4140706334
        number = 422392

        e = "{0}.{1}".format(number, a + b).split('.')

        h = int(e[0]) or 0
        g = []
        for f in range(0, len(input_str)):
            c = ord(input_str[f])
            if 128 > c:
                g.append(c)
            else:
                if 2048 > c:
                    g.append(c >> 6 | 192)
                else:
                    if (0xd800 == (c & 0xfc00)) and \
                            (f + 1 < len(input_str)) and \
                            (0xfc00 == (ord(input_str[f + 1]) & 0xdc00)):
                        f += 1
                        c = 0x10000 + ((c & 0x3ff) << 10) + (ord(input_str[f]) & 0x3ff)
                        g.append(c >> 18 | 240)
                        g.append(c >> 12 & 63 | 128)
                    else:
                        g.append(c >> 12 | 224)
                        g.append(c >> 6 & 63 | 128)
                g.append(c & 63 | 128)

        input_str = h
        for d in range(len(g)):
            input_str += g[d]
            input_str = self.operation(input_str, '+-a^+6')
        input_str = self.operation(input_str, '+-3^+b+-f')
        input_str ^= int(e[1]) or 0
        if 0 > input_str:
            input_str = (input_str & (pow(2, 31) - 1)) + pow(2, 31)
        input_str %= pow(10, 6)
        return "%d.%d" % (input_str, input_str ^ h)

    # noinspection PyMethodMayBeStatic
    def operation(self, a, b):
        for d in range(0, len(b) - 2, 3):
            c = b[d + 2]
            c = ord(c[0]) - 87 if 'a' <= c else int(c)
            c = a >> c if '+' == b[d + 1] else a << c
            a = a + c & (pow(2, 32) - 1) if '+' == b[d] else a ^ c
        return a

# 谷歌翻译
# 重点是翻译时候的header里面需要tk这个键的值, 如果这个值不正确的话翻译请求是会被禁止的
# 这个tk的值的生成算法 可以在 https://translate.google.cn 审查元素 找到以下js代码
# go jfk-button-action 翻译按钮id
#    谷歌翻译 TKK 转换源js代码
#     sr = function(a, b)
#     {
#     for (var c = 0; c < b.length - 2; c += 3) {
#         var d = b.charAt(c + 2);
#     d = "a" <= d ? d.charCodeAt(0) - 87: Number(d);
#     d = "+" == b.charAt(c + 1) ? a >> > d: a << d;
#     a = "+" == b.charAt(c) ? a + d & 4294967295: a ^ d
#     }
#     return a
#     }, tr = null, ur = function(a)
#     {
#     if (null !== tr) var b = tr; else {
#     b = rr(String.fromCharCode(84));
#     var c = rr(String.fromCharCode(75));
#     b =[b(), b()];
#     b[1] = c();
#     b = (tr = window[b.join(c())] | | "") | | ""
#     }
#     var
#     d = rr(String.fromCharCode(116));
#     c = rr(String.fromCharCode(107));
#     d = [d(), d()];
#     d[1] = c();
#     c = "&" + d.join("") + "=";
#     d = b.split(".");
#     b = Number(d[0]) | | 0;
#     for (var e =[], f = 0, g = 0; g < a.length; g++) {
#         var l = a.charCodeAt(g);
#     128 > l ? e[f++] = l: (2048 > l ? e[f++] = l >> 6 | 192: (55296 == (l & 64512) & & g + 1 < a.length & & 56320 == (
#                 a.charCodeAt(g + 1) & 64512) ? (l = 65536 + ((l & 1023) << 10) + (a.charCodeAt(++g) & 1023), e[
#         f + +] = l >> 18 | 240, e[f + +] = l >> 12 & 63 | 128):
# e[f + +] = l >> 12 | 224, e[f + +] = l >> 6 & 63 | 128),
#     e[f + +] = l & 63 | 128)
#     }
#     a = b;
#     for (f = 0; f < e.length; f++) a += e[f], a = sr(a, "+-a^+6");
#     a = sr(a, "+-3^+b+-f");
#     a ^= Number(d[1]) | | 0;
#     0 > a & & (a = (a & 2147483647) + 2147483648);
#     a %= 1E6;
#     return c + (a.toString() + "." +
#                 (a ^ b))
#
# };

if __name__ == "__main__":
    translate = TranslateGoogle()
    translate.translate_word("我爱你")


import logging
from typing import Any, Callable, Dict, Iterable, Iterator, Optional, Tuple, Union

from swh.core.db import BaseDb
from swh.model.model import (
    BaseModel,
    Directory,
    DirectoryEntry,
    ExtID,
    RawExtrinsicMetadata,
    Release,
    Revision,
    Snapshot,
    SnapshotBranch,
    TargetType,
)
from swh.model.swhids import ExtendedObjectType
from swh.storage.postgresql.converters import (
    db_to_extid,
    db_to_raw_extrinsic_metadata,
    db_to_release,
    db_to_revision,
)
from swh.storage.replay import OBJECT_CONVERTERS
from swh.storage.writer import JournalWriter

logger = logging.getLogger(__name__)

PARTITION_KEY = {
    "content": "sha1",
    "skipped_content": "sha1",
    "directory": "id",
    "extid": "target",
    "metadata_authority": "type, url",
    "metadata_fetcher": "name, version",
    "raw_extrinsic_metadata": "target",
    "revision": "revision.id",
    "release": "release.id",
    "snapshot": "id",
    "origin": "id",
    "origin_visit": "origin_visit.origin",
    "origin_visit_status": "origin_visit_status.origin",
}

COLUMNS = {
    "content": [
        "sha1",
        "sha1_git",
        "sha256",
        "blake2s256",
        "length",
        "status",
        "ctime",
    ],
    "skipped_content": [
        "sha1",
        "sha1_git",
        "sha256",
        "blake2s256",
        "length",
        "ctime",
        "status",
        "reason",
    ],
    "directory": ["id", "dir_entries", "file_entries", "rev_entries", "raw_manifest"],
    "extid": ["extid_type", "extid", "extid_version", "target_type", "target"],
    "metadata_authority": ["type", "url"],
    "metadata_fetcher": ["name", "version"],
    "origin": ["url"],
    "origin_visit": [
        "visit",
        "type",
        ("origin.url", "origin"),
        "date",
    ],
    "origin_visit_status": [
        ("origin_visit_status.visit", "visit"),
        ("origin.url", "origin"),
        ("origin_visit_status.date", "date"),
        "type",
        "snapshot",
        "status",
        "metadata",
    ],
    "raw_extrinsic_metadata": [
        "raw_extrinsic_metadata.type",
        "raw_extrinsic_metadata.target",
        "metadata_authority.type",
        "metadata_authority.url",
        "metadata_fetcher.name",
        "metadata_fetcher.version",
        "discovery_date",
        "format",
        "raw_extrinsic_metadata.metadata",
        "origin",
        "visit",
        "snapshot",
        "release",
        "revision",
        "path",
        "directory",
    ],
    "revision": [
        ("revision.id", "id"),
        "date",
        "date_offset_bytes",
        "committer_date",
        "committer_date_offset_bytes",
        "type",
        "directory",
        "message",
        "synthetic",
        "metadata",
        "extra_headers",
        (
            "array(select parent_id::bytea from revision_history rh "
            "where rh.id = revision.id order by rh.parent_rank asc)",
            "parents",
        ),
        "raw_manifest",
        ("a.id", "author_id"),
        ("a.name", "author_name"),
        ("a.email", "author_email"),
        ("a.fullname", "author_fullname"),
        ("c.id", "committer_id"),
        ("c.name", "committer_name"),
        ("c.email", "committer_email"),
        ("c.fullname", "committer_fullname"),
    ],
    "release": [
        ("release.id", "id"),
        "date",
        "date_offset_bytes",
        "comment",
        ("release.name", "name"),
        "synthetic",
        "target",
        "target_type",
        ("a.id", "author_id"),
        ("a.name", "author_name"),
        ("a.email", "author_email"),
        ("a.fullname", "author_fullname"),
        "raw_manifest",
    ],
    "snapshot": ["id", "object_id"],
}

JOINS = {
    "release": ["person a on release.author=a.id"],
    "revision": [
        "person a on revision.author=a.id",
        "person c on revision.committer=c.id",
    ],
    "origin_visit": ["origin on origin_visit.origin=origin.id"],
    "origin_visit_status": [
        "origin on origin_visit_status.origin=origin.id",
    ],
    "raw_extrinsic_metadata": [
        "metadata_authority on "
        "raw_extrinsic_metadata.authority_id=metadata_authority.id",
        "metadata_fetcher on raw_extrinsic_metadata.fetcher_id=metadata_fetcher.id",
    ],
}

EXTRA_WHERE = {
    # hack to force the right index usage on table extid
    "extid": "target_type in ('revision', 'release', 'content', 'directory')"
}

def directory_converter(db: BaseDb, directory_d: Dict[str, Any]) -> Directory:
    """Convert directory from the flat representation to swh model
    compatible objects.

    """
    columns = ["target", "name", "perms"]
    query_template = """
    select %(columns)s
    from directory_entry_%(type)s
    where id in %%s
    """

    types = ["file", "dir", "rev"]

    entries = []
    with db.cursor() as cur:
        for type in types:
            ids = directory_d.pop("%s_entries" % type)
            if not ids:
                continue
            query = query_template % {
                "columns": ",".join(columns),
                "type": type,
            }
            cur.execute(query, (tuple(ids),))
            for row in cur:
                entry_d = dict(zip(columns, row))
                entry = DirectoryEntry(
                    name=entry_d["name"],
                    type=type,
                    target=entry_d["target"],
                    perms=entry_d["perms"],
                )
                entries.append(entry)

    (is_corrupt, dir_) = Directory.from_possibly_duplicated_entries(
        id=directory_d["id"],
        entries=tuple(entries),
        raw_manifest=directory_d["raw_manifest"],
    )
    if is_corrupt:
        logger.info("%s has duplicated entries", dir_.swhid())

    return dir_

def raw_extrinsic_metadata_converter(
    db: BaseDb, metadata: Dict[str, Any]
) -> RawExtrinsicMetadata:
    """Convert a raw extrinsic metadata from the flat representation to swh model
    compatible objects.

    """
    return db_to_raw_extrinsic_metadata(metadata)

def extid_converter(db: BaseDb, extid: Dict[str, Any]) -> ExtID:
    """Convert an extid from the flat representation to swh model
    compatible objects.

    """
    return db_to_extid(extid)

def revision_converter(db: BaseDb, revision_d: Dict[str, Any]) -> Revision:
    """Convert revision from the flat representation to swh model
    compatible objects.

    """
    revision = db_to_revision(revision_d)
    assert revision is not None, revision_d["id"]
    return revision

def release_converter(db: BaseDb, release_d: Dict[str, Any]) -> Release:
    """Convert release from the flat representation to swh model
    compatible objects.

    """
    release = db_to_release(release_d)
    assert release is not None, release_d["id"]
    return release

def snapshot_converter(db: BaseDb, snapshot_d: Dict[str, Any]) -> Snapshot:
    """Convert snapshot from the flat representation to swh model
    compatible objects.

    """
    columns = ["name", "target", "target_type"]
    query = """
    select %s
    from snapshot_branches sbs
    inner join snapshot_branch sb on sb.object_id=sbs.branch_id
    where sbs.snapshot_id=%%s
    """ % ", ".join(
        columns
    )
    with db.cursor() as cur:
        cur.execute(query, (snapshot_d["object_id"],))
        branches = {}
        for name, *row in cur:
            branch_d = dict(zip(columns[1:], row))
            if branch_d["target"] is not None and branch_d["target_type"] is not None:
                branch: Optional[SnapshotBranch] = SnapshotBranch(
                    target=branch_d["target"],
                    target_type=TargetType(branch_d["target_type"]),
                )
            else:
                branch = None
            branches[name] = branch

    return Snapshot(
        id=snapshot_d["id"],
        branches=branches,
    )

CONVERTERS: Dict[str, Callable[[BaseDb, Dict[str, Any]], BaseModel]] = {
    "directory": directory_converter,
    "extid": extid_converter,
    "raw_extrinsic_metadata": raw_extrinsic_metadata_converter,
    "revision": revision_converter,
    "release": release_converter,
    "snapshot": snapshot_converter,
}

def object_to_offset(object_id, numbits):
    """Compute the index of the range containing object id, when dividing
       space into 2^numbits.

    Args:
        object_id (str): The hex representation of object_id
        numbits (int): Number of bits in which we divide input space

    Returns:
        The index of the range containing object id

    """
    q, r = divmod(numbits, 8)
    length = q + (r != 0)
    shift_bits = 8 - r if r else 0

    truncated_id = object_id[: length * 2]
    if len(truncated_id) < length * 2:
        truncated_id += "0" * (length * 2 - len(truncated_id))

    truncated_id_bytes = bytes.fromhex(truncated_id)
    return int.from_bytes(truncated_id_bytes, byteorder="big") >> shift_bits

def byte_ranges(
    numbits: int, start_object: Optional[str] = None, end_object: Optional[str] = None
) -> Iterator[Tuple[Optional[bytes], Optional[bytes]]]:
    """Generate start/end pairs of bytes spanning numbits bits and
       constrained by optional start_object and end_object.

    Args:
        numbits: Number of bits in which we divide input space
        start_object: Hex object id contained in the first range
                            returned
        end_object: Hex object id contained in the last range
                          returned

    Yields:
        2^numbits pairs of bytes

    """
    q, r = divmod(numbits, 8)
    length = q + (r != 0)
    shift_bits = 8 - r if r else 0

    def to_bytes(i):
        return int.to_bytes(i << shift_bits, length=length, byteorder="big")

    start_offset = 0
    end_offset = 1 << numbits

    if start_object is not None:
        start_offset = object_to_offset(start_object, numbits)
    if end_object is not None:
        end_offset = object_to_offset(end_object, numbits) + 1

    for start in range(start_offset, end_offset):
        end = start + 1

        if start == 0:
            yield None, to_bytes(end)
        elif end == 1 << numbits:
            yield to_bytes(start), None
        else:
            yield to_bytes(start), to_bytes(end)

def raw_extrinsic_metadata_target_ranges(
    start_object: Optional[str] = None, end_object: Optional[str] = None
) -> Iterator[Tuple[Optional[str], Optional[str]]]:
    """Generate ranges of values for the `target` attribute of `raw_extrinsic_metadata`
    objects.

    This generates one range for all values before the first SWHID (which would
    correspond to raw origin URLs), then a number of hex-based ranges for each
    known type of SWHID (2**12 ranges for directories, 2**8 ranges for all other
    types). Finally, it generates one extra range for values above all possible
    SWHIDs.
    """
    if start_object is None:
        start_object = ""

    swhid_target_types = sorted(type.value for type in ExtendedObjectType)

    first_swhid = f"swh:1:{swhid_target_types[0]}:"

    # Generate a range for url targets, if the starting object is before SWHIDs
    if start_object < first_swhid:
        yield start_object, (
            first_swhid
            if end_object is None or end_object >= first_swhid
            else end_object
        )

    if end_object is not None and end_object <= first_swhid:
        return

    # Prime the following loop, which uses the upper bound of the previous range
    # as lower bound, to account for potential targets between two valid types
    # of SWHIDs (even though they would eventually be rejected by the
    # RawExtrinsicMetadata parser, they /might/ exist...)
    end_swhid = first_swhid

    # Generate ranges for swhid targets
    for target_type in swhid_target_types:
        finished = False
        base_swhid = f"swh:1:{target_type}:"
        last_swhid = base_swhid + ("f" * 40)

        if start_object > last_swhid:
            continue

        # Generate 2**8 or 2**12 ranges
        for _, end in byte_ranges(12 if target_type == "dir" else 8):
            # Reuse previous upper bound
            start_swhid = end_swhid

            # Use last_swhid for this object type if on the last byte range
            end_swhid = (base_swhid + end.hex()) if end is not None else last_swhid

            # Ignore out of bounds ranges
            if start_object >= end_swhid:
                continue

            # Potentially clamp start of range to the first object requested
            start_swhid = max(start_swhid, start_object)

            # Handle ending the loop early if the last requested object id is in
            # the current range
            if end_object is not None and end_swhid >= end_object:
                end_swhid = end_object
                finished = True

            yield start_swhid, end_swhid

            if finished:
                return

    # Generate one final range for potential raw origin URLs after the last
    # valid SWHID
    start_swhid = max(start_object, end_swhid)
    yield start_swhid, end_object

def integer_ranges(
    start: str, end: str, block_size: int = 1000
) -> Iterator[Tuple[Optional[int], Optional[int]]]:
    for range_start in range(int(start), int(end), block_size):
        if range_start == 0:
            yield None, block_size
        elif range_start + block_size > int(end):
            yield range_start, int(end)
        else:
            yield range_start, range_start + block_size

RANGE_GENERATORS: Dict[
    str,
    Union[
        Callable[[str, str], Iterable[Tuple[Optional[str], Optional[str]]]],
        Callable[[str, str], Iterable[Tuple[Optional[bytes], Optional[bytes]]]],
        Callable[[str, str], Iterable[Tuple[Optional[int], Optional[int]]]],
    ],
] = {
    "content": lambda start, end: byte_ranges(24, start, end),
    "skipped_content": lambda start, end: [(None, None)],
    "directory": lambda start, end: byte_ranges(24, start, end),
    "extid": lambda start, end: byte_ranges(24, start, end),
    "revision": lambda start, end: byte_ranges(24, start, end),
    "release": lambda start, end: byte_ranges(16, start, end),
    "raw_extrinsic_metadata": raw_extrinsic_metadata_target_ranges,
    "snapshot": lambda start, end: byte_ranges(16, start, end),
    "origin": integer_ranges,
    "origin_visit": integer_ranges,
    "origin_visit_status": integer_ranges,
}

def compute_query(obj_type, start, end):
    columns = COLUMNS.get(obj_type)
    join_specs = JOINS.get(obj_type, [])
    join_clause = "\n".join("left join %s" % clause for clause in join_specs)
    additional_where = EXTRA_WHERE.get(obj_type)

    where = []
    where_args = []
    if start:
        where.append("%(keys)s >= %%s")
        where_args.append(start)
    if end:
        where.append("%(keys)s < %%s")
        where_args.append(end)

    if additional_where:
        where.append(additional_where)

    where_clause = ""
    if where:
        where_clause = ("where " + " and ".join(where)) % {
            "keys": "(%s)" % PARTITION_KEY[obj_type]
        }

    column_specs = []
    column_aliases = []
    for column in columns:
        if isinstance(column, str):
            column_specs.append(column)
            column_aliases.append(column)
        else:
            column_specs.append("%s as %s" % column)
            column_aliases.append(column[1])

    query = """
select %(columns)s
from %(table)s
%(join)s
%(where)s
    """ % {
        "columns": ",".join(column_specs),
        "table": obj_type,
        "join": join_clause,
        "where": where_clause,
    }

    return query, where_args, column_aliases

def fetch(db, obj_type, start, end):
    """Fetch all obj_type's identifiers from db.

    This opens one connection, stream objects and when done, close
    the connection.

    Args:
        db (BaseDb): Db connection object
        obj_type (str): Object type
        start (Union[bytes|Tuple]): Range start identifier
        end (Union[bytes|Tuple]): Range end identifier

    Raises:
        ValueError if obj_type is not supported

    Yields:
        Objects in the given range

    """
    query, where_args, column_aliases = compute_query(obj_type, start, end)
    converter = CONVERTERS.get(obj_type)
    with db.cursor() as cursor:
        logger.debug("Fetching data for table %s", obj_type)
        logger.debug("query: %s %s", query, where_args)
        cursor.execute(query, where_args)
        for row in cursor:
            record = dict(zip(column_aliases, row))
            if converter:
                record = converter(db, record)
            else:
                record = OBJECT_CONVERTERS[obj_type](record)

            logger.debug("record: %s", record)
            yield record

def _format_range_bound(bound):
    if isinstance(bound, bytes):
        return bound.hex()
    else:
        return str(bound)

MANDATORY_KEYS = ["storage", "journal_writer"]

class JournalBackfiller:
    """Class in charge of reading the storage's objects and sends those
    back to the journal's topics.

    This is designed to be run periodically.

    """

    def __init__(self, config=None):
        self.config = config
        self.check_config(config)
        self._db = None
        self.writer = JournalWriter({"cls": "kafka", **self.config["journal_writer"]})
        assert self.writer.journal is not None

    @property
    def db(self):
        if self._db is None:
            self._db = BaseDb.connect(self.config["storage"]["db"])
        return self._db

    def check_config(self, config):
        missing_keys = []
        for key in MANDATORY_KEYS:
            if not config.get(key):
                missing_keys.append(key)

        if missing_keys:
            raise ValueError(
                "Configuration error: The following keys must be"
                " provided: %s" % (",".join(missing_keys),)
            )

        if "cls" not in config["storage"] or config["storage"]["cls"] not in (
            "local",
            "postgresql",
        ):
            raise ValueError(
                "swh storage backfiller must be configured to use a local"
                " (PostgreSQL) storage"
            )

    def parse_arguments(self, object_type, start_object, end_object):
        """Parse arguments

        Raises:
            ValueError for unsupported object type
            ValueError if object ids are not parseable

        Returns:
            Parsed start and end object ids

        """
        if object_type not in COLUMNS:
            raise ValueError(
                "Object type %s is not supported. "
                "The only possible values are %s"
                % (object_type, ", ".join(sorted(COLUMNS.keys())))
            )

        if object_type in ["origin", "origin_visit", "origin_visit_status"]:
            start_object = start_object or "0"
            end_object = end_object or str(100_000_000)  # hard-coded limit

        return start_object, end_object

    def run(self, object_type, start_object, end_object, dry_run=False):
        """Reads storage's subscribed object types and send them to the
        journal's reading topic.

        """
        start_object, end_object = self.parse_arguments(
            object_type, start_object, end_object
        )

        for range_start, range_end in RANGE_GENERATORS[object_type](
            start_object, end_object
        ):
            logger.info(
                "Processing %s range %s to %s",
                object_type,
                _format_range_bound(range_start),
                _format_range_bound(range_end),
            )

            objects = fetch(self.db, object_type, start=range_start, end=range_end)

            if not dry_run:
                self.writer.write_additions(object_type, objects)
            else:
                # only consume the objects iterator to check for any potential
                # decoding/encoding errors
                for obj in objects:
                    pass

if __name__ == "__main__":
    print('Please use the "swh-journal backfiller run" command')


from collections import deque
import heapq

class TreeNode(object):
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution(object):
    def verticalTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        treequeue = deque()
        rowidx = 0
        colidx = 0
        treequeue.append((root, rowidx, colidx))
        vertical_tree = []

        # iterate through the tree, calculating coordinates
        while treequeue:
            node, rowidx, colidx = treequeue.pop()
            if node:
                heapq.heappush(vertical_tree, (colidx, rowidx, node.val))
                treequeue.append((node.left, rowidx+1, colidx-1))
                treequeue.append((node.right, rowidx+1, colidx+1))

        vertical_list = []
        mincol = vertical_tree[0][0]
        onelist = []
        while vertical_tree:
            if vertical_tree[0][0] == mincol:
                _, _, val = heapq.heappop(vertical_tree)
                onelist.append(val)
            else:
                mincol = vertical_tree[0][0]
                vertical_list.append(onelist)
                onelist = []
        if onelist:
            vertical_list.append(onelist) # append the last one

        return vertical_list

sol = Solution()
root = TreeNode(1, TreeNode(2, TreeNode(4, None, None), TreeNode(6, None, None)), TreeNode(3, TreeNode(5, None, None), TreeNode(7, None, None)))
result = sol.verticalTraversal(root)
if isinstance(result, TreeNode):
    result.prettyprint()
else:
    print(result)


from rest_framework import serializers

from .models import Departman,Personel

from django.utils.timezone import now

class DepartmanSerializer(serializers.ModelSerializer):
    count = serializers.SerializerMethodField()

    class Meta:
        model = Departman
        fields = (
            'id',
            'name',
            'count',

        )

    def get_count(self,giris):
        return giris.personel.count()

class PersonelSerializer(serializers.ModelSerializer):

    departman =serializers.StringRelatedField()
    departman_id=serializers.IntegerField()
    total = serializers.SerializerMethodField()

    class Meta :
        model =  Personel
        fields = (
            'id',
            'first_name',
            'last_name',
            'title',
            'gender',
            'salary',
            'departman',
            'departman_id',
            'start_date',
            'total'

        )
    def get_total(self,toplam):

        return (now()- toplam.start_date).days


# -*- coding: utf-8 -*-
import numpy as np
import os
import h5py
import logging

from data_exchange import DataExchangeFile, DataExchangeEntry

class Export():
    def __init__(xtomo, data=None, data_white=None,
                 data_dark=None, theta=None,
                 hdf5_file_name=None, data_exchange_type=None,
                 sample_name=None, logger=None, log='INFO'):

        #xtomo.data = data
        xtomo.data_white = data_white
        xtomo.data_dark = data_dark
        xtomo.theta = theta

        # Set the log level.
        xtomo.logger = None
        xtomo._log_level = str(log).upper()
        xtomo._init_logging()

    def xtomo_writer(data, output_file=None, x_start=0,
                     digits=5, axis=0, overwrite=False,
                     precision=True):
        """
        Write 3-D data to a stack of tif files.

        Parameters
        -----------
        output_file : str, optional
            Name of the output file.

        x_start : scalar, optional
            First index of the data on first dimension
            of the array.

        digits : scalar, optional
            Number of digits used for file indexing.
            For example if 4: test_XXXX.tiff

        axis : scalar, optional
            Imaages is read along that axis.

        overwrite: bool, optional
            if overwrite=True the existing data in the
            reconstruction folder will be overwritten

        precision : bool, optional
            Export data type precision. if True it
            saves 32-bit precision. Otherwise it
            uses 8-bit precision.

        Notes
        -----
        If file exists, saves it with a modified name.

        If output location is not specified, the data is
        saved inside ``recon`` folder where the input data
        resides. The name of the reconstructed files will
        be initialized with ``recon``

        Examples
        --------
        - Save sinogram data:

            >>> import tomopy
            >>>
            >>> # Load data
            >>> myfile = 'demo/data.h5'
            >>> data, white, dark, theta = tomopy.xtomo_reader(myfile)
            >>>
            >>> # Save data
            >>> output_file='tmp/slice_'
            >>> tomopy.xtomo_writer(data, output_file, axis=1)
            >>> print "Images are succesfully saved at " + output_file + '...'

        - Save first 16 projections:

            >>> import tomopy
            >>>
            >>> # Load data
            >>> myfile = 'demo/data.h5'
            >>> data, white, dark, theta = tomopy.xtomo_reader(myfile, projections_start=0, projections_end=16)
            >>>
            >>> # Save data
            >>> output_file='tmp/projection_'
            >>> tomopy.xtomo_writer(data, output_file, axis=0)
            >>> print "Images are succesfully saved at " + output_file + '...'

        - Save reconstructed slices:

            >>> import tomopy
            >>>
            >>> # Load data
            >>> myfile = 'demo/data.h5'
            >>> data, white, dark, theta = tomopy.xtomo_reader(myfile)
            >>>
            >>> # Perform reconstruction
            >>> d = tomopy.xtomo_dataset(log='error')
            >>> d.dataset(data, white, dark, theta)
            >>> d.center = 661.5
            >>> d.gridrec()
            >>>
            >>> # Save data
            >>> output_file='tmp/reconstruction_'
            >>> tomopy.xtomo_writer(d.data_recon, output_file, axis=0)
            >>> print "Images are succesfully saved at " + output_file + '...'
        """
        if output_file == None:
            output_file = "tmp/img_"
        output_file =  os.path.abspath(output_file)
        dir_path = os.path.dirname(output_file)

        # Remove TIFF extension if there is.
        if (output_file.endswith('tif') or
            output_file.endswith('tiff')) :
                output_file = output_file.split(".")[-2]

        if overwrite:
            if os.path.exists(dir_path):
                shutil.rmtree(dir_path)

        # Create new folders.
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)

        # Select desired x from whole data.
        num_x, num_y, num_z = data.shape
        if axis == 0:
            x_end = x_start+num_x
        elif axis == 1:
            x_end = x_start+num_y
        elif axis == 2:
            x_end = x_start+num_z

        # Write data.
        file_index = ["" for x in range(digits)]
        for m in range(digits):
            file_index[m] = '0' * (digits - m - 1)
        ind = range(x_start, x_end)
        for m in range(len(ind)):
            for n in range(digits):
                if ind[m] < np.power(10, n + 1):
                    file_body = output_file + file_index[n] + str(ind[m])
                    file_name = file_body + '.tif'
                    break
            if precision:
                if axis == 0:
                    img = misc.toimage(data[m, :, :], mode='F')
                elif axis == 1:
                    img = misc.toimage(data[:, m, :], mode='F')
                elif axis == 2:
                    img = misc.toimage(data[:, :, m], mode='F')
            else:
                if axis == 0:
                    img = misc.toimage(data[m, :, :])
                elif axis == 1:
                    img = misc.toimage(data[:, m, :])
                elif axis == 2:
                    img = misc.toimage(data[:, :, m])

            # check if file exists.
            if os.path.isfile(file_name):
                # genarate new file name.
                indq = 1
                FLAG_SAVE = False
                while not FLAG_SAVE:
                    new_file_body = file_body + '-' + str(indq)
                    new_file_name = new_file_body + '.tif'
                    if not os.path.isfile(new_file_name):
                        img.save(new_file_name)
                        FLAG_SAVE = True
                        file_name = new_file_name
                    else:
                        indq += 1
            else:
                img.save(file_name)

    def xtomo_exchange(xtomo, data, data_white=None, data_dark=None, theta=None, sample_name=None,
                       data_exchange_type=None,
                       hdf5_file_name=None,
                       log='INFO'
                       ):
        """
        Write 3-D data to a data-exchange file.

        Parameters
        ----------
        data : ndarray
            3-D X-ray absorption tomography raw data.
            Size of the dimensions should be:
            [projections, slices, pixels].

        data_white, data_dark : ndarray, optional
            3-D white-field/dark_field data. Multiple
            projections are stacked together to obtain
            a 3-D matrix. 2nd and 3rd dimensions should
            be the same as data: [shots, slices, pixels].

        theta : ndarray, optional
            Data acquisition angles corresponding
            to each projection.

        data_excahnge_type : str
            label defyining the type of data contained in data exchange file
            for raw data tomography data use 'tomography_raw_projections'

        hd5_file_name : str
            Output file.

        Notes
        -----
        If file exists, does nothing

        Examples
        --------
        - Convert tomographic projection series (raw, dark, white)  of tiff in data exchange:

            >>> from dataexchange import xtomo_importer as dx
            >>> from dataexchange import xtomo_exporter as ex

            >>> file_name = '/local/dataraid/databank/Anka/radios/image_.tif'
            >>> dark_file_name = '/local/dataraid/databank/Anka/darks/image_.tif'
            >>> white_file_name = '/local/dataraid/databank/Anka/flats/image_.tif'
            >>>
            >>> hdf5_file_name = '/local/dataraid/databank/dataExchange/microCT/xx_yy_Anka.h5'
            >>>
            >>> projections_start = 0
            >>> projections_end = 3167
            >>> white_start = 0
            >>> white_end = 100
            >>> dark_start = 0
            >>> dark_end = 100
            >>>
            >>> sample_name = 'Anka'
            >>>
            >>> mydata = dx.Import()
            >>> # Read series of images
            >>> data, white, dark, theta = mydata.series_of_images(file_name,
            >>>                                                    projections_start = projections_start,
            >>>                                                    projections_end = projections_end,
            >>>                                                    white_file_name = white_file_name,
            >>>                                                    white_start = white_start,
            >>>                                                    white_end = white_end,
            >>>                                                    dark_file_name = dark_file_name,
            >>>                                                    dark_start = dark_start,
            >>>                                                    dark_end = dark_end,
            >>>                                                    sample_name = sample_name,
            >>>                                                    projections_digits = 5,
            >>>                                                    log='INFO'
            >>>                                                    )
            >>>
            >>> mydata = ex.Export()
            >>> # Create minimal data exchange hdf5 file
            >>> mydata.xtomo_exchange(data = data,
            >>>                       data_white = white,
            >>>                       data_dark = dark,
            >>>                       theta = theta,
            >>>                       hdf5_file_name = hdf5_file_name,
            >>>                       data_exchange_type = 'tomography_raw_projections'
            >>>                       )

        """

        if (hdf5_file_name != None):
            if os.path.isfile(hdf5_file_name):
                xtomo.logger.info("Data Exchange file already exists: [%s]. Next time use the Data Exchange reader instead", hdf5_file_name)
            else:
                # Create new folder.
                dirPath = os.path.dirname(hdf5_file_name)
                if not os.path.exists(dirPath):
                    os.makedirs(dirPath)

                # Get the file_name in lower case.
                lFn = hdf5_file_name.lower()

                # Split the string with the delimeter '.'
                end = lFn.split('.')

                # Write the Data Exchange HDF5 file.
                # Open DataExchange file
                f = DataExchangeFile(hdf5_file_name, mode='w')

                xtomo.logger.info("Creating Data Exchange File [%s]", hdf5_file_name)

                # Create core HDF5 dataset in exchange group for projections_theta_range
                # deep stack of x,y images /exchange/data
                xtomo.logger.info("Adding projections to Data Exchange File [%s]", hdf5_file_name)
                f.add_entry( DataExchangeEntry.data(data={'value': data, 'units':'counts', 'description': 'transmission', 'axes':'theta:y:x', 'dataset_opts':  {'compression': 'gzip', 'compression_opts': 4} }))
                if (theta != None):
                    f.add_entry( DataExchangeEntry.data(theta={'value': theta, 'units':'degrees'}))
                    xtomo.logger.info("Adding theta to Data Exchange File [%s]", hdf5_file_name)
                if (data_dark != None):
                    xtomo.logger.info("Adding dark fields to  Data Exchange File [%s]", hdf5_file_name)
                    f.add_entry( DataExchangeEntry.data(data_dark={'value': data_dark, 'units':'counts', 'axes':'theta_dark:y:x', 'dataset_opts':  {'compression': 'gzip', 'compression_opts': 4} }))
                if (data_white != None):
                    xtomo.logger.info("Adding white fields to  Data Exchange File [%s]", hdf5_file_name)
                    f.add_entry( DataExchangeEntry.data(data_white={'value': data_white, 'units':'counts', 'axes':'theta_white:y:x', 'dataset_opts':  {'compression': 'gzip', 'compression_opts': 4} }))
                if (data_exchange_type != None):
                    xtomo.logger.info("Adding data type to  Data Exchange File [%s]", hdf5_file_name)
                    f.add_entry( DataExchangeEntry.data(title={'value': data_exchange_type}))
                if (sample_name == None):
                    sample_name = end[0]
                    f.add_entry( DataExchangeEntry.sample( name={'value':sample_name}, description={'value':'Sample name was assigned by the HDF5 converter and based on the HDF5 file name'}))
                else:
                    f.add_entry( DataExchangeEntry.sample( name={'value':sample_name}, description={'value':'Sample name was read from the user log file'}))
                f.close()
                xtomo.logger.info("DONE!!!!. Created Data Exchange File [%s]", hdf5_file_name)
        else:
            xtomo.logger.info("Nothing to do ...")

    def _init_logging(xtomo):
        """
        Setup and start command line logging.
        """
        # Top-level log setup.
        xtomo.logger = logging.getLogger("data exchange")
        if xtomo._log_level == 'DEBUG':
            xtomo.logger.setLevel(logging.DEBUG)
        elif xtomo._log_level == 'INFO':
            xtomo.logger.setLevel(logging.INFO)
        elif xtomo._log_level == 'WARN':
            xtomo.logger.setLevel(logging.WARN)
        elif xtomo._log_level == 'WARNING':
            xtomo.logger.setLevel(logging.WARNING)
        elif xtomo._log_level == 'ERROR':
            xtomo.logger.setLevel(logging.ERROR)

        # Terminal stream log.
        ch = logging.StreamHandler()
        if xtomo._log_level == 'DEBUG':
            ch.setLevel(logging.DEBUG)
        elif xtomo._log_level == 'INFO':
            ch.setLevel(logging.INFO)
        elif xtomo._log_level == 'WARN':
            ch.setLevel(logging.WARN)
        elif xtomo._log_level == 'WARNING':
            ch.setLevel(logging.WARNING)
        elif xtomo._log_level == 'ERROR':
            ch.setLevel(logging.ERROR)

        # Show date and time.
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        ch.setFormatter(formatter)

        # Update logger.
        if not len(xtomo.logger.handlers): # For fist time create handlers.
            xtomo.logger.addHandler(ch)


import os
import logging
import gzip

from psycopg2 import sql

from django.core.management.base import BaseCommand
from django.db import connection

from oac_search import models, pubmed

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

class Command(BaseCommand):
    help = 'Search and export full text OAC articles from the database (no on-the-fly XML extraction!)'

    def add_arguments(self, parser):
        parser.add_argument('queryfile', help="query file")

    def handle(self, *args, **options):
        queryfile = options['queryfile']
        path = os.path.split(os.path.abspath(queryfile))[0]
        query = open(queryfile).read().replace('\n', ' ').strip()

        idfile = os.path.join(path, queryfile + '.pmcids')
        fullfile = os.path.join(path, queryfile + '.fulltext.gz')

        a = pubmed.NCBI_search()
        pmcids = a.query(query, db='pmc', onlyOAC=True)
        pmcids = ['PMC' + x for x in pmcids]
        with open(idfile, 'w') as ofp:
            ofp.write('\n'.join(pmcids))

        logging.info('Total PMC IDs: {}; present in DB: {}'.format(len(pmcids), models.Article.objects.filter(pmcid__in=pmcids).count()))
        with gzip.open(fullfile, 'wt', encoding='utf8') as ofp:

            with connection.cursor() as cursor:
                cursor.execute('''DROP TABLE IF EXISTS _result_pmcids_''')
                cursor.execute('''CREATE TABLE _result_pmcids_ (
                                        id serial primary key,
                                        pmcid varchar(20) unique not null)''')
                connection.commit()
                with open(idfile) as fp:
                    cursor.copy_from(fp, '_result_pmcids_', columns=('pmcid',))
                connection.commit()
                cursor.execute('''SELECT oac_search_article.pmcid, oac_search_article.text
                                  FROM oac_search_article
                                  INNER JOIN _result_pmcids_ ON oac_search_article.pmcid = _result_pmcids_.pmcid''')
                for pmcid, text in cursor:
                    ofp.write('{}\t{}\n'.format(pmcid, text))
                cursor.execute('''DROP TABLE IF EXISTS _result_pmcids_''')
        logging.info('Export complete.')


import csv
import io
import json
import os.path
import pickle

from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']

FINANCE_SPREADSHEET_ID = os.getenv("FINANCE_SPREADSHEET_ID")
TEMPLATE_SHEET_ID = os.getenv("TEMPLATE_SHEET_ID")

def get_google_creds():
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)

    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_console()
        # Save the credentials for the next run
        # cloud functions have a read-only fs so just refresh the token every time
        # with open('token.pickle', 'wb') as token:
        #     pickle.dump(creds, token)

    return creds

def sheet_exists(service, name):
    try:
        service.spreadsheets().get(
                spreadsheetId=FINANCE_SPREADSHEET_ID,
                ranges=[name],
        ).execute()
        return True
    except HttpError as e:
        parsed = json.loads(e.content)
        if parsed['error']['status'] != 'INVALID_ARGUMENT':
            raise
    return False

def create_sheet(service, name):
    new_sheet = service.spreadsheets().sheets().copyTo(
            spreadsheetId=FINANCE_SPREADSHEET_ID,
            sheetId=TEMPLATE_SHEET_ID,
            body={
                "destinationSpreadsheetId": FINANCE_SPREADSHEET_ID,
            },
    ).execute()
    new_sheet_id = new_sheet['sheetId']
    service.spreadsheets().batchUpdate(
            spreadsheetId=FINANCE_SPREADSHEET_ID,
            body={
                "requests": [{
                    "updateSheetProperties": {
                        "fields": "title",
                        "properties": {
                            "sheetId": new_sheet_id,
                            "title": name,
                        },
                    }
                }],
            },
    ).execute()

def add_transaction_to_sheet(service, account, date, name, amount, categories):
    # convert categories to csv
    categories_buffer = io.StringIO()
    categories_writer = csv.writer(categories_buffer)
    categories_writer.writerow(categories)
    categories_str = categories_buffer.getvalue().rstrip()

    values = [
        date,
        name,
        amount,  # real amount
        categories_str,  # real categories
        amount,  # effective amount
        categories[-1] if len(categories) > 0 else '',  # effective category
        'No',  # ack
    ]

    body = {
        'values': [values],
    }

    service.spreadsheets().values().append(
        spreadsheetId=FINANCE_SPREADSHEET_ID, range=account,
        valueInputOption='USER_ENTERED', body=body).execute()

def process_transaction(request):
    body = request.get_json()
    account = body['transaction']['accountName']
    date = body['transaction']['date']
    name = body['transaction']['name']
    amount = body['transaction']['amount']
    categories = body['transaction']['category']

    creds = get_google_creds()
    service = build('sheets', 'v4', credentials=creds, cache_discovery=False)
    if not sheet_exists(service, account):
        create_sheet(service, account)
    add_transaction_to_sheet(service, account, date, name, amount, categories)


from pynput import keyboard
from score_following_game.agents.optimal_agent import OptimalAgent

human_action = 1

def on_press(key):
    global human_action

    if key == keyboard.Key.left:
        human_action = 0

    if key == keyboard.Key.right:
        human_action = 2

class HumanAgent(OptimalAgent):

    def __init__(self, rl_pool):
        super(HumanAgent, self).__init__(rl_pool)
        keyboard.Listener(on_press=on_press).start()

    def select_action(self, state, train=False):
        global human_action

        action = human_action
        human_action = 1
        return action


import random
from datetime import datetime

import pytest
from june import paths
from june.activity import activity_hierarchy
from june.epidemiology.epidemiology import Epidemiology
from june.epidemiology.infection import Immunity, InfectionSelector, InfectionSelectors
from june.groups.leisure import leisure
from june.groups.travel import Travel
from june.interaction import Interaction
from june.policy import Hospitalisation, MedicalCarePolicies, Policies
from june.simulator import Simulator

from camps.activity import CampActivityManager
from camps.paths import camp_data_path, camp_configs_path
from camps.world import World
from camps.groups.leisure import generate_leisure_for_world, generate_leisure_for_config
from camps.camp_creation import (
    generate_empty_world,
    populate_world,
    distribute_people_to_households,
)  # this is loaded from the ../camp_scripts folder

config_file_path = camp_configs_path / "config_demo.yaml"
interactions_file_path = camp_configs_path / "defaults/interaction/interaction_Survey.yaml"

def test__everyone_has_an_activity(camps_sim):
    for person in camps_sim.world.people.members:
        assert person.subgroups.iter().count(None) != len(person.subgroups.iter())

def test__apply_activity_hierarchy(camps_sim):
    unordered_activities = random.sample(activity_hierarchy, len(activity_hierarchy))
    ordered_activities = camps_sim.activity_manager.apply_activity_hierarchy(
        unordered_activities
    )
    assert ordered_activities == activity_hierarchy

def test__clear_world(camps_sim: Simulator):
    camps_sim.clear_world()
    for group_name in camps_sim.activity_manager.activities_to_super_groups(
        camps_sim.activity_manager.all_activities
    ):
        if group_name in ["shelter_visits"]:
            continue
        grouptype = getattr(camps_sim.world, group_name)
        for group in grouptype.members:
            for subgroup in group.subgroups:
                assert len(subgroup.people) == 0

    for person in camps_sim.world.people.members:
        assert person.busy is False

def test__move_to_active_subgroup(camps_sim: Simulator):
    camps_sim.activity_manager.move_to_active_subgroup(
        ["residence"], camps_sim.world.people.members[0]
    )
    assert camps_sim.world.people.members[0].residence.group.spec in ("shelter")

def test__move_people_to_leisure(camps_sim: Simulator):
    n_leisure = 0
    n_pump_latrines = 0
    n_e_vouchers = 0
    n_distributions = 0
    n_informal_works = 0
    n_n_f_distribution_centers = 0
    n_play_groups = 0
    n_religiouss = 0
    n_communals = 0
    n_female_communals = 0
    repetitions = 100

    camps_sim.activity_manager.leisure.generate_leisure_probabilities_for_timestep(
        delta_time=3,
        working_hours=False,
        date=datetime.strptime("2020-03-01-12", "%Y-%m-%d-%H"),
    )

    for _ in range(repetitions):
        camps_sim.clear_world()
        camps_sim.activity_manager.move_people_to_active_subgroups(["leisure", "residence"])
        for person in camps_sim.world.people.members:
            if person.leisure is not None:
                n_leisure += 1
                if person.leisure.group.spec == "pump_latrine":
                    n_pump_latrines += 1
                elif person.leisure.group.spec == "e_voucher":
                    n_e_vouchers += 1
                elif person.leisure.group.spec == "distribution_center":
                    n_distributions += 1
                elif person.leisure.group.spec == "informal_work":
                    n_informal_works += 1
                elif person.leisure.group.spec == "n_f_distribution_center":
                    n_n_f_distribution_centers += 1
                elif person.leisure.group.spec == "play_group":
                    n_play_groups += 1
                elif person.leisure.group.spec == "religious":
                    n_religiouss += 1
                elif person.leisure.group.spec == "communal":
                    n_communals += 1
                elif person.leisure.group.spec == "female_communal":
                    n_female_communals += 1
                if person not in person.residence.people:
                    assert person in person.leisure.people
    assert n_leisure > 0
    assert n_pump_latrines > 0
    assert n_e_vouchers > 0
    assert n_distributions > 0
    assert n_informal_works > 0
    assert n_n_f_distribution_centers > 0
    assert n_play_groups > 0
    assert n_religiouss > 0
    assert n_communals > 0
    assert n_female_communals > 0
    camps_sim.clear_world()

def test__venues_closed_outside_hours(camps_sim: Simulator):
    n_leisure = 0
    n_communals = 0
    n_female_communals = 0
    repetitions = 10

    camps_sim.activity_manager.leisure.generate_leisure_probabilities_for_timestep(
        delta_time=3,
        working_hours=False,
        date=datetime.strptime("2020-03-01-01", "%Y-%m-%d-%H"),
    )

    for _ in range(repetitions):
        camps_sim.clear_world()
        camps_sim.activity_manager.move_people_to_active_subgroups(["leisure", "residence"])
        for person in camps_sim.world.people.members:
            if person.leisure is not None:
                n_leisure += 1
                if person.leisure.group.spec == "communal":
                    n_communals += 1
                elif person.leisure.group.spec == "female_communal":
                    n_female_communals += 1
                if person not in person.residence.people:
                    assert person in person.leisure.people

    assert n_communals == 0
    assert n_female_communals == 0
    camps_sim.clear_world()

def test__bury_the_dead(camps_sim: Simulator):
    dummy_person = camps_sim.world.people.members[0]
    camps_sim.epidemiology.infection_selectors.infect_person_at_time(dummy_person, 0.0)
    camps_sim.epidemiology.bury_the_dead(camps_sim.world, dummy_person)
    assert dummy_person in camps_sim.world.cemeteries.members[0].people
    assert dummy_person.dead
    assert dummy_person.infection is None


from django.urls import path
from .views import cart_detail,cart_add,cart_remove

app_name='shopping'

urlpatterns = [
    path('<int:cart_id>/',cart_detail,name='cart_detail'),
    path('add/<int:product_id>/', cart_add, name='cart_add'),
    path('remove/<int:product_id>/', cart_remove, name='cart_remove'),
]


import argparse
import trimesh
import numpy as np
import json
from math import *
import math
import requests
import geopandas as gpd
from shapely import Polygon

#TODO args better
ap = argparse.ArgumentParser()
ap.add_argument("--method", help="method of gps", type=str)
ap.add_argument("--GPSFile", help="GPSFile", type=str)
ap.add_argument("--latInputPoint", help="latitudeCustom", type=float)
ap.add_argument("--lonInputPoint", help="longitudeCustom", type=float)
ap.add_argument("--geoJson", help="output GeoJson", type=str)
ap.add_argument("--outputObj", help="output obj", type=str)
args = ap.parse_args()

#what method of localisation
if args.method == "auto":
    # Opening JSON file
    with open(args.GPSFile, 'r') as inputfile:
        # Reading from json file
        json_object = json.load(inputfile)

    latitude = json_object["latitude"]
    longitude = json_object["longitude"]

    location=(latitude, longitude)
else:
    location = (args.latitudeCustom, args.longitudeCustom)

#conversion of the longitude and latitude into tiles
def deg2num(lat_deg, lon_deg, zoom):
  lat_rad = math.radians(lat_deg)
  n = 2.0 ** zoom
  xtile = int((lon_deg + 180.0) / 360.0 * n)
  ytile = int((1.0 - math.asinh(math.tan(lat_rad)) / math.pi) / 2.0 * n)
  return (xtile, ytile)

lat_rad, lon_deg = location[0], location[1]
zoom = 15
xtile, ytile = deg2num(lat_deg=lat_rad, lon_deg=lon_deg, zoom=zoom)

#request on OSM Buildings
url = "https://data.osmbuildings.org/0.2/anonymous/tile/{0}/{1}/{2}.json".format(zoom, xtile, ytile)
agentheader = {'User-Agent': 'PostmanRuntime/7.28.4'}

response = requests.get(url,headers = agentheader)

data = json.loads(response.text)

#export the GeoJSON
with open(args.geoJson, 'w') as f:
  json.dump(data, f)

#get the polygons and heights in the GeoJSON
gdf = gpd.read_file(args.geoJson)

buildings_geojson = []
heights_geojson = []

for polygon in gdf[gdf.geometry.type == "Polygon"].geometry:
    buildings_geojson.append(Polygon(polygon.exterior.coords))

for height in gdf.height:
    heights_geojson.append(height)

#convert the coordinates for the mesh
factor = 1000
min_heights = min(heights_geojson)
max_heights = max(heights_geojson)

buildings_mesh = []
heights_2 = []

max_x, max_y = 0, 0
for i in range(len(buildings_geojson)):
    if max(buildings_geojson[i].exterior.coords.xy[0]) > max_x:
        max_x = max(buildings_geojson[i].exterior.coords.xy[0])
    if max(buildings_geojson[i].exterior.coords.xy[1]) > max_y:
        max_y = max(buildings_geojson[i].exterior.coords.xy[1])

for i in range(len(buildings_geojson)):
    tab = []
    for x, y in buildings_geojson[i].exterior.coords:
        x = x - max_x
        y = y - max_y
        x = x * factor
        y = y * factor
        x = round(x, 3)
        y = round(y, 3)
        tab.append((x, y))
    buildings_mesh.append(Polygon(tab))

for i in range(len(heights_geojson)):
    h = heights_geojson[i] / max_heights
    heights_2.append(h)

#convert camera position the same way
position_x = location[1]
position_x -= max_x
position_x *= factor
position_x = round(position_x, 3)

position_y = location[0]
position_y -= max_y
position_y *= factor
position_y = round(position_y, 3)

#add all mesh to a scene
scene = trimesh.Scene()

for i in range(len(buildings_mesh)):
    mesh = trimesh.creation.extrude_polygon(buildings_mesh[i], heights_2[i])

    #relocate the mesh to align to the camera position
    mesh.apply_transform(trimesh.transformations.rotation_matrix(np.deg2rad(90), [1, 0, 0]))
    mesh.apply_transform(trimesh.transformations.rotation_matrix(np.deg2rad(180), [0, 0, 1]))
    mesh.apply_transform(trimesh.transformations.rotation_matrix(np.deg2rad(180), [0, 1, 0]))
    mesh.apply_transform(trimesh.transformations.translation_matrix([-position_x, 0, position_y]))
    mesh.apply_transform(trimesh.transformations.scale_matrix(2))
    scene.add_geometry(mesh)

#export the Obj
with open(args.outputObj, 'w') as file:
    scene.export(
        file,
        file_type='obj',
    )

  #TODO si on est sur un bord de map, récupérer les maps autour, faire un paramètre