Ejemplo n.º 1
0
def poly_area(poly):
   
    '''
    From a list of points calculates the area of the polygon
    
    Parameters
    ----------
    poly : list of list of floats (polygon)
        list with three floats with the coordinates of the first point
 
    Returns
    -------
    float: the polygon area
    
    '''
    
    # Check input data type
    
    if not isinstance(poly, list):
        raise TypeError(f'ERROR poly_area function, the input is not a list: input {poly}')
    for vtx in poly:
        if not isinstance(vtx, list) and not isinstance(vtx, tuple):
            print(type(vtx))
            raise TypeError(f'ERROR poly_area function, an input is not a list: input {vtx}')
        if len(vtx) != 3:
            raise TypeError(f'ERROR poly_area function, a vertex is not a list of 3 components: input {vtx}')
        try:
            vtx = list(vtx)
            vtx[0] = float(vtx[0])
            vtx[1] = float(vtx[1])
            vtx[2] = float(vtx[2])
        except ValueError:
            raise ValueError(f'ERROR unit_normal function, a coordinate is not a float: input {vtx}')

    # area of polygon poly
    
    if len(poly) < 3:                                                          # Not a plane - no area
        wrn('WARNING number of vertices lower than 3, the area will be zero')
        return 0
    total = [0, 0, 0]
    N = len(poly)
    for i in range(N):
        vi1 = poly[i]
        vi2 = poly[(i+1) % N]
        prod = np.cross(vi1, vi2)
        total[0] += prod[0]
        total[1] += prod[1]
        total[2] += prod[2]
    result = np.dot(total, unit_normal(poly[0], poly[1], poly[2]))
    return float(abs(result/2))
Ejemplo n.º 2
0
def checkSatCond(T, x, p):
    '''
    Check Saturation Condition
    
    This function takes as inputs temperature [°C] and humidity ratio
    [kg_vap/kg_as] to check if a point is outside saturation conditions

    Parameters
    ----------
    T : float
        Temperature [°C]
    x : float
        Specific Humidity [kg_vap/kg_as].
    p : float
        Pressure [Pa].

    Returns
    -------
    Boolean, Saturation Pressure [Pa].
    
    '''

    # Check input data type

    if not isinstance(T, float):
        raise TypeError(f'ERROR input T is not an interger: T {T}')
    if not isinstance(x, float):
        raise TypeError(f'ERROR input x is not an interger: x {x}')

    # Control input data quality
    if T < -15 or T > 60:
        wrn(f"WARNING CheckSatCond function, input temperature outside limit boundary [-15,60]: T {T}"
            )
    if x < 0.0005 or x > 0.040:
        wrn(f"WARNING CheckSatCond function, input humidity outside limit boundary [0.0005,0.04]: x {x}"
            )

    # Is or not outide the saturation condition? True/False
    pp = p * x / (0.622 + x)
    if T < 0:
        psat = 610.5 * np.exp((21.875 * T) / (265.5 + T))
    else:
        psat = 610.5 * np.exp((17.269 * T) / (237.3 + T))
    if pp - psat > 0.01:
        SatCond = False
    else:
        SatCond = True
    return SatCond, psat
Ejemplo n.º 3
0
    def __init__(self, ExtRoofArea, l):
        '''
        Initilization of the photovoltaic plant
        
        Parameters
        ----------
        ExtRoofArea : float
            building's external roof area [m2]
        l : int
            number of simulation time steps [-]
        
        Returns
        -------
        None
        
        '''

        # Check input data

        if not isinstance(ExtRoofArea, float):
            raise TypeError(
                f'ERROR DistrictPVGIS class, ExtRoofArea is not a float: ExtRoofArea {ExtRoofArea}'
            )
        if not isinstance(l, int):
            raise TypeError(
                f'ERROR DistrictPVGIS class, l is not a int: l {l}')

        # Check input data quality

        if ExtRoofArea < 0:
            wrn(f"WARNING DistrictPVGIS class, input ExtRoofArea must be positive: ExtRoofArea {ExtRoofArea}"
                )
        if l < 0:
            wrn(f"WARNING DistrictPVGIS class, input l must be positive: l {l}"
                )

        # Total area and nominal power evaluation
        self.A_all = ExtRoofArea * self.area  # Total plant area [m2]
        self.P_nom = 1000 * self.A_all * self.etaNom  # Nominal power in Standard condition [W]

        # Output vectors initialization
        self.P = np.zeros(l)
        self.etaRel = np.zeros(l)
        self.FB = np.zeros(l)
        self.P_el = np.zeros(l)
        self.l = l
Ejemplo n.º 4
0
def PVGIS_production(tilt, GR, BR, DR, RR, Ta, W, P_nom, i):
    '''
    This function allows to calculate the photovoltaic electricity production
    
    Parameters
    ----------
    tilt : float
        inclination angle of the photovoltaic panel [°]
    GR : float
        global radiation on the oriented surface [W/m2]
    BR : float
        beam radiation on the oriented surface [W/m2]
    DR : float
        diffure radiation on the oriented surface [W/m2]
    RR : float
        reflected radiation on the oriented surfaces [W/m2]
    Ta : float
        external air temperature [°C]
    W : float
        wind speed [m/s]
    P_nom : float
        nominal power of the photovoltaic plant in Standard conditions
    i : float
        angle of incidence [°]
        
    Returns
    -------
    P : float
        electrical power production [W]
    etaRel : float
        plant relative efficiency [-]
    FB : float
        angular losses factor for beam radiation [-]
    
    '''

    # Check input data type

    if not isinstance(tilt, float):
        raise TypeError(
            f'ERROR PVGIS_production function, tilt is not a float: tilt {tilt}'
        )
    if not isinstance(GR, float):
        raise TypeError(
            f'ERROR PVGIS_production function, GR is not a float: GR {GR}')
    if not isinstance(BR, float):
        raise TypeError(
            f'ERROR PVGIS_production function, BR is not a float: BR {BR}')
    if not isinstance(DR, float):
        raise TypeError(
            f'ERROR PVGIS_production function, DR is not a float: DR {DR}')
    if not isinstance(RR, float):
        raise TypeError(
            f'ERROR PVGIS_production function, RR is not a float: RR {RR}')
    if not isinstance(Ta, float):
        raise TypeError(
            f'ERROR PVGIS_production function, Ta is not a float: Ta {Ta}')
    if not isinstance(W, float):
        raise TypeError(
            f'ERROR PVGIS_production function, W is not a float: W {W}')
    if not isinstance(P_nom, float):
        raise TypeError(
            f'ERROR PVGIS_production function, P_nom is not a float: P_nom {P_nom}'
        )
    if not isinstance(i, float):
        raise TypeError(
            f'ERROR PVGIS_production function, i is not a float: i {i}')

    # Check input data quality

    if not 0 <= GR <= 3000:
        wrn(f"WARNING PVGIS_production function, input GR is out of plausible range: GR {GR}"
            )
    if not 0 <= BR <= 3000:
        wrn(f"WARNING PVGIS_production function, input BR is out of plausible range: BR {BR}"
            )
    if not 0 <= DR <= 3000:
        wrn(f"WARNING PVGIS_production function, input DR is out of plausible range: DR {DR}"
            )
    if not 0 <= RR <= 3000:
        wrn(f"WARNING PVGIS_production function, input RR is out of plausible range: RR {RR}"
            )
    if not -50 <= Ta <= 60:
        wrn(f"WARNING PVGIS_production function, input Ta is out of plausible range: Ta {Ta}"
            )
    if not 0 <= W <= 25:
        wrn(f"WARNING PVGIS_production function, input W is out of plausible range: W {W}"
            )

    # Degree to radians conversion
    i = np.radians(i)
    tiltrad = np.radians(tilt)

    # Angular losses calculation (N. Martin and JM. Ruiz)
    ar = 0.157  # Reference value for Air/Glass/Silicon
    c1 = 4 / (3 * np.pi)
    c2 = -0.074  # Reference value for Air/Glass/Silicon

    FB = (np.exp(-np.cos(i) / ar) - np.exp(-1 / ar)) / (1 - np.exp(-1 / ar))
    FD = np.exp(-1 / ar *
                (c1 * (np.sin(tiltrad) +
                       (np.pi - tilt * np.pi / 180 - np.sin(tiltrad)) /
                       (1 + np.cos(tiltrad))) + c2 *
                 (np.sin(tiltrad) +
                  (np.pi - tilt * np.pi / 180 - np.sin(tiltrad)) /
                  (1 + np.cos(tiltrad)))**2))
    FA = np.exp(-1 / ar *
                (c1 *
                 (np.sin(tiltrad) + (tilt * np.pi / 180 - np.sin(tiltrad)) /
                  (1 - np.cos(tiltrad))) + c2 *
                 (np.sin(tiltrad) + (tilt * np.pi / 180 - np.sin(tiltrad)) /
                  (1 - np.cos(tiltrad)))**2))

    # Setting curve coefficients (Reference values for c-Si modules)
    k1 = -0.017237
    k2 = -0.040465
    k3 = -0.004702
    k4 = 0.000149
    k5 = 0.000170
    k6 = 0.000005

    # Module temperature evaluation (c-Si modules)
    U0 = 26.92
    U1 = 6.24
    Tm = Ta + GR / (U0 + U1 * W)  # Module temperature [°C]
    tm = Tm - 25

    # Relative efficiency and power production calculation
    g = GR / 1000
    if g == 0:
        etaRel = 0
    else:
        etaRel = 1 + k1 * np.log(g) + k2 * np.log(
            g)**2 + k3 * tm + k4 * tm * np.log(g) + k5 * tm * np.log(
                g)**2 + k6 * tm**2
    P = 1 / 1000 * P_nom * etaRel * (BR * (1 - FB) + DR * (1 - FD) + RR *
                                     (1 - FA))  # [W]
    if P < 0:
        P = 0
    return P, etaRel, FB  # Output variables
