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:

  1. Defining an object of the component class and parsing the Plan and identifier of the component.

  2. Loading parameters of the component using load_ functions.

  3. 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 is remove_ if we run into problems