Beispiel #1
0
    def __init__(self):
        """
        Load up the necessary sub-structures to be filled with
        the code that follows
        """
        self.Compressor = CompressorClass()

        #Outdoor coil is a Condenser in cooling mode and evaporator in heating mode
        self.Condenser = CondenserClass()
        self.Condenser.Fins = FinInputs()
        self.Evaporator = EvaporatorClass()
        self.Evaporator.Fins = FinInputs()

        self.CoolingCoil = CoolingCoilClass()
        self.CoolingCoil.Fins = FinInputs()
        self.Pump = PumpClass()
        #Add both types of internal heat exchangers
        self.CoaxialIHX = CoaxialHXClass()
        self.PHEIHX = PHEHXClass()
        self.LineSetSupply = LineSetClass()
        self.LineSetReturn = LineSetClass()

        #Make IHX an empty class for holding parameters common to PHE and Coaxial IHX
        class struct:
            pass

        self.IHX = struct()
Beispiel #2
0
 def __init__(self):
     """
     Load up the necessary sub-structures to be filled with
     the code that follows
     """
     self.Compressor=CompressorClass()
     self.Condenser=CondenserClass()
     self.Condenser.Fins=FinInputs()
     self.Evaporator=EvaporatorClass()
     self.Evaporator.Fins=FinInputs()
     self.LineSetSupply=LineSetClass()
     self.LineSetReturn=LineSetClass()
 def __init__(self):
     """
     Load up the necessary sub-structures to be filled with
     the code that follows
     """
     self.Evaporator = PHEHXClass()
     self.Expander = ExpanderClass()
     self.Regenerator = PHEHXClass()
     self.Condenser = PHEHXClass()
     self.Pump = PumpCentrifugalClass()
     self.LiquidReceiver = LiquidReceiverClass()
     self.LineSetPumpEx = LineSetClass()
     self.LineSetPumpSu = LineSetClass()
     self.LineSetExpSu = LineSetClass()
     self.LineSetExpEx = LineSetClass()
     self.LineSetCondEx = LineSetClass()
Beispiel #4
0
class DXCycleClass():
    def __init__(self):
        """
        Load up the necessary sub-structures to be filled with
        the code that follows
        """
        self.Compressor=CompressorClass()
        self.Condenser=CondenserClass()
        self.Condenser.Fins=FinInputs()
        self.Evaporator=EvaporatorClass()
        self.Evaporator.Fins=FinInputs()
        self.LineSetSupply=LineSetClass()
        self.LineSetReturn=LineSetClass()
    def OutputList(self):
        """
            Return a list of parameters for this component for further output
            
            It is a list of tuples, and each tuple is formed of items:
                [0] Description of value
                [1] Units of value
                [2] The value itself
        """
        Output_List=[]
        #append optional parameters, if applicable
        if hasattr(self,'TestName'):
            Output_List.append(('Name','N/A',self.TestName)) 
        if hasattr(self,'TestDescription'):
            Output_List.append(('Description','N/A',self.TestDescription))
        if hasattr(self,'TestDetails'):
            Output_List.append(('Details','N/A',self.TestDetails))
        Output_List_default=[                                                                       #default output list
            ('Charge','kg',self.Charge),
            ('Condensation temp (dew)','K',self.Tdew_cond),
            ('Evaporation temp (dew)','K',self.Tdew_evap),
            ('Condenser Subcooling','K',self.DT_sc),
            ('Primary Ref.','-',self.Ref),
            ('COP','-',self.COP),
            ('COSP','-',self.COSP),
            ('Net Capacity','W',self.Capacity),
            ('Net Power','W',self.Power),
            ('SHR','-',self.SHR),
            ('Imposed Variable','-',self.ImposedVariable),
         ]
        for i in range(0,len(Output_List_default)):                             #append default parameters to output list
            Output_List.append(Output_List_default[i])
        return Output_List

    def Calculate(self,DT_evap,DT_cond):
        """
        Inputs are differences in temperature [K] between HX air inlet temperature 
        and the dew temperature for the heat exchanger.
        
        Required Inputs:
            DT_evap: 
                Difference in temperature [K] between evaporator air inlet temperature and refrigerant dew temperature
            DT_cond:
                Difference in temperature [K] between condenser air inlet temperature and refrigeant dew temperature 
        """
        if self.Verbosity>1:
            print 'DTevap %7.4f DTcond %7.4f,' %(DT_evap,DT_cond)
        Tdew_cond=self.Condenser.Fins.Air.Tdb+DT_cond#the values (Tin_a,..) come from line 128ff
        Tdew_evap=self.Evaporator.Fins.Air.Tdb-DT_evap
        psat_cond=Props('P','T',Tdew_cond,'Q',1,self.Ref)
        psat_evap=Props('P','T',Tdew_evap,'Q',1,self.Ref)
        Tbubble_evap=Props('T','P',psat_evap,'Q',0,self.Ref)
        
        self.Tdew_cond=Tdew_cond
        self.Tdew_evap=Tdew_evap
        
        #If the user doesn't include the Mode, fail
        assert hasattr(self,'Mode')
        
        if self.Mode=='AC':
            if not hasattr(self.Compressor,'mdot_r') or self.Compressor.mdot_r<0.00001:
                # The first run of model, run the compressor just so you can get a preliminary value 
                # for the mass flow rate for the line set 
                params={               #dictionary -> key:value, e.g. 'key':2345,
                    'pin_r': psat_evap,   
                    'pout_r': psat_cond,
                    'Tin_r': Tdew_evap+self.Evaporator.DT_sh,
                    'Ref':  self.Ref
                }
                self.Compressor.Update(**params)
                self.Compressor.Calculate()
            
            params={
                'pin': psat_evap,
                'hin': Props('H','T',Tdew_evap+self.Evaporator.DT_sh,'P',psat_evap,self.Ref)*1000,
                'mdot': self.Compressor.mdot_r,
                'Ref':  self.Ref
            }
            self.LineSetReturn.Update(**params)
            self.LineSetReturn.Calculate()
            
            params={               #dictionary -> key:value, e.g. 'key':2345,
                'pin_r': psat_evap-self.DP_low,   
                'pout_r': psat_cond+self.DP_high,
                'Tin_r': TrhoPhase_ph(self.Ref,psat_evap,self.LineSetReturn.hout,Tbubble_evap,Tdew_evap)[0],
                'Ref':  self.Ref
            }
            self.Compressor.Update(**params)
            self.Compressor.Calculate()
            if self.Verbosity>1:
                print 'Comp DP H L',self.DP_low,self.DP_high
            
            params={
                'mdot_r': self.Compressor.mdot_r,
                'Tin_r': self.Compressor.Tout_r,
                'psat_r': psat_cond,
                'Ref': self.Ref
            }
            self.Condenser.Update(**params)
            self.Condenser.Calculate()
            
            params={
                'pin':psat_cond,
                'hin':self.Condenser.hout_r,
                'mdot':self.Compressor.mdot_r,
                'Ref':self.Ref
            }
            self.LineSetSupply.Update(**params)
            self.LineSetSupply.Calculate()
            
            params={
                'mdot_r': self.Compressor.mdot_r,
                'psat_r': psat_evap,
                'hin_r': self.LineSetSupply.hout,
                'Ref': self.Ref
            }
            self.Evaporator.Update(**params)
            self.Evaporator.Calculate()
            
            self.Charge=self.Condenser.Charge+self.Evaporator.Charge+self.LineSetSupply.Charge+self.LineSetReturn.Charge
            self.EnergyBalance=self.Compressor.CycleEnergyIn+self.Condenser.Q+self.Evaporator.Q
            
            resid=np.zeros((2))
            self.DP_HighPressure=self.Condenser.DP_r+self.LineSetSupply.DP
            self.DP_LowPressure=self.Evaporator.DP_r+self.LineSetReturn.DP
            resid[0]=self.Compressor.mdot_r*(self.LineSetReturn.hin-self.Evaporator.hout_r)
            
            if self.ImposedVariable=='Subcooling':
                resid[1]=self.Condenser.DT_sc-self.DT_sc_target    
            elif self.ImposedVariable=='Charge':
                resid[1]=self.Charge-self.Charge_target
            
            if self.Verbosity>1:
                print resid
            
            self.Capacity=self.Evaporator.Capacity
            self.Power=self.Compressor.W+self.Evaporator.Fins.Air.FanPower+self.Condenser.Fins.Air.FanPower
            self.COP=self.Evaporator.Q/self.Compressor.W
            self.COSP=self.Evaporator.Capacity/self.Power
            self.SHR=self.Evaporator.SHR
            self.DT_sc=self.Condenser.DT_sc
        
        elif self.Mode=='HP':            
            params={               #dictionary -> key:value, e.g. 'key':2345,
                'pin_r': psat_evap-self.DP_low*1,   
                'pout_r': psat_cond+self.DP_high*1,
                'Tin_r': Tdew_evap+self.Evaporator.DT_sh,
                'Ref':  self.Ref
            }
            self.Compressor.Update(**params)
            self.Compressor.Calculate()
            
            params={
                'pin': psat_cond,
                'hin': self.Compressor.hout_r,
                'mdot': self.Compressor.mdot_r,
                'Ref':  self.Ref
            }
            self.LineSetSupply.Update(**params)
            self.LineSetSupply.Calculate()
            
            params={
                'mdot_r': self.Compressor.mdot_r,
                'Tin_r': self.Compressor.Tout_r,
                'psat_r': psat_cond,
                'Ref': self.Ref
            }
            self.Condenser.Update(**params)
            self.Condenser.Calculate()
            
            params={
                'pin': psat_cond,
                'hin': self.Condenser.hout_r,
                'mdot': self.Compressor.mdot_r,
                'Ref': self.Ref
            }
            self.LineSetReturn.Update(**params)
            self.LineSetReturn.Calculate()
            
            params={
                'mdot_r': self.Compressor.mdot_r,
                'psat_r': psat_evap,
                'hin_r': self.LineSetReturn.hout,
                'Ref': self.Ref
            }
            self.Evaporator.Update(**params)
            self.Evaporator.Calculate()
            
            self.Charge=self.Condenser.Charge+self.Evaporator.Charge+self.LineSetSupply.Charge+self.LineSetReturn.Charge
            self.EnergyBalance=self.Compressor.CycleEnergyIn+self.Condenser.Q+self.Evaporator.Q
            
            resid=np.zeros((2))
            resid[0]=self.Compressor.mdot_r*(self.Compressor.hin_r-self.Evaporator.hout_r)
            
            if self.ImposedVariable=='Subcooling':
                resid[1]=self.Condenser.DT_sc-self.DT_sc_target    
            elif self.ImposedVariable=='Charge':
                resid[1]=self.Charge-self.Charge_target
            
            self.Capacity=-self.Condenser.Q+self.Condenser.Fins.Air.FanPower
            self.DT_sc=self.Condenser.DT_sc
            self.Power=self.Compressor.W+self.Evaporator.Fins.Air.FanPower+self.Condenser.Fins.Air.FanPower
            self.COP=-self.Condenser.Q/self.Compressor.W
            self.COSP=self.Capacity/self.Power
            self.SHR=self.Evaporator.SHR
            self.DP_HighPressure=self.Condenser.DP_r+self.LineSetSupply.DP
            self.DP_LowPressure=self.Evaporator.DP_r+self.LineSetReturn.DP
        else:
            ValueError("DX Cycle mode must be 'AC', or 'HP'")
        if self.Verbosity>1:
            print 'DTevap %7.4f DTcond %7.4f Qres % 12.6e DTsc: % 12.6e Charge %10.4f SC: %8.4f' %(DT_evap,DT_cond,resid[0],resid[1],self.Charge,self.Condenser.DT_sc)
        self.DT_evap=DT_evap
        self.DT_cond=DT_cond
        return resid
    
    def PreconditionedSolve(self):
        """
        Solver that will precondition by trying a range of DeltaT until the model
        can solve, then will kick into 2-D Newton Raphson solve
        
        The two input variables for the system solver are the differences in 
        temperature between the inlet air temperature of the heat exchanger and the
        dew temperature of the refrigerant.  This is important for refrigerant blends
        with temperature glide during constant-pressure evaporation or condensation.
        Good examples of common working fluid with glide would be R404A or R410A.
        """
        def OBJECTIVE_DXCycle(x):
            """
            A wrapper function to convert input vector for fsolve to the proper form for the solver
            """
            try:
                resids=self.Calculate(DT_evap=float(x[0]),DT_cond=float(x[1]))#,DP_low=float(x[2]),DP_high=float(x[3]))
            except ValueError:
                raise
            return resids
        
        # Use the preconditioner to determine a reasonably good starting guess
        DT_evap_init,DT_cond_init=DXPreconditioner(self)

        GoodRun=False
        while GoodRun==False:
            try:
                self.DP_low=0
                self.DP_high=0
                DP_converged=False        
                while DP_converged==False:
                    #Actually run the Newton-Raphson solver to get the solution
                    x=Broyden(OBJECTIVE_DXCycle,[DT_evap_init,DT_cond_init])
                    delta_low=abs(self.DP_low-abs(self.DP_LowPressure)/1000)
                    delta_high=abs(self.DP_high-abs(self.DP_HighPressure)/1000)
                    self.DP_low=abs(self.DP_LowPressure)/1000
                    self.DP_high=abs(self.DP_HighPressure)/1000
                    #Update the guess values based on last converged values
                    DT_evap_init=self.DT_evap
                    DT_cond_init=self.DT_cond
                    if delta_low<1 and delta_high<1:
                        DP_converged=True
                    if self.Verbosity>4:
                        print self.DP_HighPressure/1000,self.DP_LowPressure/1000,'DPHP'
                    GoodRun=True
            except AttributeError:
                # This will be a fatal error !! Should never have attribute error
                raise 
            except:
                print "--------------  Exception Caught ---------------- " 
                print "Error of type",sys.exc_info()[0]," is: " + sys.exc_info()[1].message
                raise
        
        if self.Verbosity>0:
            print 'Capacity: ', self.Capacity
            print 'COP: ',self.COP
            print 'COP (w/ both fans): ',self.COSP
            print 'SHR: ',self.SHR
            print 'UA_r_evap',self.Evaporator.UA_r
            print 'UA_a_evap',self.Evaporator.UA_a
            print 'UA_r_cond',self.Condenser.UA_r
            print 'UA_a_cond',self.Condenser.UA_a
