Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement OffsetTransformer as another generator model #92

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,40 @@ Here is a template for new release sections

### Added
- Version number with `src/version.py` (#150)
- Constant variables in `constants.py`: `INPUT_TEMPLATE_EXCEL_XLSX`(#150), `GENSET_HOURS_OF_OPERATION` (#153)
- Constant variables in `constants.py`: `INPUT_TEMPLATE_EXCEL_XLSX`(#150), `GENSET_HOURS_OF_OPERATION` (#153), `EFFICIENCY_GENSET_TIMESERIES`, `CONSUMPTION_FUEL_TIMESERIES_KWH`, `GENSET_WITH_EFFICIENCY_CURVE` (#92)
- Added pytests for `D1.crf` and `D1.present_value_of_changing_fuel_price` (#153)
- Implement new KPI: `GENSET_HOURS_OF_OPERATION` with new function `G3.get_hours_of_operation()` for generator evaluation, including pytests (#153)
- Create `B.process_generator_settings` to evaluate different generator settings, including pytests (#92)
- Implement OffsetTransformer with new parameter `GENSET_WITH_EFFICIENCY_CURVE` with `G2a.genset_fix_capacity_efficiency_curve_and_minimal_loading`. Note: Efficiency of the new OffSet Transformer with efficiency curve (#92)
uses the `GENSET_EFFICIENCY` as maximum efficiency, and `GENSET_EFFICIENCY/2` as minimal part-load efficiency (#92)
- New folder `tests/benchmark_tests` and `tests/benchmark_tests/timeseries/test_site.csv` to serve future tests (#92)
- Benchmark test for generator with efficiency curve (OffsetTransformer): Add `tests/benchmark_tests/generator_with_efficiency_curve.xlsx`, ie. a base case with optimization of the diesel generator and a follow-up case which uses that capacities to simulate a diesel generator with efficiency with the same capacities at the same location. Only ensures that simulation does not terminate. (#92)
- Calculate `EFFICIENCY_GENSET_TIMESERIES` with `G3.get_efficiency_genset`. This calculates the effective generator efficiency. In case that multiple generators are present, it represents the average efficiency, as it is based on the aggregated generator dispatch. (#92)

### Changed
- Execute all pytests in Travis `.travis.yml` (#150)
- Added version number to `setup.py` (#150)
- Moved `main()` from `Offgridders.py` to new file `src/cli.py` (#150)
- Enable benchmark tests for Offgridders: Add optional argument `input_file` to `main()` (#150)
- Added `GENSET_HOURS_OF_OPERATION` in `C1.overall_results_title` (#153)
- Reorder variables in `constants.py` (#92)
- Change `tests/test_basic.py`: Remove pytests for black, as they do not work (#92)
- Refactor `inputs/test_input_template.xlsx` to `inputs/input_teplate_excel.xslx` (#92)
- All input templates to feature new parameter `EFFICIENCY_GENSET_TIMESERIES` (#92)
- Refactored`G2a.genset_fix` to `G2a.genset_fix_capacity_fix_efficiency_no_minload`, `G2a.genset_fix_minload` to `G2a.genset_fix_capacity_fix_efficiency_with_minload` and `G2a.genset_oem` to `G2a.genset_oem_fix_efficiency_no_minload` to make them explicit and improved logging messages (#92)
- Expand elif-statements in `G1` to choose appropriate generator model (#92)
- `G3.get_fuel()` to also store the `CONSUMPTION_FUEL_TIMESERIES_KWH` to `e_flows_df` (#92)
- `G4.save_mg_flows()` to store `EFFICIENCY_GENSET_TIMESERIES` and `CONSUMPTION_FUEL_TIMESERIES_KWH` to csv (#92)
- `G4.save_mg_flows()` to generate an efficiency curve from `EFFICIENCY_GENSET_TIMESERIES` if `GENSET_WITH_EFFICIENCY_CURVE==True` (#92)
- `F.update_dict` so that new parameter `GENSET_WITH_EFFICIENCY_CURVE` is parsed (#92)

### Removed
-

### Fixed
- Basic pytest to ensure no termination with test input file (`tests/inputs/pytest_test.xlsx`) (#150)
- `present_value_of_changing_fuel_price` now correctly calculated, fixed function call of `D1.present_value_of_changing_fuel_price` in `D0` (#153)
- Irregular use of `capacity_inverter_kW`, use only `capacity_inverter_dc_ac_kW` (#92)

## [Offgridders V4.6.1] - 2020-11-07

Expand Down
Binary file added inputs/input_template_excel.xlsx
Binary file not shown.
Binary file removed inputs/test_input_template.xlsx
Binary file not shown.
75 changes: 73 additions & 2 deletions src/B_read_from_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
VALUE,
CASE_NAME,
MAX_SHORTAGE,
CAPACITY_GENSET_KW,
NUMBER_OF_EQUAL_GENERATORS,
GENSET_WITH_EFFICIENCY_CURVE,
GENSET_WITH_MINIMAL_LOADING,
OEM,
DIMENSIONS,
CRITERIA,
PARAMETERS,
Expand Down Expand Up @@ -301,7 +305,6 @@ def get_parameters_constant(file, sheet_input_constant):
"consumed from the (fully coal-based) maingrid."
)

# print(parameters_constant_values)
return parameters_constant_units, parameters_constant_values


Expand Down Expand Up @@ -392,7 +395,6 @@ def get_case_definitions(file, sheet_project_sites):
# case_definitions.drop(case_definitions.columns[case_definitions.columns.str.contains('unnamed', case=False)], axis=1, inplace=True)

case_definitions = case_definitions.to_dict(orient="dict")

# Translate strings 'True' and 'False' from excel sheet to True and False

for case in case_definitions:
Expand All @@ -406,6 +408,8 @@ def get_case_definitions(file, sheet_project_sites):
{MAX_SHORTAGE: float(case_definitions[case][MAX_SHORTAGE])}
)

process_generator_settings(case_definition=case_definitions[case], case=case)

if case_definitions[case][EVALUATION_PERSPECTIVE] not in [
AC_SYSTEM,
DC_SYSTEM,
Expand All @@ -424,6 +428,73 @@ def get_case_definitions(file, sheet_project_sites):
return case_definitions


MISSING_PARAMETER_WARNING = (
"It will be required with the next major release of Offgridders."
)
OPTIMIZATION_NOT_POSSIBLE_MINLOAD_OEM = "Currently, this optimization is not possible with oemof or Offgridders and will be neglected."
OPTIMIZATION_NOT_POSSIBLE_OFFSET_TRANSFORMER_OEM = "This is not possible, as the efficiency curve is calculated based on the maximum and minimum dispatchable capacity of the diesel generator."
NO_MINIMAL_LOADING_WITH_OFFSET_TRANSFORMER = "In general, the generator with efficiency curve can be simulated with minimal loading, but with this setting the minimal loading is deactivated."


def process_generator_settings(case_definition, case):
r"""
Evaluate settings on tab `case_definitions` of the input file regarding the combination of possible generator settings.

Generators can be defined with parameters the CAPACITY_GENSET_KW, GENSET_WITH_EFFICIENCY_CURVE, GENSET_WITH_MINIMAL_LOADING,
but not all combinations are valid or expected. This function displays warnings when an invalid combination is used.
It especially results in an ERROR logging message if an optimization is tried with a GENSET_WITH_EFFICIENCY_CURVE==True or
GENSET_WITH_MINIMAL_LOADING == True.

Parameters
----------
case_definition: dict
Information of one specific case defined in the case tab in the excel sheet
case: str
Case name

Returns
-------
Nothing, potentially adds logging messages.
"""
if GENSET_WITH_EFFICIENCY_CURVE not in case_definition:
case_definition.update({GENSET_WITH_EFFICIENCY_CURVE: False})
logging.warning(
f"For case {case} a parameter {GENSET_WITH_EFFICIENCY_CURVE} is missing. {MISSING_PARAMETER_WARNING} For this simulation, it is set to the default setting `False`."
)
if case_definition[CAPACITY_GENSET_KW] is None:
logging.debug(f"The energy system of case {case} does not include a generator.")
else:
# Create warnings for weird combinations of diesel generator simulation settings
if case_definition[CAPACITY_GENSET_KW] == OEM:
logging.debug(f"For case {case} the diesel generator should be optimized.")
if case_definition[GENSET_WITH_MINIMAL_LOADING] is True:
logging.warning(
f"At the same time, {GENSET_WITH_MINIMAL_LOADING} is set to `True`."
f"{OPTIMIZATION_NOT_POSSIBLE_MINLOAD_OEM}"
)

if case_definition[GENSET_WITH_EFFICIENCY_CURVE] is True:
logging.error(
f"At the same time, {GENSET_WITH_EFFICIENCY_CURVE} is set to `True`. "
f"{OPTIMIZATION_NOT_POSSIBLE_OFFSET_TRANSFORMER_OEM}"
)
else:
logging.debug(
f"The energy system of {case} has a generator with fixed capacity, therefore all generator types are possible."
)
if (
case_definition[GENSET_WITH_EFFICIENCY_CURVE] is True
and case_definition[GENSET_WITH_MINIMAL_LOADING] is False
):
logging.warning(
f"For case {case} the diesel generator parameteter {GENSET_WITH_EFFICIENCY_CURVE} is set to `True`."
f"and {GENSET_WITH_MINIMAL_LOADING} is set to False. "
f"{NO_MINIMAL_LOADING_WITH_OFFSET_TRANSFORMER}"
)

return


def get_multicriteria_data(file, sheet_multicriteria_analysis, case_definitions):
"""
Defines dictionary connected to multicriteria analysis based on their case definition
Expand Down
4 changes: 2 additions & 2 deletions src/C_sensitivity_experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@
CASE,
RESULTS_DEMAND_CHARACTERISTICS,
RESULTS_BLACKOUT_CHARACTERISTICS,
CAPACITY_INVERTER_KW,
LCOE,
ANNUITY,
NPV,
Expand Down Expand Up @@ -183,6 +182,7 @@
CAPACITY_STORAGE_KWH,
POWER_STORAGE_KW,
CAPACITY_RECTIFIER_AC_DC_KW,
CAPACITY_INVERTER_DC_AC_KW,
CAPACITY_WIND_KW,
CAPACITY_GENSET_KW,
CO2_EMISSIONS_KGC02EQ,
Expand Down Expand Up @@ -1300,7 +1300,7 @@ def overall_results_title(settings, number_of_project_sites, sensitivity_array_d
CAPACITY_STORAGE_KWH,
POWER_STORAGE_KW,
CAPACITY_RECTIFIER_AC_DC_KW,
CAPACITY_INVERTER_KW,
CAPACITY_INVERTER_DC_AC_KW,
CAPACITY_WIND_KW,
CAPACITY_GENSET_KW,
CAPACITY_PCOUPLING_KW,
Expand Down
2 changes: 2 additions & 0 deletions src/F_case_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
ABS_PEAK_DEMAND_AC_SIDE,
EVALUATED_DAYS,
GENSET_WITH_MINIMAL_LOADING,
GENSET_WITH_EFFICIENCY_CURVE,
CAPACITY_PV_KWP,
CAPACITY_WIND_KW,
CAPACITY_RECTIFIER_AC_DC_KW,
Expand Down Expand Up @@ -110,6 +111,7 @@ def update_dict(capacities_oem, specific_case, experiment):
PEAK_DEMAND: experiment[ABS_PEAK_DEMAND_AC_SIDE],
EVALUATED_DAYS: experiment[EVALUATED_DAYS],
GENSET_WITH_MINIMAL_LOADING: specific_case[GENSET_WITH_MINIMAL_LOADING],
GENSET_WITH_EFFICIENCY_CURVE: specific_case[GENSET_WITH_EFFICIENCY_CURVE],
}
)

Expand Down
4 changes: 3 additions & 1 deletion src/G0_oemof_simulate.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,13 @@ def run(experiment, case_dict):
e_flows_df,
)

timeseries.get_fuel(case_dict, oemof_results, results)
e_flows_df = timeseries.get_fuel(case_dict, oemof_results, results, e_flows_df)
e_flows_df = timeseries.get_genset(
case_dict, oemof_results, electricity_bus_ac, e_flows_df
)

e_flows_df = timeseries.get_efficiency_genset(e_flows_df)

e_flows_df = timeseries.get_national_grid(
case_dict,
oemof_results,
Expand Down
28 changes: 17 additions & 11 deletions src/G1_oemof_create_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
SYMBOLIC_SOLVER_LABELS,
OEMOF_FOLDER,
CASE_DEFINITIONS,
GENSET_WITH_EFFICIENCY_CURVE
)


Expand Down Expand Up @@ -109,19 +110,14 @@ def build(experiment, case_dict):
if case_dict[GENSET_FIXED_CAPACITY] == None:
genset = None
elif case_dict[GENSET_FIXED_CAPACITY] is False:
if case_dict[GENSET_WITH_MINIMAL_LOADING] is True:
# not possible with oemof
if case_dict[GENSET_WITH_MINIMAL_LOADING] is True or case_dict[GENSET_WITH_EFFICIENCY_CURVE] is True:
logging.error(
"It is not possible to optimize a generator with minimal loading in oemof. \n "
+ " "
+ " "
+ " "
+ f"Please set {GENSET_WITH_MINIMAL_LOADING}=False for this case on tab {CASE_DEFINITIONS} in the excel template."
+ f"Please set {GENSET_WITH_MINIMAL_LOADING}=False and {GENSET_WITH_EFFICIENCY_CURVE}=False for this case on tab {CASE_DEFINITIONS} in the excel template."
)
sys.exit()
# genset = generate.genset_oem_minload(micro_grid_system, bus_fuel, bus_electricity_ac, experiment, case_dict['number_of_equal_generators'])
else:
genset = generate.genset_oem(
genset = generate.genset_oem_fix_efficiency_no_minload(
micro_grid_system,
bus_fuel,
bus_electricity_ac,
Expand All @@ -130,8 +126,18 @@ def build(experiment, case_dict):
)

elif isinstance(case_dict[GENSET_FIXED_CAPACITY], float):
if case_dict[GENSET_WITH_MINIMAL_LOADING] is True:
genset = generate.genset_fix_minload(
if case_dict[GENSET_WITH_EFFICIENCY_CURVE] is True:
genset = generate.genset_fix_capacity_efficiency_curve_and_minimal_loading(
micro_grid_system,
bus_fuel,
bus_electricity_ac,
experiment,
capacity_fuel_gen=case_dict[GENSET_FIXED_CAPACITY],
number_of_equal_generators=case_dict[NUMBER_OF_EQUAL_GENERATORS],
minimal_loading=case_dict[GENSET_WITH_MINIMAL_LOADING]
)
elif case_dict[GENSET_WITH_MINIMAL_LOADING] is True:
genset = generate.genset_fix_capacity_fix_efficiency_with_minload(
micro_grid_system,
bus_fuel,
bus_electricity_ac,
Expand All @@ -140,7 +146,7 @@ def build(experiment, case_dict):
number_of_equal_generators=case_dict[NUMBER_OF_EQUAL_GENERATORS],
)
else:
genset = generate.genset_fix(
genset = generate.genset_fix_capacity_fix_efficiency_no_minload(
micro_grid_system,
bus_fuel,
bus_electricity_ac,
Expand Down
Loading