Ejemplo n.º 5
0
    def AHUCalc(self, t, G_da_vent, AHUOnOff, AHUHUM, Sens_Recovery_eff,
                Lat_Recovery_eff, OutAirRatio, T_ext, x_ext, T_int, x_int,
                T_sup, x_sup):
        '''
        Solution for the single time step of the Air Handling Unit
        
        Parameters:
            t: timestep [-]
            G_da_vent: mass flow rate [kg/s]
            AHUOnOff: AHU availabilty [-]
            AHUHUM: Humidistat availability [-]
            SensRecoveryEff: Sensible heat recovery efficiency [-]
            LatRecoveryEff: Latent heat recovery efficiency [-]
            OutAirRatio: Outdoor air ratio [-]
            T_ext: external temperature [°C]
            x_ext: external specific humidity [kg_v/kg_da]
            T_int: zone internal temperature [°C]
            x_int: zone internal specific humidity [kg_v/kg_da]
            T_sup: supply temperature [°C]
            x_sup: supplyspecific humidity [kg_v/kg_da]
            
        Returns:
            None
        '''

        # Check input data type

        if not isinstance(t, int):
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input t is not an interger: t {t}'
            )
        if (not isinstance(G_da_vent, float)) or G_da_vent < 0:
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input G_da_vent is not a positive float: G_da_vent {G_da_vent}'
            )
        if not AHUOnOff in [0, 1, -1]:
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input AHUOnOff must be 0,1,-1: AHUOnOff {AHUOnOff}'
            )
        if not isinstance(AHUHUM, bool):
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input AHUHUM is not a boolean: AHUHUM {AHUHUM}'
            )
        if (not isinstance(Sens_Recovery_eff, float)
            ) or Sens_Recovery_eff < 0. or Sens_Recovery_eff > 1.:
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input Sens_Recovery_eff must be included in the range 0-1: Sens_Recovery_eff {Sens_Recovery_eff}'
            )
        if (not isinstance(Lat_Recovery_eff, float)
            ) or Lat_Recovery_eff < 0. or Lat_Recovery_eff > 1.:
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input Lat_Recovery_eff must be included in the range 0-1: Lat_Recovery_eff {Lat_Recovery_eff}'
            )
        if (not isinstance(OutAirRatio,
                           float)) or OutAirRatio < 0. or OutAirRatio > 1.:
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input OutAirRatio must be included in the range 0-1: OutAirRatio {OutAirRatio}'
            )
        if not isinstance(T_ext, float):
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input T_ext is not an interger: T_ext {T_ext}'
            )
        if not isinstance(T_int, float):
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input T_int is not an interger: T_int {T_int}'
            )
        if not isinstance(T_sup, float):
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input T_sup is not an interger: T_sup {T_sup}'
            )
        if not isinstance(x_ext, float):
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input x_ext is not an interger: x_ext {x_ext}'
            )
        if not isinstance(x_int, float):
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input x_int is not an interger: x_int {x_int}'
            )
        if not isinstance(x_sup, float):
            raise TypeError(
                f'ERROR AHUCalc, bd {self.bd_name}, time step {t}, input x_sup is not an interger: x_sup {x_sup}'
            )

        # Control input data quality

        if T_ext < -15 or T_ext > 60:
            wrn(f"WARNING AHU class, AHUCalc method, bd {self.bd_name}, time step {t}, input temperature outside limit boundary [-15,60]: T_ext {T_ext}"
                )
        if T_int < -15 or T_int > 60:
            wrn(f"WARNING AHU class, AHUCalc method, bd {self.bd_name}, time step {t}, input temperature outside limit boundary [-15,60]: T_int {T_int}"
                )
        if T_sup < -15 or T_sup > 60:
            wrn(f"WARNING AHU class, AHUCalc method, bd {self.bd_name}, time step {t}, input temperature outside limit boundary [-15,60]: T_sup {T_sup}"
                )
        if x_ext < 0.0005 or x_ext > 0.040:
            wrn(f"WARNING AHU class, AHUCalc method, bd {self.bd_name}, time step {t}, input humidity outside limit boundary [0.0005,0.04]: x_ext {x_ext}"
                )
        if x_int < 0.0005 or x_int > 0.040:
            wrn(f"WARNING AHU class, AHUCalc method, bd {self.bd_name}, time step {t}, input humidity outside limit boundary [0.0005,0.04]: x_int {x_int}"
                )
        if x_sup < 0.0005 or x_sup > 0.040:
            wrn(f"WARNING AHU class, AHUCalc method, bd {self.bd_name}, time step {t}, input humidity outside limit boundary [0.0005,0.04]: x_sup {x_sup}"
                )

        # Set some input variables

        self.T_supAHU[t] = T_sup
        self.x_sup = x_sup

        # Saturation conditions check
        SatCond, psat = checkSatCond(T_ext, x_ext, self.p_atm)
        if SatCond == False:
            x_ext = 0.99 * 0.622 * psat / (self.p_atm - 0.99 * psat)
            if AHUOnOff == 0:
                self.x_sup = x_ext
        SatCond, psat = checkSatCond(T_int, x_int, self.p_atm)
        if SatCond == False:
            wrn(f'ERROR  AHUCalc method, bd {self.bd_name}, time step {t}, Zone conditions outside saturation limit'
                )
        SatCond, psat = checkSatCond(self.T_supAHU[t], self.x_sup, self.p_atm)
        if SatCond == False:
            wrn(f'ERROR:  AHUCalc method, bd {self.bd_name}, time step {t}, Supply conditions outside saturation limit'
                )

        # Pre-processing on Heat Recovery and Mixer
        self.h_ext = self.cp_air * T_ext + (self.r_0 +
                                            self.cpv * T_ext) * x_ext
        self.h_z = self.cp_air * T_int + (self.r_0 + self.cpv * T_int) * x_int

        # Heat Recovery Bypass in condition of free heating or cooling
        if (T_int - T_ext) * AHUOnOff > 0:
            self.T_hr = T_ext + Sens_Recovery_eff * (T_int - T_ext)
            self.T_out = T_int - Sens_Recovery_eff * (T_int - T_ext)
        else:
            self.T_hr = T_ext
            self.T_out = T_int
            OutAirRatio = 1
        if (x_int - x_ext) * AHUOnOff > 0:
            self.x_hr = x_ext + Lat_Recovery_eff * (x_int - x_ext)
        else:
            self.x_hr = x_ext
        self.h_hr = self.cp_air * self.T_hr + (
            self.r_0 + self.cpv * self.T_hr) * self.x_hr

        # Mixer
        self.h_mix = OutAirRatio * self.h_hr + (1 - OutAirRatio) * self.h_z
        self.x_mix = OutAirRatio * self.x_hr + (1 - OutAirRatio) * x_int
        self.T_mix = (self.h_mix - self.r_0 * self.x_mix) / (
            self.cp_air + self.cpv * self.x_mix)

        # BATTERIES DEMAND CALCULATION

        # SENSIBLE AND LATENT CONTROL MODE
        if AHUHUM == True:

            # Heating mode
            if AHUOnOff == 1:

                # Adiabatic Saturator
                self.x_as = self.x_sup
                p_as = self.p_atm * self.x_as / (0.622 + self.x_as)
                if p_as >= 610.5:
                    self.T_as = 237.3 * np.log(
                        p_as / 610.5) / (17.269 - np.log(p_as / 610.5))
                else:
                    self.T_as = 265.5 * np.log(
                        p_as / 610.5) / (21.875 - np.log(p_as / 610.5))
                self.h_as = self.cp_air * self.T_as + (
                    self.r_0 + self.cpv * self.T_as) * self.x_as

                # Pre-Heater control
                if self.h_mix < self.h_as:
                    self.h_ph = self.h_as
                    self.x_ph = self.x_mix
                    self.T_ph = (self.h_ph - self.r_0 * self.x_ph) / (
                        1.006 + self.cpv * self.x_ph)
                else:
                    # In this case the Pre-Heater is by-passed
                    self.h_ph = self.h_mix
                    self.x_ph = self.x_mix
                    self.T_ph = self.T_mix
                self.h_as = self.h_ph

                # Humidification need check
                if self.x_ph > self.x_sup:
                    self.x_as = self.x_ph
                    self.x_sup = self.x_as
                    self.T_as = (self.h_as - self.r_0 * self.x_as) / (
                        self.cp_air + self.cpv * self.x_as)

                # Controlling T_supAHU > T_as
                if self.T_supAHU[t] < self.T_as:
                    self.T_supAHU[t] = self.T_as
                self.h_sup = self.cp_air * self.T_supAHU[t] + (
                    self.r_0 + self.cpv * self.T_supAHU[t]) * self.x_sup

                # Batteries Demand [kW]
                # Pre-Heater
                preh_Dem = G_da_vent * (self.h_ph - self.h_mix)
                preh_Dem_sens = G_da_vent * self.cp_air * (self.T_ph -
                                                           self.T_mix)
                preh_Dem_lat = G_da_vent * self.r_0 * (self.x_ph - self.x_mix)
                # Adiabatic Saturator
                sat_Dem = G_da_vent * (self.h_as - self.h_ph)
                sat_Dem_lat = G_da_vent * self.r_0 * (self.x_as - self.x_ph)
                sat_Dem_sens = sat_Dem - sat_Dem_lat
                # Post-Heater
                posth_Dem = G_da_vent * (self.h_sup - self.h_as)
                posth_Dem_sens = G_da_vent * self.cp_air * (self.T_supAHU[t] -
                                                            self.T_as)
                posth_Dem_lat = G_da_vent * self.r_0 * (self.x_sup - self.x_as)
                # Total Demand
                self.AHUDemand[t] = preh_Dem + sat_Dem + posth_Dem
                self.AHUDemand_sens[
                    t] = preh_Dem_sens + sat_Dem_sens + posth_Dem_sens
                self.AHUDemand_lat[
                    t] = preh_Dem_lat + sat_Dem_lat + posth_Dem_lat

                # Cooling mode
            elif AHUOnOff == -1:

                # Dehumidificator
                self.x_de = self.x_sup
                p_de = self.p_atm * self.x_de / (0.622 + self.x_de)
                if p_de >= 610.5:
                    self.T_de = 237.3 * np.log(
                        p_de / 610.5) / (17.269 - np.log(p_de / 610.5))
                else:
                    self.T_de = 265.5 * np.log(
                        p_de / 610.5) / (21.875 - np.log(p_de / 610.5))

                # Dehumidifcator and post-heater control
                if self.x_de >= self.x_mix:
                    self.x_de = self.x_mix
                    self.x_sup = self.x_de
                    if self.T_supAHU[t] <= self.T_mix:
                        self.T_de = self.T_supAHU[t]
                    else:
                        self.T_de = self.T_mix
                        self.T_supAHU[t] = self.T_de
                self.h_de = self.cp_air * self.T_de + (
                    self.r_0 + self.cpv * self.T_de) * self.x_de
                self.h_sup = self.cp_air * self.T_supAHU[t] + (
                    self.r_0 + self.cpv * self.T_supAHU[t]) * self.x_sup

                # Batteries Demand [kW]
                # Dehumidificator
                deu_Dem = G_da_vent * (self.h_de - self.h_mix)
                deu_Dem_sens = G_da_vent * self.cp_air * (self.T_de -
                                                          self.T_mix)
                deu_Dem_lat = G_da_vent * self.r_0 * (self.x_de - self.x_mix)
                # Post-Heater
                posth_Dem = G_da_vent * (self.h_sup - self.h_de)
                posth_Dem_sens = G_da_vent * self.cp_air * (self.T_supAHU[t] -
                                                            self.T_de)
                posth_Dem_lat = G_da_vent * self.r_0 * (self.x_sup - self.x_de)
                # Total Demand
                self.AHUDemand[t] = deu_Dem + posth_Dem
                self.AHUDemand_sens[t] = deu_Dem_sens + posth_Dem_sens
                self.AHUDemand_lat[t] = deu_Dem_lat + posth_Dem_lat

            elif AHUOnOff == 0:

                # Plant Off
                self.T_hr, self.T_mix, self.T_supAHU[t] = T_ext, T_ext, T_ext
                self.x_hr, self.x_mix, self.x_sup = x_ext, x_ext, x_ext
                self.h_hr, self.h_mix, self.h_sup = self.h_ext, self.h_ext, self.h_ext

                # Batteries Demand [kW]
                self.AHUDemand[t] = 0
                self.AHUDemand_sens[t] = 0
                self.AHUDemand_lat[t] = 0

            else:
                print('AHUOnOff value not allowed')

        # SENSIBLE CONTROL MODE
        if AHUHUM == False:

            # Heating mode
            if AHUOnOff == 1:

                # Pre-Heater and Adiabatic Saturator doesn't exist!!
                self.h_ph = self.h_mix
                self.x_ph = self.x_mix
                self.T_ph = self.T_mix
                self.h_as = self.h_ph
                self.x_as = self.x_ph
                self.T_as = self.T_ph

                # Post-Heater
                if self.T_supAHU[t] < self.T_as:
                    self.T_supAHU[t] = self.T_as

                self.x_sup = self.x_as
                self.h_sup = self.cp_air * self.T_supAHU[t] + (
                    self.r_0 + self.cpv * self.T_supAHU[t]) * self.x_sup

                # Batteries Demand [kW]
                self.AHUDemand[t] = G_da_vent * self.cp_air * (
                    self.T_supAHU[t] - self.T_as)
                self.AHUDemand_sens[t] = self.AHUDemand[t]
                self.AHUDemand_lat[t] = 0

            elif AHUOnOff == -1:
                # Cooling mode

                if self.T_supAHU[t] > self.T_mix:
                    self.T_supAHU[t] = self.T_mix
                    self.x_sup = self.x_mix
                    self.h_sup = self.h_mix
                else:
                    SatCond, psat = checkSatCond(self.T_supAHU[t], self.x_mix,
                                                 self.p_atm)
                    if SatCond == False:
                        # print('Info: supply temperature is too low -- changed')

                        if self.T_supAHU[t] < 0:
                            p_sat = 610.5 * np.exp(
                                (21.875 * self.T_supAHU[t]) /
                                (265.5 + self.T_supAHU[t]))
                        else:
                            p_sat = 610.5 * np.exp(
                                (17.269 * self.T_supAHU[t]) /
                                (237.3 + self.T_supAHU[t]))
                        self.x_sup = 0.99 * 0.622 * p_sat / (self.p_atm -
                                                             0.99 * p_sat)
                        self.h_sup = self.cp_air * self.T_supAHU[t] + (
                            self.r_0 +
                            self.cpv * self.T_supAHU[t]) * self.x_sup
                    else:
                        self.x_sup = self.x_mix
                        self.h_sup = self.cp_air * self.T_supAHU[t] + (
                            self.r_0 +
                            self.cpv * self.T_supAHU[t]) * self.x_sup

                #  Batteries Demand [kW]
                self.AHUDemand[t] = G_da_vent * (self.h_sup - self.h_mix)
                self.AHUDemand_sens[t] = self.AHUDemand[t]
                self.AHUDemand_lat[t] = 0

            elif AHUOnOff == 0:
                # Plant OFF

                self.T_hr, self.T_mix, self.T_supAHU[t] = T_ext, T_ext, T_ext
                self.x_hr, self.x_mix, self.x_sup = x_ext, x_ext, x_ext
                self.h_hr, self.h_mix, self.h_sup = self.h_ext, self.h_ext, self.h_ext

                # Batteries Demand [kW]
                self.AHUDemand[t] = 0
                self.AHUDemand_sens[t] = 0
                self.AHUDemand_lat[t] = 0

            else:
                sys.exit('AHUOnOff value not allowed at time step: ' + str(t))
