Skip to content

Commit

Permalink
Add unittests for input validations
Browse files Browse the repository at this point in the history
 - fuels
  • Loading branch information
gerritdm committed Aug 6, 2019
1 parent 090bf85 commit b1b6585
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 21 deletions.
77 changes: 56 additions & 21 deletions gridpath/project/fuels.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,43 @@ def validate_inputs(subscenarios, subproblem, stage, conn):
)

# Check that fuels specified for projects exist in fuels table
validation_errors = validate_fuel_projects(prj_df, fuels_df)
for error in validation_errors:
validation_results.append(
(subscenarios.SCENARIO_ID,
__name__,
"PROJECT_OPERATIONAL_CHARS",
"inputs_project_operational_chars",
"Non existent fuel",
error)
)

# Check that fuel prices exist for the period and month
validation_errors = validate_fuel_prices(fuels_df, fuel_prices_df,
periods_months)
for error in validation_errors:
validation_results.append(
(subscenarios.SCENARIO_ID,
__name__,
"PROJECT_FUEL_PRICES",
"inputs_project_fuel_prices",
"Missing fuel price",
error
)
)

# Write all input validation errors to database
write_validation_to_database(validation_results, conn)


def validate_fuel_projects(prj_df, fuels_df):
"""
Check that fuels specified for projects exist in fuels table
:param prj_df:
:param fuels_df:
:return:
"""
results = []
fuel_mask = pd.notna(prj_df["fuel"])
existing_fuel_mask = prj_df["fuel"].isin(fuels_df["fuel"])
invalids = fuel_mask & ~existing_fuel_mask
Expand All @@ -192,35 +229,33 @@ def validate_inputs(subscenarios, subproblem, stage, conn):
bad_fuels = prj_df["fuel"][invalids].values
print_bad_projects = ", ".join(bad_projects)
print_bad_fuels = ", ".join(bad_fuels)
validation_results.append(
(subscenarios.SCENARIO_ID,
__name__,
"PROJECT_OPERATIONAL_CHARS",
"inputs_project_operational_chars",
"Non existent fuel",
"Project(s) '{}': Specified fuel(s) '{}' do(es) not exist"
.format(print_bad_projects, print_bad_fuels)
)
results.append(
"Project(s) '{}': Specified fuel(s) '{}' do(es) not exist"
.format(print_bad_projects, print_bad_fuels)
)

# Check that fuel prices exist for the period and month
return results


def validate_fuel_prices(fuels_df, fuel_prices_df, periods_months):
"""
Check that fuel prices exist for the period and month
:param fuels_df:
:param fuel_prices_df:
:param periods_months:
:return:
"""
results = []
for f in fuels_df["fuel"].values:
df = fuel_prices_df[fuel_prices_df["fuel"] == f]
for period, month in periods_months:
if not ((df.period == period) & (df.month == month)).any():
validation_results.append(
(subscenarios.SCENARIO_ID,
__name__,
"PROJECT_FUEL_PRICES",
"inputs_project_fuel_prices",
"Missing fuel price",
"Fuel '{}': Missing price for period '{}', month '{}')"
.format(f, str(period), str(month))
)
results.append(
"Fuel '{}': Missing price for period '{}', month '{}')"
.format(f, str(period), str(month))
)

# Write all input validation errors to database
write_validation_to_database(validation_results, conn)
return results


def write_model_inputs(inputs_directory, subscenarios, subproblem, stage, conn):
Expand Down
72 changes: 72 additions & 0 deletions tests/project/test_fuels.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

from tests.common_functions import create_abstract_model, \
add_components_and_load_data
from gridpath.project.fuels import \
validate_fuel_projects, validate_fuel_prices

TEST_DATA_DIRECTORY = \
os.path.join(os.path.dirname(__file__), "..", "test_data")
Expand Down Expand Up @@ -133,6 +135,76 @@ def test_initialized_components(self):
)
self.assertDictEqual(expected_price, actual_price)

def test_fuel_validations(self):
test_cases = {
# Make sure correct inputs don't throw error
1: {"prj_df": pd.DataFrame(
columns=["project", "fuel"],
data=[["gas_ct", "gas"], ["coal_plant", "coal"]]),
"fuels_df": pd.DataFrame(
columns=["fuel", "co2_intensity_tons_per_mmbtu"],
data=[["gas", 0.4], ["coal", 0.8]]),
"fuel_prices_df": pd.DataFrame(
columns=["fuel", "period", "month", "fuel_price_per_mmbtu"],
data=[["gas", 2018, 1, 3], ["gas", 2018, 2, 4],
["coal", 2018, 1, 2], ["coal", 2018, 2, 2]]),
"periods_months": [(2018, 1), (2018, 2)],
"fuel_project_error": [],
"fuel_prices_error": []
},
# If a project's fuel does not exist in the fuels_df, there should
# be an error. Similarly, if a fuel price is missing for a certain
# month/period, there should be an error.
2: {"prj_df": pd.DataFrame(
columns=["project", "fuel"],
data=[["gas_ct", "invalid_fuel"], ["coal_plant", "coal"]]),
"fuels_df": pd.DataFrame(
columns=["fuel", "co2_intensity_tons_per_mmbtu"],
data=[["gas", 0.4], ["coal", 0.8]]),
"fuel_prices_df": pd.DataFrame(
columns=["fuel", "period", "month", "fuel_price_per_mmbtu"],
data=[["gas", 2018, 1, 3],
["coal", 2018, 1, 2], ["coal", 2018, 2, 2]]),
"periods_months": [(2018, 1), (2018, 2)],
"fuel_project_error": [
"Project(s) 'gas_ct': Specified fuel(s) 'invalid_fuel' do(es) not exist"],
"fuel_prices_error": [
"Fuel 'gas': Missing price for period '2018', month '2')"]
},
# It's okay if there are more fuels and fuels prices specified than
# needed for the active projects
3: {"prj_df": pd.DataFrame(
columns=["project", "fuel"],
data=[["gas_ct", "gas"]]),
"fuels_df": pd.DataFrame(
columns=["fuel", "co2_intensity_tons_per_mmbtu"],
data=[["gas", 0.4], ["coal", 0.8]]),
"fuel_prices_df": pd.DataFrame(
columns=["fuel", "period", "month", "fuel_price_per_mmbtu"],
data=[["gas", 2018, 1, 3], ["gas", 2018, 2, 4],
["coal", 2018, 1, 2], ["coal", 2018, 2, 2]]),
"periods_months": [(2018, 1), (2018, 2)],
"fuel_project_error": [],
"fuel_prices_error": []
}
}

for test_case in test_cases.keys():
expected_list = test_cases[test_case]["fuel_project_error"]
actual_list = validate_fuel_projects(
prj_df=test_cases[test_case]["prj_df"],
fuels_df=test_cases[test_case]["fuels_df"]
)
self.assertListEqual(expected_list, actual_list)

expected_list = test_cases[test_case]["fuel_prices_error"]
actual_list = validate_fuel_prices(
fuels_df=test_cases[test_case]["fuels_df"],
fuel_prices_df=test_cases[test_case]["fuel_prices_df"],
periods_months=test_cases[test_case]["periods_months"]
)
self.assertListEqual(expected_list, actual_list)


if __name__ == "__main__":
unittest.main()

0 comments on commit b1b6585

Please sign in to comment.