Beispiel #5
0
class SecondaryCycleClass():
    def __init__(self):
        """
        Load up the necessary sub-structures to be filled with
        the code that follows
        """
        self.Compressor=CompressorClass()
        
        #Outdoor coil is a Condenser in cooling mode and evaporator in heating mode
        self.Condenser=CondenserClass()
        self.Condenser.Fins=FinInputs()
        self.Evaporator=EvaporatorClass()
        self.Evaporator.Fins=FinInputs()
        
        self.CoolingCoil=CoolingCoilClass()
        self.CoolingCoil.Fins=FinInputs()
        self.Pump=PumpClass()
        #Add both types of internal heat exchangers
        self.CoaxialIHX=CoaxialHXClass()
        self.PHEIHX=PHEHXClass()
        self.LineSetSupply=LineSetClass()
        self.LineSetReturn=LineSetClass()
        #Make IHX an empty class for holding parameters common to PHE and Coaxial IHX
        class struct: pass
        self.IHX=struct()
        
    def OutputList(self):
        """
            Return a list of parameters for this component for further output
            
            It is a list of tuples, and each tuple is formed of items:
                [0] Description of value
                [1] Units of value
                [2] The value itself
        """
        return [
            ('Charge','kg',self.Charge),
            ('Condenser Subcooling','K',self.DT_sc),
            ('Primary Ref.','-',self.Ref),
            ('Secondary Ref.','-',self.SecLoopFluid),
            ('Imposed Variable','-',self.ImposedVariable),
            ('IHX Type','-',self.IHXType),
            ('COP','-',self.COP),
            ('COSP','-',self.COSP),
            ('Net Capacity','W',self.CoolingCoil.Capacity),
            ('Net Power','W',self.Power),
            ('SHR','-',self.SHR),
            ('Condensation temp (dew)','K',self.Tdew_cond),
            ('Evaporation temp (dew)','K',self.Tdew_evap),
         ]

    def Calculate(self,DT_evap,DT_cond,Tin_CC):
        """
        Inputs are differences in temperature [K] between HX air inlet temperature 
        and the dew temperature for the heat exchanger.
        
        Required Inputs:
            DT_evap: 
                Difference in temperature [K] between cooling coil air inlet temperature and refrigerant dew temperature
            DT_cond:
                Difference in temperature [K] between condenser air inlet temperature and refrigerant dew temperature
            Tin_CC:
                Inlet "glycol" temperature to line set feeding cooling coil   
        """
        if self.Verbosity>1:
            print 'Inputs: DTevap %7.4f DTcond %7.4f fT_IHX %7.4f'%(DT_evap,DT_cond,Tin_CC) 
        
        #Store the values to save on computation for later
        self.DT_evap=DT_evap
        self.DT_cond=DT_cond
        self.Tin_CC=Tin_CC
        
        #If the user doesn't include the Mode, set it to Air Conditioning 
        if not hasattr(self,'Mode'):
            self.Mode='AC'
            
        if self.Mode=='AC':
            self.Tdew_cond=self.Condenser.Fins.Air.Tdb+DT_cond
            self.Tdew_evap=self.CoolingCoil.Fins.Air.Tdb-DT_evap
        elif self.Mode=='HP':
            self.Tdew_cond=Tin_CC+DT_cond
            self.Tdew_evap=self.Evaporator.Fins.Air.Tdb-DT_evap
        else:
            raise ValueError('Mode must be AC or HP')
        
        psat_cond=Props('P','T',self.Tdew_cond,'Q',1,self.Ref)
        psat_evap=Props('P','T',self.Tdew_evap,'Q',1,self.Ref)
        self.Tbubble_evap=Props('T','P',psat_evap,'Q',0,self.Ref)
        self.Tbubble_cond=Props('T','P',psat_cond,'Q',0,self.Ref)
        
        if self.Mode=='AC':
            
            params={               #dictionary -> key:value, e.g. 'key':2345,
                'pin_r': psat_evap+self.DP_low,   
                'pout_r': psat_cond-self.DP_high,
                'Tin_r': self.Tdew_evap+self.PHEIHX.DT_sh, # TrhoPhase_ph(self.Ref,psat_evap,self.LineSetReturn.hout,self.Tbubble_evap,self.Tdew_evap)[0],
                'Ref':  self.Ref
            }
            self.Compressor.Update(**params)
            self.Compressor.Calculate()
            
            params={
                'mdot_r': self.Compressor.mdot_r,
                'Tin_r': self.Compressor.Tout_r,
                'psat_r': psat_cond,
                'Ref': self.Ref
            }
            self.Condenser.Update(**params)
            self.Condenser.Calculate()
            
            
            params={
                'mdot': self.Pump.mdot_g,
                'hin': Props('H','T',Tin_CC,'P',self.Pump.pin_g,self.SecLoopFluid)*1000,
            }
            self.LineSetSupply.Update(**params)
            self.LineSetSupply.Calculate()
            
            #Now run CoolingCoil to predict inlet glycol temperature to IHX
            params={
                'mdot_g': self.Pump.mdot_g,
                'Tin_g': self.LineSetSupply.Tout,
            }
            self.CoolingCoil.Update(**params)
            self.CoolingCoil.Calculate()
            
            params={
                'mdot': self.Pump.mdot_g,
                'hin': Props('H','T',self.CoolingCoil.Tout_g,'P',self.Pump.pin_g,self.SecLoopFluid)*1000,
            }
            self.LineSetReturn.Update(**params)
            self.LineSetReturn.Calculate()
            
            if self.IHXType=='Coaxial':
                params={
                    'mdot_g': self.Pump.mdot_g,
                    'Tin_g': self.CoolingCoil.Tout_g,
                    'pin_r': psat_evap,
                    'hin_r': self.Condenser.hout_r,
                    'Ref_r': self.Ref,
                    'mdot_r': self.Compressor.mdot_r,
                }
                self.CoaxialIHX.Update(**params)
                self.CoaxialIHX.Calculate()
                self.IHX.Charge_r=self.CoaxialIHX.Charge_r
                self.IHX.Q=self.CoaxialIHX.Q
                self.IHX.Tout_g=self.CoaxialIHX.Tout_g
                self.IHX.DP_g=self.CoaxialIHX.DP_g
                self.IHX.hout_r=self.CoaxialIHX.hout_r
                self.IHX.DP_r=self.CoaxialIHX.DP_r
                if hasattr(self,'PHEIHX'):
                    del self.PHEIHX
            elif self.IHXType=='PHE':
                params={
                    'mdot_h': self.Pump.mdot_g,
                    'hin_h': Props('H','T',self.CoolingCoil.Tout_g,'P',self.PHEIHX.pin_h,self.SecLoopFluid)*1000,
                    
                    'mdot_c': self.Compressor.mdot_r,
                    'pin_c': psat_evap,
                    'hin_c': self.Condenser.hout_r,
                }
                self.PHEIHX.Update(**params)
                self.PHEIHX.Calculate()
                self.IHX.Charge_r=self.PHEIHX.Charge_c
                self.IHX.Q=self.PHEIHX.Q
                self.IHX.Tout_g=self.PHEIHX.Tout_h
                self.IHX.DP_g=self.PHEIHX.DP_h
                self.IHX.DP_r=self.PHEIHX.DP_c
                self.IHX.hout_r=self.PHEIHX.hout_c
                if hasattr(self,'CoaxialIHX'):
                    del self.CoaxialIHX
            
            params={
                'DP_g': self.IHX.DP_g+self.CoolingCoil.DP_g+self.LineSetSupply.DP+self.LineSetReturn.DP,
                'Tin_g': self.CoolingCoil.Tout_g
            }
            self.Pump.Update(**params)
            self.Pump.Calculate()
            
            self.Charge=self.Condenser.Charge+self.IHX.Charge_r
            self.EnergyBalance=self.Compressor.CycleEnergyIn+self.Condenser.Q+self.IHX.Q
            
            self.DT_sc=(Props('H','T',self.Tbubble_cond,'Q',0,self.Ref)*1000-self.Condenser.hout_r)/(Props('C','T',self.Tbubble_cond,'Q',0,self.Ref)*1000)
            deltaH_sc=self.Compressor.mdot_r*(Props('H','T',self.Tbubble_cond,'Q',0,self.Ref)*1000-Props('H','T',self.Tbubble_cond-self.DT_sc_target,'P',psat_cond,self.Ref)*1000)
            