Ejemplo n.º 6
0
    def __init__(self,name,azSubdiv,hSubdiv,wwr,rh_gross,vertList=[[0,0,0],[0,0,0],[0,0,0]],surfType='ExtWall'):
        
        '''
        input:
            list of vertices: [[x1,y1,z1],[x2,y2,z2],[x3,y3,z3],..]
            typology: one of these strings: 'ExtWall','Roof','GroundFloor'

        complanarity:
            https://www.geeksforgeeks.org/program-to-check-whether-4-points-in-a-3-d-plane-are-coplanar/

        the area is calculated from:
            https://stackoverflow.com/questions/12642256/python-find-area-of-polygon-from-xyz-coordinates
        
        Parameters
            ----------
            name : string
                name of the surface
            azSubdiv: int
                number of azimuth subdivision
            hSubdiv: int
                number of tilt subdivision
            wwr : list of floats
                four floats with the window to wall ratio (N E S W)
            rh_gross : float
                multiplicator of the surface area
            vertList : list of list of floats (polygon)
                list with n lists of three floats (n vertices)
            surfType : string
                string that defines the surface type.
                'ExtWall' or 'GroundFloor' or 'Roof' 
                
        Returns
        -------
        None.        
        
        '''

        # Check input data type
        
        if not isinstance(name, str):
            raise TypeError(f'ERROR Surface class geometry, name is not a string: name {name}') 
        if not isinstance(azSubdiv, int):
            raise TypeError(f'ERROR Surface class geometry, azSubdiv is not a int: azSubdiv {azSubdiv}') 
        if not isinstance(hSubdiv, int):
            raise TypeError(f'ERROR Surface class geometry, azSubdiv is not a int: azSubdiv {hSubdiv}') 
        if not isinstance(wwr, list) or not isinstance(wwr[0], float) or not isinstance(wwr[1], float) or not isinstance(wwr[2], float) or not isinstance(wwr[3], float):
            raise TypeError(f'ERROR Surface class geometry, wwr is not a list of floats: wwr {wwr}') 
        if not isinstance(rh_gross, float):
            raise TypeError(f'ERROR Surface class geometry, rh_gross is not a float: rh_gross {rh_gross}') 
        if not surfType in ['ExtWall' , 'GroundFloor' , 'Roof' ]:
            raise TypeError(f'ERROR Surface class geometry, surfType is not a correct string: surfType {surfType}')
            
        if not isinstance(vertList, list):
            raise TypeError(f'ERROR Surface class geometry , the input is not a list: input {vertList}')
        for vtx in vertList:
            if not isinstance(vtx, list):
                raise TypeError(f'ERROR Surface class geometry, an input is not a list: input {vtx}')
            if len(vtx) != 3:
                raise TypeError(f'ERROR Surface class geometry, a vertex is not a list of 3 components: input {vtx}')
            try:
                vtx[0] = float(vtx[0])
                vtx[1] = float(vtx[1])
                vtx[2] = float(vtx[2])
            except ValueError:
                raise ValueError(f'ERROR Surface class geometry, a coordinate is not a float: input {vtx}')          

        # Check input data quality
        
        if azSubdiv > 10 or hSubdiv > 5:
            wrn(f"WARNING Surface class, init, solar calculation could be long..... azSubdiv {azSubdiv}, hSubdiv {hSubdiv}")
        for wwr_ in wwr:
            if wwr_ < 0. or wwr_ > 0.9:
                wrn(f"WARNING Surface class, init, are you sure about the window to wall ratio ? wwr {wwr}")
        if rh_gross < 0.5 or rh_gross > 1.5:
            wrn(f"WARNING Surface class, init, are you sure about the external walls multiplication coeff?? rh_gross {rh_gross}")
           
        self.name = name

        # Check coplanarity

        if not check_complanarity(vertList):
            print('surface points not planar')
            self.type = '--'
            self.area = 0.
            self.normal = 0.
            self.height = 0.
            self.azimuth = 0.
            return
        
        self.OnOff_shading = 'Off'
        self.type = surfType
        self.vertList = vertList
        
        # Area calculation
        
        self.area = poly_area(self.vertList)
        if self.area == 0.:
            self.area = 0.0000001
        
        '''
        Considering only three points in calculating the normal vector could create
        reverse orientations if the three points are in a non-convex angle of the surface

        for this reason theres an alternative way to calculate the normal,
        implemented in function: normalAlternative

        reference: https://stackoverflow.com/questions/32274127/how-to-efficiently-determine-the-normal-to-a-polygon-in-3d-space
        '''
        
        #self.normal = unit_normal(self.vertList[0], self.vertList[1], self.vertList[2])
        self.normal = normalAlternative(self.vertList)

        # set the azimuth and zenith

        if self.normal[2] == 1:
            self.height = 0
            self.azimuth = 0
        elif self.normal[2] == -1:
            self.height= 180
            self.azimuth = 0
        else:
            self.height = 90 - np.degrees(np.arctan((self.normal[2]/(np.sqrt(self.normal[0]**2+self.normal[1]**2)))))
            if self.normal[1] == 0:
                if self.normal[0] > 0:
                    self.azimuth = -90
                elif self.normal[0] < 0:
                    self.azimuth = 90
            else:
                if self.normal[1]<0:
                    self.azimuth = np.degrees(np.arctan(self.normal[0]/self.normal[1]))
                else:
                    if self.normal[0] < 0:
                        self.azimuth = 180 + np.degrees(np.arctan(self.normal[0]/self.normal[1]))
                    else:
                        self.azimuth = -180 + np.degrees(np.arctan(self.normal[0]/self.normal[1]))
        
        # Set surface inclination
        
        if self.height < 40:
            self.type = 'Roof'
        if self.height > 150:
            self.type = 'GroundFloor'
        if self.type == 'ExtWall':
            self.area = self.area*rh_gross
        
        # Azimuth and tilt approximation 
        
        delta_a = 360/(2*azSubdiv)
        delta_h = 90/(2*hSubdiv)
        x = np.arange(-delta_h,90+2*delta_h,2*delta_h)
        
        for n in range(len(x)-1):
            if self.height >= x[n] and self.height < x[n+1]:
                self.height_round = int((x[n]+x[n+1])/2)
                self.F_r = (1+np.cos(np.radians(self.height_round)))/2                                                          
            elif self.height >= x[-1] and self.height < 150:
                self.height_round = 90
                self.F_r = (1+np.cos(np.radians(self.height_round)))/2
            else:
                self.height_round = 0                                          # Only to avoid errors           
                
        y = np.arange(-180-delta_a,180+2*delta_a,2*delta_a)
        for n in range(len(y)-1):
            if self.azimuth >= y[n] and self.azimuth < y[n+1]:
                self.azimuth_round = int((y[n]+y[n+1])/2)
                if self.azimuth_round == 180:
                    self.azimuth_round = -180
                    
        if self.height_round == 0:
            self.azimuth_round = 0
        
        # Set the window area
        
        if self.type == 'ExtWall':
            self.centroid_coord = centroid(vertList)
            if 135 < self.azimuth_round <= 180 or -180 <= self.azimuth_round < -135:
                self.wwr = wwr[0]
            elif -135 <= self.azimuth_round <= -45:
                self.wwr = wwr[1]
            elif -45 < self.azimuth_round < 45:
                self.wwr = wwr[2]
            elif 45 <= self.azimuth_round <= 135:
                self.wwr = wwr[3]
        else:
            self.wwr = 0
            
        self.opaqueArea = (1-self.wwr)*self.area
        self.glazedArea = (self.wwr)*self.area
        if self.glazedArea == 0:
            self.glazedArea = 0.0000001                                        #Avoid zero division
        if self.opaqueArea == 0:
            self.opaqueArea = 0.0000001                                        #Avoid zero division
