Skip to content

Commit 968c98e

Browse files
Ported some doctests out of utilities into proper unit tests to make them more robust. They had been failing off and on for a while, especially when pyomo changed its output formatting. I also tweaked the "no emissions" value in dispatch export from None to zero to avoid a weird pandas Future warning that occurred in the examples/storage test when every value in the emissions column was None.
1 parent d0122f6 commit 968c98e

File tree

6 files changed

+55
-77
lines changed

6 files changed

+55
-77
lines changed

examples/storage/outputs/dispatch.csv

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
generation_project,timestamp,DispatchEmissions_tCO2_per_typical_yr,DispatchGen_MW,Energy_GWh_typical_yr,VariableCost_per_yr,gen_dbid,gen_energy_source,gen_load_zone,gen_tech,period,tp_weight_in_year_hrs
2-
S-Geothermal,2025011600,,4.44411428571,19.4785529143,561566.680519,33.0,Geothermal,South,Geothermal,2020,4383.0
3-
S-Geothermal,2025011512,,4.44411428571,19.4785529143,561566.680519,33.0,Geothermal,South,Geothermal,2020,4383.0
4-
S-Central_PV-1,2025011600,,0.0,0.0,0.0,41.0,Solar,South,Central_PV,2020,4383.0
5-
Battery_Storage,2025011512,,2.95808571429,12.9652896857,129.652896857,Battery_Storage,Electricity,South,Battery_Storage,2020,4383.0
6-
S-Central_PV-1,2025011512,,0.5978,2.6201574,0.0,41.0,Solar,South,Central_PV,2020,4383.0
7-
Battery_Storage,2025011600,,0.0,0.0,0.0,Battery_Storage,Electricity,South,Battery_Storage,2020,4383.0
2+
S-Geothermal,2025011600,0,4.44411428571429,19.478552914285736,561566.6805188577,33.0,Geothermal,South,Geothermal,2020,4383.0
3+
S-Geothermal,2025011512,0,4.44411428571429,19.478552914285736,561566.6805188577,33.0,Geothermal,South,Geothermal,2020,4383.0
4+
S-Central_PV-1,2025011600,0,0.0,0.0,0.0,41.0,Solar,South,Central_PV,2020,4383.0
5+
Battery_Storage,2025011512,0,2.95808571428571,12.965289685714268,129.65289685714268,Battery_Storage,Electricity,South,Battery_Storage,2020,4383.0
6+
S-Central_PV-1,2025011512,0,0.5978,2.6201574,0.0,41.0,Solar,South,Central_PV,2020,4383.0
7+
Battery_Storage,2025011600,0,0.0,0.0,0.0,Battery_Storage,Electricity,South,Battery_Storage,2020,4383.0
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
gen_tech,gen_energy_source,period,Energy_GWh_typical_yr,VariableCost_per_yr,DispatchEmissions_tCO2_per_typical_yr
2-
Battery_Storage,Electricity,2020,12.9652896857,129.652896857,
3-
Central_PV,Solar,2020,2.6201574,0.0,
4-
Geothermal,Geothermal,2020,38.9571058286,1123133.36104,
2+
Battery_Storage,Electricity,2020,12.965289685714268,129.65289685714268,0
3+
Central_PV,Solar,2020,2.6201574,0.0,0
4+
Geothermal,Geothermal,2020,38.95710582857147,1123133.3610377153,0
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
gen_tech,gen_load_zone,gen_energy_source,period,Energy_GWh_typical_yr,VariableCost_per_yr,DispatchEmissions_tCO2_per_typical_yr
2-
Battery_Storage,South,Electricity,2020,12.9652896857,129.652896857,
3-
Central_PV,South,Solar,2020,2.6201574,0.0,
4-
Geothermal,South,Geothermal,2020,38.9571058286,1123133.36104,
2+
Battery_Storage,South,Electricity,2020,12.965289685714268,129.65289685714268,0
3+
Central_PV,South,Solar,2020,2.6201574,0.0,0
4+
Geothermal,South,Geothermal,2020,38.95710582857147,1123133.3610377153,0

switch_model/generators/core/dispatch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ def post_solve(instance, outdir):
374374
"DispatchEmissions_tCO2_per_typical_yr": value(sum(
375375
instance.DispatchEmissions[g, t, f] * instance.tp_weight_in_year[t]
376376
for f in instance.FUELS_FOR_GEN[g]
377-
)) if instance.gen_uses_fuel[g] else None
377+
)) if instance.gen_uses_fuel[g] else 0
378378
} for g, t in instance.GEN_TPS ]
379379
dispatch_full_df = pd.DataFrame(dispatch_normalized_dat)
380380
dispatch_full_df.set_index(["generation_project", "timestamp"], inplace=True)

switch_model/utilities.py

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -263,36 +263,9 @@ def min_data_check(model, *mandatory_model_components):
263263

