Troubleshooting 101
Contents
Troubleshooting 101#
How to: NEMGLO components#
A quick exploration of some simple checks you can use to for your NEMGLO model components and Plan object.
# Import Packages
# NEMGLO Packages
from nemglo import *
# Generic Packages
import pandas as pd
Fetching Data as per Fundamentals 1#
inputdata = nemosis_data(intlength=30, local_cache=r'E:\TEMPCACHE')
start = "02/01/2020 00:00"
end = "09/01/2020 00:00"
region = 'VIC1'
inputdata.set_dates(start, end)
inputdata.set_region(region)
prices = inputdata.get_prices()
Compiling data for table DISPATCHPRICE.
Returning DISPATCHPRICE.
Construct the Planner + Adding Electrolyser#
As per Fundamentals 1, we create a Plan and load market prices. Calling the load_market_prices twice will simply overwrite the existing values stored in the Plan.
Warning
It is possible (and very dangerous) to create multiple Plan objects of the same identifier or variable name in python. Avoid this at all costs.
P2G = Plan(identifier = "H2_VIC")
P2G.load_market_prices(prices)
P2G.load_market_prices(prices)
WARNING: Overwriting existing market_prices
However! Trying to add NEMGLO components twice will produce an error…
h2e = Electrolyser(P2G, identifier='H2E')
h2e = Electrolyser(P2G, identifier='H2E')
---------------------------------------------------------------------------
ComponentError Traceback (most recent call last)
e:\PROJECTS\NEMGLO\docs\source\help\trouble101.ipynb Cell 10 in <cell line: 1>()
----> <a href='vscode-notebook-cell:/e%3A/PROJECTS/NEMGLO/docs/source/help/trouble101.ipynb#X12sZmlsZQ%3D%3D?line=0'>1</a> h2e = Electrolyser(P2G, identifier='H2E')
File c:\Users\derlu\.conda\envs\nempy\lib\site-packages\nemglo\components\electrolyser.py:25, in Electrolyser.__init__(self, system_plan, identifier)
23 assert isinstance(system_plan, Plan), "Electrolyser Argument: 'system_plan' must be nemglo.planner.Plan object"
24 assert isinstance(identifier, str), "Electrolyser Argument: 'identifier' must be a str"
---> 25 inv.validate_unique_id(self.__class__, system_plan, identifier)
27 # Link object to Plan
28 self._system_plan = system_plan
File c:\Users\derlu\.conda\envs\nempy\lib\site-packages\nemglo\backend\input_validation.py:115, in validate_unique_id(c_definition, system_plan, identifier)
113 for other_gen in [c for c in system_plan._components if c.__class__ is c_definition]:
114 if other_gen._id == identifier:
--> 115 raise ComponentError("Cannot create a {} object of the same name as an existing instance in Plan '{}'."\
116 .format(c_definition, system_plan._id))
ComponentError: Cannot create a <class 'nemglo.components.electrolyser.Electrolyser'> object of the same name as an existing instance in Plan 'H2_VIC'.
To update or get around this you can use the function remove_, where the function name will match the main add_ function for the respective component. So for the Electrolyser class, the main function call is add_electrolyser_operation. Hence we can call remove_electrolyser_operation.
h2e.remove_electrolyser_operation()
Plan 'H2_VIC' unlinked the component 'H2E'
Now if you create an Electrolyser with the same identifier as earlier, it will add this new object to the Plan successfully.
h2e = Electrolyser(P2G, identifier='H2E')
Another way to check the components in the Plan object is to get the _components attribute directly. This will produce a list of all components (Electrolyser, Generator, Emissions, etc.) linked to the Plan.
P2G._components
[<nemglo.components.electrolyser.Electrolyser at 0x1fa95589c70>]
Loading Parameters to Components#
Incorrect loading of parameters to components will likely cause an input error. For example an invalid entry for sec_profile.
h2e.load_h2_parameters_preset(capacity = 100.0,
maxload = 100.0,
minload = 10.0,
offload = 0.0,
electrolyser_type = 'PEM',
sec_profile='a')
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
e:\PROJECTS\NEMGLO\docs\source\help\trouble101.ipynb Cell 18 in <cell line: 1>()
----> <a href='vscode-notebook-cell:/e%3A/PROJECTS/NEMGLO/docs/source/help/trouble101.ipynb#X26sZmlsZQ%3D%3D?line=0'>1</a> h2e.load_h2_parameters_preset(capacity = 100.0,
<a href='vscode-notebook-cell:/e%3A/PROJECTS/NEMGLO/docs/source/help/trouble101.ipynb#X26sZmlsZQ%3D%3D?line=1'>2</a> maxload = 100.0,
<a href='vscode-notebook-cell:/e%3A/PROJECTS/NEMGLO/docs/source/help/trouble101.ipynb#X26sZmlsZQ%3D%3D?line=2'>3</a> minload = 10.0,
<a href='vscode-notebook-cell:/e%3A/PROJECTS/NEMGLO/docs/source/help/trouble101.ipynb#X26sZmlsZQ%3D%3D?line=3'>4</a> offload = 0.0,
<a href='vscode-notebook-cell:/e%3A/PROJECTS/NEMGLO/docs/source/help/trouble101.ipynb#X26sZmlsZQ%3D%3D?line=4'>5</a> electrolyser_type = 'PEM',
<a href='vscode-notebook-cell:/e%3A/PROJECTS/NEMGLO/docs/source/help/trouble101.ipynb#X26sZmlsZQ%3D%3D?line=5'>6</a> sec_profile='a')
File c:\Users\derlu\.conda\envs\nempy\lib\site-packages\nemglo\components\electrolyser.py:94, in Electrolyser.load_h2_parameters_preset(self, capacity, maxload, minload, offload, electrolyser_type, sec_profile, h2_price_kg)
89 assert isinstance(h2_price_kg, (float, type(None))), "Electrolyser Argument: 'h2_price_kg' must be a \
90 (float, or None)"
92 assert electrolyser_type in ['PEM','AE'], \
93 "Electrolyser Argument: 'electrolyser_type' must be one of ['PEM','AE']"
---> 94 assert sec_profile in ['variable','fixed'], \
95 "Electrolyser Argument: 'sec_profile' must be one of ['variable','fixed']"
97 # Store Values
98 self._capacity = capacity
AssertionError: Electrolyser Argument: 'sec_profile' must be one of ['variable','fixed']
If we check the attributes of the python variable, we notice nothing has been loaded correctly.
h2e.__dict__
{'_system_plan': <nemglo.planner.Plan at 0x1fa95589eb0>,
'_id': 'H2E',
'_capacity': None,
'_maxload': None,
'_minload': None,
'_offload': None,
'_type': None,
'_profile': 'fixed',
'_sec_nominal': None,
'_sec_conversion': None,
'_sec_system': None,
'_sec_variable_points': None,
'_h2_price_kg': None,
'_storage_max': None,
'_storage_initial': None,
'_storage_final': None,
'_storage_drain': None}
Entering correct details with a successful load would instead show…
h2e.load_h2_parameters_preset(capacity = 100.0,
maxload = 100.0,
minload = 10.0,
offload = 0.0,
electrolyser_type = 'PEM',
sec_profile='fixed')
h2e.__dict__
{'_system_plan': <nemglo.planner.Plan at 0x1fa95589eb0>,
'_id': 'H2E',
'_capacity': 100.0,
'_maxload': 100.0,
'_minload': 10.0,
'_offload': 0.0,
'_type': 'PEM',
'_profile': 'fixed',
'_sec_nominal': 66,
'_sec_conversion': 1.0,
'_sec_system': 66.0,
'_sec_variable_points': h2e_load_pct nominal_sec_pct
0 0.0 0.8383
1 0.2 0.8383
2 0.4 0.8598
3 0.6 0.8982
4 0.8 0.9315
5 1.0 1.0101,
'_h2_price_kg': None,
'_storage_max': None,
'_storage_initial': None,
'_storage_final': None,
'_storage_drain': None}
One may mistakeningly assume that the component variables and constraints are now entered in the optimiser model and ready to run Plan.optimise. If you check for the electrolyser variables of identifer H2E in the Plan using view_variable you will find nothing.
P2G.view_variable('H2E')
Variable name not found in Plan: 'H2_VIC'
{}
Adding Component Functionality to Optimiser#
The important final step before running optimise here is using add_ function calls. If you now add_electrolyser_operation you will find the optimiser variables belonging to the Plan.
The function view_variable can be used to find the identifier or individually named variables in the Plan.
h2e.add_electrolyser_operation()
P2G.view_variable('H2E')
| variable_name | variable_id | interval | lower_bound | upper_bound | type | |
|---|---|---|---|---|---|---|
| 0 | H2E-mw_load | 0 | 0 | 0.0 | 100.0 | continuous |
| 1 | H2E-mw_load | 1 | 1 | 0.0 | 100.0 | continuous |
| 2 | H2E-mw_load | 2 | 2 | 0.0 | 100.0 | continuous |
| 3 | H2E-mw_load | 3 | 3 | 0.0 | 100.0 | continuous |
| 4 | H2E-mw_load | 4 | 4 | 0.0 | 100.0 | continuous |
| ... | ... | ... | ... | ... | ... | ... |
| 1676 | H2E-msl_relieve | 1676 | 331 | 0.0 | 1.0 | binary |
| 1677 | H2E-msl_relieve | 1677 | 332 | 0.0 | 1.0 | binary |
| 1678 | H2E-msl_relieve | 1678 | 333 | 0.0 | 1.0 | binary |
| 1679 | H2E-msl_relieve | 1679 | 334 | 0.0 | 1.0 | binary |
| 1680 | H2E-msl_relieve | 1680 | 335 | 0.0 | 1.0 | binary |
1681 rows × 6 columns
P2G.view_variable('H2E-mw_load_sum')
| variable_name | variable_id | interval | lower_bound | upper_bound | type | |
|---|---|---|---|---|---|---|
| 0 | H2E-mw_load_sum | 336 | None | 0.0 | inf | continuous |
Changing component characteristics#
If you want to change the component after adding it but before optimising for whatever reason you need not clear the python kernel, simply use the remove_ function call as before. Note here it will print out explicitly what has been removed from the Plan in terms of variables, constraints and objective costs.
h2e.remove_electrolyser_operation()
Plan 'H2_VIC' removed variable 'H2E-mw_load'
Plan 'H2_VIC' removed variable 'H2E-mw_load_sum'
Plan 'H2_VIC' removed variable 'H2E-h2_produced'
Plan 'H2_VIC' removed variable 'H2E-msl_violate'
Plan 'H2_VIC' removed variable 'H2E-msl_penalise'
Plan 'H2_VIC' removed variable 'H2E-msl_relieve'
Plan 'H2_VIC' removed objective cost 'H2E-mw_load'
Plan 'H2_VIC' removed objective cost 'H2E-msl_penalise'
Plan 'H2_VIC' removed objective cost 'H2E-msl_relieve'
Plan 'H2_VIC' removed constraint LHS 'H2E-mw_load_sum'
Plan 'H2_VIC' removed constraint LHS 'H2E-h2_produced'
Plan 'H2_VIC' removed constraint LHS 'H2E-msl_violate'
Plan 'H2_VIC' removed constraint RHS 'H2E-msl_violate'
Plan 'H2_VIC' removed constraint RHS dynamic 'H2E-mw_load_sum'
Plan 'H2_VIC' removed constraint RHS dynamic 'H2E-h2_produced'
Plan 'H2_VIC' removed objective cost 'H2E-msl_penalise'
Plan 'H2_VIC' removed objective cost 'H2E-msl_relieve'
Plan 'H2_VIC' unlinked the component 'H2E'
Recap#
As a recap, the 3 key steps to using NEMGLO are:
Defining an object of the component class and parsing the
Planandidentifierof the component.Loading parameters of the component using
load_functions.Adding variables and constraints that define how this component behaves in the optimiser using
add_For debugging as well, we can use the inverse call, that isremove_if we run into problems