Ejemplo n.º 7
0
    def __init__(self,
                 epw_name,
                 input_path='.',
                 tz='Europe/Rome',
                 year=2020,
                 ts=2,
                 hours=8760,
                 n_years=1,
                 irradiances_calc=True,
                 azSubdiv=8,
                 hSubdiv=3,
                 shad_tol=[80., 100., 80.]):
        '''
        initialize weather obj
        It processes the epw file to extract arrays of temperature, wind, humidity etc......
    
        Parameters
        ----------
        epw_name : str
            path of the epw file.
        input_path : str
            path of the Input files.
        tz : str
            this is the time zone. For a list of the avilable see: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
        year : int 
            the year of simulation. it is used only to create a pd.DataFrame.
        ts : int
            number of time steps in a hour.
        hours : int 
            number of hours
        n_years : int
            number of years of sim
        azSubdiv: int
            number of the different direction (azimuth) solar radiation will be calculated
        hSubdiv: int
            number of the different direction (solar height) solar radiation will be calculated      
        shad_tol: list of floats
            list of the tollerances for urban shading calc (azimuth, disance, theta)
            
        Returns
        -------
        None
        '''

        # Check input data type

        if not isinstance(epw_name, str):
            raise TypeError(
                f'ERROR Weather object, init, input epw_file is not a string: epw_file {epw_name}'
            )
        if not isinstance(input_path, str):
            raise TypeError(
                f'ERROR Weather object, init, input input_path is not a string: input_path {input_path}'
            )
        if not isinstance(tz, str):
            raise TypeError(
                f'ERROR Weather object, init, input tz is not a string: tz {tz}'
            )
        if not isinstance(year, int):
            try:
                year = int(year)
            except:
                raise TypeError(
                    f'ERROR Weather object, init, input year is not an int: year {year}'
                )
        if not isinstance(ts, int):
            try:
                ts = int(ts)
            except:
                raise TypeError(
                    f'ERROR Weather object, init, input ts is not an int: ts {ts}'
                )
        if not isinstance(hours, int):
            try:
                hours = int(hours)
            except:
                raise TypeError(
                    f'ERROR Weather object, init, input hours is not an int: hours {hours}'
                )
        if not isinstance(n_years, int):
            try:
                n_years = int(n_years)
            except:
                raise TypeError(
                    f'ERROR Weather object, init, input n_years is not an int: n_years {n_years}'
                )
        if not isinstance(azSubdiv, int):
            raise TypeError(
                f'ERROR Weather object, init, input azSubdiv is not an integer: azSubdiv {azSubdiv}'
            )
        if not isinstance(hSubdiv, int):
            raise TypeError(
                f'ERROR Weather object, init, input hSubdiv is not an integer: hSubdiv {hSubdiv}'
            )
        if not isinstance(shad_tol, list):
            raise TypeError(
                f'ERROR Weather object, init, input shad_tol is not list: shad_tol {shad_tol}'
            )
        if not isinstance(shad_tol[0], float) or not isinstance(
                shad_tol[1], float) or not isinstance(shad_tol[2], float):
            try:
                shad_tol[0] = float(shad_tol[0])
                shad_tol[1] = float(shad_tol[1])
                shad_tol[2] = float(shad_tol[2])
            except:
                raise TypeError(
                    f'ERROR Weather object, init, input shad_tol is not a list of floats: shad_tol {shad_tol}'
                )

        # Check input data quality

        if ts > 4:
            wrn(f"WARNING Weather object, init,  input ts is higher than 4, this means more than 4 time steps per hours were set: ts {ts}"
                )
        if azSubdiv > 10 or hSubdiv > 5:
            wrn(f"WARNING Weather object, init,  solar calculation could be long..... azSubdiv {azSubdiv}, hSubdiv {hSubdiv}"
                )
        if shad_tol[0] < 0.0 or shad_tol[0] > 90.0:
            wrn(f"WARNING Weather object, init,  toll_az is out of range [0-90]..... toll_az {shad_tol[0]}"
                )
        if shad_tol[1] < 0.0 or shad_tol[1] > 200.0:
            wrn(f"WARNING Weather object, init,  toll_dist is out of range [0-200]..... toll_dist {shad_tol[1]}"
                )
        if shad_tol[2] < 0.0 or shad_tol[2] > 90.0:
            wrn(f"WARNING Weather object, init,  toll_theta is out of range [0-90]..... toll_theta {shad_tol[2]}"
                )

        epw_file = os.path.join(input_path, epw_name)

        # Importing and processing weather data from .epw
        try:
            epw = pvlib.iotools.read_epw(
                epw_file, coerce_year=year)  # Reading the epw via pvlib
        except FileNotFoundError:
            raise FileNotFoundError(
                f"ERROR Weather epw file not found in the Input folder: epw name {epw_name}, input folder {input_path}"
            )

        epw_res = epw[0].reset_index(drop=True)  # Exporting the hourly values
        lat, lon = epw[1]['latitude'], epw[1][
            'longitude']  # Extracting latitude and longitude from the epw
        site = pvlib.location.Location(lat, lon,
                                       tz=tz)  # Creating a location variable
        time = np.arange(8760)  # Time vector inizialization

        # Weather Data and Average temperature difference between Text and Tsky
        w = epw_res['wind_speed']  # [m/s]
        T_ext = epw_res['temp_air']  # [°C]
        T_ext_H_avg = np.mean([T_ext[0:2160], T_ext[6599:8759]])  # [°C]
        RH_ext = epw_res['relative_humidity'] / 100  # [0-1]
        T_dp = epw_res['temp_dew']  # [°C]
        P_ = epw_res['atmospheric_pressure']  # [Pa]
        n_opaque = epw_res['opaque_sky_cover']  # [0-10]
        dT_er = TskyCalc(
            T_ext, T_dp, P_,
            n_opaque)  # Average temperature difference between Text and Tsky
        w, T_ext, RH_ext, T_dp, P_, n_opaque = rescale_weather(
            ts, w, T_ext, RH_ext, T_dp, P_, n_opaque)
        Solar_position = site.get_solarposition(
            times=epw[0].index).reset_index(drop=True)
        Solar_position = SolarPosition(ts, Solar_position)

        # Inizialization of Solar Gain DataFrame
        # Creates a dataframe with the hourly solar radiation ond angle of incidence for several directions

        if irradiances_calc:
            Irradiances = PlanesIrradiances(site, epw, year, azSubdiv, hSubdiv)
            Irradiances.Irradiances.to_csv(
                os.path.join(input_path, 'PlanesIrradiances.csv'))

        # Solar Gain DataFrame
        Solar_Gains = pd.read_csv(os.path.join(input_path,
                                               'PlanesIrradiances.csv'),
                                  header=[0, 1, 2],
                                  index_col=[0])
        Solar_Gains = rescale_sol_gain(ts, Solar_Gains)

        # Check some weather data values
        if not np.all(np.greater(T_ext, -50.)) or not np.all(
                np.less(T_ext, 60.)):
            wrn(f"WARNING Weather class, input T_ext is out of plausible range: T_ext {T_ext}"
                )
        if not np.all(np.greater(w, -0.001)) or not np.all(np.less(w, 25.001)):
            wrn(f"WARNING Weather class, input w is out of plausible range: w {w}"
                )
        if not np.all(np.greater(RH_ext, -0.0001)) or not np.all(
                np.less(RH_ext, 1.)):
            wrn(f"WARNING Weather class, input w is out of plausible range: w {w}"
                )

        # Memorizing the attributes needed for the sim
        self.ts = ts  # number of timesteps in an hour
        self.hours = hours  # number of hours of a sim
        self.sim_time = [ts, hours]  #
        self.tau = 3600 / ts  # number of seconds of a time step (for the solution of the networks)
        self.Text = T_ext  # External air temperature [°C]
        self.RHext = RH_ext  # External relative humidity [0-1]
        self.azSubdiv = azSubdiv  # Number of azimuth subdivision [-]
        self.hSubdiv = hSubdiv  # Number of height subdivision [-]
        self.w = w  # wind velocity [m/s]
        self.dT_er = dT_er  # Average temperature diff between external air and sky vault[°C]
        self.THextAv = T_ext_H_avg  # Average heating season air temperature [°C]

        self.SolarPosition = Solar_position
        self.SolarGains = Solar_Gains

        # tollerances for urban shading calculation
        self.Az_toll = shad_tol[0]  # [°]
        self.Dist_toll = shad_tol[1]  # [m]
        self.Theta_toll = shad_tol[2]  # [°]
