import numpy as np
import pandas as pd
import sys

sys.path.insert(0, dirName) # dirName = location where the files listed here are located
from psychClass import Psych
from heatTransClass import HeatTrans
from miscUncClass import MiscUnc
from heatTransAirUncClass import HeatTransAirUnc

def zsCalcs(df1,mData):
    '''Calculations for the zone simulators (emulators).'''
    ht = HeatTrans() # Create an instance of the heat transfer class
    ps = Psych() # Create an instance of the psychrometric class
    # Unit conversions for volumetric flow
    CFFlow = 0.0004719 # m3/s / cfm 
    CFGpm = 0.000063 # m3/s / gpm
 
    # Calculate humidity ratio and enthalpy at the inlet of the VAVs
    # Note: the humidity ratio at the inlet is the same as the humidity ratio at the outlet of the AHU
    df1['w_vav1_in'] = df1.w_ahu2_out
    df1['w_vav2_in'] = df1.w_ahu2_out
    df1['w_vav3_in'] = df1.w_ahu1_out
    df1['w_vav4_in'] = df1.w_ahu1_out
    df1['h_vav1_in'] = ps.enthalpy(np.array(df1.vav1_t_in),df1.w_vav1_in)
    df1['h_vav2_in'] = ps.enthalpy(np.array(df1.vav2_t_in),df1.w_vav2_in)
    df1['h_vav3_in'] = ps.enthalpy(np.array(df1.vav3_t_in),df1.w_vav3_in)
    df1['h_vav4_in'] = ps.enthalpy(np.array(df1.vav4_t_in),df1.w_vav4_in)
    # Calculate humidity ratio and enthalpy at the outlet of the VAVs
    # Note: the humidity ratio at the outlet is the same as the humidity ratio at the outlet of the AHU
    df1['w_vav1_out'] = df1.w_ahu2_out
    df1['w_vav2_out'] = df1.w_ahu2_out
    df1['w_vav3_out'] = df1.w_ahu1_out
    df1['w_vav4_out'] = df1.w_ahu1_out
    df1['h_vav1_out'] = ps.enthalpy(np.array(df1.vav1_out_rtd),df1.w_vav1_out)
    df1['h_vav2_out'] = ps.enthalpy(np.array(df1.vav2_out_rtd),df1.w_vav2_out)
    df1['h_vav3_out'] = ps.enthalpy(np.array(df1.vav3_out_rtd),df1.w_vav3_out)
    df1['h_vav4_out'] = ps.enthalpy(np.array(df1.vav4_out_rtd),df1.w_vav4_out)
    # Calculate humidity ratio at the inlet of the zone
    # Note: the humidity ratio at the inlet is the same as the humidity ratio at the outlet of the VAV
    df1['w_zs1_in'] = df1.w_vav1_out
    df1['w_zs2_in'] = df1.w_vav2_out
    df1['w_zs3_in'] = df1.w_vav3_out
    df1['w_zs4_in'] = df1.w_vav4_out
    # Estimate the mass flow rate of steam in the humidifier in the zone based on valve position, where 10 V is the max, 
    # and the manufacturer specified max flow rate. This calculation is very uncertain.
    m_dot_s_max = 0.000504 # [kg/s] 4 lb/hr
    df1['m_dot_s_1'] = df1.v14_pos_c/10*m_dot_s_max
    df1['m_dot_s_2'] = df1.v15_pos_c/10*m_dot_s_max
    df1['m_dot_s_3'] = df1.v16_pos_c/10*m_dot_s_max
    df1['m_dot_s_4'] = df1.v17_pos_c/10*m_dot_s_max
    h_w = 2659 # [kJ/kg] From EES T_w=temperature(Water,P=10 [psi]*convert(psi,kPa),x=0); h_w=enthalpy(Water,T=T_w,x=1)
    # Estimate the heat transfer from the injection of steam into the airflow. Very uncertain calculation.
    df1['q_st_1'] = h_w*df1.m_dot_s_1
    df1['q_st_2'] = h_w*df1.m_dot_s_2
    df1['q_st_3'] = h_w*df1.m_dot_s_3
    df1['q_st_4'] = h_w*df1.m_dot_s_4
    # Calculate the humidity ratio at the outlet of the zones using dry bulb temperature and relative humidity
    df1['w_zs1_out'] = ps.omega(np.array(df1.zs1_out_rtd),np.array(df1.zs1_rh),np.array(df1.indoor_p))
    df1['w_zs2_out'] = ps.omega(np.array(df1.zs2_out_rtd),np.array(df1.zs2_rh),np.array(df1.indoor_p))
    df1['w_zs3_out'] = ps.omega(np.array(df1.zs3_out_rtd),np.array(df1.zs3_rh),np.array(df1.indoor_p))
    df1['w_zs4_out'] = ps.omega(np.array(df1.zs4_out_rtd),np.array(df1.zs4_rh),np.array(df1.indoor_p))

    # Calculate the total heat transfer in the zone
    # kW,kgDA/s,kJ/kgDA,kJ/kgDA
    df1['q_zs1'],df1['m_dot_vav1'],df1['h_zs1_in'],df1['h_zs1_out'],df1['nu_vav1'] =\
            ht.qAirTotal(df1.vav1_out_rtd,df1.zs1_out_rtd,df1.vav1_f,df1.w_vav1_out,df1.w_zs1_out, \
                             df1.w_vav1_in,df1.vav1_t_in,df1.indoor_p,units = 'IP')
    df1['q_zs2'],df1['m_dot_vav2'],df1['h_zs2_in'],df1['h_zs2_out'],df1['nu_vav2'] = \
            ht.qAirTotal(df1.vav2_out_rtd,df1.zs2_out_rtd,df1.vav2_f,df1.w_vav2_out,df1.w_zs2_out, \
                             df1.w_vav2_in,df1.vav2_t_in,df1.indoor_p,units = 'IP')
    df1['q_zs3'],df1['m_dot_vav3'],df1['h_zs3_in'],df1['h_zs3_out'],df1['nu_vav3'] = \
            ht.qAirTotal(df1.vav3_out_rtd,df1.zs3_out_rtd,df1.vav3_f,df1.w_vav3_out,df1.w_zs3_out, \
                             df1.w_vav3_in,df1.vav3_t_in,df1.indoor_p,units = 'IP')
    df1['q_zs4'],df1['m_dot_vav4'],df1['h_zs4_in'],df1['h_zs4_out'],df1['nu_vav4'] = \
            ht.qAirTotal(df1.vav4_out_rtd,df1.zs4_out_rtd,df1.vav4_f,df1.w_vav4_out,df1.w_zs4_out, \
                             df1.w_vav4_in,df1.vav4_t_in,df1.indoor_p,units = 'IP')
                             
    # Calculate the total heat transfer in the VAV (this is just the reheat
    df1['q_vav1_heat'],_,df1['h_vav1_in'],df1['h_vav1_out'],_ = \
            ht.qAirTotal(df1.vav1_t_in,df1.vav1_out_rtd,df1.vav1_f,df1.w_vav1_in,df1.w_vav1_out, \
                             df1.w_vav1_in,df1.vav1_t_in,df1.indoor_p,units = 'IP')
    df1['q_vav2_heat'],_,df1['h_vav2_in'],df1['h_vav2_out'],_ = \
            ht.qAirTotal(df1.vav2_t_in,df1.vav2_out_rtd,df1.vav2_f,df1.w_vav2_in,df1.w_vav2_out, \
                             df1.w_vav2_in,df1.vav2_t_in,df1.indoor_p,units = 'IP')
    df1['q_vav3_heat'],_,df1['h_vav3_in'],df1['h_vav3_out'],_ = \
            ht.qAirTotal(df1.vav3_t_in,df1.vav3_out_rtd,df1.vav3_f,df1.w_vav3_in,df1.w_vav3_out, \
                             df1.w_vav3_in,df1.vav3_t_in,df1.indoor_p,units = 'IP')
    df1['q_vav4_heat'],_,df1['h_vav4_in'],df1['h_vav4_out'],_ = \
            ht.qAirTotal(df1.vav4_t_in,df1.vav4_out_rtd,df1.vav4_f,df1.w_vav4_in,df1.w_vav4_out, \
                             df1.w_vav4_in,df1.vav4_t_in,df1.indoor_p,units = 'IP')
    
    # Calculate the heat transfer at the heater in the zone - neglects the humidifier effect, so uncertain
    # kW,,,kJ/kgDA
    df1['q_zs1_h'],_,_,df1['h_zs1_h'],_ = ht.qAirTotal(df1.vav1_out_rtd,df1.zs1_heat_rtd,df1.vav1_f,df1.w_vav1_out,df1.w_vav1_out, \
                                                  df1.w_vav1_in,df1.vav1_t_in,df1.indoor_p,units = 'IP')
    df1['q_zs2_h'],_,_,df1['h_zs2_h'],_ = ht.qAirTotal(df1.vav2_out_rtd,df1.zs2_heat_rtd,df1.vav2_f,df1.w_vav2_out,df1.w_vav2_out, \
                                                  df1.w_vav2_in,df1.vav2_t_in,df1.indoor_p,units = 'IP')
    df1['q_zs3_h'],_,_,df1['h_zs3_h'],_ = ht.qAirTotal(df1.vav3_out_rtd,df1.zs3_heat_rtd,df1.vav3_f,df1.w_vav3_out,df1.w_vav3_out, \
                                                  df1.w_vav3_in,df1.vav3_t_in,df1.indoor_p,units = 'IP')
    df1['q_zs4_h'],_,_,df1['h_zs4_h'],_ = ht.qAirTotal(df1.vav4_out_rtd,df1.zs4_heat_rtd,df1.vav4_f,df1.w_vav4_out,df1.w_vav4_out, \
                                                  df1.w_vav4_in,df1.vav4_t_in,df1.indoor_p,units = 'IP')
                                                  
    # Calculate the overall sensible load - includes parasitic loads. This is the value used in the IBAL reports.
    # kW,kJ/kgDA,kJ/kgDA
    df1['q_zs1_sens'],df1['hSens_zs1_in'],df1['hSens_zs1_out'],_,_ = \
    ht.qSens(df1.w_vav1_in,df1.vav1_t_in,df1.indoor_p,df1.w_zs1_in,df1.vav1_out_rtd,df1.w_zs1_out,df1.zs1_out_rtd, \
              df1.vav1_f,'IP')
    df1['q_zs2_sens'],df1['hSens_zs2_in'],df1['hSens_zs2_out'],_,_ = \
    ht.qSens(df1.w_vav2_in,df1.vav2_t_in,df1.indoor_p,df1.w_zs2_in,df1.vav2_out_rtd,df1.w_zs2_out,df1.zs2_out_rtd, \
              df1.vav2_f,'IP')
    df1['q_zs3_sens'],df1['hSens_zs3_in'],df1['hSens_zs3_out'],_,_ = \
    ht.qSens(df1.w_vav3_in,df1.vav3_t_in,df1.indoor_p,df1.w_zs3_in,df1.vav3_out_rtd,df1.w_zs3_out,df1.zs3_out_rtd, \
              df1.vav3_f,'IP')
    df1['q_zs4_sens'],df1['hSens_zs4_in'],df1['hSens_zs4_out'],_,_ = \
    ht.qSens(df1.w_vav4_in,df1.vav4_t_in,df1.indoor_p,df1.w_zs4_in,df1.vav4_out_rtd,df1.w_zs4_out,df1.zs4_out_rtd, \
              df1.vav4_f,'IP')    
              
    # Calculate the overall latent load
    df1['q_zs1_lat'],_,_ = ht.qLatent(df1.vav1_f,df1.vav1_t_in,df1.w_vav1_in,df1.indoor_p,df1.w_vav1_out,df1.w_zs1_out,'IP')
    df1['q_zs2_lat'],_,_ = ht.qLatent(df1.vav2_f,df1.vav2_t_in,df1.w_vav2_in,df1.indoor_p,df1.w_vav2_out,df1.w_zs2_out,'IP')
    df1['q_zs3_lat'],_,_ = ht.qLatent(df1.vav3_f,df1.vav3_t_in,df1.w_vav3_in,df1.indoor_p,df1.w_vav3_out,df1.w_zs3_out,'IP')
    df1['q_zs4_lat'],_,_ = ht.qLatent(df1.vav4_f,df1.vav4_t_in,df1.w_vav4_in,df1.indoor_p,df1.w_vav4_out,df1.w_zs4_out,'IP')
    
    # Estimate the mass flow rate of the steam based on the difference between the latent load and steam; very uncertain
    df1['m_dot_st_1_est'] = (df1.q_zs1_lat - df1.q_st_1)/h_w
    df1['m_dot_st_2_est'] = (df1.q_zs2_lat - df1.q_st_2)/h_w
    df1['m_dot_st_3_est'] = (df1.q_zs3_lat - df1.q_st_3)/h_w
    df1['m_dot_st_4_est'] = (df1.q_zs4_lat - df1.q_st_4)/h_w
    
    # calculate differences between various points in the system
    df1['zs1_h_in'] = df1.zs1_heat_rtd - df1.vav1_out_rtd
    df1['zs2_h_in'] = df1.zs2_heat_rtd - df1.vav2_out_rtd
    df1['zs3_h_in'] = df1.zs3_heat_rtd - df1.vav3_out_rtd
    df1['zs4_h_in'] = df1.zs4_heat_rtd - df1.vav4_out_rtd
    df1['zs1_out_h'] = df1.zs1_out_rtd - df1.zs1_heat_rtd
    df1['zs2_out_h'] = df1.zs2_out_rtd - df1.zs2_heat_rtd
    df1['zs3_out_h'] = df1.zs3_out_rtd - df1.zs3_heat_rtd
    df1['zs4_out_h'] = df1.zs4_out_rtd - df1.zs4_heat_rtd
    df1['zs1_dt'] = df1.zs1_out_rtd - df1.vav1_out_rtd
    df1['zs2_dt'] = df1.zs2_out_rtd - df1.vav2_out_rtd
    df1['zs3_dt'] = df1.zs3_out_rtd - df1.vav3_out_rtd
    df1['zs4_dt'] = df1.zs4_out_rtd - df1.vav4_out_rtd
    df1['zs1_drh'] = df1.zs1_rh - df1.ahu2_rh_down
    df1['zs2_drh'] = df1.zs2_rh - df1.ahu2_rh_down
    df1['zs3_drh'] = df1.zs3_rh - df1.ahu1_rh_down
    df1['zs4_drh'] = df1.zs4_rh - df1.ahu1_rh_down
    df1['zs1_dw'] = df1.w_zs1_out - df1.w_zs1_in
    df1['zs2_dw'] = df1.w_zs2_out - df1.w_zs2_in
    df1['zs3_dw'] = df1.w_zs3_out - df1.w_zs3_in
    df1['zs4_dw'] = df1.w_zs4_out - df1.w_zs4_in
    df1['zs1_dh'] = df1.h_zs1_out - df1.h_zs1_in
    df1['zs2_dh'] = df1.h_zs2_out - df1.h_zs2_in
    df1['zs3_dh'] = df1.h_zs3_out - df1.h_zs3_in
    df1['zs4_dh'] = df1.h_zs4_out - df1.h_zs4_in
    df1['vav1_dt'] = df1.vav1_out_rtd - df1.vav1_t_in
    df1['vav2_dt'] = df1.vav2_out_rtd - df1.vav2_t_in
    df1['vav3_dt'] = df1.vav3_out_rtd - df1.vav3_t_in
    df1['vav4_dt'] = df1.vav4_out_rtd - df1.vav4_t_in
    df1['vav1_dw'] = df1.w_vav1_out - df1.w_vav1_in
    df1['vav2_dw'] = df1.w_vav2_out - df1.w_vav2_in
    df1['vav3_dw'] = df1.w_vav3_out - df1.w_vav3_in
    df1['vav4_dw'] = df1.w_vav4_out - df1.w_vav4_in
    df1['vav1_dh'] = df1.h_vav1_out - df1.h_vav1_in
    df1['vav2_dh'] = df1.h_vav2_out - df1.h_vav2_in
    df1['vav3_dh'] = df1.h_vav3_out - df1.h_vav3_in
    df1['vav4_dh'] = df1.h_vav4_out - df1.h_vav4_in
    df1['tmc1_dt'] = df1.tmc1_out_rtd - df1.tmc1_in_rtd
    df1['tmc2_dt'] = df1.tmc2_out_rtd - df1.tmc2_in_rtd
    df1['tmc3_dt'] = df1.tmc3_out_rtd - df1.tmc3_in_rtd
    df1['tmc4_dt'] = df1.tmc4_out_rtd - df1.tmc4_in_rtd
    df1['zs1_dq_sp'] = df1.q_zs1_sens - df1.zs1_heat_power/1000
    df1['zs2_dq_sp'] = df1.q_zs2_sens - df1.zs2_heat_power/1000
    df1['zs3_dq_sp'] = df1.q_zs3_sens - df1.zs3_heat_power/1000
    df1['zs4_dq_sp'] = df1.q_zs4_sens - df1.zs4_heat_power/1000
    df1['zs1_dq_spnorm'] = (df1.q_zs1_sens - df1.zs1_heat_power/1000)/(df1.zs1_heat_power/1000)
    df1['zs2_dq_spnorm'] = (df1.q_zs2_sens - df1.zs2_heat_power/1000)/(df1.zs2_heat_power/1000)
    df1['zs3_dq_spnorm'] = (df1.q_zs3_sens - df1.zs3_heat_power/1000)/(df1.zs3_heat_power/1000)
    df1['zs4_dq_spnorm'] = (df1.q_zs4_sens - df1.zs4_heat_power/1000)/(df1.zs4_heat_power/1000)
    
    # Calculate the AHU heat transfers with VAV flow data instead of AHU flow data    
    df1['q_ahu1_cc_vav'],df1['mDotAhu1VAV'],_,_,_ = \
            ht.qAHUAirTotal(df1.ahu1_heat_rtd,df1.ahu1_cc_rtd,df1.vav3_f,df1.vav4_f,
                            df1.w_ahu1_heat,df1.w_ahu1_cc,df1.w_vav3_in,df1.vav3_t_in,df1.w_vav4_in,
                            df1.vav4_t_in,df1.indoor_p,units = 'IP') # kW, kg/s, kJ/kg, kJ/kg    
    
    df1['q_ahu2_cc_vav'],df1['mDotAhu2VAV'],_,_,_  = \
            ht.qAHUAirTotal(df1.ahu2_heat_rtd,df1.ahu2_cc_rtd,df1.vav1_f,df1.vav2_f,
                            df1.w_ahu2_heat,df1.w_ahu2_cc,df1.w_vav1_in,df1.vav1_t_in,df1.w_vav2_in,
                            df1.vav2_t_in,df1.indoor_p,units = 'IP') # kW, kg/s, kJ/kg, kJ/kg 
    
    # Calculate undertainties of the heat transfer calculations neglecting cross terms
    uQAir = HeatTransAirUnc() # Create an instance of the heat transfer uncertainty class

    df1 = uQAir.uQsens('w_zs1_in','w_zs1_out','vav1_out_rtd','zs1_out_rtd','indoor_p',\
                       ['vav1_f'],'m_dot_vav1','nu_vav1',df1,mData,'_q_zs1',[],[],[],[],units = 'IP',cross = 0, k = 0)
    df1 = uQAir.uQsens('w_zs2_in','w_zs2_out','vav2_out_rtd','zs2_out_rtd','indoor_p',\
                       ['vav2_f'],'m_dot_vav2','nu_vav2',df1,mData,'_q_zs2',[],[],[],[],units = 'IP',cross = 0, k = 0)
    df1 = uQAir.uQsens('w_zs3_in','w_zs3_out','vav3_out_rtd','zs3_out_rtd','indoor_p',\
                       ['vav3_f'],'m_dot_vav3','nu_vav3',df1,mData,'_q_zs3',[],[],[],[],units = 'IP',cross = 0, k = 0)
    df1 = uQAir.uQsens('w_zs4_in','w_zs4_out','vav4_out_rtd','zs4_out_rtd','indoor_p',\
                       ['vav4_f'],'m_dot_vav4','nu_vav4',df1,mData,'_q_zs4',[],[],[],[],units = 'IP',cross = 0, k = 0)
    df1 = uQAir.uQlat('w_zs1_in','w_zs1_out','vav1_out_rtd','zs1_out_rtd','indoor_p',\
                       ['vav1_f'],'m_dot_vav1','nu_vav1',df1,mData,'_q_zs1',[],[],[],[],units = 'IP',cross = 0, k = 0)
    df1 = uQAir.uQlat('w_zs2_in','w_zs2_out','vav2_out_rtd','zs2_out_rtd','indoor_p',\
                       ['vav2_f'],'m_dot_vav2','nu_vav2',df1,mData,'_q_zs2',[],[],[],[],units = 'IP',cross = 0, k = 0)
    df1 = uQAir.uQlat('w_zs3_in','w_zs3_out','vav3_out_rtd','zs3_out_rtd','indoor_p',\
                       ['vav3_f'],'m_dot_vav3','nu_vav3',df1,mData,'_q_zs3',[],[],[],[],units = 'IP',cross = 0, k = 0)
    df1 = uQAir.uQlat('w_zs4_in','w_zs4_out','vav4_out_rtd','zs4_out_rtd','indoor_p',\
                       ['vav4_f'],'m_dot_vav4','nu_vav4',df1,mData,'_q_zs4',[],[],[],[],units = 'IP',cross = 0, k = 0)
    
    df1 = uQAir.uQ('w_ahu1_heat','w_ahu1_cc','ahu1_heat_rtd','ahu1_cc_rtd','h_ahu1_heat','h_ahu1_cc','indoor_p',\
             ['vav3_f','vav4_f'],'mDotAhu1VAV','nu_ahu1_cc',df1,mData,'q_ahu1_cc_vav',[],[],[],[],units = 'IP',cross = 0, k = 0) 
    df1 = uQAir.uQ('w_ahu2_heat','w_ahu2_cc','ahu2_heat_rtd','ahu2_cc_rtd','h_ahu2_heat','h_ahu2_cc','indoor_p',\
             ['vav1_f','vav2_f'],'mDotAhu2VAV','nu_ahu2_cc',df1,mData,'q_ahu2_cc_vav',[],[],[],[],units = 'IP',cross = 0, k = 0)   
    
    uM = MiscUnc() # Create an instance of the MiscUnc class
    powerMeas = ['zs1_heat_power','zs2_heat_power','zs3_heat_power','zs4_heat_power']
    # Calculate the uncertainty of the zone heater power measurements
    for pn in powerMeas:
        df1 = uM.uPower(df1,mData,pn)
        
    return df1