#            ## Plot a p-h plot
#            Ph(self.Ref,hbounds=(100,500))
#            pylab.plot([self.Compressor.hin_r/1000,self.Compressor.hout_r/1000,self.Condenser.hout_r/1000,self.PHEIHX.hin_c/1000,self.Compressor.hin_r/1000],[psat_evap,psat_cond,psat_cond,psat_evap,psat_evap])
#            pylab.show()
            
            resid=np.zeros((3))
            resid[0]=self.Compressor.mdot_r*(self.Compressor.hin_r-self.IHX.hout_r)
            
            if self.ImposedVariable=='Subcooling':
                resid[1]=self.Condenser.DT_sc-self.DT_sc_target    
            elif self.ImposedVariable=='Charge':
                resid[1]=self.Charge-self.Charge_target
#            resid[2]=self.IHX.Q-self.CoolingCoil.Q+self.Pump.W

            self.residSL=self.IHX.Q-self.CoolingCoil.Q+self.Pump.W+self.LineSetSupply.Q+self.LineSetReturn.Q
            resid[2]=self.residSL
            
            
            
            if self.Verbosity>7:
                print 'Wcomp % 12.6e Qcond: % 12.6e QPHE %10.4f ' %(self.Compressor.W,self.Condenser.Q,self.IHX.Q)
            if self.Verbosity>1:
                print 'Qres % 12.6e Resid2: % 12.6e ResSL %10.4f  Charge %10.4f SC: %8.4f' %(resid[0],resid[1],self.residSL,self.Charge,self.Condenser.DT_sc)
                
            self.Capacity=self.CoolingCoil.Capacity
            self.COP=self.CoolingCoil.Q/self.Compressor.W
            self.COSP=self.CoolingCoil.Capacity/(self.Compressor.W+self.Pump.W+self.CoolingCoil.Fins.Air.FanPower+self.Condenser.Fins.Air.FanPower)
            self.SHR=self.CoolingCoil.SHR
            self.Power=self.Compressor.W+self.Pump.W+self.CoolingCoil.Fins.Air.FanPower+self.Condenser.Fins.Air.FanPower
            self.DP_high_Model=self.Condenser.DP_r #[Pa]
            self.DP_low_Model=self.IHX.DP_r #[Pa]
        elif self.Mode=='HP':
            if psat_evap+self.DP_low<0:
                raise ValueError('Compressor inlet pressure less than zero ['+str(psat_evap+self.DP_low)+' kPa] - is low side pressure drop too high?')
            params={               #dictionary -> key:value, e.g. 'key':2345,
                'pin_r': psat_evap+self.DP_low,   
                'pout_r': psat_cond-self.DP_high,
                'Tin_r': self.Tdew_evap+self.Evaporator.DT_sh, # TrhoPhase_ph(self.Ref,psat_evap,self.LineSetReturn.hout,self.Tbubble_evap,self.Tdew_evap)[0],
                'Ref':  self.Ref
            }
            self.Compressor.Update(**params)
            self.Compressor.Calculate()
            
            params={
                'mdot': self.Pump.mdot_g,
                'hin': Props('H','T',Tin_CC,'P',self.Pump.pin_g,self.SecLoopFluid)*1000,
            }
            self.LineSetSupply.Update(**params)
            self.LineSetSupply.Calculate()
            
            #Now run CoolingCoil to predict inlet glycol temperature to IHX
            params={
                'mdot_g': self.Pump.mdot_g,
                'Tin_g': self.LineSetSupply.Tout,
            }
            self.CoolingCoil.Update(**params)
            self.CoolingCoil.Calculate()
            
            params={
                'mdot': self.Pump.mdot_g,
                'hin': Props('H','T',self.CoolingCoil.Tout_g,'P',self.Pump.pin_g,self.SecLoopFluid)*1000,
            }
            self.LineSetReturn.Update(**params)
            self.LineSetReturn.Calculate()
            
            params={
                'mdot_h': self.Compressor.mdot_r,
                'hin_h': self.Compressor.hout_r,
                'pin_h': psat_cond,
                
                'mdot_c': self.Pump.mdot_g,
                'hin_c': Props('H','T',self.LineSetReturn.Tout,'P',self.PHEIHX.pin_c,self.SecLoopFluid)*1000,
            }
            self.PHEIHX.Update(**params)
            self.PHEIHX.Calculate()
            
            params={
                'mdot_r': self.Compressor.mdot_r,
                'psat_r': psat_evap,
                'hin_r': self.PHEIHX.hout_h,
                'Ref': self.Ref
            }
            self.Evaporator.Update(**params)
            self.Evaporator.Calculate()
            
            params={
                'DP_g': self.PHEIHX.DP_c+self.CoolingCoil.DP_g,
                'Tin_g': self.CoolingCoil.Tout_g
            }
            self.Pump.Update(**params)
            self.Pump.Calculate()
            
            self.Charge=self.Evaporator.Charge+self.PHEIHX.Charge_h
            
            #Calculate an effective subcooling amount by deltah/cp_satL
            #Can be positive or negative (negative is quality at outlet
            self.DT_sc=self.PHEIHX.DT_sc_h#(Props('H','T',self.Tbubble_cond,'Q',0,self.Ref)*1000-self.PHEIHX.hout_h)/(Props('C','T',self.Tbubble_cond,'Q',0,self.Ref)*1000)
            deltaH_sc=self.Compressor.mdot_r*(Props('H','T',self.Tbubble_cond,'Q',0,self.Ref)*1000-Props('H','T',self.Tbubble_cond-self.DT_sc_target,'P',psat_cond,self.Ref)*1000)
            
            resid=np.zeros((3))
            resid[0]=self.Compressor.mdot_r*(self.Compressor.hin_r-self.Evaporator.hout_r)
            
            if self.ImposedVariable=='Subcooling':
                resid[1]=self.DT_sc-self.DT_sc_target
            elif self.ImposedVariable=='Charge':
                resid[1]=self.Charge-self.Charge_target
            self.residSL=self.PHEIHX.Q+self.CoolingCoil.Q+self.Pump.W+self.LineSetSupply.Q+self.LineSetReturn.Q
            resid[2]=self.residSL
            
            if self.Verbosity>1:
                print 'Qres % 12.6e Resid2: % 12.6e ResSL %10.4f Charge %10.4f SC: %8.4f' %(resid[0],resid[1],self.residSL,self.Charge,self.DT_sc)
                
            self.Capacity=-self.CoolingCoil.Q+self.CoolingCoil.Fins.Air.FanPower
            self.COP=-self.CoolingCoil.Q/self.Compressor.W
            self.COSP=self.Capacity/(self.Compressor.W+self.Pump.W+self.CoolingCoil.Fins.Air.FanPower+self.Evaporator.Fins.Air.FanPower)
            self.Power=self.Compressor.W+self.Pump.W+self.CoolingCoil.Fins.Air.FanPower+self.Evaporator.Fins.Air.FanPower
            self.SHR=-self.CoolingCoil.SHR
            self.DP_high_Model=self.PHEIHX.DP_h #[Pa]
            self.DP_low_Model=self.Evaporator.DP_r #[Pa]
        self.DT_evap=DT_evap
        self.DT_cond=DT_cond   
        return resid

    def PreconditionedSolve(self,PrecondValues=None):
        '''
        PrecondValues = dictionary of values DT_evap, DT_cond and Tin_CC
        '''
        
        def OBJECTIVE(x):
            """
            Takes the place of a lambda function since lambda functions do not bubble error properly
            """
            return self.Calculate(x[0],x[1],x[2])
        def OBJECTIVE2(x,Tin):
            """
            Takes the place of a lambda function since lambda functions do not bubble error properly
            """
            return self.Calculate(x[0],x[1],Tin)
        def OBJECTIVE_SL(Tin_CC):
            """
            Objective function for the inner loop of the vapor compression system
            
            Using the MultiDimNewtRaph function will re-evaluate the Jacobian at 
            every step.  Slower, but more robust since the solution surfaces aren't
            smooth enough
            
            Note: This function is not currently used!
            """
            x=MultiDimNewtRaph(OBJECTIVE2,[self.DT_evap,self.DT_cond],args=(Tin_CC,))
   
            # Update the guess values for Delta Ts starting 
            # at the third step (after at least one update away 
            # from the boundaries)
            if self.OBJ_SL_counter>=0:
                self.DT_evap=x[0]
                self.DT_cond=x[1]
                pass
            self.OBJ_SL_counter+=1
            return self.residSL
            
        def PrintDPs():
            print 'DP_LP :: Input:',self.DP_low,'kPa / Model calc:',self.DP_low_Model/1000,'kPa'
            print 'DP_HP :: Input:',self.DP_high,'kPa / Model calc:',self.DP_high_Model/1000,'kPa'         
        
        #Some variables need to be initialized
        self.DP_low=0 #The actual low-side pressure drop to be used in kPa
        self.DP_high=0 #The actual low-side pressure drop to be used in kPa
        self.OBJ_SL_counter=0
        
        #Run the preconditioner to get guess values for the temperatures
        if PrecondValues is None:
            self.DT_evap,self.DT_cond,Tin_CC=SecondaryLoopPreconditioner(self)
        else:
            self.DT_evap=PrecondValues['DT_evap']
            self.DT_cond=PrecondValues['DT_cond']
            Tin_CC=PrecondValues['Tin_CC']
            
        
        #Remove the other, non-used IHX class if found
        if self.IHXType=='PHE':
            if hasattr(self,'CoaxialIHX'):
                del self.CoaxialIHX
        else:
            if hasattr(self,'PHEIHX'):
                del self.PHEIHX
            
        #Remove the condenser if in heating mode and condenser found
        if self.Mode=='HP':
            if hasattr(self,'Condenser'):
                del self.Condenser
        iter=1
        max_error_DP=999
        #Outer loop with a more relaxed convergence criterion
        while max_error_DP>0.5:
            iter_inner=1
            #Inner loop to determine pressure drop for high and low sides
            while max_error_DP>0.05 and iter_inner<10:
                
                #Run to calculate the pressure drop as starting point
                OBJECTIVE([self.DT_evap,self.DT_cond,Tin_CC])
                
                #Calculate the max error
                max_error_DP=max([abs(self.DP_low_Model/1000-self.DP_low),abs(self.DP_high_Model/1000-self.DP_high)])
                
                if self.Verbosity>0:
                    PrintDPs()
                    print 'Max pressure drop error [inner loop] is',max_error_DP,'kPa'
                    
                #Update the pressure drop terms
                self.DP_low=self.DP_low_Model/1000
                self.DP_high=self.DP_high_Model/1000
                
                iter_inner+=1
                
            if self.Verbosity > 0:
                print "Done with the inner loop on pressure drop"
                
            # Use Newton-Raphson solver
            (self.DT_evap,self.DT_cond,Tin_CC)=MultiDimNewtRaph(OBJECTIVE,[self.DT_evap,self.DT_cond,Tin_CC],dx=0.1)
            
            #Calculate the error
            max_error_DP=max([abs(self.DP_low_Model/1000-self.DP_low),abs(self.DP_high_Model/1000-self.DP_high)])
            
            if self.Verbosity>0:
                PrintDPs()    
                print 'Max pressure drop error [outer loop] is',max_error_DP,'kPa'
        
        if self.Verbosity>1:
            print 'Capacity: ', self.Capacity
            print 'COP: ',self.COP
            print 'COP (w/ both fans): ',self.COSP
            print 'SHR: ',self.SHR
        return