Ejemplo n.º 8
0
def rescale_weather(ts, w, T_ext, RH_ext, T_dp, P_, n_opaque):
    '''
    rescales weather variables arrays
    returns numpy arrays!!!!
    
    Parameters
    ----------
    ts : int
        Number of time steps per hour.
    w : dataframe column
        External wind speed [m/s]
    T_ext : dataframe column
        External dry bulb temperature [°C]
    RH_ext : dataframe column
        External relative humidity [0-1]    
    T_dp : dataframe column
        External dew point temperature [°C]
    P_ : dataframe column
        External pressure [Pa]
    n_opaque : dataframe column
        Opaque sky covering [-]

    Returns
    -------
    w: np array, wind speed [m/s]
    t: np array, temperature [°C]
    rh: np array, relative humidity [0-1] 
    dp: np array, dew point temperature [°C]
    p: np array, pressure [Pa]
    nop: np array, opaque sky covering [-]   
    
    '''

    # Check input data type

    if not isinstance(ts, int):
        raise TypeError(f'ERROR input ts is not an integer: ts {ts}')
    if not isinstance(w, pd.core.series.Series):
        raise TypeError(f'ERROR input w is not a pandas series: w {w}')
    if not isinstance(T_ext, pd.core.series.Series):
        raise TypeError(
            f'ERROR input T_ext is not a pandas series: T_ext {T_ext}')
    if not isinstance(RH_ext, pd.core.series.Series):
        raise TypeError(
            f'ERROR input RH_ext is not a pandas series: RH_ext {RH_ext}')
    if not isinstance(T_dp, pd.core.series.Series):
        raise TypeError(
            f'ERROR input T_dp is not a pandas series: T_dp {T_dp}')
    if not isinstance(P_, pd.core.series.Series):
        raise TypeError(f'ERROR input P_ is not a pandas series: P_ {P_}')
    if not isinstance(n_opaque, pd.core.series.Series):
        raise TypeError(
            f'ERROR input n_opaque is not a pandas series: n_opaque {n_opaque}'
        )

    # Check input data quality

    if not np.all(np.greater(w, -0.001)) or not np.all(np.less(w, 25.001)):
        wrn(f"WARNING rescale_weather function, input w is out of plausible range: w {w}"
            )

    # Rescale the data with pandas rescale

    data = pd.DataFrame(zip(w, T_ext, RH_ext, T_dp, P_, n_opaque),
                        columns=['w', 't', 'rh', 'dp', 'p', 'nop'])
    m = str(60 / float(ts)) + 'min'
    time = pd.date_range('2020-01-01', periods=8760, freq='1h')
    data.set_index(time, inplace=True)
    data = data.resample(m).interpolate(
        method='linear')  # Steps interpolation Resampling
    return data['w'].to_numpy(), data['t'].to_numpy(), data['rh'].to_numpy(
    ), data['dp'].to_numpy(), data['p'].to_numpy(), data['nop'].to_numpy()
