Skip to content

Commit

Permalink
Catch KeyError when exporting duals from MIP problems (#1068)
Browse files Browse the repository at this point in the history
  • Loading branch information
anamileva authored Dec 11, 2023
1 parent d725962 commit 8605355
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 104 deletions.
23 changes: 23 additions & 0 deletions gridpath/common_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import os.path
import sys
import warnings

from argparse import ArgumentParser

Expand Down Expand Up @@ -398,3 +399,25 @@ def create_results_df(index_columns, results_columns, data):
).set_index(index_columns)

return df


def duals_wrapper(m, component, verbose=False):
try:
return m.dual[component]
except KeyError:
if verbose:
warnings.warn(
f"""
KeyError caught when saving duals for {component}. Duals were
not exported. This is expected if solving a MIP with CPLEX (and
possibly other solvers), not otherwise.
"""
)
return None


def none_dual_type_error_wrapper(component, coefficient):
try:
return component / coefficient
except TypeError:
return None
105 changes: 65 additions & 40 deletions gridpath/project/capacity/capacity_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from pyomo.environ import Set, Param, Constraint, NonNegativeReals, Expression, value

from gridpath.auxiliary.auxiliary import get_required_subtype_modules
from gridpath.common_functions import duals_wrapper, none_dual_type_error_wrapper
from gridpath.project.capacity.common_functions import (
load_project_capacity_type_modules,
)
Expand Down Expand Up @@ -370,9 +371,12 @@ def export_results(scenario_directory, subproblem, stage, m, d):
m.capacity_group_new_capacity_max[grp, prd],
m.capacity_group_total_capacity_min[grp, prd],
m.capacity_group_total_capacity_max[grp, prd],
m.dual[
getattr(m, "Max_Group_Build_in_Period_Constraint")[grp, prd]
]
duals_wrapper(
m,
getattr(m, "Max_Group_Build_in_Period_Constraint")[
grp, prd
],
)
if (grp, prd)
in [
idx
Expand All @@ -381,9 +385,12 @@ def export_results(scenario_directory, subproblem, stage, m, d):
)
]
else None,
m.dual[
getattr(m, "Min_Group_Build_in_Period_Constraint")[grp, prd]
]
duals_wrapper(
m,
getattr(m, "Min_Group_Build_in_Period_Constraint")[
grp, prd
],
)
if (grp, prd)
in [
idx
Expand All @@ -392,24 +399,26 @@ def export_results(scenario_directory, subproblem, stage, m, d):
)
]
else None,
m.dual[
duals_wrapper(
m,
getattr(m, "Max_Group_Total_Cap_in_Period_Constraint")[
grp, prd
]
]
if (grp, prd)
in [
idx
for idx in getattr(
m, "Max_Group_Total_Cap_in_Period_Constraint"
)
]
else None,
m.dual[
getattr(m, "Min_Group_Total_Cap_in_Period_Constraint")[
grp, prd
if (grp, prd)
in [
idx
for idx in getattr(
m, "Max_Group_Total_Cap_in_Period_Constraint"
)
]
]
else None,
duals_wrapper(
m,
getattr(m, "Min_Group_Total_Cap_in_Period_Constraint")[
grp, prd
],
),
)
if (grp, prd)
in [
idx
Expand All @@ -418,10 +427,15 @@ def export_results(scenario_directory, subproblem, stage, m, d):
)
]
else None,
m.dual[
getattr(m, "Max_Group_Build_in_Period_Constraint")[grp, prd]
]
/ m.period_objective_coefficient[prd]
none_dual_type_error_wrapper(
duals_wrapper(
m,
getattr(m, "Max_Group_Build_in_Period_Constraint")[
grp, prd
],
),
m.period_objective_coefficient[prd],
)
if (grp, prd)
in [
idx
Expand All @@ -430,10 +444,15 @@ def export_results(scenario_directory, subproblem, stage, m, d):
)
]
else None,
m.dual[
getattr(m, "Min_Group_Build_in_Period_Constraint")[grp, prd]
]
/ m.period_objective_coefficient[prd]
none_dual_type_error_wrapper(
duals_wrapper(
m,
getattr(m, "Min_Group_Build_in_Period_Constraint")[
grp, prd
],
),
m.period_objective_coefficient[prd],
)
if (grp, prd)
in [
idx
Expand All @@ -442,12 +461,15 @@ def export_results(scenario_directory, subproblem, stage, m, d):
)
]
else None,
m.dual[
getattr(m, "Max_Group_Total_Cap_in_Period_Constraint")[
grp, prd
]
]
/ m.period_objective_coefficient[prd]
none_dual_type_error_wrapper(
duals_wrapper(
m,
getattr(m, "Max_Group_Total_Cap_in_Period_Constraint")[
grp, prd
],
),
m.period_objective_coefficient[prd],
)
if (grp, prd)
in [
idx
Expand All @@ -456,12 +478,15 @@ def export_results(scenario_directory, subproblem, stage, m, d):
)
]
else None,
m.dual[
getattr(m, "Min_Group_Total_Cap_in_Period_Constraint")[
grp, prd
]
]
/ m.period_objective_coefficient[prd]
none_dual_type_error_wrapper(
duals_wrapper(
m,
getattr(m, "Min_Group_Total_Cap_in_Period_Constraint")[
grp, prd
],
),
m.period_objective_coefficient[prd],
)
if (grp, prd)
in [
idx
Expand Down
18 changes: 9 additions & 9 deletions gridpath/project/capacity/potential.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
validate_column_monotonicity,
)
from gridpath.auxiliary.auxiliary import get_required_subtype_modules
from gridpath.common_functions import create_results_df
from gridpath.common_functions import create_results_df, duals_wrapper
from gridpath.project import PROJECT_PERIOD_DF
from gridpath.project.capacity.common_functions import (
load_project_capacity_type_modules,
Expand Down Expand Up @@ -586,28 +586,28 @@ def export_results(scenario_directory, subproblem, stage, m, d):
[
prj,
prd,
m.dual[getattr(m, "Min_Build_Power_Constraint")[prj, prd]]
duals_wrapper(m, getattr(m, "Min_Build_Power_Constraint")[prj, prd])
if (prj, prd) in [idx for idx in getattr(m, "Min_Build_Power_Constraint")]
else None,
m.dual[getattr(m, "Max_Build_Power_Constraint")[prj, prd]]
duals_wrapper(m, getattr(m, "Max_Build_Power_Constraint")[prj, prd])
if (prj, prd) in [idx for idx in getattr(m, "Max_Build_Power_Constraint")]
else None,
m.dual[getattr(m, "Min_Power_Constraint")[prj, prd]]
duals_wrapper(m, getattr(m, "Min_Power_Constraint")[prj, prd])
if (prj, prd) in [idx for idx in getattr(m, "Min_Power_Constraint")]
else None,
m.dual[getattr(m, "Max_Power_Constraint")[prj, prd]]
duals_wrapper(m, getattr(m, "Max_Power_Constraint")[prj, prd])
if (prj, prd) in [idx for idx in getattr(m, "Max_Power_Constraint")]
else None,
m.dual[getattr(m, "Min_Build_Energy_Constraint")[prj, prd]]
duals_wrapper(m, getattr(m, "Min_Build_Energy_Constraint")[prj, prd])
if (prj, prd) in [idx for idx in getattr(m, "Min_Build_Energy_Constraint")]
else None,
m.dual[getattr(m, "Max_Build_Energy_Constraint")[prj, prd]]
duals_wrapper(m, getattr(m, "Max_Build_Energy_Constraint")[prj, prd])
if (prj, prd) in [idx for idx in getattr(m, "Max_Build_Energy_Constraint")]
else None,
m.dual[getattr(m, "Min_Energy_Constraint")[prj, prd]]
duals_wrapper(m, getattr(m, "Min_Energy_Constraint")[prj, prd])
if (prj, prd) in [idx for idx in getattr(m, "Min_Energy_Constraint")]
else None,
m.dual[getattr(m, "Max_Energy_Constraint")[prj, prd]]
duals_wrapper(m, getattr(m, "Max_Energy_Constraint")[prj, prd])
if (prj, prd) in [idx for idx in getattr(m, "Max_Energy_Constraint")]
else None,
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
subset_init_by_set_membership,
)
from gridpath.auxiliary.dynamic_components import headroom_variables, footroom_variables
from gridpath.common_functions import duals_wrapper
from gridpath.project.operations.operational_types.common_functions import (
determine_relevant_timepoints,
load_optype_model_data,
Expand Down Expand Up @@ -3803,7 +3804,7 @@ def add_duals_to_dispatch_results(mod, Bin_or_Lin, BIN_OR_LIN):
for c in sorted(constraint_column_dict.keys()):
constraint_object = getattr(mod, c)
if (prj, tmp) in constraint_object:
duals.append(mod.dual[constraint_object[prj, tmp]])
duals.append(duals_wrapper(mod, constraint_object[prj, tmp]))
else:
duals.append(None)

Expand Down
17 changes: 0 additions & 17 deletions gridpath/run_scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -1020,23 +1020,6 @@ def save_duals(
)
n += 1

# for index in constraint_object:
# try:
# duals_writer.writerow(
# list(index) + [instance.dual[constraint_object[index]]]
# )
# # We get an error when trying to export duals with CPLEX
# # when solving MIPs, so catch it here and ignore to avoid
# # breaking the script, but throw a warning
# except KeyError:
# warnings.warn(
# """
# KeyError caught when saving duals. Duals were not exported.
# This is expected if solving a MIP with CPLEX,
# not otherwise.
# """
# )


def summarize_results(scenario_directory, subproblem, stage, parsed_arguments):
"""
Expand Down
14 changes: 10 additions & 4 deletions gridpath/system/load_balance/load_balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@
load_balance_consumption_components,
load_balance_production_components,
)
from gridpath.common_functions import create_results_df
from gridpath.common_functions import (
create_results_df,
duals_wrapper,
none_dual_type_error_wrapper,
)
from gridpath.system.load_balance import LOAD_ZONE_TMP_DF


Expand Down Expand Up @@ -198,9 +202,11 @@ def export_results(scenario_directory, subproblem, stage, m, d):
tmp,
value(m.Overgeneration_MW_Expression[lz, tmp]),
value(m.Unserved_Energy_MW_Expression[lz, tmp]),
m.dual[getattr(m, "Meet_Load_Constraint")[lz, tmp]],
m.dual[getattr(m, "Meet_Load_Constraint")[lz, tmp]]
/ m.tmp_objective_coefficient[tmp],
duals_wrapper(m, getattr(m, "Meet_Load_Constraint")[lz, tmp]),
none_dual_type_error_wrapper(
duals_wrapper(m, getattr(m, "Meet_Load_Constraint")[lz, tmp]),
m.tmp_objective_coefficient[tmp],
),
]
for lz in getattr(m, "LOAD_ZONES")
for tmp in getattr(m, "TMPS")
Expand Down
14 changes: 10 additions & 4 deletions gridpath/system/policy/carbon_cap/carbon_balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
carbon_cap_balance_emission_components,
carbon_cap_balance_credit_components,
)
from gridpath.common_functions import create_results_df
from gridpath.common_functions import (
create_results_df,
duals_wrapper,
none_dual_type_error_wrapper,
)
from gridpath.system.policy.carbon_cap import CARBON_CAP_ZONE_PRD_DF


Expand Down Expand Up @@ -107,12 +111,14 @@ def export_results(scenario_directory, subproblem, stage, m, d):
p,
value(m.Total_Carbon_Emissions_from_All_Sources_Expression[z, p]),
value(m.Total_Carbon_Credits_from_All_Sources_Expression[z, p]),
m.dual[getattr(m, "Carbon_Cap_Constraint")[z, p]]
duals_wrapper(m, getattr(m, "Carbon_Cap_Constraint")[z, p])
if (z, p) in [idx for idx in getattr(m, "Carbon_Cap_Constraint")]
else None,
(
m.dual[getattr(m, "Carbon_Cap_Constraint")[z, p]]
/ m.period_objective_coefficient[p]
none_dual_type_error_wrapper(
duals_wrapper(m, getattr(m, "Carbon_Cap_Constraint")[z, p]),
m.period_objective_coefficient[p],
)
if (z, p) in [idx for idx in getattr(m, "Carbon_Cap_Constraint")]
else None
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@

from pyomo.environ import Var, Constraint, NonNegativeReals, Expression, value

from gridpath.common_functions import create_results_df
from gridpath.common_functions import (
create_results_df,
duals_wrapper,
none_dual_type_error_wrapper,
)
from gridpath.system.policy.energy_targets import ENERGY_TARGET_ZONE_HRZ_DF


Expand Down Expand Up @@ -114,13 +118,17 @@ def export_results(scenario_directory, subproblem, stage, m, d):
+ value(m.Total_Curtailed_Horizon_Energy_Target_Energy_MWh[z, bt, h])
),
value(m.Horizon_Energy_Target_Shortage_MWh_Expression[z, bt, h]),
m.dual[getattr(m, "Horizon_Energy_Target_Constraint")[z, bt, h]]
duals_wrapper(m, getattr(m, "Horizon_Energy_Target_Constraint")[z, bt, h])
if (z, bt, h)
in [idx for idx in getattr(m, "Horizon_Energy_Target_Constraint")]
else None,
(
m.dual[getattr(m, "Horizon_Energy_Target_Constraint")[z, bt, h]]
/ m.hrz_objective_coefficient[bt, h]
none_dual_type_error_wrapper(
duals_wrapper(
m, getattr(m, "Horizon_Energy_Target_Constraint")[z, bt, h]
),
m.hrz_objective_coefficient[bt, h],
)
if (z, bt, h)
in [idx for idx in getattr(m, "Horizon_Energy_Target_Constraint")]
else None
Expand Down
Loading

0 comments on commit 8605355

Please sign in to comment.