def test_raised_exception_05(): """Test if an exception is raised if ... """ with pytest.raises(ValueError): cmpr_hp_chllr.calc_cops(temp_high=[39], temp_low=[17], quality_grade=0.4, mode='chiller', temp_threshold_icing=2, factor_icing=0.8)
def test_raised_exception_01(): """Test if an exception is raised if temp_low is not a list.""" with pytest.raises(TypeError): cmpr_hp_chllr.calc_cops( temp_high=[40], temp_low=12, # ERROR - temp_low has to be a list! quality_grade=0.4, mode='heat_pump', temp_threshold_icing=2, factor_icing=0.8)
def test_raised_exception_03(): """Test if an exception is raised if temp_high and temp_low have different length AND none of them is of length 1.""" with pytest.raises(IndexError): cmpr_hp_chllr.calc_cops( temp_high=[40, 39, 39], temp_low=[12, 10], # ERROR - len(temp_low) has # to be 1 or equal to len(temp_high) quality_grade=0.4, mode='heat_pump', temp_threshold_icing=2, factor_icing=0.8)
def test_cop_calculation_airsource_hp_with_icing_02(): cops_ASHP = cmpr_hp_chllr.calc_cops(temp_high=[40], temp_low=[2.3], quality_grade=0.5, mode='heat_pump', temp_threshold_icing=2, factor_icing=0.8) assert cops_ASHP == [4.15318302387268]
def test_calc_cops_with_Series_02(): set_temp_each_hour = {'01:00': 40, '02:00': 40, '03:00': 40} temp_h_series = pd.Series(set_temp_each_hour) cops_HP = cmpr_hp_chllr.calc_cops(temp_high=temp_h_series, temp_low=[12], quality_grade=0.4, mode='heat_pump') assert cops_HP == [4.473571428571428, 4.473571428571428, 4.473571428571428]
def test_calc_cops_with_Series_01(): ambient_temp_each_hour = {'01:00': 12, '02:00': 12, '03:00': 12} temp_l_series = pd.Series(ambient_temp_each_hour) cops_HP = cmpr_hp_chllr.calc_cops(temp_high=[40], temp_low=temp_l_series, quality_grade=0.4, mode='heat_pump') assert cops_HP == [4.473571428571428, 4.473571428571428, 4.473571428571428]
def test_cop_calculation_airsource_hp_with_icing_01(): cops_ASHP = cmpr_hp_chllr.calc_cops(temp_high=[40], temp_low=[1.3], quality_grade=0.5, mode='heat_pump', temp_threshold_icing=2, factor_icing=0.8) assert cops_ASHP == [3.236692506459949]
# Delta t temp_difference = range(10, 71, 1) temp_difference_industrial = range(20, 142, 2) temperature_diff_q_grade = range(5, 147, 2) # Quality grades quality_grades = [q / 10 for q in range(2, 11, 2)] cops = pd.DataFrame() # COPs of ax exemplary heat pump for domestic hot water # (sink temperature below 100 degC) cops['temperature_difference'] = temp_difference list_temp_low = [temp_high - temp_diff for temp_diff in temp_difference] cops[temp_high] = cmpr_hp_chiller.calc_cops(temp_high=[temp_high], temp_low=list_temp_low, quality_grade=0.35, mode='heat_pump') # COPs of ax exemplary hight temperature heat pump for industrial applications # (sink temperature above 100 degC and higher quality grade) cops['temperature_difference_industrial'] = temp_difference_industrial temp_l_ind = [ temp_high_industrial - temp_diff for temp_diff in temp_difference_industrial ] cops[temp_high_industrial] = cmpr_hp_chiller.calc_cops( temp_high=[temp_high_industrial], temp_low=temp_l_ind, quality_grade=0.45, mode='heat_pump')
def calculate_cops_and_eers( weather, lat, lon, mode, temperature_col="temp_air", user_inputs_pvcompare_directory=None, user_inputs_mvs_directory=None, ): r""" Calculates the COPs of a heat pump or EERs of a chiller depending on `mode`. Temperature dependency is taken into consideration. For these calculations the ``calc_cops()` <functionality>`_ functionality of `oemof.thermal <https://oemof-thermal.readthedocs.io/en/stable/>`_ is used. Data like quality grade and factor icing is read from the file `heat_pumps_and_chillers.csv` in the `input_directory`. Negative values, which might occur due to high ambient temperatures in summer are set to zero. Parameters ---------- weather : :pandas:`pandas.DataFrame<frame>` Contains weather data time series. Required: ambient temperature in column `temperature_col`. lat : float Latitude of ambient temperature location in `weather`. lon : float Longitude of ambient temperature location in `weather`. temperature_col : str Name of column in `weather` containing ambient temperature. Default: "temp_air". mode : str Defines whether COPs of heat pump ("heat_pump") or EERs of chiller ("chiller") are calculated. Default: "heat_pump". user_inputs_pvcompare_directory: str or None Path to user input directory. If None, `constants.DEFAULT_USER_INPUTS_PVCOMPARE_DIRECTORY` is used. Default: None. user_inputs_mvs_directory: str or None Path to input directory containing files that describe the energy system and that are an input to MVS. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. Returns ------- None """ # read parameters from file if user_inputs_pvcompare_directory == None: user_inputs_pvcompare_directory = ( constants.DEFAULT_USER_INPUTS_PVCOMPARE_DIRECTORY) if user_inputs_mvs_directory == None: user_inputs_mvs_directory = constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY filename = os.path.join(user_inputs_pvcompare_directory, "heat_pumps_and_chillers.csv") try: parameters_complete = pd.read_csv(filename) parameters = pd.read_csv(filename, header=0, index_col=0).loc[mode] except KeyError: raise ValueError( f"Parameter `mode` should be 'heat_pump' or 'chiller' but is {mode}" ) # prepare parameters for calc_cops def process_temperatures(temperature, level, mode, technology): r""" Processes temperatures for specific `level`, `mode`, and `technology`. `temperature` can be passed in the following way: 1. As NaN - The lower/higher temperature of the heat pump/chiller equals the ambient temperature time series 2. As single value (float or int) - The temperature is constant 3. As time series - The temperature is not constant or differs from ambient temperature (eg. ground source) Parameters ---------- temperature : float, int, np.nan, :pandas:`pandas.Series<series> Passed temperature which was written from input data. level : str Defines whether high or low temperature has been passed. mode : str Defines whether COPs of heat pump ("heat_pump") or EERs of chiller ("chiller") are calculated. technology: str Defines whether technology is a "brine-water", "air-air" or "air-water". Returns ------- temperature: list Temperature adjusted to use case of plant. """ if isinstance(temperature, float): if pd.isna(temperature): # In case of NaN if (level == "low" and mode == "heat_pump") or (level == "high" and mode == "chiller"): if technology == "brine-water": # Prepare mean yearly ambient temperature for calc_cops (numeric) temperature = np.average( weather[temperature_col].values) temperature = [temperature] elif technology == "air-air" or technology == "air-water": # Prepare ambient temperature for calc_cops (list) temperature = weather[temperature_col].values.tolist() logging.info( f"The {mode} is modeled with the ambient temperature from weather data as {level} temperature." ) else: # Prepare ambient temperature for calc_cops (list) temperature = weather[temperature_col].values.tolist() logging.warning( f"The technology of the {mode} should be either 'air-air', 'air-water' or 'brine-water'." f"'{technology}' is not a valid technology. The {mode} is modeled as an air source {mode} by default" f" and with the ambient temperature from weather data as {level} temperature." ) return temperature else: # Required parameter is missing raise ValueError( f"Missing required value of {mode}: Please provide a numeric as {mode}'s {level} temperature in heat_pumps_and_chillers.csv." ) elif isinstance(temperature, (float, int)): # Numerics pass temperature = [temperature] logging.info( f"The {mode} is modeled with the constant {level} temperature of {temperature} °C" ) return temperature elif isinstance(temperature, str): # In case temperatures are provided as time series in separate file try: temp_string = temperature.split("'") temp_filename = temp_string[3] temp_header = temp_string[7] temperature_df = pd.read_csv( os.path.join(user_inputs_pvcompare_directory, temp_filename)) temperature_df = temperature_df.set_index(temp_header) temperature = temperature_df.index.tolist() logging.info( f"The {mode} is modeled with passed time series as {level} temperature." ) return temperature except AttributeError: raise ValueError( f"Wrong value: Please check the {level} temperature of the {mode}. See the documentation on passing the {mode}'s temperatures for further information" ) else: # Required parameter is missing in case of None or else raise ValueError( f"Missing required value of {mode}: Please provide a numeric as {mode}'s {level} temperature in heat_pumps_and_chillers.csv." ) low_temperature = process_temperatures(parameters.temp_low, "low", mode, parameters.technology) high_temperature = process_temperatures(parameters.temp_high, "high", mode, parameters.technology) if pd.isna(parameters.quality_grade): if parameters.technology == "air-air": if mode == "heat_pump": quality_grade = 0.1852 elif mode == "chiller": quality_grade = 0.3 elif parameters.technology == "air-water": if mode == "heat_pump": quality_grade = 0.403 elif mode == "chiller": # Required parameter is missing in case of None or else raise ValueError( f"Missing required value of {mode}: There is no default value of a quality grade provided for an {parameters.technology} {mode}" f"Please provide a valid value of the quality grade.") elif parameters.technology == "brine-water": if mode == "heat_pump": quality_grade = 0.53 elif mode == "chiller": # Required parameter is missing in case of None or else raise ValueError( f"Missing required value of {mode}: There is no default value of a quality grade provided for a {parameters.technology} {mode}. " f"Please provide a valid value of the quality grade.") else: # Required parameter is missing in case of different technology raise ValueError( f"Missing required value of {mode}: '{parameters.quality_grade}' could not be processed as quality grade. " f"Please provide a valid value or the technology of the {mode} in order to model with default quality grade." ) elif isinstance(parameters.quality_grade, (float, int)): quality_grade = float(parameters.quality_grade) else: # Required parameter is missing in case of None or else raise ValueError( f"Missing required value of {mode}: '{parameters.quality_grade}' could not be processed as quality grade." f"Please provide a valid value or the technology of the {mode} in order to model from default quality grade." ) # Save default quality grade to heat_pumps_and_chillers.csv parameters_complete.quality_grade = quality_grade parameters_complete.to_csv(filename, index=False, header=True, float_format="%g") # create add on to filename (year, lat, lon) year = maya.parse(weather.index[int(len(weather) / 2)]).datetime().year # calculate COPs or EERs with oemof thermal if mode == "heat_pump": if len(high_temperature) > 1: add_on = f"_{year}_{lat}_{lon}" elif len(high_temperature) == 1: add_on = f"_{year}_{lat}_{lon}_{high_temperature[0]}" # additional parameters for heat_pump mode factor_icing = (None if parameters.factor_icing == "None" else float( parameters.factor_icing)) temp_threshold_icing = (None if parameters.temp_threshold_icing == "None" else float(parameters.temp_threshold_icing)) efficiency = cmpr_hp_chiller.calc_cops( temp_high=high_temperature, temp_low=low_temperature, quality_grade=quality_grade, mode=mode, temp_threshold_icing=temp_threshold_icing, factor_icing=factor_icing, ) # define variables for later proceeding column_name = "cop" filename = f"cops_heat_pump{add_on}.csv" elif mode == "chiller": if len(low_temperature) > 1: add_on = f"_{year}_{lat}_{lon}" elif len(low_temperature) == 1: add_on = f"_{year}_{lat}_{lon}_{low_temperature[0]}" efficiency = cmpr_hp_chiller.calc_cops( temp_high=high_temperature, temp_low=low_temperature, quality_grade=quality_grade, mode=mode, ) column_name = "eer" filename = f"eers_chiller{add_on}.csv" # add list of cops/eers to data frame df = pd.DataFrame(weather[temperature_col]) try: df[column_name] = efficiency except ValueError: df[column_name] = np.multiply(efficiency, np.ones(len(df))) # set negative COPs/EERs to np.inf # COP/EER below zero results from temp_low > temp_high # and will therefore be represented with COP/EER -> infinity indices = df.loc[df[column_name] < 0].index df[column_name][indices] = np.inf # extract COPs/EERs as pd.Series from data frame efficiency_series = df[column_name] efficiency_series.name = "no_unit" # save time series to `user_inputs_mvs_directory/time_series` time_series_directory = os.path.join(user_inputs_mvs_directory, "time_series") logging.info( f"The cops of a heat pump are calculated and saved under {time_series_directory}." ) efficiency_series.to_csv(os.path.join(time_series_directory, filename), index=False, header=True) return efficiency_series
""" Example on how to use the 'calc_cops' function to get the COPs of a compression chiller. We use the ambient air as heat sink (high temperature reservoir). The input is a list to show how the function can be applied on several time steps. The output is a list as well and may serve as input (conversion_factor) for a oemof.solph.transformer. """ import oemof.thermal.compression_heatpumps_and_chillers as cmpr_hp_chiller # Ambient temperatures in degC for a single day (24h) temp_ambient = [ 24, 24, 24, 25, 25, 25, 26, 27, 28, 29, 31, 32, 35, 34, 27, 26, 25, 24, 24, 24, 24, 24, 24, 23 ] cops_chiller = cmpr_hp_chiller.calc_cops(temp_high=temp_ambient, temp_low=[18], quality_grade=0.3, mode='chiller') print("") print("Coefficients of Performance (COP):") t = 1 for cop_chiller in cops_chiller: print(t, "h: {:2.2f}".format(cop_chiller)) t += 1 print("")
def test_cop_calculation_chiller(): cops_chiller = cmpr_hp_chllr.calc_cops(temp_high=[35], temp_low=[17], quality_grade=0.45, mode='chiller') assert cops_chiller == [7.25375]
""" Example on how to use the 'calc_cops' function to get the COPs of an exemplary ground-source heat pump (GSHP). We use the soil temperature as low temperature heat reservoir. """ import oemof.thermal.compression_heatpumps_and_chillers as cmpr_hp_chiller import pandas as pd import os # set path path_data= r'C:\Users\Stefanie.nguyen\git\COP_calculation\oemof-thermal\examples\compression_heatpump_and_chiller' # Precalculation of COPs cops_GSHP = cmpr_hp_chiller.calc_cops( temp_high=[37.43], temp_low=[10], quality_grade=0.53, mode='heat_pump') GSHP_dict={'ground_temperature':[10], 'temperature_sink':[37.43], 'COP':cops_GSHP} data=pd.DataFrame(GSHP_dict) #data.to_csv(os.path.join(os.path.dirname(__file__) , 'data/results/2021-03-16_GSHP_COP.csv'))
def test_cop_calculation_hp_list_input_02(): cops_HP = cmpr_hp_chllr.calc_cops(temp_high=[40], temp_low=[12, 12], quality_grade=0.4, mode='heat_pump') assert cops_HP == [4.473571428571428, 4.473571428571428]
# Borehole that acts as heat source for the heat pump with # limited extraction heat flow rate energysystem.add( solph.Source(label='ambient', outputs={b_th_low: solph.Flow(nominal_value=30)})) energysystem.add( solph.Sink(label='demand', inputs={ b_th_high: solph.Flow(fix=data['demand_heat'], nominal_value=1) })) # Precalculation of COPs cops_GSHP = cmpr_hp_chiller.calc_cops(temp_high=[40], temp_low=data['ground_temperature'], quality_grade=0.4, mode='heat_pump') # Ground-Source Heat Pump energysystem.add( solph.Transformer( label="GSHP", inputs={ b_el: solph.Flow(), b_th_low: solph.Flow() }, outputs={b_th_high: solph.Flow(nominal_value=25, variable_costs=5)}, conversion_factors={ b_el: [1 / cop for cop in cops_GSHP], b_th_low: [(cop - 1) / cop for cop in cops_GSHP] }))
label='backup_heating', outputs={b_heat: solph.Flow(variable_costs=10)})) energysystem.add(solph.Sink( label='demand', inputs={b_heat: solph.Flow(actual_value=data['demand_heat'], fixed=True, nominal_value=1)})) temp_threshold_icing = 2 # Pre-Calculate COPs cops_ASHP = cmpr_hp_chiller.calc_cops( temp_high=[40], temp_low=data['ambient_temperature'], quality_grade=0.4, mode='heat_pump', consider_icing=True, temp_threshold_icing=temp_threshold_icing, factor_icing=0.8) # Air-Source Heat Pump energysystem.add(solph.Transformer( label="ASHP", inputs={b_el: solph.Flow()}, outputs={b_heat: solph.Flow(nominal_value=25, variable_costs=5)}, conversion_factors={b_heat: cops_ASHP})) model = solph.Model(energysystem) model.solve(solver=solver, solve_kwargs={'tee': solver_verbose})
def __init__(self, params): """Constructor method """ # Call the init function of the mother class. Component.__init__(self) # ------------------- PARAMETERS ------------------- self.name = 'Heat_pump_default_name' self.bus_el = None self.bus_th = None # Max. heating output [W] self.power_max = 1000e3 # Life time [a] self.life_time = 20 self.csv_filename = None self.csv_separator = ',' self.column_title = 0 self.path = os.path.dirname(__file__) # ------------------- PARAMETERS BASED ON OEMOF THERMAL EXAMPLE ------------------- # Temperature below which icing occurs [K] self.temp_threshold_icing = 275.15 # Convert to degrees C for oemof_thermal function self.temp_threshold_icing_C = self.temp_threshold_icing - 273.15 # The output temperature from the heat pump [K] self.temp_high = 313.15 # Convert to degrees C for oemof_thermal function self.temp_high_C = self.temp_high - 273.15 # Convert to a list for oemof_thermal function self.temp_high_C_list = [self.temp_high_C] # The ambient temperature [K] self.temp_low = 283.15 # Convert to degrees C for oemof_thermal function self.temp_low_C = self.temp_low - 273.15 # Quality grade of heat pump [-] self.quality_grade = 0.4 # Can be set to heat pump or chiller self.mode = 'heat_pump' # COP reduction caused by icing [-] self.factor_icing = 0.8 # Ask Jann about this/look more into detail # self.consider_icing = False # ------------------- UPDATE PARAMETER DEFAULT VALUES ------------------- self.set_parameters(params) if self.csv_filename is not None: # A csv file containing data for the ambient temperature is required [deg C] self.temp_low = func.read_data_file(self.path, self.csv_filename, self.csv_separator, self.column_title) self.temp_low_series = self.temp_low[self.column_title] self.temp_low_series_C = pd.Series(self.temp_low_series - 273.15) else: self.temp_low_list = [self.temp_low_C ] * self.sim_params.n_intervals self.temp_low_series_C = pd.Series(self.temp_low_list) # A function taken from oemof thermal that calculates the coefficient # of performance (pre-calculated) self.cops = cmpr_hp_chiller.calc_cops( self.mode, self.temp_high_C_list, self.temp_low_series_C, self.quality_grade, self.temp_threshold_icing_C, # self.consider_icing, self.factor_icing)
data_reduct = data.loc['2016-01-01 00:00:00':'2017-01-01 00:00:00'].reset_index() #print(data_reduct) else: raise Exception('Date time range does not exist. Please try another data set.') dataframe = pd.concat([data_reduct['date_time'], data_reduct['ambient_temperature'], data_reduct['temperature_sink']], axis=1).set_index('date_time') #if ambient temperature is higher than 20°C, set temperature sinks to 46.9°C for warm water use only dataframe.loc[dataframe.ambient_temperature > 20, 'temperature_sink'] = 46.9 # Precalculation of COPs cops_ASHP = cmpr_hp_chiller.calc_cops( temp_high=dataframe['temperature_sink'], temp_low=dataframe['ambient_temperature'], quality_grade=0.4030, mode='heat_pump') COP=pd.DataFrame(cops_ASHP, data_reduct['date_time'], columns=['COP']) #pre processing sink temperature list_temp_low = dataframe['ambient_temperature'].values.tolist() # External temperature of evaporator list_temp_medium = dataframe['temperature_sink'].values.tolist() # External temperature of condenser # Calculate temperature difference between condenser and evaporator temp_diff = [(t_m - t_l) for (t_m, t_l) in zip(list_temp_medium, list_temp_low)] temp_diff_dataframe = pd.DataFrame(temp_diff, data_reduct['date_time'], columns=['temp_diff']) #Concatenate final data and save COP_data=pd.concat([dataframe, COP, temp_diff_dataframe], axis=1)