Ejemplo n.º 9
0
    def __init__(self, site, epw, year=2020, azSubdiv=8, hSubdiv=3):
        '''
        initialize PlaneIrradiances object
        
        Parameters
        ----------
        site : pvlib.location.Location
            Location object from pvlib.
        epw : tuple from pvlib read_epw
            contains 2 dataframe with the epw characteristics
        year : int
            year of the simulation, just to set the dataframe index
        azSubdiv: int
            number of the different direction (azimuth) solar radiation will be calculated
        hSubdiv: int
            number of the different direction (solar height) solar radiation will be calculated      
            
        Returns
        -------
        None
        '''

        # Check input data type

        if not isinstance(site, pvlib.location.Location):
            raise TypeError(
                f'ERROR input site is not a pvlib location object: site {site}'
            )
        if not isinstance(epw, tuple):
            raise TypeError(f'ERROR input epw is not a tuple: epw {epw}')
        if not isinstance(epw[0], pd.core.frame.DataFrame):
            raise TypeError(
                f'ERROR input epw[0] is not a pandas dataframe: epw[0] {epw[0]}'
            )
        if not isinstance(epw[1], dict):
            raise TypeError(
                f'ERROR input epw[1] is not a dictionary: epw[1] {epw[1]}')
        if not isinstance(year, int):
            raise TypeError(f'ERROR input year is not an integer: year {year}')
        if not isinstance(azSubdiv, int):
            raise TypeError(
                f'ERROR input azSubdiv is not an integer: azSubdiv {azSubdiv}')
        if not isinstance(hSubdiv, int):
            raise TypeError(
                f'ERROR input hSubdiv is not an integer: hSubdiv {hSubdiv}')

        # Control input data quality

        if azSubdiv > 10 or hSubdiv > 5:
            wrn(f"WARNING PlanesIrradiances class, init, solar calculation could be long..... azSubdiv {azSubdiv}, hSubdiv {hSubdiv}"
                )

        # Creates the dataframe with global beam and Angle of Incidence for many directions

        time = epw[0].index
        irradiance = epw[0][['ghi', 'dni', 'dhi']]
        self.solar_position = site.get_solarposition(times=time)

        azimuth = np.linspace(-180, 180, azSubdiv + 1)[:-1]
        height = np.linspace(90, 0, hSubdiv + 1)[:-1]
        components = ['global', 'direct', 'AOI']

        col = pd.MultiIndex.from_product(
            [azimuth, height, components],
            names=['Azimuth', 'Height', 'Component'])
        col = col.union(
            pd.MultiIndex.from_product(
                [[0], [0], components],
                names=['Azimuth', 'Height', 'Component']))
        Irradiances = pd.DataFrame(0., index=time, columns=col)

        for az in azimuth:
            for h in height:
                POA = get_irradiance(site, time, self.solar_position, h, az,
                                     irradiance, year)
                Irradiances[az, h, 'global'] = POA['POA']
                Irradiances[az, h, 'direct'] = POA['POA_B']
                Irradiances[az, h, 'AOI'] = POA['AOI']

        POA = get_irradiance(site, time, self.solar_position, 0, 0, irradiance,
                             year)

        Irradiances[0, 0, 'global'] = POA['POA']
        Irradiances[0, 0, 'direct'] = POA['POA_B']
        Irradiances[0, 0, 'AOI'] = POA['AOI']

        self.Irradiances = Irradiances
