Source code for src.Sink.characterization.greenhouse

import math
import copy
from ...General.Auxiliary_General.schedule_hour_simplified import schedule_hour_simplified
from ...General.Auxiliary_General.month_last_hour import month_last_hour
from ...General.Simple_User.adjust_capacity import adjust_capacity
from .Auxiliary.building_climate_api import building_climate_api
from .Auxiliary.wall_area import wall_area
from .Auxiliary.h_convection_horizontal import h_convection_horizontal
from .Auxiliary.h_convection_vertical import h_convection_vertical
from .Auxiliary.ht_radiation_equation import ht_radiation_equation
from .Auxiliary.info_time_step_climate_data import info_time_step_climate_data
from ...Error_Handling.error_greenhouse import PlatformGreenhouse
from ...Error_Handling.runtime_error import ModuleRuntimeException


[docs]def greenhouse(in_var): """Greenhouse characterization Simulates the heat (space heating) needs over the year according to the greenhouse specifications and climate weather data of the location Parameters ---------- in_var : dict All necessary data to perform the building characterization data, with the following key: platform: dict Data obtained from the platform, with the following keys: - location : list Location [º]; [latitude,longitude] - width: float: Width [m] - length: float: Length [m] - height: float: Height [m] - greenhouse_orientation: str: Greenhouse’s main facade orientation; "N","S","E" or "W" - daily_periods: float: Period of daily periods [h] - shutdown_periods: list: Period of days stream is not available [day] - greenhouse_efficiency: Greenhouse air infiltration tightness: 1 = tight cover with low infiltrations 2 = medium sealing 3 = leaky cover - T_heat_on: float: Heating setpoint temperature [ºC] - thermal_blanket: If greenhouse has a thermal blanket/curtain being used at night; 1=yes,0=no - artificial_lights_system: lighting hours in greenhouse; 1=yes,0=no - ref_system_fuel_type: str Fuel type associated; e.g. "natural_gas","electricity","biomass","fuel_oil","none" - ref_system_eff_equipment: float, optional COP of the cooling equipment; - real_monthly_capacity: dict, optional Real monthly data - for each month of the year - real_yearly_capacity: float, optional Real yearly data - single value - hours_lights_needed: hours of light the plant needs (accounting with daily solar hours) [h] - supply_temperature_heat: float, optional Heating System ReturnTemperature [ºC]; DEFAULT=30 - target_temperature_heat: float, optional Heating System Supply Temperature [ºC]; DEFAULT=50 - leaf_area_index, optional Ratio of leaf area over ground area []; DEFAULT=1 - rh_air, optional Relative humidity [%]; DEFAULT=80 - u_cover, optional Cover thermal conductivity [W/m2.K]; DEFAULT=6 - indoor_air_speed, optional Indoor air velocity [m/s]; DEFAULT=0.1 - leaf_length, optional Characteristic length of a plant leaf [m]; DEFAULT=0.027 - tau_cover_long_wave_radiation, optional Cover transmissivity coefficient to long-wave radiation; DEFAULT=0.3 - emissivity_cover_long_wave_radiation, optional Cover emissivity coefficient to long-wave radiation; DEFAULT=0.2 - tau_cover_solar_radiation, optional Cover's transmissivity coefficient to solar radiation []; DEFAULT=0.9 - power_lights, optional Light power per square meter [W/m2]; DEFAULT=20 kb : dict Knowledge base data Returns ------- output : dict Streams data - streams : list List with dicts of all streams with the following keys: - id : int stream ID [] - name : str Stream name [] - object_type : str DEFAULT = "stream" [] - object_linked_id None: DEFAULT=NONE, since no equipment/process is associated - stream_type : str Stream designation []; inflow, outflow, excess_heat - supply_temperature : float Stream's supply/initial temperature [ºC] - target_temperature : float Stream's target/final temperature [ºC] - fluid : str Stream fluid name - flowrate : float Stream mass flowrate[kg/h] - schedule : list Hourly values between 0 and 1, according to the capacity ration on that hour - hourly_generation: list Stream's hourly capacity [kWh] - capacity : float Stream's capacity [kW] - monthly_generation : list Stream's monthly capacity [kWh] - fuel : str Associated equipment fuel name [] - eff_equipment : float Associated equipment efficiency [] """ ################################################################################################################## # INPUT ---------------------------------------------- # validate inputs platform_data = PlatformGreenhouse(**in_var['platform']) latitude, longitude = platform_data.location width = platform_data.width length = platform_data.length height = platform_data.height shutdown_periods = platform_data.shutdown_periods daily_periods = platform_data.daily_periods greenhouse_orientation = platform_data.greenhouse_orientation artificial_lights_system = platform_data.artificial_lights_system T_cool_on = platform_data.T_cool_on T_heat_on = platform_data.T_heat_on thermal_blanket = platform_data.thermal_blanket saturday_on = platform_data.saturday_on sunday_on = platform_data.sunday_on f_c = platform_data.f_c supply_temperature_heat = platform_data.supply_temperature_heat target_temperature_heat = platform_data.target_temperature_heat leaf_area_index = platform_data.leaf_area_index # ratio of area_plants/area_floor rh_air = platform_data.rh_air # controlled interior air RH u_cover = platform_data.u_cover # heat transfer coefficient cover [W/m2.K] indoor_air_speed = platform_data.indoor_air_speed # indoor_air_speed [m/s] leaf_length = platform_data.leaf_length # characteristic leaf length [m] tau_cover_long_wave_radiation = platform_data.tau_cover_long_wave_radiation # cover transmissivity long wave radiation emissivity_cover_long_wave_radiation = platform_data.emissivity_cover_long_wave_radiation # emissivity long wave radiation tau_cover_solar_radiation = platform_data.tau_cover_solar_radiation # cover transmissivity solar radiation power_lights = platform_data.power_lights # lighting power per square meter [W/m2] hours_lights_needed = platform_data.hours_lights_needed # lighting hours in greenhouse (counting with daily iluminance) [h] real_heating_monthly_capacity = platform_data.real_heating_monthly_capacity real_heating_yearly_capacity = platform_data.real_heating_yearly_capacity ref_system_fuel_type = platform_data.ref_system_fuel_type ref_system_eff_equipment = platform_data.ref_system_eff_equipment ################################################################################################################## # DEFINED VARS ---------------------------------------------------------------------------------- # Greenhouse characteristics alpha_plants_and_soil = 0.75 alpha_greenhouse = tau_cover_solar_radiation * alpha_plants_and_soil emissivity_greenhouse = 0.9 T_ground = 15 # ground temperature [ºC] L_ground = 3 # [m] k_ground = 1.4 # [W/m.K] u_ground = k_ground / L_ground # [W/m2.K] u_thermal_cover = 0.75 # Fluids Properties p_atmospheric = 101 # atmospheric pressure [kPa] rho_air = 1.225 # [kg/m3] cp_air = 1005 # [J/kg.K] latent_heat_water = 2450 * 1000 # [J/kg] ################################################################################################################## # COMPUTE ---------------------------------------------------------------------------------- # Schedule profile = schedule_hour_simplified(daily_periods,saturday_on,sunday_on,shutdown_periods) month_last_hour_vector = month_last_hour() # Climate data try: df_climate = building_climate_api(latitude, longitude) except: raise ModuleRuntimeException( code="1", type="greenhouse.py", msg="Greenhouse characterization infeasible. Climate data not possible to obtain, change location or try later." ) # Guarantee desired minimum plant illumination df_climate['turn_on_lights'] = 0 save_first_hour = -10 # random value save_last_hour = -10 if artificial_lights_system == 1: for index, solar_radiation in enumerate(df_climate['Q_sun_roof']): if index != 0: if solar_radiation > 0 and df_climate.loc[index - 1, 'Q_sun_roof'] == 0: save_first_hour = copy.copy(index - 1) elif solar_radiation == 0 and df_climate.loc[index - 1, 'Q_sun_roof'] > 0: save_last_hour = copy.copy(index) if save_first_hour != -10 and save_last_hour != -10: hours_sun_light = save_last_hour - save_first_hour if hours_sun_light < hours_lights_needed: hours_light_missing = round( (hours_lights_needed - hours_sun_light) / 2) # hours of artificial light needed for i in range(hours_light_missing): df_climate.loc[save_first_hour - i, 'turn_on_lights'] = 1 df_climate.loc[save_last_hour + i, 'turn_on_lights'] = 1 save_first_hour = -10 # reset vars save_last_hour = -10 # Greenhouse Properties area_floor = width * length # [m2] area_plants = area_floor * leaf_area_index area_N_wall = wall_area('N', greenhouse_orientation, width, length, height) # area North facade [m2] area_S_wall = wall_area('S', greenhouse_orientation, width, length, height) area_E_wall = wall_area('E', greenhouse_orientation, width, length, height) area_W_wall = wall_area('W', greenhouse_orientation, width, length, height) volume_greenhouse = area_floor * height # indoor air volume per floor [m3] total_cover_area = (area_W_wall + area_N_wall + area_S_wall + area_E_wall + area_floor) ################################################################################################################## # SIMULATION ---------------------------------------------------------------- # Initialize vars profile_hourly_heat = [] profile_monthly_heat = [] profile_monthly_cool = [] cumulative_heat_monthly = 0 cumulative_cool_monthly = 0 T_initial = 15 if T_initial < T_heat_on: T_initial = copy.copy(T_heat_on) T_interior = copy.copy(T_initial) # floor interior air temperature # Simulation Info time_step = 60 * 15 # time step [s] one_hour = int(3600 / time_step) # time step number max_air_delta_T_per_minute = 1 # 1ºC per min max_air_delta_T_allowed = time_step * max_air_delta_T_per_minute / 60 try: for profile_index, profile_operating in enumerate(profile): if (profile_index in month_last_hour_vector) or (profile_index == (len(profile) - 1)): profile_monthly_heat.append(round(cumulative_heat_monthly, 2)) # space heating demand [kWh] profile_monthly_cool.append(round(cumulative_cool_monthly, 2)) # space cooling demand [kWh] cumulative_heat_monthly = 0 # reset monthly heating needs cumulative_cool_monthly = 0 # reset monthly cooling needs cumulative_heat_hourly = 0 # reset hourly heating needs if profile_index == (len(profile) - 1): break for i in range(one_hour): # Climate data T_exterior, T_sky, Q_sun_N_facade, Q_sun_S_facade, Q_sun_E_facade, Q_sun_W_facade, Q_sun_roof, wind_speed = info_time_step_climate_data( df_climate, profile_index, one_hour, i) if thermal_blanket == 1: if Q_sun_roof <= 80: # simplification to determine when blanket is covering greenhouse Q_sun_roof = 0 # Correct wind speed z_0 = 0.01 # surface roughness wind_speed = wind_speed * (math.log((height / 2) / z_0)) / (math.log(10 / z_0)) u_exterior = (5.8 + 3.94 * wind_speed) # outside heat convection coef. [W/m2.K] # GREENHOUSE HEAT GAINS/LOSSES # Solar radiation Q_sun_greenhouse = (Q_sun_roof * area_floor) * alpha_greenhouse # Infiltrations f_t = 0.16 c_w = 0.22 area_infiltration = total_cover_area * f_c air_change_per_second = area_infiltration * math.sqrt( c_w ** 2 * wind_speed + f_t ** 2 * (abs(T_interior - T_exterior))) # [m3/s] # Evapotranspiration vapour_p_plants = (math.exp(20.386 - 5132 / (T_interior + 273.1))) * 0.13 # [kPa] vapour_p_air = (math.exp(20.386 - 5132 / (T_interior + 273.1))) * (rh_air / 100) * 0.13 # [kPa] w_plant = 0.6219 * vapour_p_plants / (p_atmospheric - vapour_p_plants) # [kg_water/kg_air] w_air = 0.6219 * vapour_p_air / (p_atmospheric - vapour_p_air) R_aerodynamic = 220 * (leaf_length ** 0.2) / (indoor_air_speed ** 0.8) R_stomatal = 200 * (1 + 1 / (math.exp(0.05 * (Q_sun_roof * alpha_greenhouse - 50)))) m_evap_water = area_plants * rho_air * (w_plant - w_air) / (R_aerodynamic + R_stomatal) # [kg/s] if m_evap_water < 0: m_evap_water = 0 Q_plants = m_evap_water * latent_heat_water # [W] # Conduction Ground Losses Q_lost_ground = u_ground * area_floor * (T_ground - T_interior) # Convection Cover Losses T_cover = 2 / 3 * T_exterior + T_interior * 1 / 3 # average T_cover [ºC] h_vertical = h_convection_vertical(T_cover, T_interior) h_horizontal = h_convection_horizontal(T_cover, T_interior) coef_horizontal = 1 coef_vertical = 1 if h_horizontal == 0: h_horizontal = 1 coef_horizontal = 0 if h_vertical == 0: h_vertical = 1 coef_vertical = 0 if Q_sun_greenhouse == 0 and thermal_blanket == 1: val_thermal_blanket = 1 else: val_thermal_blanket = 0 u_horizontal = (1 / u_cover + 1 / u_thermal_cover * val_thermal_blanket + 1 / u_exterior + 1 / h_horizontal * coef_horizontal) ** ( -1) u_vertical = (1 / u_cover + 1 / u_thermal_cover * val_thermal_blanket + 1 / u_exterior + 1 / h_vertical * coef_vertical) ** ( -1) Q_top = area_floor * u_horizontal * (T_exterior - T_interior) Q_vertical_wall_small = area_E_wall * u_vertical * (T_exterior - T_interior) Q_vertical_wall_big = area_N_wall * u_vertical * (T_exterior - T_interior) Q_lost_exterior = Q_top + 2 * (Q_vertical_wall_small + Q_vertical_wall_big) # Radiation Losses if Q_sun_greenhouse == 0: Q_rad_lost = 0 else: view_factor = 1 area_sky = total_cover_area Q_rad_sky = ht_radiation_equation(emissivity_greenhouse, area_sky, T_interior, T_sky, view_factor) * tau_cover_long_wave_radiation Q_rad_ground = ht_radiation_equation(emissivity_cover_long_wave_radiation, area_sky, T_interior, T_cover, view_factor) Q_rad_lost = (Q_rad_sky + Q_rad_ground) # [W] # Infiltration Q_infiltrations = rho_air * cp_air * air_change_per_second * (T_exterior - T_interior) # Lights if df_climate.loc[profile_index, 'turn_on_lights'] == 1: Q_lights = power_lights * area_floor else: Q_lights = 0 # Greenhouse Air Heat Balance Q_greenhouse = Q_lights + \ Q_infiltrations + \ Q_lost_ground + \ Q_lost_exterior + \ Q_sun_greenhouse - \ Q_plants + \ Q_rad_lost # SPACE HEATING/COOLING ACTUATION # on work time if profile_operating == 1: T_interior_guess = T_interior + Q_greenhouse * time_step / (rho_air * cp_air * volume_greenhouse) # activating space heating if T_interior < T_heat_on and T_interior_guess < T_heat_on: if Q_greenhouse < 0: if T_heat_on - T_interior < max_air_delta_T_allowed: Q_heat_required = abs(Q_greenhouse) + (rho_air * cp_air * volume_greenhouse) * ( T_heat_on - T_interior) / time_step else: Q_heat_required = abs(Q_greenhouse) + ( rho_air * cp_air * volume_greenhouse) * max_air_delta_T_allowed / time_step else: if T_interior_guess - T_interior < max_air_delta_T_allowed: Q_heat_required = (rho_air * cp_air * volume_greenhouse) * ( max_air_delta_T_allowed - (T_interior_guess - T_interior)) / time_step else: Q_heat_required = 0 elif T_interior >= T_heat_on and T_interior_guess < T_heat_on: Q_heat_required = (rho_air * cp_air * volume_greenhouse) * ( T_heat_on - T_interior_guess) / time_step else: Q_heat_required = 0 else: Q_heat_required = 0 # COMPUTE INTERIOR TEMPERATURE T_interior = T_interior + (Q_greenhouse + Q_heat_required) * time_step / ( rho_air * cp_air * volume_greenhouse) # [ºC] if T_interior >= T_cool_on and T_cool_on >= T_exterior: T_interior = T_cool_on elif T_interior >= T_cool_on and T_exterior >= T_cool_on: T_interior = T_exterior if Q_heat_required > 0: cumulative_heat_monthly += Q_heat_required * time_step / 3600000 # [kW] cumulative_heat_hourly += Q_heat_required * time_step / 3600000 # Hourly Profiles profile_hourly_heat.append(round(cumulative_heat_hourly, 2)) # space heating demand [kWh] stream_hot = { "id": 1, "name": "greenhouse heating", "object_type": "stream", "fluid": 'water', "stream_type": "inflow", "capacity": max(profile_hourly_heat), "monthly_generation": profile_monthly_heat, # [kWh] "hourly_generation": profile_hourly_heat, # [kWh] "supply_temperature": supply_temperature_heat, # [ºC] "target_temperature": target_temperature_heat, # [ºC] "schedule": profile, "fuel": ref_system_fuel_type, "eff_equipment": ref_system_eff_equipment } if real_heating_monthly_capacity is not None: stream_hot = adjust_capacity(stream_hot, user_monthly_capacity=real_heating_monthly_capacity) elif real_heating_yearly_capacity is not None: stream_hot = adjust_capacity(stream_hot, user_yearly_capacity=real_heating_yearly_capacity) except: raise ModuleRuntimeException( code="2", type="greenhouse.py", msg="Greenhouse characterization infeasible. Please check your inputs. \n " "If all inputs are correct report to the platform." ) ############### # OUTPUT output = {'streams': [stream_hot]} return output