264264
def _add_min_data_check(model):
265265
"""
266-
267266
Bind the min_data_check() method to an instance of a Pyomo AbstractModel
268267
object if it has not already been added. Also add a counter to keep
269268
track of what to name the next check that is added.
270-
271-
>>> from switch_model.utilities import _add_min_data_check
272-
>>> mod = AbstractModel()
273-
>>> _add_min_data_check(mod)
274-
>>> mod.set_A = Set(initialize=[1,2])
275-
>>> mod.paramA_full = Param(mod.set_A, initialize={1:'a',2:'b'})
276-
>>> mod.paramA_empty = Param(mod.set_A)
277-
>>> mod.min_data_check('set_A', 'paramA_full')
278-
>>> if hasattr(mod, 'create_instance'):
279-
... instance_pass = mod.create_instance()
280-
... else:
281-
... instance_pass = mod.create()
282-
>>> mod.min_data_check('set_A', 'paramA_empty')
283-
>>> try:
284-
... if hasattr(mod, 'create_instance'):
285-
... instance_fail = mod.create_instance()
286-
... else:
287-
... instance_fail = mod.create()
288-
... except ValueError as e:
289-
... print e # doctest: +NORMALIZE_WHITESPACE
290-
ERROR: Constructing component 'min_data_check_2' from data=None failed:
291-
ValueError: Values are not provided for every element of the mandatory
292-
parameter 'paramA_empty'. Missing data for 2 values, including: [1, 2]
293-
Values are not provided for every element of the mandatory parameter
294-
'paramA_empty'. Missing data for 2 values, including: [1, 2]
295-
296269
"""
297270
if getattr(model, 'min_data_check', None) is None:
298271
model.__num_min_data_checks = 0
@@ -331,43 +304,6 @@ def check_mandatory_components(model, *mandatory_model_components):
331304
If an argument is a simple parameter, it must have a value.
332305
333306
This does not work with indexed sets.
334-
335-
EXAMPLE:
336-
>>> from pyomo.environ import *
337-
>>> import switch_model.utilities as utilities
338-
>>> mod = ConcreteModel()
339-
>>> mod.set_A = Set(initialize=[1,2])
340-
>>> mod.paramA_full = Param(mod.set_A, initialize={1:'a',2:'b'})
341-
>>> mod.paramA_empty = Param(mod.set_A)
342-
>>> mod.set_B = Set()
343-
>>> mod.paramB_empty = Param(mod.set_B)
344-
>>> mod.paramC = Param(initialize=1)
345-
>>> mod.paramD = Param()
346-
>>> utilities.check_mandatory_components(mod, 'set_A', 'paramA_full')
347-
True
348-
>>> utilities.check_mandatory_components(mod, 'paramB_empty')
349-
True
350-
>>> utilities.check_mandatory_components(mod, 'paramC')
351-
True
352-
>>> utilities.check_mandatory_components(\
353-
mod, 'set_A', 'paramA_empty') # doctest: +NORMALIZE_WHITESPACE
354-
Traceback (most recent call last):
355-
...
356-
ValueError: Values are not provided for every element of the mandatory
357-
parameter 'paramA_empty'. Missing data for 2 values, including: [1, 2]
358-
>>> utilities.check_mandatory_components(mod, 'set_A', 'set_B')
359-
Traceback (most recent call last):
360-
...
361-
ValueError: No data is defined for the mandatory set 'set_B'.
362-
>>> utilities.check_mandatory_components(mod, 'paramC', 'paramD')
363-
Traceback (most recent call last):
364-
...
365-
ValueError: Value not provided for mandatory parameter 'paramD'
366-
367-
# Demonstration of incorporating this function into Pyomo's BuildCheck()
368-
>>> mod.min_dat_pass = BuildCheck(\
369-
rule=lambda m: utilities.check_mandatory_components(\
370-
m, 'set_A', 'paramA_full','paramB_empty', 'paramC'))
371307
"""
372308

373309
for component_name in mandatory_model_components:

tests/utilities_test.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright 2015 The Switch Authors. All rights reserved.
22
# Licensed under the Apache License, Version 2, which is in the LICENSE file.
33

4+
import logging
45
import os
56
import shutil
67
import tempfile
@@ -34,6 +35,47 @@ def test_save_inputs_as_dat(self):
3435
finally:
3536
shutil.rmtree(temp_dir)
3637

38+
def test_check_mandatory_components(self):
39+
from pyomo.environ import ConcreteModel, Param, Set
40+
from switch_model.utilities import check_mandatory_components
41+
mod = ConcreteModel()
42+
mod.set_A = Set(initialize=[1,2])
43+
mod.paramA_full = Param(mod.set_A, initialize={1:'a',2:'b'})
44+
mod.paramA_empty = Param(mod.set_A)
45+
mod.set_B = Set()
46+
mod.paramB_empty = Param(mod.set_B)
47+
mod.paramC = Param(initialize=1)
48+
mod.paramD = Param()
49+
check_mandatory_components(mod, 'set_A', 'paramA_full')
50+
check_mandatory_components(mod, 'paramB_empty')
51+
check_mandatory_components(mod, 'paramC')
52+
with self.assertRaises(ValueError):
53+
check_mandatory_components(mod, 'set_A', 'paramA_empty')
54+
with self.assertRaises(ValueError):
55+
check_mandatory_components(mod, 'set_A', 'set_B')
56+
with self.assertRaises(ValueError):
57+
check_mandatory_components(mod, 'paramC', 'paramD')
58+
59+
60+
def test_min_data_check(self):
61+
from switch_model.utilities import _add_min_data_check
62+
from pyomo.environ import AbstractModel, Param, Set
63+
mod = AbstractModel()
64+
_add_min_data_check(mod)
65+
mod.set_A = Set(initialize=[1,2])
66+
mod.paramA_full = Param(mod.set_A, initialize={1:'a',2:'b'})
67+
mod.paramA_empty = Param(mod.set_A)
68+
mod.min_data_check('set_A', 'paramA_full')
69+
self.assertIsNotNone(mod.create_instance())
70+
mod.min_data_check('set_A', 'paramA_empty')
71+
# Fiddle with the pyomo logger to suppress its error message
72+
logger = logging.getLogger('pyomo.core')
73+
orig_log_level = logger.level
74+
logger.setLevel(logging.FATAL)
75+
with self.assertRaises(ValueError):
76+
mod.create_instance()
77+
logger.setLevel(orig_log_level)
78+
3779

3880
if __name__ == '__main__':
3981
unittest.main()

0 commit comments

Comments
 (0)