Ejemplo n.º 10
0
def get_irradiance(site, time, solar_position, surf_tilt, surf_az, irradiance,
                   year):
    '''
    function from pvlib to calculate irradiance on a specific surface
    https://pvlib-python.readthedocs.io/en/stable/auto_examples/plot_ghi_transposition.html#sphx-glr-auto-examples-plot-ghi-transposition-py    
    
    Parameters
    ----------
    site : pvlib.location.Location
        Location object from pvlib.
    time: pandas series
        time index of the epw object from pvlib
    solar_position : pandas dataframe 
            the solar position dataframe from pvlib
    surf_tilt: float
        tilt of the surface
    surf_az: float
        azimuth of the surface
    irradiance:   pandas dataframe  
        dataframe from the epw with ghi, dni, dhi
    year : int
        year of the simulation, just to set the dataframe index
        
    Returns
    -------
    pandas DataFrame with the irradiances on the surface 
    '''

    # Check input data type

    if not isinstance(site, pvlib.location.Location):
        raise TypeError(
            f'ERROR input site is not a pvlib location object: site {site}')
    if not isinstance(time, pd.core.indexes.datetimes.DatetimeIndex):
        raise TypeError(
            f'ERROR input time is not a pandas series: time {time}')
    if not isinstance(solar_position, pd.core.frame.DataFrame):
        raise TypeError(
            f'ERROR input solar_position is not a pandas dataframe: solar_position {solar_position}'
        )
    if not isinstance(surf_tilt, float):
        try:
            surf_tilt = float(surf_tilt)
        except:
            raise TypeError(
                f'ERROR input surf_tilt is not a float: surf_tilt {surf_tilt}')
    if not isinstance(surf_az, float):
        try:
            surf_az = float(surf_az)
        except:
            raise TypeError(
                f'ERROR input surf_az is not a float: surf_az {surf_az}')
    if not isinstance(irradiance, pd.core.frame.DataFrame):
        raise TypeError(
            f'ERROR input irradiance is not a pandas dataframe: irradiance {irradiance}'
        )
    if not isinstance(year, int):
        try:
            year = int(year)
        except:
            raise TypeError(f'ERROR input year is not an integer: year {year}')

    # Control input data quality

    if surf_tilt < 0 or surf_tilt > 90 or surf_az < -180 or surf_az > 180:
        wrn(f"WARNING get_irradiance funtion, are you sure that the surface orientation is correct?? surf_tilt {surf_tilt}, surf_az {surf_az}"
            )

    # Use pvlib function to calculate the irradiance on the surface

    surf_az = surf_az + 180
    POA_irradiance = pvlib.irradiance.get_total_irradiance(
        surface_tilt=surf_tilt,
        surface_azimuth=surf_az,
        dni_extra=pvlib.irradiance.get_extra_radiation(time,
                                                       solar_constant=1366.1,
                                                       method='spencer',
                                                       epoch_year=year),
        dni=irradiance['dni'],
        ghi=irradiance['ghi'],
        dhi=irradiance['dhi'],
        solar_zenith=solar_position['apparent_zenith'],
        solar_azimuth=solar_position['azimuth'],
        model='isotropic',
        model_perez='allsitescomposite1990',
        airmass=site.get_airmass(solar_position=solar_position))
    AOI = pvlib.irradiance.aoi(surface_tilt=surf_tilt,
                               surface_azimuth=surf_az,
                               solar_zenith=solar_position['apparent_zenith'],
                               solar_azimuth=solar_position['azimuth'])

    # Cleaning AOI vector

    for i in range(len(AOI)):
        if AOI[i] > 90 or solar_position['apparent_zenith'][i] > 90:
            AOI[i] = 90

    return pd.DataFrame({
        'GHI':
        irradiance['ghi'],
        'POA':
        POA_irradiance['poa_global'],
        'POA_B':
        POA_irradiance['poa_direct'],
        'POA_D':
        POA_irradiance['poa_global'] - POA_irradiance['poa_direct'],
        'AOI':
        AOI,
        'solar zenith':
        solar_position['apparent_zenith']
    })
Ejemplo n.º 11
0
def loadSimpleArchetype(path,
                        timeIndex,
                        first_day=1,
                        ts=1,
                        PlantDays=[2520, 3984, 6192, 6912]):
    '''
    Archetype loading in case you use loadSchedSemp
    This function takes the path of the excel file constining the schedules and loads it
    Works for the daily schedule (see file ScheduleSemp.xlsx in /Input/
    
    Parameters
    ----------
    path : string
        Path containing the string of the file_schedule.xlsx
    timeIndex : np array of int
        This is the array containing the index of the simulation time steps .
    first_day : int
        First day of the week (1 monday, 2 tuesday, ..... 7 sunday)
    ts : int
        Number of time steps per hour.
    PlantDays : list
        List of integers that sets the 4 time steps of heating and cooling season start and stops
        [last heating timestep,
         first cooling timestep,
         last cooling timstep,
         fist heating time step]

    Returns
    -------
    archetypes: dictionary with archetype_key/Archetype(object) data
    '''

    # Check input data type

    if not isinstance(path, str):
        raise TypeError(f'ERROR input path is not a string: path {path}')
    if not isinstance(timeIndex, np.ndarray):
        raise TypeError(
            f'ERROR input timeIndex is not a np.array: timeIndex {timeIndex}')
    if not isinstance(first_day, int):
        raise TypeError(
            f'ERROR input first_day is not an integer: first_day {first_day}')
    if not isinstance(ts, int):
        raise TypeError(f'ERROR input ts is not an integer: ts {ts}')
    if not isinstance(PlantDays, list):
        raise TypeError(
            f'ERROR input PlantDays is not a list: PlantDays {PlantDays}\nThis parameter must be a list of integers (default [2520,3984,6192,6912])'
        )
    if not isinstance(PlantDays[0], int) or not isinstance(
            PlantDays[1], int) or not isinstance(
                PlantDays[2], int) or not isinstance(PlantDays[3], int):
        raise TypeError(
            f'ERROR input PlantDays in not a list of integers: PlantDays {PlantDays}'
        )

    # Control input data quality

    if first_day > 7 or first_day < 1:
        wrn(f"WARNING loadSimpleArchetype function, input fisrt_day should be in the range [0,7]: first_day {first_day}"
            )
    if ts > 4:
        wrn(f"WARNING loadSimpleArchetype function, input ts is higher than 4, this means more than 4 time steps per hours were set: ts {ts}"
            )

    try:
        ex = pd.ExcelFile(path)
    except FileNotFoundError:
        raise FileNotFoundError(
            f'ERROR Failed to open the schedule xlsx file {path}... Insert a proper path'
        )

    # Creation of the archetypes' dictionary

    archetypes = dict()
    last_H_day = PlantDays[0]
    first_C_day = PlantDays[1]
    last_C_day = PlantDays[2]
    first_H_day = PlantDays[3]

    # read archetype names from the excel sheet
    archetype_list = pd.read_excel(path,
                                   sheet_name='GeneralData',
                                   header=[0],
                                   index_col=[0],
                                   skiprows=1)
    names = archetype_list.index

    for use in names:
        archetypes[use] = Archetype(use)
        year = pd.DataFrame()
        schedule = pd.read_excel(path,
                                 sheet_name=use,
                                 header=[0, 1, 2],
                                 index_col=[0])
        schedule = schedule.iloc[1:25] * schedule.loc['Valore nominale']
        week = pd.concat([schedule['Weekday']] * 5 + [schedule['Weekend']] * 2)

        # The heating cooling availabilty is create considering the PlantDays variable

        first_week = week.iloc[(first_day - 1) * 24:]
        year = pd.concat([first_week] +
                         [week] * 53).iloc[:8760].set_index(timeIndex)
        year.loc[last_H_day:first_C_day,
                 ('Plant Availability',
                  '[-]')] = year.loc[last_H_day:first_C_day,
                                     ('Plant Availability', '[-]')] * 0
        year.loc[first_C_day:last_C_day,
                 ('Plant Availability',
                  '[-]')] = year.loc[first_C_day:last_C_day,
                                     ('Plant Availability', '[-]')] * -1
        year.loc[last_C_day:first_H_day,
                 ('Plant Availability',
                  '[-]')] = year.loc[last_C_day:first_H_day,
                                     ('Plant Availability', '[-]')] * 0
        archetypes[use].loadSchedSemp(year, archetype_list.loc[use])
        archetypes[use].rescale_df(ts)
        archetypes[use].create_np()

    return archetypes
