Source code for pvcompare.check_inputs

"""
This module reads existing csv files from "user_inputs_mvs_directory/csv_elements/"
and adapts the values of parameters according to the current simulation.

functions this module contains:
- add_scenario_name_to_project_data
- add_location_and_year_to_project_data
- check_for_valid_country_year
- add_local_grid_parameters
- overwrite_mvs_energy_production_file
- add_parameters_to_energy_production_file
- add_file_name_to_energy_consumption_file
- add_evaluated_period_to_simulation_settings
- add_parameter_to_mvs_file
- load_parameter_from_mvs_file
- add_parameters_to_storage_xx_file

"""
import pandas as pd
import os
import logging
from pvcompare import constants

try:
    import matplotlib.pyplot as plt
except ImportError:
    plt = None


[docs]def add_scenario_name_to_project_data(user_inputs_mvs_directory, scenario_name): r""" Matches user input `scenario_name` with `scenario_name` in 'project_data.csv'. If user input `scenario_name` is different to the parameter in 'project_data.csv', a warning is returned and 'project_data.csv' is overwritten. Parameters ---------- user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. scenario_name: str Name of the Scenario. Returns ------- None """ add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="project_data.csv", mvs_row="scenario_name", mvs_column="project_data", pvcompare_parameter=scenario_name, warning=True, )
[docs]def add_location_and_year_to_project_data( user_inputs_mvs_directory, static_inputs_directory, latitude, longitude, country, year, ): r""" Matches user input for year, latitude, longitude and country with mvs_inputs. If location (latitude, longitude, country) and year are entered as user input, the according parameters in 'mvs_inputs/csv_elements' are overwritten. If one of the location elements is None, an error is returned. If location or year is None, the according parameter is loaded from 'mvs_inputs/csv_elements'. Finally, it is checked whether country and year are valid. Parameters ---------- user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. static_inputs_directory: str or None Path to pvcompare static inputs. If None, `constants.DEFAULT_STATIC_INPUTS_DIRECTORY` is used. Default: None. latitude: float Latitude of the location. longitude: float Longitude of the location. country: str Country of the location. year: int Year of the simulation. Returns ------- Latitude: float Latitude of the location. Longitude: float Longitude of the location. country: str Country of the location. year: int Year of the simulation. """ params = {"latitude": latitude, "longitude": longitude, "country": country} if all(value is None for value in params.values()): output = {} for key in params: output[key] = load_parameter_from_mvs_file( user_inputs_mvs_directory, mvs_filename="project_data.csv", mvs_row=key, mvs_column="project_data", ) latitude = float(output["latitude"]) longitude = float(output["longitude"]) country = output["country"] elif any(x is None for x in params.values()): raise ValueError( "If you want to overwrite the location parameters in the " "mvs_input files, please enter all three input parameters: " "latitude, longitude and country into the main.py user inputs." ) else: for key in params: add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="project_data.csv", mvs_row=key, mvs_column="project_data", pvcompare_parameter=params[key], warning=True, ) if year is None: start_date = load_parameter_from_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="simulation_settings.csv", mvs_row="start_date", mvs_column="simulation_settings", ) year = str(start_date)[:-15] else: start_date = str(year) + "-01-01 00:00:00" add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="simulation_settings.csv", mvs_row="start_date", mvs_column="simulation_settings", pvcompare_parameter=start_date, warning=True, ) # check if country and year are valid check_for_valid_country_year(country, year, static_inputs_directory) return latitude, longitude, country, int(year)
[docs]def check_for_valid_country_year(country, year, static_inputs_directory): r""" Checks static input files for valid countries and years. Returns error if the country or year of the simulation is not valid. Static input files that are checked: 'EUROSTAT_population.csv', 'list_of_workalender_countries.csv', 'total_electricity_consumption_residential.csv' Parameters ---------- country: str country of simulation year: int year of simulation static_inputs_directory: str or None Path to pvcompare static inputs. If None, `constants.DEFAULT_STATIC_INPUTS_DIRECTORY` is used. Default: None. Returns ------- None """ pop = pd.read_csv( os.path.join(static_inputs_directory, "EUROSTAT_population.csv"), header=0, sep=",", ) workalendar = pd.read_csv( os.path.join(static_inputs_directory, "list_of_workalender_countries.csv"), header=0, ) consumption = pd.read_excel( os.path.join( static_inputs_directory, "electricity_consumption_residential.xlsx" ), header=1, index_col=0, ) countries_pop = set(pop["country"][:43]) countries_workalender = set(workalendar["country"]) countries_consumption = set(consumption.index[:30]) years_pop = set([x for x in pop.columns if x != "country"]) years_consumption = set( [ str(x) for x in consumption.columns if x not in ["country", "ISO code", "Unit", "Source Code", "Note", "Source"] ] ) possible_countries = countries_pop & countries_workalender & countries_consumption possible_years = years_pop & years_consumption if country not in possible_countries: raise ValueError( f"The given country {country} is not recognized. " f"Please select one of the following " f"countries: {possible_countries}" ) if str(year) not in possible_years: raise ValueError( f"The given year {year} is not recognized. " f"Please select one of the following " f"years: {possible_years}" )
[docs]def add_local_grid_parameters(static_inputs_directory, user_inputs_mvs_directory): r""" Adds grid parameters such as electricity price or feed-in tariff to 'energyProviders.csv'. This function adds the grid parameters (electricity price, feed-in tariff, CO2 emissions, renewable share, gas price) from 'local_grid_parameters.xlsx' to 'energyProviders.csv'. The gas_price is only inserted if a column that starts with "Gas plant" exists in 'energProviders.csv'. If the value is already provided in the 'energyProviders.csv' and this value differs from the one in 'electricity_prices.csv' a warning is returned. If no value is available for the specific country, a default value is inserted instead and a warning is returned. Parameters ----------- user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. static_inputs_directory: str or None Path to pvcompare static inputs. If None, `constants.DEFAULT_STATIC_INPUTS_DIRECTORY` is used. Default: None. Returns -------- None """ # load grid_parameters grid_file_path = os.path.join(static_inputs_directory, "local_grid_parameters.xlsx") grid_parameters = pd.read_excel(grid_file_path, index_col=0, header=0) # load project data to select country project_data_filename = os.path.join( user_inputs_mvs_directory, "csv_elements/" "project_data.csv" ) project_data = pd.read_csv(project_data_filename, index_col=0) country = project_data.at["country", "project_data"] energy_providers_filename = os.path.join( user_inputs_mvs_directory, "csv_elements/" "energyProviders.csv" ) energy_providers = pd.read_csv(energy_providers_filename, index_col=0) list_parameters = [ "electricity_price", "gas_price", "feedin_tariff", "emission_factor", "renewable_share", ] if not energy_providers.columns.str.contains("Gas plant").any(): list_parameters.remove("gas_price") for parameter in list_parameters: value = grid_parameters.at[country, parameter] # check if parameter value is available if pd.isna(value) is True: value = grid_parameters.at["default", parameter] logging.warning( f"The parameter {parameter} for country {country} " f"is not available. Instead a default value of " f"{value} is inserted into the mvs csv." ) if parameter == "gas_price": for column in energy_providers.columns: if column.startswith("Gas plant"): add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="energyProviders.csv", mvs_row="energy_price", mvs_column=column, pvcompare_parameter=value, warning=True, ) elif parameter == "electricity_price": add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="energyProviders.csv", mvs_row="energy_price", mvs_column="Electricity grid", pvcompare_parameter=value, warning=True, ) else: add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="energyProviders.csv", mvs_row=parameter, mvs_column="Electricity grid", pvcompare_parameter=value, warning=True, )
[docs]def overwrite_mvs_energy_production_file( pv_setup, user_inputs_mvs_directory, user_inputs_pvcompare_directory, overwrite_pv_parameters, collections_mvs_inputs_directory=None, ): r""" Inserts default values for PV technologies defined in 'pv_setup.csv'. This function compares the number of powerplants in 'energyProduction.csv' with the number of rows in 'pv_setup.csv'. If the number differs the process throws an error. Parameters ---------- pv_setup: dict Dictionary that contains the surface types with technology and orientation. user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. Returns --------- None """ # load pv_setup.csv if pv_setup is None: pv_setup = pd.read_csv( os.path.join(user_inputs_pvcompare_directory, "pv_setup.csv"), index_col=0 ) technologies = pv_setup["technology"].values # load mvs user input file if user_inputs_mvs_directory is None: user_inputs_mvs_directory = constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY if collections_mvs_inputs_directory is None: collections_mvs_inputs_directory = ( constants.DEFAULT_COLLECTION_MVS_INPUTS_DIRECTORY ) filename = os.path.join( user_inputs_mvs_directory, "csv_elements/" "energyProduction.csv" ) user_input_ep = pd.read_csv(filename, index_col=0) counter = 1 if not overwrite_pv_parameters: if len(technologies) < len(user_input_ep.columns) - 1: raise ValueError( "The number of pv plants in pv_setup.csv is lower " "than the number of columns in energyProduction.csv. " "Please adapt the files or set 'overwrite_pv_parameters == True'." ) for t in technologies: label = "PV " + t if label in user_input_ep.columns: logging.info( "The technology in setup.py equals the column name " "in energyProduction.csv. It will not be overwritten." ) else: raise ValueError( "The technology in 'pv_setup.py' differs from the " "column name in 'energyProduction.csv'. Please " "adapt the technology or set 'overwrite_pv_parameters == True'." ) else: if counter == 1: user_input_ep.drop( user_input_ep.columns.difference(["index", "unit"]), 1, inplace=True ) counter += 1 # get pv parameters from collection_mvs_inputs if collections_mvs_inputs_directory is None: collections_mvs_inputs_directory = ( constants.DEFAULT_COLLECTION_MVS_INPUTS_DIRECTORY ) collection_filename = os.path.join( collections_mvs_inputs_directory, "csv_elements", "energyProduction.csv" ) collection_ep = pd.read_csv(collection_filename, index_col=0) i = 1 count_duplicates = ( pv_setup.groupby(["technology"]).size().reset_index(name="count") ) for t in technologies: label = "PV " + t for index, r in count_duplicates.iterrows(): if str(r["technology"]) == t and r["count"] > 1: new_label = "PV " + t + str(i) i += 1 else: new_label = label user_input_ep[new_label] = collection_ep[label] logging.info( f"The column {t} has been successfully added to " f"user_inputs/mvs_inputs/csv_elements/energyProduction.csv." ) user_input_ep.to_csv(filename)
[docs]def add_parameters_to_energy_production_file( technology, ts_filename, nominal_value, user_inputs_mvs_directory=None ): r""" Enters new parameters into 'energyProduction.csv'. Parameters --------- technology: str Technology of the pv plant. Should equal column name in 'energyProduction.csv'. ts_filename: str File name of the pv time series. nominal_value: float Maximum value of installable capacity. user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. Returns ------- None """ # add maximum capacity label = "PV " + technology add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="energyProduction.csv", mvs_row="maximumCap", mvs_column=label, pvcompare_parameter=nominal_value, warning=False, ) # add file name add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="energyProduction.csv", mvs_row="file_name", mvs_column=label, pvcompare_parameter=ts_filename, warning=False, )
[docs]def add_file_name_to_energy_consumption_file( column, ts_filename, user_inputs_mvs_directory=None ): r""" Enters demand time series file name to 'energyProduction.csv'. Parameters --------- column: str column name of 'energyProduction.csv' ts_filename: str file name of the demand time series user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. Returns ------- None """ add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="energyConsumption.csv", mvs_row="file_name", mvs_column=column, pvcompare_parameter=ts_filename, warning=False, )
[docs]def add_evaluated_period_to_simulation_settings(time_series, user_inputs_mvs_directory): r""" Adds number of days of the time series into 'simulation_settings.csv'. Parameters ---------- time_series: :pandas:`pandas.DataFrame<frame>` Pv time series. user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. Returns ------ None """ length = len(time_series.index) / 24 add_parameter_to_mvs_file( user_inputs_mvs_directory=user_inputs_mvs_directory, mvs_filename="simulation_settings.csv", mvs_row="evaluated_period", mvs_column="simulation_settings", pvcompare_parameter=length, warning=False, )
[docs]def add_parameter_to_mvs_file( user_inputs_mvs_directory, mvs_filename, mvs_row, mvs_column, pvcompare_parameter, warning=True, ): r""" Overwrites a value from a file in 'mvs_inputs/csv_elements' with a user input. Parameters ---------- user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. mvs_filename: str Name of the mvs-csv file. mvs_row: str Row name of the value in `mvs_filename`. mvs_column: str Column name of the value in `mvs_filename`. pvcompare_parameter: str Parameter that should be added to the mvs_csv file. warning: bool If True, a warning is returned that the parameter with the name `mvs_row` is overwritten. Returns ------ None """ if user_inputs_mvs_directory == None: user_inputs_mvs_directory = constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY filename = os.path.join(user_inputs_mvs_directory, "csv_elements", mvs_filename) # load mvs_csv_file mvs_file = pd.read_csv(filename, index_col=0) if warning is True: if mvs_file.at[mvs_row, mvs_column] != pvcompare_parameter: logging.warning( f"The parameter {pvcompare_parameter} differs from " f"the parameter {mvs_row} in {mvs_filename} and thus will " f"be overwritten." ) mvs_file.loc[[mvs_row], [mvs_column]] = pvcompare_parameter mvs_file.to_csv(filename) logging.info( f"The parameter {mvs_row} has been added to the " f"mvs input file {mvs_filename}." )
[docs]def load_parameter_from_mvs_file( user_inputs_mvs_directory, mvs_filename, mvs_row, mvs_column ): r""" Loads a value from a file in 'mvs_inputs/csv_elements'. Parameters ---------- user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. mvs_filename: str Name of the mvs-csv file. mvs_row: str Row name of the value in `mvs_filename`. mvs_column: str Column name of the value in `mvs_filename`. Returns ------ pvcompare_parameter: str, float, int Parameter that is loaded from mvs_file. """ if user_inputs_mvs_directory == None: user_inputs_mvs_directory = constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY filename = os.path.join(user_inputs_mvs_directory, "csv_elements", mvs_filename) # load mvs_csv_file mvs_file = pd.read_csv(filename, index_col=0) pvcompare_parameter = mvs_file.at[mvs_row, mvs_column] logging.info( f"The parameter {mvs_row} has been loaded from the " f"mvs input file {mvs_filename}." ) return pvcompare_parameter
[docs]def add_parameters_to_storage_xx_file( nominal_storage_capacity, loss_rate, storage_csv, user_inputs_mvs_directory=None ): r""" Enters new parameters into 'storage_xx.csv'. Parameters --------- nominal_storage_capacity : float Maximum amount of stored thermal energy [MWh]. loss_rate : float (sequence or scalar) The relative loss of the storage capacity between two consecutive timesteps [-]. storage_csv: str Name of the storage specific file. user_inputs_mvs_directory: str or None Path to MVS specific input directory. If None, `constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY` is used. Default: None. Returns ------- None """ if user_inputs_mvs_directory == None: user_inputs_mvs_directory = constants.DEFAULT_USER_INPUTS_MVS_DIRECTORY # Read storage_xx.csv from input value storage_xx_path = os.path.join( user_inputs_mvs_directory, "csv_elements", storage_csv ) storage_xx = pd.read_csv(storage_xx_path, header=0, index_col=0,) parameters = {"installedCap": nominal_storage_capacity, "efficiency": 1 - loss_rate} for name, param in parameters.items(): # Check if efficiency and nominal storage capacity already exist and if not # replace with calculated value from loss_rate try: int(float(storage_xx.at[name, "storage capacity"])) logging.info( f"The {name} of the storage already exists in {storage_csv}. If you want to calculate the storage's {name} with pvcompare please delete the value in {storage_csv}." ) except ValueError: # insert parameter values storage_xx.loc[[name], ["storage capacity"]] = param logging.info(f"The {name} of the storage has been added to {storage_csv}.") # Save values in storage_xx.csv storage_xx.to_csv(storage_xx_path)