class ORCClass():
    def __init__(self):
        """
        Load up the necessary sub-structures to be filled with
        the code that follows
        """
        self.Evaporator = PHEHXClass()
        self.Expander = ExpanderClass()
        self.Regenerator = PHEHXClass()
        self.Condenser = PHEHXClass()
        self.Pump = PumpCentrifugalClass()
        self.LiquidReceiver = LiquidReceiverClass()
        self.LineSetPumpEx = LineSetClass()
        self.LineSetPumpSu = LineSetClass()
        self.LineSetExpSu = LineSetClass()
        self.LineSetExpEx = LineSetClass()
        self.LineSetCondEx = LineSetClass()

    def OutputList(self):
        """
        Return a list of parameters for this component for further output
        It is a list of tuples, and each tuple is formed of items:
        [0] Description of value
        [1] Units of value
        [2] The value itself
        """
        try:
            return [
                #Residuals
                ('resid_subcool', 'K', self.resid_DT_sc),
                ('resid_charge', 'kg', self.resid_charge),
                ('resid_ebal', 'W', self.resid_EB),
                ('resid_mdot', 'kg/s', self.resid_mf),
                #Hot source
                ('Th2', 'C', self.Evaporator.Tout_h - 273.15),
                ('Tc2', 'C', self.Condenser.Tout_c - 273.15),
                #Pump
                ('T_pump_su', 'C', self.Pump.Tin),
                ('T_pump_ex', 'C', self.Pump.Tout - 273.15),
                ('P_pump_su', 'kPa', self.Pump.pin_r),
                ('P_pump_ex', 'kPa', self.Pump.pout_r),
                ('mdot_pump', 'kg/s', self.Pump.m_dot),
                ('Power_pump', 'W', self.Pump.W_dot),
                #Expander
                ('T_exp_su', 'C', self.Expander.T_su),
                ('T_exp_ex', 'C', self.Expander.T_ex - 273.15),
                ('P_exp_su', 'kPa', self.Expander.P_su),
                ('P_exp_ex', 'kPa', self.Expander.P_ex),
                ('mdot_exp', 'kg/s', self.Expander.m_dot),
                ('power_exp', 'W', self.Expander.W_dot),
                ('expander isentropic efficiency', '-', self.Expander.eta_s),
                ('delta_T_subcool', 'K', self.DELTAT_sc_cd),
                ('delta_T_superheat', 'K',
                 self.Evaporator.Tout_c - self.Evaporator.Tdew_c),
                ('eta_cyc', '-', self.eta_cycle),
                ('eta_II_finite', '-', self.eta_cycle_II),
                #Charge
                ('Charge', 'kg', self.Charge)
            ]
        except AttributeError:
            return []

    def Calculate(self, Inputs, Tdew_evap, Tdew_cond):

        psat_cond = PropsSI('P', 'T', Tdew_cond + 273.15, 'Q', 1,
                            Inputs['Ref']) / 1000
        psat_evap = PropsSI('P', 'T', Tdew_evap + 273.15, 'Q', 1,
                            Inputs['Ref']) / 1000

        self.Tdew_cond = Tdew_cond
        self.Tdew_evap = Tdew_evap
        self.p_cd = psat_cond
        self.p_ev = psat_evap

        if self.Tdew_cond > self.Tdew_evap:
            self.Tdew_cond = 20
            self.Tdew_evap = 70
        else:
            pass

        ##Pump
        #M are regression coefficients to compute the mass flow rate.
        #'eta' are regression coefficients to compute the isentropic efficiency.
        params = {
            'Ref': Inputs['Ref'],
            'pin_r': psat_cond,
            'pout_r': psat_evap,
            'f_pp': Inputs['f_pp'],
            'Tin': self.Tdew_cond - Inputs['DT_sc']
        }
        self.Pump.Update(**params)
        self.Pump.Calculate()

        ##PumpEx Line
        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_evap,
            'hin':
            PropsSI('H', 'T', self.Pump.Tout, 'P', psat_evap * 1000,
                    Inputs['Ref']),
            'mdot':
            self.Pump.m_dot,
            #geometric parameters
            'OD':
            1.5 * convert('in', 'm'),
            'ID':
            1.3 * convert('in', 'm'),
            'L':
            3 * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetPumpEx.Update(**params)
        self.LineSetPumpEx.Calculate()

        ##Evaporapor
        params = {
            'Ref_c':
            Inputs['Ref'],
            'mdot_c':
            self.Pump.m_dot,
            'pin_c':
            psat_evap,
            'Tin_c':
            self.Pump.Tout - 273.15,
            'hin_c':
            PropsSI('H', 'T', self.Pump.Tout, 'P', psat_evap * 1000,
                    Inputs['Ref']),
            'Ref_h':
            Inputs['Ref_h'],
            'mdot_h':
            Inputs['mdot_h'],
            'pin_h':
            Inputs['pin_h'] * 1000,
            'hin_h':
            PropsSI('H', 'T', Inputs['Tin_h'] + 273.15, 'P',
                    Inputs['pin_h'] * 1000, Inputs['Ref_h']),
        }
        self.Evaporator.Update(**params)
        self.Evaporator.Calculate()

        ##ExpanderSu Line
        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_evap,
            'hin':
            PropsSI('H', 'T', self.Evaporator.Tout_c, 'P', psat_evap * 1000,
                    Inputs['Ref']),
            'mdot':
            self.Expander.m_dot,
            #geometric parameters
            'OD':
            2 * convert('in', 'm'),
            'ID':
            1.8 * convert('in', 'm'),
            'L':
            3 * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetExpSu.Update(**params)
        self.LineSetExpSu.Calculate()

        ##Expander
        params = {
            'P_su': psat_evap,
            'P_ex': psat_cond,
            'h_su': self.Evaporator.hout_c,
            'inputs': 'Psu_Pex_h'
        }
        self.Expander.Update(**params)
        self.Expander.Calculate()

        ##CondSu Line
        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_cond,
            'hin':
            PropsSI('H', 'T', self.Expander.T_ex, 'P', psat_cond * 1000 + 100,
                    Inputs['Ref']),
            'mdot':
            self.Pump.m_dot,
            #geometric parameters
            'OD':
            2 * convert('in', 'm'),
            'ID':
            1.8 * convert('in', 'm'),
            'L':
            3 * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetExpEx.Update(**params)
        self.LineSetExpEx.Calculate()

        ##Condenser
        params = {
            'Ref_c':
            Inputs['Ref_c'],
            'mdot_c':
            Inputs['mdot_c'],
            'pin_c':
            Inputs['pin_c'],
            'hin_c':
            PropsSI('H', 'T', Inputs['Tin_c'] + 273.15, 'P',
                    Inputs['pin_c'] * 1000, Inputs['Ref_c']),
            'Ref_h':
            Inputs['Ref'],
            'mdot_h':
            self.Expander.m_dot,
            'pin_h':
            psat_cond,
            'hin_h':
            PropsSI('H', 'T', self.Expander.T_ex, 'P', psat_cond * 1000 + 100,
                    Inputs['Ref']),
        }
        self.Condenser.Update(**params)
        self.Condenser.Calculate()

        ##LiquidReceiverSu Line
        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_cond,
            'hin':
            PropsSI('H', 'T', self.Condenser.Tout_h, 'P',
                    (1 + 1e-5) * psat_cond * 1000, Inputs['Ref']),
            'mdot':
            self.Expander.m_dot,
            #geometric parameters
            'OD':
            2 * convert('in', 'm'),
            'ID':
            1.8 * convert('in', 'm'),
            'L':
            3 * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetCondEx.Update(**params)
        self.LineSetCondEx.Calculate()

        ##Liquid Receiver
        params = {
            'Ref': Inputs['Ref'],
            'pin': psat_cond,
            'Tin': self.Condenser.Tout_h,
            'ID': 0.35,
            'h_receiver': 0.9,
            'h_ports': 0.5
        }
        self.LiquidReceiver.Update(**params)
        self.LiquidReceiver.Calculate()

        ##PumpSu Line
        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_cond,
            'hin':
            PropsSI('H', 'T', self.Condenser.Tout_h, 'P', psat_cond * 1000 + 1,
                    Inputs['Ref']),
            'mdot':
            self.Expander.m_dot,
            #geometric parameters
            'OD':
            1.5 * convert('in', 'm'),
            'ID':
            1.3 * convert('in', 'm'),
            'L': (11 + 3) * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetPumpSu.Update(**params)
        self.LineSetPumpSu.Calculate()

        ############################
        #      Cycle Performance
        ############################

        #cycle efficiency
        self.Ref = Inputs['Ref']
        self.T_amb = 25  #Reference ambient temperature[C]

        level = (self.Condenser.hsatV_h - self.LiquidReceiver.hin) / (
            self.Condenser.hsatV_h - self.Condenser.hsatL_h) * (
                self.LiquidReceiver.rho_in / self.Condenser.rhosatL_h)

        #Back-Work Ratio (BWR)
        self.BWR = self.Pump.W_dot / self.Expander.W_dot

        #Heat recovery efficiency
        #From "Dynamic modeling and optimal control strategy of waste heat recovery Organic Rankine Cycles" Quoilin
        self.h_amb = PropsSI('H', 'T', self.T_amb + 273.15, 'P',
                             self.Evaporator.pin_h * 1000,
                             self.Evaporator.Ref_h)  #*1000
        self.Q_maxtoamb = self.Evaporator.mdot_h * (self.Evaporator.hin_h -
                                                    self.h_amb)

        self.epsilon_hr = self.Evaporator.Q / self.Q_maxtoamb

        #first-law efficiency
        self.eta_cycle = (self.Expander.W_dot -
                          self.Pump.W_dot) / self.Evaporator.Q
        self.eta_overall = self.eta_cycle * self.epsilon_hr

        #Second-law efficiency
        self.Exergy_hs = self.Evaporator.mdot_h * (
            (self.Evaporator.hin_h - self.Condenser.hin_c) -
            (Inputs['Tin_c'] + 273.15) *
            (PropsSI('S', 'H', self.Evaporator.hin_h, 'P',
                     self.Evaporator.pin_h * 1000, self.Evaporator.Ref_h) -
             PropsSI('S', 'H', self.Condenser.hin_c, 'P',
                     self.Condenser.pin_c * 1000, self.Condenser.Ref_c)))

        self.eta_cycle_II = self.Expander.W_dot / self.Exergy_hs

        #residuals
        resid = np.zeros((2))

        resid[
            0] = self.Pump.W_dot + self.Evaporator.Q - self.Expander.W_dot - self.Condenser.Q
        resid_mf = self.Pump.m_dot - self.Expander.m_dot
        self.DELTAT_sc_cd = (self.Tdew_cond - (self.Condenser.Tout_h - 273.15))
        self.DELTAT_sh_ev = self.Evaporator.Tout_c - self.Evaporator.Tdew_c

        self.Charge = self.LineSetPumpEx.Charge + self.LineSetPumpSu.Charge + self.Evaporator.Charge_c + self.Condenser.Charge_h + self.LineSetExpEx.Charge + self.LineSetExpSu.Charge + self.LineSetCondEx.Charge + self.LiquidReceiver.Charge_Tank

        e_DT_sc = Inputs['DT_sc'] - self.DELTAT_sc_cd

        if Inputs['Solver'] == 'Subcooling':
            resid[1] = Inputs['DT_sc'] - self.DELTAT_sc_cd

        elif Inputs['Solver'] == 'Charge':
            resid[1] = self.Charge - Inputs['Tot_Charge']

        self.resid_EB = resid[0]
        self.resid_mf = resid_mf
        self.resid_DT_sc = e_DT_sc
        self.resid_charge = self.Charge - Inputs['Tot_Charge']

        return resid

    def Calculate_Regen(self, Inputs, Tdew_evap, Tdew_cond, hin_reg_h):

        if Tdew_evap > PropsSI(Inputs['Ref'], 'Tcrit') - 273.15:
            Tdew_evap = Inputs['Tin_s'] - 50
            print 'Tdew_evep > Tcrit'

        elif Tdew_evap < PropsSI(Inputs['Ref'], 'Tmin') - 273.15:
            Tdew_evap = Inputs['Tin_s'] - 50
            print 'Tdew_evep < Tmin'

        else:
            pass

        if Tdew_cond > PropsSI(Inputs['Ref'], 'Tcrit') - 273.15:
            Tdew_cond = Inputs['Tin_w'] + 5
            print 'Tdew_cond > Tcrit'

        elif Tdew_cond < PropsSI(Inputs['Ref'], 'Tmin') - 273.15:
            Tdew_cond = Inputs['Tin_w'] + 5
            print 'Tdew_cond < Tmin'

        else:
            pass

        if Tdew_cond > Tdew_evap:
            print "Im here"
            Tdew_cond = 20
            Tdew_evap = 70
        else:
            pass

        psat_cond = PropsSI('P', 'T', Tdew_cond + 273.15, 'Q', 1,
                            Inputs['Ref']) / 1000
        psat_evap = PropsSI('P', 'T', Tdew_evap + 273.15, 'Q', 1,
                            Inputs['Ref']) / 1000

        self.Tdew_cond = Tdew_cond
        self.Tdew_evap = Tdew_evap
        self.p_cd = psat_cond
        self.p_ev = psat_evap

        #Control variable
        self.hin_reg_h = hin_reg_h

        ##Pump
        #M are regression coefficients to compute the mass flow rate.
        #'eta' are regression coefficients to compute the isentropic efficiency.
        params = {
            'Ref': Inputs['Ref'],
            'pin_r': psat_cond,
            'pout_r': psat_evap,
            'f_pp': Inputs['f_pp'],
            'Tin': self.Tdew_cond - Inputs['DT_sc']
        }
        self.Pump.Update(**params)
        self.Pump.Calculate()

        ##PumpEx Line
        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_evap,
            'hin':
            PropsSI('H', 'T', self.Pump.Tout, 'P', psat_evap * 1000,
                    Inputs['Ref']),
            'mdot':
            self.Pump.m_dot,
            #geometric parameters
            'OD':
            1.5 * convert('in', 'm'),
            'ID':
            1.3 * convert('in', 'm'),
            'L':
            3 * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetPumpEx.Update(**params)
        self.LineSetPumpEx.Calculate()

        ##Regenerator
        params = {
            'Ref_c':
            Inputs['Ref'],
            'mdot_c':
            self.Pump.m_dot,
            'pin_c':
            self.p_ev,
            'Tin_c':
            self.Pump.Tout - 273.15,
            'hin_c':
            PropsSI('H', 'T', self.Pump.Tout, 'P', psat_evap * 1000 + 100,
                    Inputs['Ref']),
            'Ref_h':
            Inputs['Ref'],
            'mdot_h':
            self.Expander.m_dot,
            'pin_h':
            self.p_cd,
            'hin_h':
            self.hin_reg_h,  #[J/kg]
        }
        self.Regenerator.Update(**params)
        self.Regenerator.Calculate()

        ##Evaporapor
        params = {
            'Ref_c':
            Inputs['Ref'],
            'mdot_c':
            self.Pump.m_dot,
            'pin_c':
            psat_evap,
            'Tin_c':
            self.Regenerator.Tout_c,
            'hin_c':
            PropsSI('H', 'T', self.Regenerator.Tout_c, 'P',
                    psat_evap * 1000 + 100, Inputs['Ref']),
            'Ref_h':
            Inputs['Ref_h'],
            'mdot_h':
            Inputs['mdot_h'],
            'pin_h':
            Inputs['pin_h'],
            'hin_h':
            PropsSI('H', 'T', Inputs['Tin_h'] + 273.15, 'P',
                    Inputs['pin_h'] * 1000, Inputs['Ref_h']),
        }
        self.Evaporator.Update(**params)
        self.Evaporator.Calculate()

        ##ExpanderSu Line
        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_evap,
            'hin':
            PropsSI('H', 'T', self.Evaporator.Tout_c, 'P', psat_evap * 1000,
                    Inputs['Ref']),
            'mdot':
            self.Pump.m_dot,
            #geometric parameters
            'OD':
            2 * convert('in', 'm'),
            'ID':
            1.8 * convert('in', 'm'),
            'L':
            3 * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetExpSu.Update(**params)
        self.LineSetExpSu.Calculate()

        ##Expander
        params = {
            'P_su': psat_evap,
            'P_ex': psat_cond,
            'h_su': self.Evaporator.hout_c,
            'inputs': 'Psu_Pex_h'
        }
        self.Expander.Update(**params)
        self.Expander.Calculate()

        ##CondSu Line

        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_cond,
            'hin':
            PropsSI('H', 'T', self.Regenerator.Tout_h, 'P',
                    psat_cond * 1000 + 100, Inputs['Ref']),
            'mdot':
            self.Pump.m_dot,
            #geometric parameters
            'OD':
            2 * convert('in', 'm'),
            'ID':
            1.8 * convert('in', 'm'),
            'L':
            3 * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetExpEx.Update(**params)
        self.LineSetExpEx.Calculate()

        ##Condenser
        params = {
            'Ref_c':
            Inputs['Ref_c'],
            'mdot_c':
            Inputs['mdot_c'],
            'pin_c':
            Inputs['pin_c'],
            'hin_c':
            PropsSI('H', 'T', Inputs['Tin_c'] + 273.15, 'P',
                    Inputs['pin_c'] * 1000, Inputs['Ref_c']),  #*1000,
            'Ref_h':
            Inputs['Ref'],
            'mdot_h':
            self.Expander.m_dot,
            'pin_h':
            psat_cond,
            'hin_h':
            PropsSI('H', 'T', self.Regenerator.Tout_h, 'P',
                    psat_cond * 1000 - 100, Inputs['Ref']),  #*1000,
        }

        self.Condenser.Update(**params)
        self.Condenser.Calculate()

        ##LiquidReceiverSu Line
        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_cond,
            'hin':
            PropsSI('H', 'T', self.Condenser.Tout_h, 'P',
                    (1 + 1e-5) * psat_cond * 1000, Inputs['Ref']),
            'mdot':
            self.Expander.m_dot,
            #geometric parameters
            'OD':
            2 * convert('in', 'm'),
            'ID':
            1.8 * convert('in', 'm'),
            'L':
            3 * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetCondEx.Update(**params)
        self.LineSetCondEx.Calculate()

        ##Liquid Receiver
        params = {
            'Ref': Inputs['Ref'],
            'pin': psat_cond,
            'Tin': self.Condenser.Tout_h,
            'ID': 0.30,
            'h_receiver': 0.7,
            'h_ports': 0.5
        }
        self.LiquidReceiver.Update(**params)
        self.LiquidReceiver.Calculate()

        ##PumpSu Line
        params = {
            'Ref':
            Inputs['Ref'],
            'pin':
            psat_cond,
            'hin':
            PropsSI('H', 'T', self.Condenser.Tout_h, 'P',
                    psat_cond * 1000 + 100, Inputs['Ref']),  #*1000,
            #'mdot':self.Expander_2.m_dot,
            'mdot':
            self.Expander.m_dot,
            #geometric parameters
            'OD':
            1.5 * convert('in', 'm'),
            'ID':
            1.3 * convert('in', 'm'),
            'L': (11 + 3) * convert('f', 'm'),
            'k_tube':
            300,
            't_insul':
            1 * convert('in', 'm'),
            'k_insul':
            0.05,
            'h_air':
            10,
            'T_air':
            300
        }
        self.LineSetPumpSu.Update(**params)
        self.LineSetPumpSu.Calculate()

        ############################
        #      ORC with Regen Performance
        ############################

        #cycle efficiency
        self.Ref = Inputs['Ref']
        self.T_amb = 25  #Reference ambient temperature[C]

        level = (self.Condenser.hsatV_h - self.LiquidReceiver.hin) / (
            self.Condenser.hsatV_h - self.Condenser.hsatL_h) * (
                self.LiquidReceiver.rho_in / self.Condenser.rhosatL_h)

        #Back-Work Ratio (BWR)
        self.BWR = self.Pump.W_dot / self.Expander.W_dot

        #Heat recovery efficiency
        #From "Dynamic modeling and optimal control strategy of waste heat recovery Organic Rankine Cycles" Quoilin
        self.h_amb = PropsSI('H', 'T', self.T_amb + 273.15, 'P',
                             self.Evaporator.pin_h * 1000,
                             self.Evaporator.Ref_h)  #*1000
        self.Q_maxtoamb = self.Evaporator.mdot_h * (self.Evaporator.hin_h -
                                                    self.h_amb)

        self.epsilon_hr = self.Evaporator.Q / self.Q_maxtoamb

        #first-law efficiency
        self.eta_cycle = (self.Expander.W_dot -
                          self.Pump.W_dot) / self.Evaporator.Q
        self.eta_overall = self.eta_cycle * self.epsilon_hr

        #Second-law efficiency
        self.Exergy_hs = self.Evaporator.mdot_h * (
            (self.Evaporator.hin_h - self.Condenser.hin_c) -
            (Inputs['Tin_c'] + 273.15) *
            (PropsSI('S', 'H', self.Evaporator.hin_h, 'P',
                     self.Evaporator.pin_h * 1000, self.Evaporator.Ref_h) -
             PropsSI('S', 'H', self.Condenser.hin_c, 'P',
                     self.Condenser.pin_c * 1000, self.Condenser.Ref_c)))

        self.eta_cycle_II = self.Expander.W_dot / self.Exergy_hs

        #residuals
        resid = np.zeros((3))

        ##Residuals
        """
        resid[0]: overall energy balance
        resid[1]: subcooling or refrigerant charge
        resid[2]: enthalpy at expander outlet
        """
        resid[
            0] = self.Pump.W_dot + self.Evaporator.Q - self.Expander.W_dot - self.Condenser.Q
        resid_mf = self.Pump.m_dot - self.Expander.m_dot
        self.DELTAT_sc_cd = (self.Tdew_cond - (self.Condenser.Tout_h - 273.15))
        self.DELTAT_sh_ev = self.Evaporator.Tout_c - self.Evaporator.Tdew_c
        e_DT_sc = Inputs['DT_sc'] - self.DELTAT_sc_cd
        self.Charge = self.LineSetPumpEx.Charge + self.LineSetPumpSu.Charge + self.Evaporator.Charge_c + self.Condenser.Charge_h + self.LineSetExpEx.Charge + self.LineSetExpSu.Charge + self.LineSetCondEx.Charge + self.LiquidReceiver.Charge_Tank + self.Regenerator.Charge_c + self.Regenerator.Charge_h

        if Inputs['Solver'] == 'Subcooling':

            resid[1] = Inputs['DT_sc'] - self.DELTAT_sc_cd

        elif Inputs['Solver'] == 'Charge':

            resid[1] = self.Charge - Inputs['Tot_Charge']

        resid[2] = (self.hin_reg_h - self.Expander.hout)

        self.resid_EB = resid[0]
        self.resid_mf = resid_mf
        self.resid_DT_sc = e_DT_sc
        self.resid_charge = self.Charge - Inputs['Tot_Charge']

        return resid