Ejemplo n.º 12
0
    def loadSchedSemp(self, year_df, supplementary_data):
        '''
        Used for ScheduleSemp.xlsx Excel file
        
        Parameters
            ----------
            arch : pandas dataframe
                This includes the yearly schedule of a single archetype
            supplementary_data : pd.series
                This series includes some additional data about the archetype (Sensible and 
                                                                               Latent AHU recovery, 
                                                                               Convective fraction of internal gains)
            
        Returns
        -------
        None.
        
        '''

        # Each schedule is set to a different attribute of the class

        try:
            self.sched_df['appliances'] = year_df['Appliances', '[W/m²]']
            self.sched_df['lighting'] = year_df['Lighting', '[W/m²]']
            self.sched_df['people'] = year_df['Occupancy (Sensible)', '[W/m²]']
            self.sched_df['vapour'] = year_df[
                'Vapour FlowRate', '[g/(m² s)]'] / 1000  #--> kg conversion (a)
            self.sched_df['heatingTSP'] = year_df['HeatSP', '[°C]']
            self.sched_df['coolingTSP'] = year_df['CoolSP', '[°C]']
            self.sched_df['HeatingRHSP'] = year_df['HumSP', '[%]'] / 100
            self.sched_df['CoolingRHSP'] = year_df['DehumSP', '[%]'] / 100
            self.sched_df['ventFlowRate'] = year_df['Ventilation FlowRate',
                                                    '[m³/(s m²)]']
            self.sched_df['infFlowRate'] = year_df['Infiltration FlowRate',
                                                   '[Vol/h]']
            self.sched_df['plantOnOffSens'] = year_df['Plant Availability',
                                                      '[-]']
            self.sched_df['plantOnOffLat'] = year_df['Plant Availability',
                                                     '[-]']
            self.sched_df['AHUOnOff'] = year_df['Plant Availability', '[-]']
        except KeyError:
            raise KeyError(
                f'ERROR Archetype object {self.name}: can not find all schedules'
            )

        # Following parameters are not set in the Excel file

        self.sched_df['AHUTSupp'] = pd.Series(
            [22.] * 8760, index=self.sched_df['appliances'].index)
        self.sched_df['AHUxSupp'] = pd.Series(
            [0.005] * 8760, index=self.sched_df['appliances'].index)
        self.sched_df['AHUxSupp'].iloc[3984:6192] = 0.007

        try:
            self.scalar_data['conFrac'] = float(
                supplementary_data.loc['ConvFrac'])
            self.scalar_data['AHUHUM'] = bool(supplementary_data.loc['AHUHum'])
            self.scalar_data['sensRec'] = float(
                supplementary_data.loc['SensRec'])
            self.scalar_data['latRec'] = float(
                supplementary_data.loc['LatRec'])
            self.scalar_data['outdoorAirRatio'] = float(
                supplementary_data.loc['OutAirRatio'])
        except KeyError:
            raise KeyError(
                f"ERROR Loading end use {self.name}. GeneralData does not have the correct columns names: ConvFrac, AHUHum, SensRec, LatRec, OutAirRatio"
            )
        except ValueError:
            raise ValueError(f"""ERROR 
                             Loading end use {self.name}. GeneralData
                             I'm not able to parse the General data. 
                                 ConvFrac should be a float {supplementary_data['ConvFrac']}
                                 AHUHum should be a boolean {supplementary_data['AHUHum']}
                                 SensRec should be a float {supplementary_data['SensRec']}
                                 LatRec  should be a float {supplementary_data['LatRec']}
                                 OutAirRatio   should be a float {supplementary_data['OutAirRatio']}
                             """)

        # Check the quality of input data
        if not 0. <= self.scalar_data['conFrac'] <= 1.:
            wrn(f"WARNING Loading end use {self.name}. Convective fraction of the heat gain outside boundary condition [0-1]: ConvFrac {self.scalar_data['conFrac']}"
                )
        if not 0. <= self.scalar_data['sensRec'] <= 1.:
            wrn(f"WARNING Loading end use {self.name}. Sensible recovery of the AHU outside boundary condition [0-1]: sensRec {self.scalar_data['sensRec']}"
                )
        if not 0. <= self.scalar_data['latRec'] <= 1.:
            wrn(f"WARNING Loading end use {self.name}. Latent recovery of the AHU outside boundary condition [0-1]: sensRec {self.scalar_data['latRec']}"
                )
        if not 0. <= self.scalar_data['outdoorAirRatio'] <= 1.:
            wrn(f"WARNING Loading end use {self.name}. Outdoor air ratio of the AHU outside boundary condition [0-1]: outdoorAirRatio {self.scalar_data['outdoorAirRatio']}"
                )
Ejemplo n.º 13
0
def loadArchetype(path, timeIndex, ts):
    '''
    Archetype loading in case you use loadSchedComp
    This function takes the path of the excel file constining the schedules and loads it
    Works for the yearly schedule (see file ScheduleComp.xlsx in /Input/
    
    Parameters
    ----------
    path : string
        Path containing the string of the file_schedule.xlsx
    timeIndex : np array of int
        This is the array containing the index of the simulation time steps .
    ts : int
        Number of time steps per hour.

    Returns
    -------
    archetypes: dictionary with archetype_key/Archetype(object) data
    '''

    # Check input data type

    if not isinstance(path, str):
        raise TypeError(f'ERROR input path is not a string: path {path}')
    if not isinstance(timeIndex, np.ndarray):
        raise TypeError(
            f'ERROR input timeIndex is not a np.array: timeIndex {timeIndex}')
    if not isinstance(ts, int):
        raise TypeError(f'ERROR input ts is not an integer: ts {ts}')

    # Control input data quality

    if ts > 4:
        wrn(f"WARNING loadSimpleArchetype function, input ts is higher than 4, this means more than 4 time steps per hours were set: ts {ts}"
            )

    try:
        sched = pd.read_excel(path,
                              sheet_name="Schedule",
                              header=2,
                              index_col=[0]).set_index(timeIndex)
        arch = pd.read_excel(path,
                             sheet_name="Archetype",
                             header=1,
                             index_col=[0])
    except FileNotFoundError:
        raise FileNotFoundError(
            f'ERROR Failed to open the schedule xlsx file {path}... Insert a proper path'
        )

    # Reset some indexes set the right index

    sched = sched.reset_index().drop(columns=["Time"])
    sched.index = timeIndex

    # Creation of the archetypes' dictionary

    archetypes = dict()
    for i in arch.index:
        if i != 'Archetype':
            archetypes[i] = Archetype(i)
            archetypes[i].loadSchedComp(arch.loc[i], sched)
            archetypes[i].rescale_df(ts)
            archetypes[i].create_np()
    return archetypes