##########################################################################
#    Solvers
########################################################################

    def PreconditionedSolve(self, Inputs):

        iteration_precond = []
        resid1_precond = []
        resid2_precond = []

        def OBJECTIVE_ORC(x):

            iteration = my_counter.next()
            # print iteration
            """
            A wrapper function to convert input vector for fsolve to the proper form for the solver
            """

            try:
                resids = self.Calculate(Inputs,
                                        Tdew_evap=float(x[0]),
                                        Tdew_cond=float(x[1]))
                iteration_precond.append(iteration)
                resid1_precond.append(resids[0])
                resid2_precond.append(resids[1])

                if Inputs['Solver'] == 'Subcooling':
                    print 'EnergyBalance,DT_sc:', resids[0], resids[1]
                elif Inputs['Solver'] == 'Charge':
                    print 'EnergyBalance,Charge:', resids[0], resids[1]

            except ValueError:
                raise
            #print it

            self.iteration_precond = np.array(iteration_precond)
            self.resid1_precond = np.array(resid1_precond)
            self.resid2_precond = np.array(resid2_precond)

            return resids

        # Use the preconditioner to determine a reasonably good starting guess

        Tdew_cond_init, Tdew_evap_init = ORC_Preconditioner(self, Inputs)

        #Actually run the solver to get the solution
        x = fsolve(OBJECTIVE_ORC, [Tdew_cond_init, Tdew_evap_init],
                   full_output=True,
                   xtol=1e-6)
        #x=MultiDimNewtRaph(OBJECTIVE_ORC,[Tdew_cond_init,Tdew_evap_init],dx=1e-6,args=(),ytol=1e-4,w=1.0,JustOneStep=False)

    def PreconditionedSolve_ORCRegen(self, Inputs):

        iteration_precond = []
        resid1_precond = []
        resid2_precond = []
        resid3_precond = []

        def OBJECTIVE_ORCRegen(x):

            iteration = my_counter.next()
            # print iteration
            """
            A wrapper function to convert input vector for fsolve to the proper form for the solver
            """

            try:
                resids = self.Calculate_Regen(Inputs,
                                              Tdew_evap=float(x[0]),
                                              Tdew_cond=float(x[1]),
                                              hin_reg_h=float(x[2]))
                iteration_precond.append(iteration)
                resid1_precond.append(resids[0])
                resid2_precond.append(resids[1])
                resid3_precond.append(resids[2])

                if Inputs['Solver'] == 'Subcooling':
                    print 'EnergyBalance,DT_sc,hin_reg_h:', resids[0], resids[
                        1], resids[2]
                elif Inputs['Solver'] == 'Charge':
                    print 'EnergyBalance,Charge,hin_reg_h:', resids[0], resids[
                        1], resids[2]

            except ValueError:
                raise
            #print it

            self.iteration_precond = np.array(iteration_precond)
            self.resid1_precond = np.array(resid1_precond)
            self.resid2_precond = np.array(resid2_precond)
            self.resid3_precond = np.array(resid3_precond)
            #print 'iteration_precond',self.iteration_precond
            return resids

        # Use the preconditioner to determine a reasonably good starting guess
        Tdew_cond_init, Tdew_evap_init, hin_reg_h_init = ORCRegen_Preconditioner(
            self, Inputs)

        #Actually run the solver to get the solution
        x = fsolve(OBJECTIVE_ORCRegen,
                   [Tdew_cond_init, Tdew_evap_init, hin_reg_h_init],
                   full_output=True,
                   xtol=1e-6)

    def ConvergencePlot(self):

        matplotlib.rc('text', usetex=True)
        plt.rc('font', family='serif')
        fig = figure(figsize=(8, 6))
        ax = fig.add_subplot(1, 1, 1)

        ax2 = ax.twinx()

        plot1 = ax.plot(self.iteration_precond,
                        fabs(self.resid1_precond),
                        'bo-',
                        linewidth=2,
                        markersize=10,
                        markerfacecolor="blue",
                        markeredgewidth=1,
                        markeredgecolor="black",
                        label='Energy Balance')
        plot2 = ax2.plot(self.iteration_precond,
                         fabs(self.resid2_precond),
                         'r-^',
                         linewidth=2,
                         markersize=10,
                         markerfacecolor="red",
                         markeredgewidth=1,
                         markeredgecolor="black",
                         label='Ref Charge')

        ax.axhline(y=1e-5, color='b', ls='dashed', linewidth=2.5)
        ax2.axhline(y=1e-5, color='r', ls='dashed', linewidth=2.5)

        # Only one legend with different axis plots
        lines, labels = ax.get_legend_handles_labels()
        lines2, labels2 = ax2.get_legend_handles_labels()

        ax2.legend(lines + lines2,
                   labels + labels2,
                   loc=0,
                   shadow=True,
                   fancybox=True,
                   prop={'size': 15})

        ax.set_xlabel('Iteration [-]', fontsize=18)
        ax.set_ylabel(r'$|Resid_{Energy Balance}|$', fontsize=18)
        ax2.set_ylabel(r'$|Resid_{Charge}|$', fontsize=18)
        plt.title('Resids Convergence', fontsize=18)

        ax.set_yscale('log')
        ax.tick_params(axis='y', which='minor', bottom='off')
        ax2.set_yscale('log')
        ax2.tick_params(axis='y', which='minor', bottom='off')

        for tickx in ax.xaxis.get_major_ticks():
            tickx.label.set_fontsize(20)
        for ticky in ax.yaxis.get_major_ticks():
            ticky.label.set_fontsize(20)
        for ticky in ax2.yaxis.get_major_ticks():
            ticky.label.set_fontsize(20)

        print 'Saving convergence plot...'
        fig.savefig('ConvergencePlot.png', dpi=600)

    def BaselineTs(self, Inputs, **kwargs):

        matplotlib.rc('text', usetex=True)
        plt.rc('font', family='serif')
        fig = figure(figsize=(8, 6))
        ax = fig.add_subplot(1, 1, 1)

        if 'Tmin' in kwargs:
            Tmin = float(kwargs['Tmin'])
        else:
            Tmin = 220.

        Tsat = linspace(Tmin, PropsSI(Inputs['Ref'], 'Tcrit') - 0.0001, 1000)
        (ssatL, psatL, ssatV, psatV) = (0.0 * Tsat, 0.0 * Tsat, 0.0 * Tsat,
                                        0.0 * Tsat)
        for i in arange(len(Tsat)):
            ssatL[i] = PropsSI('S', 'T', Tsat[i], 'Q', 0, Inputs['Ref']) / 1000
            ssatV[i] = PropsSI('S', 'T', Tsat[i], 'Q', 1, Inputs['Ref']) / 1000

        ax.plot(ssatL, Tsat, 'k')
        ax.plot(ssatV, Tsat, 'k')

        epss = 0.05
        epsT = 5

        # Base Cycle
        #Expander
        s_exp = r_[self.Expander.s_su / 1000, self.Expander.s_out / 1000]
        T_exp = r_[self.Expander.T_su + 273.15, self.Expander.T_ex]
        ax.plot(s_exp, T_exp, 'k-')
        ax.plot(s_exp,
                T_exp,
                'ko-',
                linewidth=2,
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")
        ax.text(s_exp[0] + epss / 2, T_exp[0] + epsT, '3', va='top', ha='left')

        s_exp_s = r_[self.Expander.s_su / 1000, self.Expander.s_su / 1000]
        T_exp_s = r_[self.Expander.T_su + 273.15, self.Expander.T_ex_s]

        ax.plot(s_exp_s, T_exp_s, 'k--', linewidth=1.5)
        ax.plot(s_exp_s[1],
                T_exp_s[1],
                'ko-',
                linewidth=2,
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")
        ax.text(s_exp_s[1], T_exp_s[1] - epsT, '4s', va='top', ha='left')

        #Condenser
        T_cond = linspace(self.Condenser.Tout_h, self.Expander.T_ex, 200)
        s_cond = 0.0 * T_cond
        p_cond = self.p_cd
        for i in range(len(T_cond)):
            s_cond[i] = PropsSI('S', 'T', T_cond[i], 'P', p_cond * 1000 + 100,
                                self.Ref) / 1000
        ax.plot(s_cond, T_cond, 'k-', linewidth=2)
        ax.plot(r_[s_cond[0], s_cond[-1]],
                r_[T_cond[0], T_cond[-1]],
                'ko',
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")
        ax.text(s_cond[-1] + epss / 2,
                T_cond[-1] + epsT,
                '4',
                va='top',
                ha='left')

        s_EXV = r_[self.Condenser.sout_h / 1000, self.Pump.s_in]
        T_EXV = r_[self.Condenser.Tout_h, self.Pump.Tin]

        ax.text(s_EXV[0] + epss, T_EXV[0] + epsT, '1', va='top', ha='left')

        #Pump
        s_pump = r_[self.Pump.s_in, self.Pump.s_out]
        T_pump = r_[self.Pump.Tin + 273.15, self.Pump.Tout]
        ax.plot(s_pump, T_pump, 'b-', linewidth=2)
        ax.plot([self.Pump.s_in, self.Pump.s_in],
                [self.Pump.Tin + 273.15, self.Pump.Tout_s],
                'ko--',
                linewidth=2,
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")
        ax.plot([self.Pump.s_in, self.Pump.s_out],
                [self.Pump.Tout_s, self.Pump.Tout],
                'ko--',
                linewidth=2,
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")
        ax.plot(s_pump[0],
                T_pump[0],
                'bo',
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")
        ax.plot(s_pump[1],
                T_pump[1],
                'bo',
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")
        ax.text(s_pump[1] - epss,
                T_pump[1] + 2 * epsT,
                '2',
                va='top',
                ha='left')

        #Evaporator
        #Zone1
        s_evap_zone1 = r_[self.Pump.s_out, self.Evaporator.s_c_liq]
        T_evap_zone1 = r_[self.Pump.Tout_s, self.Evaporator.Tdew_c]
        ax.plot(s_evap_zone1, T_evap_zone1, 'k-', linewidth=2)
        ax.plot(s_evap_zone1[1],
                T_evap_zone1[1],
                'ko',
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")
        ax.text(s_evap_zone1[1],
                T_evap_zone1[1] - epsT,
                '2i',
                va='top',
                ha='left')
        #Zone2
        s_evap_zone2 = r_[self.Evaporator.s_c_liq, self.Evaporator.s_c_vap]
        T_evap_zone2 = r_[self.Evaporator.Tdew_c, self.Evaporator.Tdew_c]
        ax.plot(s_evap_zone2, T_evap_zone2, 'k-', linewidth=2)
        ax.plot(s_evap_zone2[1],
                T_evap_zone2[1],
                'ko',
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")
        ax.text(s_evap_zone2[1] - 1.5 * epss,
                T_evap_zone2[1] + 2 * epsT,
                '2ii',
                va='top',
                ha='left')
        #Zone3
        #s_evap_zone3=r_[self.Evaporator.s_c_vap,self.Expander_2.s_in]
        s_evap_zone3 = r_[self.Evaporator.s_c_vap, self.Expander.s_su / 1000]
        T_evap_zone3 = r_[self.Evaporator.Tdew_c, self.Evaporator.Tout_c]
        ax.plot(s_evap_zone3, T_evap_zone3, 'k-', linewidth=2)

        #Regenerator
        T_regen_out = self.Regenerator.Tout_c
        s_regen_out = self.Regenerator.sout_c / 1000
        T_regen_out_meas = 74.77 + 273.15
        s_regen_out_meas = PropsSI('S', 'P', 895.072 * 1000 + 100, 'T',
                                   T_regen_out, Inputs['Ref']) / 1000
        ax.plot(s_regen_out,
                T_regen_out,
                'bo',
                markersize=7,
                markerfacecolor="red",
                markeredgewidth=2,
                markeredgecolor="black")

        #Hot source
        T_evap_h = r_[self.Evaporator.Tin_h, self.Evaporator.Tout_h]
        s_evap_h = r_[self.Expander.s_su / 1000,
                      self.Regenerator.sout_c / 1000]
        ax.plot(s_evap_h,
                T_evap_h,
                'ro-',
                markersize=7,
                markerfacecolor="red",
                markeredgewidth=2,
                markeredgecolor="black")

        #Cold source
        T_cond_c = r_[self.Condenser.Tin_c, self.Condenser.Tout_c]
        s_cond_c = r_[self.Condenser.sout_h / 1000,
                      self.Regenerator.sout_h / 1000]
        ax.plot(s_cond_c,
                T_cond_c,
                'bo-',
                markersize=7,
                markerfacecolor="blue",
                markeredgewidth=2,
                markeredgecolor="black")

        #     pylab.xticks([-1.8,-1.4,-1.0,-0.6,-0.2])
        plt.ylim([250, 450])
        plt.xlim([0.8, 2.0])

        plt.xlabel('Entropy [kJ/(kg$\cdot$K)]', fontsize=17)
        plt.ylabel('Temperature [K]', fontsize=17)
        plt.title(Inputs['Ref'], fontsize=17)

        for tickx in ax.xaxis.get_major_ticks():
            tickx.label.set_fontsize(20)
        for ticky in ax.yaxis.get_major_ticks():
            ticky.label.set_fontsize(20)

        print 'Saving T-s diagram ...'
        fig.savefig('Ts.png', dpi=600)