From bf7ca099f7263e6370673378204a2c53bbce0406 Mon Sep 17 00:00:00 2001 From: grgmiller Date: Sat, 3 Sep 2022 21:56:15 -0700 Subject: [PATCH 01/12] update data quality metrics --- src/data_pipeline.py | 19 +-- src/validation.py | 316 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 266 insertions(+), 69 deletions(-) diff --git a/src/data_pipeline.py b/src/data_pipeline.py index 64c9cddb..a2f8b8b7 100644 --- a/src/data_pipeline.py +++ b/src/data_pipeline.py @@ -146,6 +146,13 @@ def main(): #################################################################################### print("4. Cleaning CEMS data") cems = data_cleaning.clean_cems(year, args.small, primary_fuel_table) + # output data quality metrics about measured vs imputed CEMS data + output_data.output_data_quality_metrics( + validation.summarize_cems_measurement_quality(cems), + "cems_pollutant_measurement_quality", + path_prefix, + args.skip_outputs, + ) # calculate biomass-adjusted emissions while cems data is at the unit level cems = emissions.adjust_emissions_for_biomass(cems) @@ -165,7 +172,7 @@ def main(): ) # output data quality metrics about annually-reported EIA-923 data output_data.output_data_quality_metrics( - validation.identify_annually_reported_eia_data(eia923_allocated, year), + validation.summarize_annually_reported_eia_data(eia923_allocated, year), "annually_reported_eia_data", path_prefix, args.skip_outputs, @@ -341,14 +348,8 @@ def main(): del eia930_data # validate how well the wind and solar imputation methods work output_data.output_data_quality_metrics( - validation.validate_diba_imputation_method(hourly_profiles, year), - "diba_imputation_performance", - path_prefix, - args.skip_outputs, - ) - output_data.output_data_quality_metrics( - validation.validate_national_imputation_method(hourly_profiles), - "national_imputation_performance", + validation.validate_wind_solar_imputation(hourly_profiles, year), + "wind_solar_profile_imputation_performance", path_prefix, args.skip_outputs, ) diff --git a/src/validation.py b/src/validation.py index e98a67d2..af1ebe78 100644 --- a/src/validation.py +++ b/src/validation.py @@ -439,7 +439,15 @@ def hourly_profile_source_metric( cems, partial_cems_subplant, partial_cems_plant, shaped_eia_data ): """Calculates the percentage of data whose hourly profile was determined by method""" - data_metrics = ["net_generation_mwh", "co2_mass_lb"] + data_metrics = [ + "net_generation_mwh", + "co2_mass_lb", + "co2_mass_lb_for_electricity", + "nox_mass_lb", + "nox_mass_lb_for_electricity", + "so2_mass_lb", + "so2_mass_lb_for_electricity", + ] # determine the source of the hourly profile profile_from_cems = pd.DataFrame(cems[data_metrics].sum(axis=0)).T @@ -475,7 +483,23 @@ def hourly_profile_source_metric( ] ) profile_source = profile_source.set_index("profile_method") - profile_source = profile_source / profile_source.sum(axis=0) + profile_source = (profile_source / profile_source.sum(axis=0)).round(4) + + # re-order values from best quality to lowest quality + profile_source = profile_source.reindex( + [ + "cems_reported", + "eia_scaled_partial_cems_subplant", + "eia_shaped_partial_cems_plant", + "eia_shaped_residual_profile", + "eia_shaped_shifted_residual_profile", + "eia_shaped_eia930_profile", + "eia_shaped_cems_profile", + "eia_shaped_DIBA_average", + "eia_shaped_national_average", + "eia_shaped_assumed_flat", + ] + ) profile_source = profile_source.reset_index() return profile_source @@ -485,16 +509,33 @@ def identify_percent_of_data_by_input_source( cems, partial_cems_subplant, partial_cems_plant, eia_only_data, year ): """Identifies what percent of output data comes from each input source (CEMS or EIA).""" + + columns_to_use = [ + "net_generation_mwh", + "co2_mass_lb", + "co2_mass_lb_for_electricity", + "co2e_mass_lb", + "co2e_mass_lb_for_electricity", + "nox_mass_lb", + "nox_mass_lb_for_electricity", + "so2_mass_lb", + "so2_mass_lb_for_electricity", + ] + + # add data resolution column to data that is based on EIA + eia_only_data = identify_reporting_frequency(eia_only_data, year) + partial_cems_subplant = identify_reporting_frequency(partial_cems_subplant, year) + partial_cems_plant = identify_reporting_frequency(partial_cems_plant, year) + + # associate each dataframe with a data source label data_sources = { "cems": cems, "partial_cems_subplant": partial_cems_subplant, "partial_cems_plant": partial_cems_plant, "eia": eia_only_data, } - if year % 4 == 0: - hours_in_year = 8784 - else: - hours_in_year = 8760 + ## get a count of the number of observations (subplant-hours) from each source + source_of_input_data = [] for name, df in data_sources.items(): if len(df) == 0: # Empty df. May occur when running `small` @@ -502,38 +543,69 @@ def identify_percent_of_data_by_input_source( continue if name == "eia": subplant_data = df.groupby( - ["plant_id_eia", "subplant_id"], dropna=False - ).sum()[ - ["net_generation_mwh", "co2_mass_lb", "co2_mass_lb_for_electricity"] - ] - subplant_hours = len(subplant_data) * hours_in_year + ["plant_id_eia", "subplant_id", "eia_data_resolution"], dropna=False + ).sum()[columns_to_use] + # because EIA data is not hourly, we have to multiply the number of subplants by the number of hours in a year + if year % 4 == 0: + hours_in_year = 8784 + else: + hours_in_year = 8760 + subplant_data["subplant_hours"] = hours_in_year + # group the data by resolution + subplant_data = ( + subplant_data.reset_index() + .groupby("eia_data_resolution", dropna=False) + .sum()[["subplant_hours"] + columns_to_use] + .reset_index() + ) + subplant_data = subplant_data.rename( + columns={"eia_data_resolution": "source"} + ) + subplant_data["source"] = subplant_data["source"].replace( + {"annual": "eia_annual", "monthly": "eia_monthly"} + ) + source_of_input_data.append(subplant_data) + # for the partial cems data + elif (name == "partial_cems_subplant") | (name == "partial_cems_plant"): + subplant_data = df.groupby( + ["plant_id_eia", "subplant_id", "datetime_utc", "eia_data_resolution"], + dropna=False, + ).sum()[columns_to_use] + subplant_data["subplant_hours"] = 1 + # group the data by resolution + subplant_data = ( + subplant_data.reset_index() + .groupby("eia_data_resolution", dropna=False) + .sum()[["subplant_hours"] + columns_to_use] + .reset_index() + ) + subplant_data = subplant_data.rename( + columns={"eia_data_resolution": "source"} + ) + subplant_data["source"] = subplant_data["source"].replace( + {"annual": "eia_annual", "monthly": "eia_monthly"} + ) + source_of_input_data.append(subplant_data) + # for the cems data else: subplant_data = df.groupby( ["plant_id_eia", "subplant_id", "datetime_utc"], dropna=False - ).sum()[ - ["net_generation_mwh", "co2_mass_lb", "co2_mass_lb_for_electricity"] - ] - subplant_hours = len(subplant_data) - summary = pd.DataFrame.from_dict( - { - "source": [name], - "subplant_hours": [subplant_hours], - "net_generation_mwh": [subplant_data["net_generation_mwh"].sum()], - "co2_mass_lb": [subplant_data["co2_mass_lb"].sum()], - "co2_mass_lb_for_electricity": [ - subplant_data["co2_mass_lb_for_electricity"].sum() - ], - } - ) - source_of_input_data.append(summary) - source_of_input_data = pd.concat(source_of_input_data) + ).sum()[columns_to_use] + subplant_data["subplant_hours"] = 1 + subplant_data["source"] = "cems_hourly" + # group the data by resolution + subplant_data = ( + subplant_data.reset_index() + .groupby("source", dropna=False) + .sum()[["subplant_hours"] + columns_to_use] + .reset_index() + ) + source_of_input_data.append(subplant_data) - source_of_input_data["source"] = source_of_input_data["source"].replace( - "partial_cems_subplant", "eia" - ) - source_of_input_data["source"] = source_of_input_data["source"].replace( - "partial_cems_plant", "eia" - ) + # concat the dataframes together + source_of_input_data = pd.concat(source_of_input_data, axis=0) + + # groupby and calculate percentages source_of_input_data = source_of_input_data.groupby("source").sum() source_of_input_data = source_of_input_data / source_of_input_data.sum(axis=0) @@ -542,33 +614,58 @@ def identify_percent_of_data_by_input_source( return source_of_input_data -def identify_annually_reported_eia_data(eia923_allocated, year): - """Creates table summarizing the percent of final data from annually-reported EIA data.""" +def identify_reporting_frequency(eia923_allocated, year): + """Identifies if EIA data was reported as an annual total or monthly totals. + Returns input dataframe with `eia_data_resolution` column added""" # load data about the respondent frequency for each plant and merge into the EIA-923 data pudl_out = load_data.initialize_pudl_out(year) plant_frequency = pudl_out.plants_eia860()[ ["plant_id_eia", "reporting_frequency_code"] ] + # rename the column and recode the values + plant_frequency = plant_frequency.rename( + columns={"reporting_frequency_code": "eia_data_resolution"} + ) + plant_frequency["eia_data_resolution"] = plant_frequency[ + "eia_data_resolution" + ].replace({"A": "annual", "AM": "monthly", "M": "monthly"}) + # merge the data resolution column into the EIA data eia_data = eia923_allocated.merge( plant_frequency, how="left", on="plant_id_eia", validate="m:1" ) + return eia_data + + +def summarize_annually_reported_eia_data(eia923_allocated, year): + """Creates table summarizing the percent of final data from annually-reported EIA data.""" + + columns_to_summarize = [ + "fuel_consumed_mmbtu", + "net_generation_mwh", + "co2_mass_lb", + "co2_mass_lb_for_electricity", + "nox_mass_lb", + "nox_mass_lb_for_electricity", + "so2_mass_lb", + "so2_mass_lb_for_electricity", + ] + + eia_data = identify_reporting_frequency(eia923_allocated, year) data_from_annual = ( - eia_data.groupby(["reporting_frequency_code"], dropna=False)[ - ["fuel_consumed_mmbtu", "net_generation_mwh", "co2_mass_lb"] + eia_data.groupby(["eia_data_resolution"], dropna=False)[ + columns_to_summarize ].sum() - / eia_data[["fuel_consumed_mmbtu", "net_generation_mwh", "co2_mass_lb"]].sum() + / eia_data[columns_to_summarize].sum() * 100 ).reset_index() annual_eia_used = ( eia_data[eia_data["hourly_data_source"] != "cems"] - .groupby(["reporting_frequency_code"], dropna=False)[ - ["fuel_consumed_mmbtu", "net_generation_mwh", "co2_mass_lb"] - ] + .groupby(["eia_data_resolution"], dropna=False)[columns_to_summarize] .sum() - / eia_data[["fuel_consumed_mmbtu", "net_generation_mwh", "co2_mass_lb"]].sum() + / eia_data[columns_to_summarize].sum() * 100 ).reset_index() @@ -584,10 +681,10 @@ def identify_annually_reported_eia_data(eia923_allocated, year): multi_source_subplants, how="inner", on=["plant_id_eia", "subplant_id"] ) multi_source_summary = ( - multi_source_subplants.groupby(["reporting_frequency_code"], dropna=False)[ - ["fuel_consumed_mmbtu", "net_generation_mwh", "co2_mass_lb"] + multi_source_subplants.groupby(["eia_data_resolution"], dropna=False)[ + columns_to_summarize ].sum() - / eia_data[["fuel_consumed_mmbtu", "net_generation_mwh", "co2_mass_lb"]].sum() + / eia_data[columns_to_summarize].sum() * 100 ).reset_index() @@ -595,30 +692,32 @@ def identify_annually_reported_eia_data(eia923_allocated, year): [ pd.DataFrame( data_from_annual.loc[ - data_from_annual["reporting_frequency_code"] == "A", : + data_from_annual["eia_data_resolution"] == "annual", : ] - .set_index("reporting_frequency_code") + .set_index("eia_data_resolution") .rename( - index={"A": "% of EIA-923 input data from EIA annual reporters"} + index={ + "annual": "% of EIA-923 input data from EIA annual reporters" + } ) .round(2) ), pd.DataFrame( annual_eia_used.loc[ - annual_eia_used["reporting_frequency_code"] == "A", : + annual_eia_used["eia_data_resolution"] == "annual", : ] - .set_index("reporting_frequency_code") - .rename(index={"A": "% of output data from EIA annual reporters"}) + .set_index("eia_data_resolution") + .rename(index={"annual": "% of output data from EIA annual reporters"}) .round(2) ), pd.DataFrame( multi_source_summary.loc[ - multi_source_summary["reporting_frequency_code"] == "A", : + multi_source_summary["eia_data_resolution"] == "annual", : ] - .set_index("reporting_frequency_code") + .set_index("eia_data_resolution") .rename( index={ - "A": "% of output data mixing CEMS and annually-reported EIA data" + "annual": "% of output data mixing CEMS and annually-reported EIA data" } ) .round(2) @@ -627,13 +726,86 @@ def identify_annually_reported_eia_data(eia923_allocated, year): axis=0, ) - annual_data_summary.rename(columns={"reporting_frequency_code": "category"}) + annual_data_summary.rename(columns={"eia_data_resolution": "category"}) annual_data_summary = annual_data_summary.reset_index() return annual_data_summary +def summarize_cems_measurement_quality(cems): + """Creates a table summarizing what percent of CO2, SO2, and NOx mass in CEMS was measured or imputed from other hourly values""" + cems_quality = cems[ + [ + "co2_mass_lb", + "co2_mass_measurement_code", + "so2_mass_lb", + "so2_mass_measurement_code", + "nox_mass_lb", + "nox_mass_measurement_code", + ] + ].copy() + + # convert categorical columns to strings + cems_quality[ + [ + "co2_mass_measurement_code", + "so2_mass_measurement_code", + "nox_mass_measurement_code", + ] + ] = cems_quality[ + [ + "co2_mass_measurement_code", + "so2_mass_measurement_code", + "nox_mass_measurement_code", + ] + ].astype( + str + ) + # replace the CEMS mass measurement codes with two categories + measurement_code_map = { + "Measured": "Measured", + "Measured and Substitute": "Measured", + "LME": "Imputed", + "Substitute": "Imputed", + "Imputed": "Imputed", + "Calculated": "Imputed", + "Other": "Imputed", + } + cems_quality[ + [ + "co2_mass_measurement_code", + "so2_mass_measurement_code", + "nox_mass_measurement_code", + ] + ] = cems_quality[ + [ + "co2_mass_measurement_code", + "so2_mass_measurement_code", + "nox_mass_measurement_code", + ] + ].replace( + measurement_code_map + ) + + cems_quality_summary = [] + # calculate the percent of mass for each pollutant that is measured or imputed + for pollutant in ["co2", "nox", "so2"]: + percent = ( + cems_quality.groupby( + [f"{pollutant}_mass_measurement_code"], dropna=False + ).sum()[f"{pollutant}_mass_lb"] + / cems_quality[f"{pollutant}_mass_lb"].sum() + ) + cems_quality_summary.append(percent) + cems_quality_summary = pd.concat(cems_quality_summary, axis=1).round(4) + # drop NA values + cems_quality_summary = cems_quality_summary.loc[["Measured", "Imputed"], :] + cems_quality_summary = cems_quality_summary.reset_index() + + return cems_quality_summary + + def identify_cems_gtn_method(cems): method_summary = cems.groupby("gtn_method", dropna=False).sum()[ "gross_generation_mwh" @@ -645,7 +817,27 @@ def identify_cems_gtn_method(cems): return method_summary +def validate_wind_solar_imputation(hourly_profiles, year): + """Creates a table showing cross-validaton results of the wind and solar profile imputation method""" + + # calculate the results and merge together + diba_results = validate_diba_imputation_method(hourly_profiles, year) + nationaal_results = validate_national_imputation_method(hourly_profiles) + + imputation_results = diba_results.merge( + nationaal_results, how="outer", on=["fuel_category", "ba_code"], validate="1:1" + ) + + return imputation_results + + def validate_diba_imputation_method(hourly_profiles, year): + """Validates the method for imputing missing wind and solar profiles. + + Calculates an imputed profile for regions where we have actual wind and solar profiles, + then calculates how well each imputed profile is correlated with the actual profile. + Calculates the correlation for each month, then calculates an annual average correlation coefficient. + """ # only keep wind and solar data data_to_validate = hourly_profiles[ @@ -707,7 +899,7 @@ def validate_diba_imputation_method(hourly_profiles, year): hourly_profiles_to_add, axis=0, ignore_index=True ) - # calculate the correlations + # merge the imputed data with the actual data compare_method = data_to_validate.merge( hourly_profiles_to_add, how="left", @@ -721,6 +913,7 @@ def validate_diba_imputation_method(hourly_profiles, year): validate="1:1", ) + # calculate the correlation coefficient for each fleet-month compare_method = ( compare_method.groupby(["fuel_category", "report_date", "ba_code"]) .corr() @@ -728,6 +921,7 @@ def validate_diba_imputation_method(hourly_profiles, year): ) compare_method = compare_method[compare_method["level_3"] == "eia930_profile"] + # calculate the annual average correlation coefficent for each month compare_method = ( compare_method.groupby(["fuel_category", "ba_code"]) .mean()["imputed_profile"] @@ -735,7 +929,7 @@ def validate_diba_imputation_method(hourly_profiles, year): ) compare_method = compare_method.rename( - columns={"imputed_profile": "average_correlation_coefficient"} + columns={"imputed_profile": "diba_method_correlation_coefficient"} ) return compare_method @@ -785,7 +979,7 @@ def validate_national_imputation_method(hourly_profiles): hourly_profiles_to_add, axis=0, ignore_index=True ) - # calculate the correlations + # merge the imputed data with the actual data compare_method = data_to_validate.merge( hourly_profiles_to_add, how="left", @@ -793,6 +987,7 @@ def validate_national_imputation_method(hourly_profiles): validate="1:1", ) + # calculate the correlation coefficient for each fleet-month compare_method = ( compare_method.groupby(["fuel_category", "report_date", "ba_code"]) .corr() @@ -800,6 +995,7 @@ def validate_national_imputation_method(hourly_profiles): ) compare_method = compare_method[compare_method["level_3"] == "eia930_profile"] + # calculate the annual average correlation coefficent for each month compare_method = ( compare_method.groupby(["fuel_category", "ba_code"]) .mean()["imputed_profile"] @@ -807,7 +1003,7 @@ def validate_national_imputation_method(hourly_profiles): ) compare_method = compare_method.rename( - columns={"imputed_profile": "average_correlation_coefficient"} + columns={"imputed_profile": "national_method_correlation_coefficient"} ) return compare_method From b3ad0f368075737de3986f2a92885e1dd7fc2801 Mon Sep 17 00:00:00 2001 From: grgmiller Date: Mon, 5 Sep 2022 20:30:35 -0700 Subject: [PATCH 02/12] fix so2 bugs --- data/manual/emission_factors_for_nox.csv | 14 +- data/manual/emission_factors_for_so2.csv | 390 +++++++++--------- .../explore_intermediate_outputs.ipynb | 34 +- notebooks/validation/validate_vs_egrid.ipynb | 36 +- src/emissions.py | 10 +- src/validation.py | 104 +++-- 6 files changed, 313 insertions(+), 275 deletions(-) diff --git a/data/manual/emission_factors_for_nox.csv b/data/manual/emission_factors_for_nox.csv index 3aa031fd..b382ad61 100644 --- a/data/manual/emission_factors_for_nox.csv +++ b/data/manual/emission_factors_for_nox.csv @@ -15,7 +15,7 @@ ST,BIT,WET,CYCLONE,33,lb,ton ST,BIT,DRY,FLUIDIZED,5,lb,ton ST,BIT,N/A,FLUIDIZED,5,lb,ton ST,BIT,WET,FLUIDIZED,5,lb,ton -ST,BIT,N/A,N/A,12,lb,ton +ST,BIT,N/A,N/A,31,lb,ton ST,BIT,DRY,OTHER,12,lb,ton ST,BIT,N/A,OTHER,12,lb,ton ST,BIT,WET,OTHER,31,lb,ton @@ -177,9 +177,9 @@ ST,NG,WET,DUCTBURNER,0.28,lb,mcf ST,NG,DRY,FLUIDIZED,0.28,lb,mcf ST,NG,N/A,FLUIDIZED,0.28,lb,mcf ST,NG,WET,FLUIDIZED,0.28,lb,mcf -ST,NG,DRY,N/A,0.17,lb,mcf -ST,NG,N/A,N/A,0.17,lb,mcf -ST,NG,WET,N/A,0.17,lb,mcf +ST,NG,DRY,N/A,0.28,lb,mcf +ST,NG,N/A,N/A,0.28,lb,mcf +ST,NG,WET,N/A,0.28,lb,mcf ST,NG,DRY,OTHER,0.28,lb,mcf ST,NG,N/A,OTHER,0.28,lb,mcf ST,NG,WET,OTHER,0.28,lb,mcf @@ -396,9 +396,9 @@ ST,WDS,N/A,DUCTBURNER,2.51,lb,ton ST,WDS,DRY,FLUIDIZED,2,lb,ton ST,WDS,N/A,FLUIDIZED,2,lb,ton ST,WDS,WET,FLUIDIZED,2,lb,ton -ST,WDS,DRY,N/A,1.5,lb,ton -ST,WDS,N/A,N/A,1.5,lb,ton -ST,WDS,WET,N/A,1.5,lb,ton +ST,WDS,DRY,N/A,2.51,lb,ton +ST,WDS,N/A,N/A,2.51,lb,ton +ST,WDS,WET,N/A,2.51,lb,ton ST,WDS,DRY,OTHER,2.51,lb,ton ST,WDS,N/A,OTHER,2.51,lb,ton ST,WDS,DRY,STOKER,1.5,lb,ton diff --git a/data/manual/emission_factors_for_so2.csv b/data/manual/emission_factors_for_so2.csv index e33575c7..84a9ec63 100644 --- a/data/manual/emission_factors_for_so2.csv +++ b/data/manual/emission_factors_for_so2.csv @@ -3,7 +3,7 @@ OT,AB,CELLBURNER,0.08,lb,short ton,0 OT,AB,CYCLONE,0.08,lb,short ton,0 OT,AB,DUCTBURNER,0.08,lb,short ton,0 OT,AB,FLUIDIZED,0.01,lb,short ton,0 -OT,AB,N/A,0.01,lb,short ton,0 +OT,AB,N/A,0.08,lb,short ton,0 OT,AB,OTHER,0.08,lb,short ton,0 OT,AB,STOKER,0.08,lb,short ton,0 OT,AB,TANGENTIAL,0.08,lb,short ton,0 @@ -13,67 +13,67 @@ ST,AB,CELLBURNER,0.08,lb,short ton,0 ST,AB,CYCLONE,0.08,lb,short ton,0 ST,AB,DUCTBURNER,0.08,lb,short ton,0 ST,AB,FLUIDIZED,0.01,lb,short ton,0 -ST,AB,N/A,0.01,lb,short ton,0 +ST,AB,N/A,0.08,lb,short ton,0 ST,AB,OTHER,0.08,lb,short ton,0 ST,AB,STOKER,0.08,lb,short ton,0 ST,AB,TANGENTIAL,0.08,lb,short ton,0 ST,AB,VERTICAL,0.08,lb,short ton,0 ST,AB,WALL,0.08,lb,short ton,0 -CA,BFG,CELLBURNER,0.001,lb,Mcf,0 +CA,BFG,CELLBURNER,0.0006,lb,Mcf,0 CA,BFG,CYCLONE,0.0006,lb,Mcf,0 -CA,BFG,DUCTBURNER,0.0011,lb,Mcf,0 -CA,BFG,FLUIDIZED,0.0007,lb,Mcf,0 -CA,BFG,N/A,0.0014,lb,Mcf,0 -CA,BFG,OTHER,0.0014,lb,Mcf,0 -CA,BFG,STOKER,0.0008,lb,Mcf,0 -CA,BFG,TANGENTIAL,0.0009,lb,Mcf,0 -CA,BFG,VERTICAL,0.0013,lb,Mcf,0 -CA,BFG,WALL,0.0012,lb,Mcf,0 -CS,BFG,CELLBURNER,0.001,lb,Mcf,0 +CA,BFG,DUCTBURNER,0.0006,lb,Mcf,0 +CA,BFG,FLUIDIZED,0.0006,lb,Mcf,0 +CA,BFG,N/A,0.0006,lb,Mcf,0 +CA,BFG,OTHER,0.0006,lb,Mcf,0 +CA,BFG,STOKER,0.0006,lb,Mcf,0 +CA,BFG,TANGENTIAL,0.0006,lb,Mcf,0 +CA,BFG,VERTICAL,0.0006,lb,Mcf,0 +CA,BFG,WALL,0.0006,lb,Mcf,0 +CS,BFG,CELLBURNER,0.0006,lb,Mcf,0 CS,BFG,CYCLONE,0.0006,lb,Mcf,0 -CS,BFG,DUCTBURNER,0.0011,lb,Mcf,0 -CS,BFG,FLUIDIZED,0.0007,lb,Mcf,0 -CS,BFG,N/A,0.0014,lb,Mcf,0 -CS,BFG,OTHER,0.0014,lb,Mcf,0 -CS,BFG,STOKER,0.0008,lb,Mcf,0 -CS,BFG,TANGENTIAL,0.0009,lb,Mcf,0 -CS,BFG,VERTICAL,0.0013,lb,Mcf,0 -CS,BFG,WALL,0.0012,lb,Mcf,0 -CT,BFG,CELLBURNER,0.001,lb,Mcf,0 +CS,BFG,DUCTBURNER,0.0006,lb,Mcf,0 +CS,BFG,FLUIDIZED,0.0006,lb,Mcf,0 +CS,BFG,N/A,0.0006,lb,Mcf,0 +CS,BFG,OTHER,0.0006,lb,Mcf,0 +CS,BFG,STOKER,0.0006,lb,Mcf,0 +CS,BFG,TANGENTIAL,0.0006,lb,Mcf,0 +CS,BFG,VERTICAL,0.0006,lb,Mcf,0 +CS,BFG,WALL,0.0006,lb,Mcf,0 +CT,BFG,CELLBURNER,0.0006,lb,Mcf,0 CT,BFG,CYCLONE,0.0006,lb,Mcf,0 -CT,BFG,DUCTBURNER,0.0011,lb,Mcf,0 -CT,BFG,FLUIDIZED,0.0007,lb,Mcf,0 -CT,BFG,N/A,0.0014,lb,Mcf,0 -CT,BFG,OTHER,0.0014,lb,Mcf,0 -CT,BFG,STOKER,0.0008,lb,Mcf,0 -CT,BFG,TANGENTIAL,0.0009,lb,Mcf,0 -CT,BFG,VERTICAL,0.0013,lb,Mcf,0 -CT,BFG,WALL,0.0012,lb,Mcf,0 -GT,BFG,CELLBURNER,0.001,lb,Mcf,0 +CT,BFG,DUCTBURNER,0.0006,lb,Mcf,0 +CT,BFG,FLUIDIZED,0.0006,lb,Mcf,0 +CT,BFG,N/A,0.0006,lb,Mcf,0 +CT,BFG,OTHER,0.0006,lb,Mcf,0 +CT,BFG,STOKER,0.0006,lb,Mcf,0 +CT,BFG,TANGENTIAL,0.0006,lb,Mcf,0 +CT,BFG,VERTICAL,0.0006,lb,Mcf,0 +CT,BFG,WALL,0.0006,lb,Mcf,0 +GT,BFG,CELLBURNER,0.0006,lb,Mcf,0 GT,BFG,CYCLONE,0.0006,lb,Mcf,0 -GT,BFG,DUCTBURNER,0.0011,lb,Mcf,0 -GT,BFG,FLUIDIZED,0.0007,lb,Mcf,0 -GT,BFG,N/A,0.0014,lb,Mcf,0 -GT,BFG,OTHER,0.0014,lb,Mcf,0 -GT,BFG,STOKER,0.0008,lb,Mcf,0 -GT,BFG,TANGENTIAL,0.0009,lb,Mcf,0 -GT,BFG,VERTICAL,0.0013,lb,Mcf,0 -GT,BFG,WALL,0.0012,lb,Mcf,0 -IC,BFG,CELLBURNER,0.001,lb,Mcf,0 +GT,BFG,DUCTBURNER,0.0006,lb,Mcf,0 +GT,BFG,FLUIDIZED,0.0006,lb,Mcf,0 +GT,BFG,N/A,0.0006,lb,Mcf,0 +GT,BFG,OTHER,0.0006,lb,Mcf,0 +GT,BFG,STOKER,0.0006,lb,Mcf,0 +GT,BFG,TANGENTIAL,0.0006,lb,Mcf,0 +GT,BFG,VERTICAL,0.0006,lb,Mcf,0 +GT,BFG,WALL,0.0006,lb,Mcf,0 +IC,BFG,CELLBURNER,0.0006,lb,Mcf,0 IC,BFG,CYCLONE,0.0006,lb,Mcf,0 -IC,BFG,DUCTBURNER,0.0011,lb,Mcf,0 -IC,BFG,FLUIDIZED,0.0007,lb,Mcf,0 -IC,BFG,N/A,0.0014,lb,Mcf,0 -IC,BFG,OTHER,0.0014,lb,Mcf,0 -IC,BFG,STOKER,0.0008,lb,Mcf,0 -IC,BFG,TANGENTIAL,0.0009,lb,Mcf,0 -IC,BFG,VERTICAL,0.0013,lb,Mcf,0 -IC,BFG,WALL,0.0012,lb,Mcf,0 +IC,BFG,DUCTBURNER,0.0006,lb,Mcf,0 +IC,BFG,FLUIDIZED,0.0006,lb,Mcf,0 +IC,BFG,N/A,0.0006,lb,Mcf,0 +IC,BFG,OTHER,0.0006,lb,Mcf,0 +IC,BFG,STOKER,0.0006,lb,Mcf,0 +IC,BFG,TANGENTIAL,0.0006,lb,Mcf,0 +IC,BFG,VERTICAL,0.0006,lb,Mcf,0 +IC,BFG,WALL,0.0006,lb,Mcf,0 OT,BFG,CELLBURNER,0.0006,lb,Mcf,0 OT,BFG,CYCLONE,0.0006,lb,Mcf,0 OT,BFG,DUCTBURNER,0.0006,lb,Mcf,0 OT,BFG,FLUIDIZED,0.00006,lb,Mcf,0 -OT,BFG,N/A,0.00006,lb,Mcf,0 +OT,BFG,N/A,0.0006,lb,Mcf,0 OT,BFG,OTHER,0.0006,lb,Mcf,0 OT,BFG,STOKER,0.0006,lb,Mcf,0 OT,BFG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -83,7 +83,7 @@ ST,BFG,CELLBURNER,0.0006,lb,Mcf,0 ST,BFG,CYCLONE,0.0006,lb,Mcf,0 ST,BFG,DUCTBURNER,0.0006,lb,Mcf,0 ST,BFG,FLUIDIZED,0.00006,lb,Mcf,0 -ST,BFG,N/A,0.00006,lb,Mcf,0 +ST,BFG,N/A,0.0006,lb,Mcf,0 ST,BFG,OTHER,0.0006,lb,Mcf,0 ST,BFG,STOKER,0.0006,lb,Mcf,0 ST,BFG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -93,7 +93,7 @@ OT,BIT,CELLBURNER,38*S,lb,short ton,1 OT,BIT,CYCLONE,38*S,lb,short ton,1 OT,BIT,DUCTBURNER,38*S,lb,short ton,1 OT,BIT,FLUIDIZED,3.8*S,lb,short ton,1 -OT,BIT,N/A,3.8*S,lb,short ton,1 +OT,BIT,N/A,38*S,lb,short ton,1 OT,BIT,OTHER,38*S,lb,short ton,1 OT,BIT,STOKER,38*S,lb,short ton,1 OT,BIT,TANGENTIAL,38*S,lb,short ton,1 @@ -103,7 +103,7 @@ ST,BIT,CELLBURNER,38*S,lb,short ton,1 ST,BIT,CYCLONE,38*S,lb,short ton,1 ST,BIT,DUCTBURNER,38*S,lb,short ton,1 ST,BIT,FLUIDIZED,3.8*S,lb,short ton,1 -ST,BIT,N/A,3.8*S,lb,short ton,1 +ST,BIT,N/A,38*S,lb,short ton,1 ST,BIT,OTHER,38*S,lb,short ton,1 ST,BIT,STOKER,38*S,lb,short ton,1 ST,BIT,TANGENTIAL,38*S,lb,short ton,1 @@ -113,7 +113,7 @@ OT,BLQ,CELLBURNER,7,lb,short ton,0 OT,BLQ,CYCLONE,7,lb,short ton,0 OT,BLQ,DUCTBURNER,7,lb,short ton,0 OT,BLQ,FLUIDIZED,0.7,lb,short ton,0 -OT,BLQ,N/A,0.7,lb,short ton,0 +OT,BLQ,N/A,7,lb,short ton,0 OT,BLQ,OTHER,7,lb,short ton,0 OT,BLQ,STOKER,7,lb,short ton,0 OT,BLQ,TANGENTIAL,7,lb,short ton,0 @@ -123,7 +123,7 @@ ST,BLQ,CELLBURNER,7,lb,short ton,0 ST,BLQ,CYCLONE,7,lb,short ton,0 ST,BLQ,DUCTBURNER,7,lb,short ton,0 ST,BLQ,FLUIDIZED,0.7,lb,short ton,0 -ST,BLQ,N/A,0.7,lb,short ton,0 +ST,BLQ,N/A,7,lb,short ton,0 ST,BLQ,OTHER,7,lb,short ton,0 ST,BLQ,STOKER,7,lb,short ton,0 ST,BLQ,TANGENTIAL,7,lb,short ton,0 @@ -183,7 +183,7 @@ OT,DFO,CELLBURNER,5.964*S,lb,barrel,1 OT,DFO,CYCLONE,5.964*S,lb,barrel,1 OT,DFO,DUCTBURNER,5.964*S,lb,barrel,1 OT,DFO,FLUIDIZED,0.5964*S,lb,barrel,1 -OT,DFO,N/A,0.5964*S,lb,barrel,1 +OT,DFO,N/A,5.964*S,lb,barrel,1 OT,DFO,OTHER,5.964*S,lb,barrel,1 OT,DFO,STOKER,5.964*S,lb,barrel,1 OT,DFO,TANGENTIAL,5.964*S,lb,barrel,1 @@ -193,7 +193,7 @@ ST,DFO,CELLBURNER,5.964*S,lb,barrel,1 ST,DFO,CYCLONE,5.964*S,lb,barrel,1 ST,DFO,DUCTBURNER,5.964*S,lb,barrel,1 ST,DFO,FLUIDIZED,0.5964*S,lb,barrel,1 -ST,DFO,N/A,0.5964*S,lb,barrel,1 +ST,DFO,N/A,5.964*S,lb,barrel,1 ST,DFO,OTHER,5.964*S,lb,barrel,1 ST,DFO,STOKER,5.964*S,lb,barrel,1 ST,DFO,TANGENTIAL,5.964*S,lb,barrel,1 @@ -253,7 +253,7 @@ OT,JF,CELLBURNER,5.964*S,lb,barrel,1 OT,JF,CYCLONE,5.964*S,lb,barrel,1 OT,JF,DUCTBURNER,5.964*S,lb,barrel,1 OT,JF,FLUIDIZED,0.5964*S,lb,barrel,1 -OT,JF,N/A,0.5964*S,lb,barrel,1 +OT,JF,N/A,5.964*S,lb,barrel,1 OT,JF,OTHER,5.964*S,lb,barrel,1 OT,JF,STOKER,5.964*S,lb,barrel,1 OT,JF,TANGENTIAL,5.964*S,lb,barrel,1 @@ -263,7 +263,7 @@ ST,JF,CELLBURNER,5.964*S,lb,barrel,1 ST,JF,CYCLONE,5.964*S,lb,barrel,1 ST,JF,DUCTBURNER,5.964*S,lb,barrel,1 ST,JF,FLUIDIZED,0.5964*S,lb,barrel,1 -ST,JF,N/A,0.5964*S,lb,barrel,1 +ST,JF,N/A,5.964*S,lb,barrel,1 ST,JF,OTHER,5.964*S,lb,barrel,1 ST,JF,STOKER,5.964*S,lb,barrel,1 ST,JF,TANGENTIAL,5.964*S,lb,barrel,1 @@ -323,7 +323,7 @@ OT,KER,CELLBURNER,5.964*S,lb,barrel,1 OT,KER,CYCLONE,5.964*S,lb,barrel,1 OT,KER,DUCTBURNER,5.964*S,lb,barrel,1 OT,KER,FLUIDIZED,0.5964*S,lb,barrel,1 -OT,KER,N/A,0.5964*S,lb,barrel,1 +OT,KER,N/A,5.964*S,lb,barrel,1 OT,KER,OTHER,5.964*S,lb,barrel,1 OT,KER,STOKER,5.964*S,lb,barrel,1 OT,KER,TANGENTIAL,5.964*S,lb,barrel,1 @@ -333,67 +333,67 @@ ST,KER,CELLBURNER,5.964*S,lb,barrel,1 ST,KER,CYCLONE,5.964*S,lb,barrel,1 ST,KER,DUCTBURNER,5.964*S,lb,barrel,1 ST,KER,FLUIDIZED,0.5964*S,lb,barrel,1 -ST,KER,N/A,0.5964*S,lb,barrel,1 +ST,KER,N/A,5.964*S,lb,barrel,1 ST,KER,OTHER,5.964*S,lb,barrel,1 ST,KER,STOKER,5.964*S,lb,barrel,1 ST,KER,TANGENTIAL,5.964*S,lb,barrel,1 ST,KER,VERTICAL,5.964*S,lb,barrel,1 ST,KER,WALL,5.964*S,lb,barrel,1 -CA,LFG,CELLBURNER,0.001,lb,Mcf,0 +CA,LFG,CELLBURNER,0.0006,lb,Mcf,0 CA,LFG,CYCLONE,0.0006,lb,Mcf,0 -CA,LFG,DUCTBURNER,0.0011,lb,Mcf,0 -CA,LFG,FLUIDIZED,0.0007,lb,Mcf,0 -CA,LFG,N/A,0.0014,lb,Mcf,0 -CA,LFG,OTHER,0.0014,lb,Mcf,0 -CA,LFG,STOKER,0.0008,lb,Mcf,0 -CA,LFG,TANGENTIAL,0.0009,lb,Mcf,0 -CA,LFG,VERTICAL,0.0013,lb,Mcf,0 -CA,LFG,WALL,0.0012,lb,Mcf,0 -CS,LFG,CELLBURNER,0.001,lb,Mcf,0 +CA,LFG,DUCTBURNER,0.0006,lb,Mcf,0 +CA,LFG,FLUIDIZED,0.0006,lb,Mcf,0 +CA,LFG,N/A,0.0006,lb,Mcf,0 +CA,LFG,OTHER,0.0006,lb,Mcf,0 +CA,LFG,STOKER,0.0006,lb,Mcf,0 +CA,LFG,TANGENTIAL,0.0006,lb,Mcf,0 +CA,LFG,VERTICAL,0.0006,lb,Mcf,0 +CA,LFG,WALL,0.0006,lb,Mcf,0 +CS,LFG,CELLBURNER,0.0006,lb,Mcf,0 CS,LFG,CYCLONE,0.0006,lb,Mcf,0 -CS,LFG,DUCTBURNER,0.0011,lb,Mcf,0 -CS,LFG,FLUIDIZED,0.0007,lb,Mcf,0 -CS,LFG,N/A,0.0014,lb,Mcf,0 -CS,LFG,OTHER,0.0014,lb,Mcf,0 -CS,LFG,STOKER,0.0008,lb,Mcf,0 -CS,LFG,TANGENTIAL,0.0009,lb,Mcf,0 -CS,LFG,VERTICAL,0.0013,lb,Mcf,0 -CS,LFG,WALL,0.0012,lb,Mcf,0 -CT,LFG,CELLBURNER,0.001,lb,Mcf,0 +CS,LFG,DUCTBURNER,0.0006,lb,Mcf,0 +CS,LFG,FLUIDIZED,0.0006,lb,Mcf,0 +CS,LFG,N/A,0.0006,lb,Mcf,0 +CS,LFG,OTHER,0.0006,lb,Mcf,0 +CS,LFG,STOKER,0.0006,lb,Mcf,0 +CS,LFG,TANGENTIAL,0.0006,lb,Mcf,0 +CS,LFG,VERTICAL,0.0006,lb,Mcf,0 +CS,LFG,WALL,0.0006,lb,Mcf,0 +CT,LFG,CELLBURNER,0.0006,lb,Mcf,0 CT,LFG,CYCLONE,0.0006,lb,Mcf,0 -CT,LFG,DUCTBURNER,0.0011,lb,Mcf,0 -CT,LFG,FLUIDIZED,0.0007,lb,Mcf,0 -CT,LFG,N/A,0.0014,lb,Mcf,0 -CT,LFG,OTHER,0.0014,lb,Mcf,0 -CT,LFG,STOKER,0.0008,lb,Mcf,0 -CT,LFG,TANGENTIAL,0.0009,lb,Mcf,0 -CT,LFG,VERTICAL,0.0013,lb,Mcf,0 -CT,LFG,WALL,0.0012,lb,Mcf,0 -GT,LFG,CELLBURNER,0.001,lb,Mcf,0 +CT,LFG,DUCTBURNER,0.0006,lb,Mcf,0 +CT,LFG,FLUIDIZED,0.0006,lb,Mcf,0 +CT,LFG,N/A,0.0006,lb,Mcf,0 +CT,LFG,OTHER,0.0006,lb,Mcf,0 +CT,LFG,STOKER,0.0006,lb,Mcf,0 +CT,LFG,TANGENTIAL,0.0006,lb,Mcf,0 +CT,LFG,VERTICAL,0.0006,lb,Mcf,0 +CT,LFG,WALL,0.0006,lb,Mcf,0 +GT,LFG,CELLBURNER,0.0006,lb,Mcf,0 GT,LFG,CYCLONE,0.0006,lb,Mcf,0 -GT,LFG,DUCTBURNER,0.0011,lb,Mcf,0 -GT,LFG,FLUIDIZED,0.0007,lb,Mcf,0 -GT,LFG,N/A,0.0014,lb,Mcf,0 -GT,LFG,OTHER,0.0014,lb,Mcf,0 -GT,LFG,STOKER,0.0008,lb,Mcf,0 -GT,LFG,TANGENTIAL,0.0009,lb,Mcf,0 -GT,LFG,VERTICAL,0.0013,lb,Mcf,0 -GT,LFG,WALL,0.0012,lb,Mcf,0 -IC,LFG,CELLBURNER,0.001,lb,Mcf,0 +GT,LFG,DUCTBURNER,0.0006,lb,Mcf,0 +GT,LFG,FLUIDIZED,0.0006,lb,Mcf,0 +GT,LFG,N/A,0.0006,lb,Mcf,0 +GT,LFG,OTHER,0.0006,lb,Mcf,0 +GT,LFG,STOKER,0.0006,lb,Mcf,0 +GT,LFG,TANGENTIAL,0.0006,lb,Mcf,0 +GT,LFG,VERTICAL,0.0006,lb,Mcf,0 +GT,LFG,WALL,0.0006,lb,Mcf,0 +IC,LFG,CELLBURNER,0.0006,lb,Mcf,0 IC,LFG,CYCLONE,0.0006,lb,Mcf,0 -IC,LFG,DUCTBURNER,0.0011,lb,Mcf,0 -IC,LFG,FLUIDIZED,0.0007,lb,Mcf,0 -IC,LFG,N/A,0.0014,lb,Mcf,0 -IC,LFG,OTHER,0.0014,lb,Mcf,0 -IC,LFG,STOKER,0.0008,lb,Mcf,0 -IC,LFG,TANGENTIAL,0.0009,lb,Mcf,0 -IC,LFG,VERTICAL,0.0013,lb,Mcf,0 -IC,LFG,WALL,0.0012,lb,Mcf,0 +IC,LFG,DUCTBURNER,0.0006,lb,Mcf,0 +IC,LFG,FLUIDIZED,0.00006,lb,Mcf,0 +IC,LFG,N/A,0.0006,lb,Mcf,0 +IC,LFG,OTHER,0.0006,lb,Mcf,0 +IC,LFG,STOKER,0.0006,lb,Mcf,0 +IC,LFG,TANGENTIAL,0.0006,lb,Mcf,0 +IC,LFG,VERTICAL,0.0006,lb,Mcf,0 +IC,LFG,WALL,0.0006,lb,Mcf,0 OT,LFG,CELLBURNER,0.0006,lb,Mcf,0 OT,LFG,CYCLONE,0.0006,lb,Mcf,0 OT,LFG,DUCTBURNER,0.0006,lb,Mcf,0 OT,LFG,FLUIDIZED,0.00006,lb,Mcf,0 -OT,LFG,N/A,0.00006,lb,Mcf,0 +OT,LFG,N/A,0.0006,lb,Mcf,0 OT,LFG,OTHER,0.0006,lb,Mcf,0 OT,LFG,STOKER,0.0006,lb,Mcf,0 OT,LFG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -403,7 +403,7 @@ ST,LFG,CELLBURNER,0.0006,lb,Mcf,0 ST,LFG,CYCLONE,0.0006,lb,Mcf,0 ST,LFG,DUCTBURNER,0.0006,lb,Mcf,0 ST,LFG,FLUIDIZED,0.00006,lb,Mcf,0 -ST,LFG,N/A,0.00006,lb,Mcf,0 +ST,LFG,N/A,0.0006,lb,Mcf,0 ST,LFG,OTHER,0.0006,lb,Mcf,0 ST,LFG,STOKER,0.0006,lb,Mcf,0 ST,LFG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -413,7 +413,7 @@ OT,LIG,CELLBURNER,30*S,lb,short ton,1 OT,LIG,CYCLONE,30*S,lb,short ton,1 OT,LIG,DUCTBURNER,30*S,lb,short ton,1 OT,LIG,FLUIDIZED,3*S,lb,short ton,1 -OT,LIG,N/A,3*S,lb,short ton,1 +OT,LIG,N/A,30*S,lb,short ton,1 OT,LIG,OTHER,30*S,lb,short ton,1 OT,LIG,STOKER,30*S,lb,short ton,1 OT,LIG,TANGENTIAL,30*S,lb,short ton,1 @@ -423,7 +423,7 @@ ST,LIG,CELLBURNER,30*S,lb,short ton,1 ST,LIG,CYCLONE,30*S,lb,short ton,1 ST,LIG,DUCTBURNER,30*S,lb,short ton,1 ST,LIG,FLUIDIZED,3*S,lb,short ton,1 -ST,LIG,N/A,3*S,lb,short ton,1 +ST,LIG,N/A,30*S,lb,short ton,1 ST,LIG,OTHER,30*S,lb,short ton,1 ST,LIG,STOKER,30*S,lb,short ton,1 ST,LIG,TANGENTIAL,30*S,lb,short ton,1 @@ -433,7 +433,7 @@ ST,MSB,CELLBURNER,1.7,lb,short ton,0 ST,MSB,CYCLONE,1.7,lb,short ton,0 ST,MSB,DUCTBURNER,1.7,lb,short ton,0 ST,MSB,FLUIDIZED,0.17,lb,short ton,0 -ST,MSB,N/A,0.17,lb,short ton,0 +ST,MSB,N/A,1.7,lb,short ton,0 ST,MSB,OTHER,1.7,lb,short ton,0 ST,MSB,STOKER,1.7,lb,short ton,0 ST,MSB,TANGENTIAL,1.7,lb,short ton,0 @@ -443,7 +443,7 @@ ST,MSN,CELLBURNER,1.7,lb,short ton,0 ST,MSN,CYCLONE,1.7,lb,short ton,0 ST,MSN,DUCTBURNER,1.7,lb,short ton,0 ST,MSN,FLUIDIZED,0.17,lb,short ton,0 -ST,MSN,N/A,0.17,lb,short ton,0 +ST,MSN,N/A,1.7,lb,short ton,0 ST,MSN,OTHER,1.7,lb,short ton,0 ST,MSN,STOKER,1.7,lb,short ton,0 ST,MSN,TANGENTIAL,1.7,lb,short ton,0 @@ -453,7 +453,7 @@ OT,MSW,CELLBURNER,1.7,lb,short ton,0 OT,MSW,CYCLONE,1.7,lb,short ton,0 OT,MSW,DUCTBURNER,1.7,lb,short ton,0 OT,MSW,FLUIDIZED,0.17,lb,short ton,0 -OT,MSW,N/A,0.17,lb,short ton,0 +OT,MSW,N/A,1.7,lb,short ton,0 OT,MSW,OTHER,1.7,lb,short ton,0 OT,MSW,STOKER,1.7,lb,short ton,0 OT,MSW,TANGENTIAL,1.7,lb,short ton,0 @@ -463,7 +463,7 @@ ST,MSW,CELLBURNER,1.7,lb,short ton,0 ST,MSW,CYCLONE,1.7,lb,short ton,0 ST,MSW,DUCTBURNER,1.7,lb,short ton,0 ST,MSW,FLUIDIZED,0.17,lb,short ton,0 -ST,MSW,N/A,0.17,lb,short ton,0 +ST,MSW,N/A,1.7,lb,short ton,0 ST,MSW,OTHER,1.7,lb,short ton,0 ST,MSW,STOKER,1.7,lb,short ton,0 ST,MSW,TANGENTIAL,1.7,lb,short ton,0 @@ -524,7 +524,7 @@ OT,NG,CELLBURNER,0.0006,lb,Mcf,0 OT,NG,CYCLONE,0.0006,lb,Mcf,0 OT,NG,DUCTBURNER,0.0006,lb,Mcf,0 OT,NG,FLUIDIZED,0.00006,lb,Mcf,0 -OT,NG,N/A,0.00006,lb,Mcf,0 +OT,NG,N/A,0.0006,lb,Mcf,0 OT,NG,OTHER,0.0006,lb,Mcf,0 OT,NG,STOKER,0.0006,lb,Mcf,0 OT,NG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -534,7 +534,7 @@ ST,NG,CELLBURNER,0.0006,lb,Mcf,0 ST,NG,CYCLONE,0.0006,lb,Mcf,0 ST,NG,DUCTBURNER,0.0006,lb,Mcf,0 ST,NG,FLUIDIZED,0.00006,lb,Mcf,0 -ST,NG,N/A,0.00006,lb,Mcf,0 +ST,NG,N/A,0.0006,lb,Mcf,0 ST,NG,OTHER,0.0006,lb,Mcf,0 ST,NG,STOKER,0.0006,lb,Mcf,0 ST,NG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -594,7 +594,7 @@ OT,OBG,CELLBURNER,0.0006,lb,Mcf,0 OT,OBG,CYCLONE,0.0006,lb,Mcf,0 OT,OBG,DUCTBURNER,0.0006,lb,Mcf,0 OT,OBG,FLUIDIZED,0.00006,lb,Mcf,0 -OT,OBG,N/A,0.00006,lb,Mcf,0 +OT,OBG,N/A,0.0006,lb,Mcf,0 OT,OBG,OTHER,0.0006,lb,Mcf,0 OT,OBG,STOKER,0.0006,lb,Mcf,0 OT,OBG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -604,7 +604,7 @@ ST,OBG,CELLBURNER,0.0006,lb,Mcf,0 ST,OBG,CYCLONE,0.0006,lb,Mcf,0 ST,OBG,DUCTBURNER,0.0006,lb,Mcf,0 ST,OBG,FLUIDIZED,0.00006,lb,Mcf,0 -ST,OBG,N/A,0.00006,lb,Mcf,0 +ST,OBG,N/A,0.0006,lb,Mcf,0 ST,OBG,OTHER,0.0006,lb,Mcf,0 ST,OBG,STOKER,0.0006,lb,Mcf,0 ST,OBG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -664,7 +664,7 @@ OT,OBL,CELLBURNER,5.964*S,lb,barrel,1 OT,OBL,CYCLONE,5.964*S,lb,barrel,1 OT,OBL,DUCTBURNER,5.964*S,lb,barrel,1 OT,OBL,FLUIDIZED,0.5964*S,lb,barrel,1 -OT,OBL,N/A,0.5964*S,lb,barrel,1 +OT,OBL,N/A,5.964*S,lb,barrel,1 OT,OBL,OTHER,5.964*S,lb,barrel,1 OT,OBL,STOKER,5.964*S,lb,barrel,1 OT,OBL,TANGENTIAL,5.964*S,lb,barrel,1 @@ -674,7 +674,7 @@ ST,OBL,CELLBURNER,5.964*S,lb,barrel,1 ST,OBL,CYCLONE,5.964*S,lb,barrel,1 ST,OBL,DUCTBURNER,5.964*S,lb,barrel,1 ST,OBL,FLUIDIZED,0.5964*S,lb,barrel,1 -ST,OBL,N/A,0.5964*S,lb,barrel,1 +ST,OBL,N/A,5.964*S,lb,barrel,1 ST,OBL,OTHER,5.964*S,lb,barrel,1 ST,OBL,STOKER,5.964*S,lb,barrel,1 ST,OBL,TANGENTIAL,5.964*S,lb,barrel,1 @@ -684,7 +684,7 @@ OT,OBS,CELLBURNER,0.23,lb,short ton,0 OT,OBS,CYCLONE,0.23,lb,short ton,0 OT,OBS,DUCTBURNER,0.23,lb,short ton,0 OT,OBS,FLUIDIZED,0.02,lb,short ton,0 -OT,OBS,N/A,0.02,lb,short ton,0 +OT,OBS,N/A,0.23,lb,short ton,0 OT,OBS,OTHER,0.23,lb,short ton,0 OT,OBS,STOKER,0.23,lb,short ton,0 OT,OBS,TANGENTIAL,0.23,lb,short ton,0 @@ -694,7 +694,7 @@ ST,OBS,CELLBURNER,0.23,lb,short ton,0 ST,OBS,CYCLONE,0.23,lb,short ton,0 ST,OBS,DUCTBURNER,0.23,lb,short ton,0 ST,OBS,FLUIDIZED,0.02,lb,short ton,0 -ST,OBS,N/A,0.02,lb,short ton,0 +ST,OBS,N/A,0.23,lb,short ton,0 ST,OBS,OTHER,0.23,lb,short ton,0 ST,OBS,STOKER,0.23,lb,short ton,0 ST,OBS,TANGENTIAL,0.23,lb,short ton,0 @@ -754,7 +754,7 @@ OT,OG,CELLBURNER,0.0006,lb,Mcf,0 OT,OG,CYCLONE,0.0006,lb,Mcf,0 OT,OG,DUCTBURNER,0.0006,lb,Mcf,0 OT,OG,FLUIDIZED,0.00006,lb,Mcf,0 -OT,OG,N/A,0.00006,lb,Mcf,0 +OT,OG,N/A,0.0006,lb,Mcf,0 OT,OG,OTHER,0.0006,lb,Mcf,0 OT,OG,STOKER,0.0006,lb,Mcf,0 OT,OG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -764,7 +764,7 @@ ST,OG,CELLBURNER,0.0006,lb,Mcf,0 ST,OG,CYCLONE,0.0006,lb,Mcf,0 ST,OG,DUCTBURNER,0.0006,lb,Mcf,0 ST,OG,FLUIDIZED,0.00006,lb,Mcf,0 -ST,OG,N/A,0.00006,lb,Mcf,0 +ST,OG,N/A,0.0006,lb,Mcf,0 ST,OG,OTHER,0.0006,lb,Mcf,0 ST,OG,STOKER,0.0006,lb,Mcf,0 ST,OG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -824,7 +824,7 @@ OT,OTH,CELLBURNER,0.0006,lb,Mcf,0 OT,OTH,CYCLONE,0.0006,lb,Mcf,0 OT,OTH,DUCTBURNER,0.0006,lb,Mcf,0 OT,OTH,FLUIDIZED,0.00006,lb,Mcf,0 -OT,OTH,N/A,0.00006,lb,Mcf,0 +OT,OTH,N/A,0.0006,lb,Mcf,0 OT,OTH,OTHER,0.0006,lb,Mcf,0 OT,OTH,STOKER,0.0006,lb,Mcf,0 OT,OTH,TANGENTIAL,0.0006,lb,Mcf,0 @@ -834,7 +834,7 @@ ST,OTH,CELLBURNER,0.0006,lb,Mcf,0 ST,OTH,CYCLONE,0.0006,lb,Mcf,0 ST,OTH,DUCTBURNER,0.0006,lb,Mcf,0 ST,OTH,FLUIDIZED,0.00006,lb,Mcf,0 -ST,OTH,N/A,0.00006,lb,Mcf,0 +ST,OTH,N/A,0.0006,lb,Mcf,0 ST,OTH,OTHER,0.0006,lb,Mcf,0 ST,OTH,STOKER,0.0006,lb,Mcf,0 ST,OTH,TANGENTIAL,0.0006,lb,Mcf,0 @@ -844,7 +844,7 @@ OT,PC,CELLBURNER,39*S,lb,short ton,1 OT,PC,CYCLONE,39*S,lb,short ton,1 OT,PC,DUCTBURNER,39*S,lb,short ton,1 OT,PC,FLUIDIZED,3.9*S,lb,short ton,1 -OT,PC,N/A,3.9*S,lb,short ton,1 +OT,PC,N/A,39*S,lb,short ton,1 OT,PC,OTHER,39*S,lb,short ton,1 OT,PC,STOKER,39*S,lb,short ton,1 OT,PC,TANGENTIAL,39*S,lb,short ton,1 @@ -854,67 +854,67 @@ ST,PC,CELLBURNER,39*S,lb,short ton,1 ST,PC,CYCLONE,39*S,lb,short ton,1 ST,PC,DUCTBURNER,39*S,lb,short ton,1 ST,PC,FLUIDIZED,3.9*S,lb,short ton,1 -ST,PC,N/A,3.9*S,lb,short ton,1 +ST,PC,N/A,39*S,lb,short ton,1 ST,PC,OTHER,39*S,lb,short ton,1 ST,PC,STOKER,39*S,lb,short ton,1 ST,PC,TANGENTIAL,39*S,lb,short ton,1 ST,PC,VERTICAL,39*S,lb,short ton,1 ST,PC,WALL,39*S,lb,short ton,1 -CA,PG,CELLBURNER,0.001,lb,Mcf,0 +CA,PG,CELLBURNER,0.0006,lb,Mcf,0 CA,PG,CYCLONE,0.0006,lb,Mcf,0 -CA,PG,DUCTBURNER,0.0011,lb,Mcf,0 -CA,PG,FLUIDIZED,0.0007,lb,Mcf,0 -CA,PG,N/A,0.0014,lb,Mcf,0 -CA,PG,OTHER,0.0014,lb,Mcf,0 -CA,PG,STOKER,0.0008,lb,Mcf,0 -CA,PG,TANGENTIAL,0.0009,lb,Mcf,0 -CA,PG,VERTICAL,0.0013,lb,Mcf,0 -CA,PG,WALL,0.0012,lb,Mcf,0 -CS,PG,CELLBURNER,0.001,lb,Mcf,0 +CA,PG,DUCTBURNER,0.0006,lb,Mcf,0 +CA,PG,FLUIDIZED,0.0006,lb,Mcf,0 +CA,PG,N/A,0.0006,lb,Mcf,0 +CA,PG,OTHER,0.0006,lb,Mcf,0 +CA,PG,STOKER,0.0006,lb,Mcf,0 +CA,PG,TANGENTIAL,0.0006,lb,Mcf,0 +CA,PG,VERTICAL,0.0006,lb,Mcf,0 +CA,PG,WALL,0.0006,lb,Mcf,0 +CS,PG,CELLBURNER,0.0006,lb,Mcf,0 CS,PG,CYCLONE,0.0006,lb,Mcf,0 -CS,PG,DUCTBURNER,0.0011,lb,Mcf,0 -CS,PG,FLUIDIZED,0.0007,lb,Mcf,0 -CS,PG,N/A,0.0014,lb,Mcf,0 -CS,PG,OTHER,0.0014,lb,Mcf,0 -CS,PG,STOKER,0.0008,lb,Mcf,0 -CS,PG,TANGENTIAL,0.0009,lb,Mcf,0 -CS,PG,VERTICAL,0.0013,lb,Mcf,0 -CS,PG,WALL,0.0012,lb,Mcf,0 -CT,PG,CELLBURNER,0.001,lb,Mcf,0 +CS,PG,DUCTBURNER,0.0006,lb,Mcf,0 +CS,PG,FLUIDIZED,0.0006,lb,Mcf,0 +CS,PG,N/A,0.0006,lb,Mcf,0 +CS,PG,OTHER,0.0006,lb,Mcf,0 +CS,PG,STOKER,0.0006,lb,Mcf,0 +CS,PG,TANGENTIAL,0.0006,lb,Mcf,0 +CS,PG,VERTICAL,0.0006,lb,Mcf,0 +CS,PG,WALL,0.0006,lb,Mcf,0 +CT,PG,CELLBURNER,0.0006,lb,Mcf,0 CT,PG,CYCLONE,0.0006,lb,Mcf,0 -CT,PG,DUCTBURNER,0.0011,lb,Mcf,0 -CT,PG,FLUIDIZED,0.0007,lb,Mcf,0 -CT,PG,N/A,0.0014,lb,Mcf,0 -CT,PG,OTHER,0.0014,lb,Mcf,0 -CT,PG,STOKER,0.0008,lb,Mcf,0 -CT,PG,TANGENTIAL,0.0009,lb,Mcf,0 -CT,PG,VERTICAL,0.0013,lb,Mcf,0 -CT,PG,WALL,0.0012,lb,Mcf,0 -GT,PG,CELLBURNER,0.001,lb,Mcf,0 +CT,PG,DUCTBURNER,0.0006,lb,Mcf,0 +CT,PG,FLUIDIZED,0.0006,lb,Mcf,0 +CT,PG,N/A,0.0006,lb,Mcf,0 +CT,PG,OTHER,0.0006,lb,Mcf,0 +CT,PG,STOKER,0.0006,lb,Mcf,0 +CT,PG,TANGENTIAL,0.0006,lb,Mcf,0 +CT,PG,VERTICAL,0.0006,lb,Mcf,0 +CT,PG,WALL,0.0006,lb,Mcf,0 +GT,PG,CELLBURNER,0.0006,lb,Mcf,0 GT,PG,CYCLONE,0.0006,lb,Mcf,0 -GT,PG,DUCTBURNER,0.0011,lb,Mcf,0 -GT,PG,FLUIDIZED,0.0007,lb,Mcf,0 -GT,PG,N/A,0.0014,lb,Mcf,0 -GT,PG,OTHER,0.0014,lb,Mcf,0 -GT,PG,STOKER,0.0008,lb,Mcf,0 -GT,PG,TANGENTIAL,0.0009,lb,Mcf,0 -GT,PG,VERTICAL,0.0013,lb,Mcf,0 -GT,PG,WALL,0.0012,lb,Mcf,0 -IC,PG,CELLBURNER,0.001,lb,Mcf,0 +GT,PG,DUCTBURNER,0.0006,lb,Mcf,0 +GT,PG,FLUIDIZED,0.0006,lb,Mcf,0 +GT,PG,N/A,0.0006,lb,Mcf,0 +GT,PG,OTHER,0.0006,lb,Mcf,0 +GT,PG,STOKER,0.0006,lb,Mcf,0 +GT,PG,TANGENTIAL,0.0006,lb,Mcf,0 +GT,PG,VERTICAL,0.0006,lb,Mcf,0 +GT,PG,WALL,0.0006,lb,Mcf,0 +IC,PG,CELLBURNER,0.0006,lb,Mcf,0 IC,PG,CYCLONE,0.0006,lb,Mcf,0 -IC,PG,DUCTBURNER,0.0011,lb,Mcf,0 -IC,PG,FLUIDIZED,0.0007,lb,Mcf,0 -IC,PG,N/A,0.0014,lb,Mcf,0 -IC,PG,OTHER,0.0014,lb,Mcf,0 -IC,PG,STOKER,0.0008,lb,Mcf,0 -IC,PG,TANGENTIAL,0.0009,lb,Mcf,0 -IC,PG,VERTICAL,0.0013,lb,Mcf,0 -IC,PG,WALL,0.0012,lb,Mcf,0 +IC,PG,DUCTBURNER,0.0006,lb,Mcf,0 +IC,PG,FLUIDIZED,0.0006,lb,Mcf,0 +IC,PG,N/A,0.0006,lb,Mcf,0 +IC,PG,OTHER,0.0006,lb,Mcf,0 +IC,PG,STOKER,0.0006,lb,Mcf,0 +IC,PG,TANGENTIAL,0.0006,lb,Mcf,0 +IC,PG,VERTICAL,0.0006,lb,Mcf,0 +IC,PG,WALL,0.0006,lb,Mcf,0 OT,PG,CELLBURNER,0.0006,lb,Mcf,0 OT,PG,CYCLONE,0.0006,lb,Mcf,0 OT,PG,DUCTBURNER,0.0006,lb,Mcf,0 OT,PG,FLUIDIZED,0.00006,lb,Mcf,0 -OT,PG,N/A,0.00006,lb,Mcf,0 +OT,PG,N/A,0.0006,lb,Mcf,0 OT,PG,OTHER,0.0006,lb,Mcf,0 OT,PG,STOKER,0.0006,lb,Mcf,0 OT,PG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -924,7 +924,7 @@ ST,PG,CELLBURNER,0.0006,lb,Mcf,0 ST,PG,CYCLONE,0.0006,lb,Mcf,0 ST,PG,DUCTBURNER,0.0006,lb,Mcf,0 ST,PG,FLUIDIZED,0.00006,lb,Mcf,0 -ST,PG,N/A,0.00006,lb,Mcf,0 +ST,PG,N/A,0.0006,lb,Mcf,0 ST,PG,OTHER,0.0006,lb,Mcf,0 ST,PG,STOKER,0.0006,lb,Mcf,0 ST,PG,TANGENTIAL,0.0006,lb,Mcf,0 @@ -934,7 +934,7 @@ OT,RC,CELLBURNER,38*S,lb,short ton,1 OT,RC,CYCLONE,38*S,lb,short ton,1 OT,RC,DUCTBURNER,38*S,lb,short ton,1 OT,RC,FLUIDIZED,3.8*S,lb,short ton,1 -OT,RC,N/A,3.8*S,lb,short ton,1 +OT,RC,N/A,38*S,lb,short ton,1 OT,RC,OTHER,38*S,lb,short ton,1 OT,RC,STOKER,38*S,lb,short ton,1 OT,RC,TANGENTIAL,38*S,lb,short ton,1 @@ -944,7 +944,7 @@ ST,RC,CELLBURNER,38*S,lb,short ton,1 ST,RC,CYCLONE,38*S,lb,short ton,1 ST,RC,DUCTBURNER,38*S,lb,short ton,1 ST,RC,FLUIDIZED,3.8*S,lb,short ton,1 -ST,RC,N/A,3.8*S,lb,short ton,1 +ST,RC,N/A,38*S,lb,short ton,1 ST,RC,OTHER,38*S,lb,short ton,1 ST,RC,STOKER,38*S,lb,short ton,1 ST,RC,TANGENTIAL,38*S,lb,short ton,1 @@ -1004,7 +1004,7 @@ OT,RFO,CELLBURNER,6.594*S,lb,barrel,1 OT,RFO,CYCLONE,6.594*S,lb,barrel,1 OT,RFO,DUCTBURNER,6.594*S,lb,barrel,1 OT,RFO,FLUIDIZED,0.6594*S,lb,barrel,1 -OT,RFO,N/A,0.6594*S,lb,barrel,1 +OT,RFO,N/A,6.594*S,lb,barrel,1 OT,RFO,OTHER,6.594*S,lb,barrel,1 OT,RFO,STOKER,6.594*S,lb,barrel,1 OT,RFO,TANGENTIAL,6.594*S,lb,barrel,1 @@ -1014,7 +1014,7 @@ ST,RFO,CELLBURNER,6.594*S,lb,barrel,1 ST,RFO,CYCLONE,6.594*S,lb,barrel,1 ST,RFO,DUCTBURNER,6.594*S,lb,barrel,1 ST,RFO,FLUIDIZED,0.6594*S,lb,barrel,1 -ST,RFO,N/A,0.6594*S,lb,barrel,1 +ST,RFO,N/A,6.594*S,lb,barrel,1 ST,RFO,OTHER,6.594*S,lb,barrel,1 ST,RFO,STOKER,6.594*S,lb,barrel,1 ST,RFO,TANGENTIAL,6.594*S,lb,barrel,1 @@ -1074,7 +1074,7 @@ OT,SGC,CELLBURNER,0.0006,lb,Mcf,0 OT,SGC,CYCLONE,0.0006,lb,Mcf,0 OT,SGC,DUCTBURNER,0.0006,lb,Mcf,0 OT,SGC,FLUIDIZED,0.00006,lb,Mcf,0 -OT,SGC,N/A,0.00006,lb,Mcf,0 +OT,SGC,N/A,0.0006,lb,Mcf,0 OT,SGC,OTHER,0.0006,lb,Mcf,0 OT,SGC,STOKER,0.0006,lb,Mcf,0 OT,SGC,TANGENTIAL,0.0006,lb,Mcf,0 @@ -1084,7 +1084,7 @@ ST,SGC,CELLBURNER,0.0006,lb,Mcf,0 ST,SGC,CYCLONE,0.0006,lb,Mcf,0 ST,SGC,DUCTBURNER,0.0006,lb,Mcf,0 ST,SGC,FLUIDIZED,0.00006,lb,Mcf,0 -ST,SGC,N/A,0.00006,lb,Mcf,0 +ST,SGC,N/A,0.0006,lb,Mcf,0 ST,SGC,OTHER,0.0006,lb,Mcf,0 ST,SGC,STOKER,0.0006,lb,Mcf,0 ST,SGC,TANGENTIAL,0.0006,lb,Mcf,0 @@ -1144,7 +1144,7 @@ OT,SGP,CELLBURNER,0.0006,lb,Mcf,0 OT,SGP,CYCLONE,0.0006,lb,Mcf,0 OT,SGP,DUCTBURNER,0.0006,lb,Mcf,0 OT,SGP,FLUIDIZED,0.00006,lb,Mcf,0 -OT,SGP,N/A,0.00006,lb,Mcf,0 +OT,SGP,N/A,0.0006,lb,Mcf,0 OT,SGP,OTHER,0.0006,lb,Mcf,0 OT,SGP,STOKER,0.0006,lb,Mcf,0 OT,SGP,TANGENTIAL,0.0006,lb,Mcf,0 @@ -1154,7 +1154,7 @@ ST,SGP,CELLBURNER,0.0006,lb,Mcf,0 ST,SGP,CYCLONE,0.0006,lb,Mcf,0 ST,SGP,DUCTBURNER,0.0006,lb,Mcf,0 ST,SGP,FLUIDIZED,0.00006,lb,Mcf,0 -ST,SGP,N/A,0.00006,lb,Mcf,0 +ST,SGP,N/A,0.0006,lb,Mcf,0 ST,SGP,OTHER,0.0006,lb,Mcf,0 ST,SGP,STOKER,0.0006,lb,Mcf,0 ST,SGP,TANGENTIAL,0.0006,lb,Mcf,0 @@ -1164,7 +1164,7 @@ OT,SLW,CELLBURNER,2.8,lb,short ton,0 OT,SLW,CYCLONE,2.8,lb,short ton,0 OT,SLW,DUCTBURNER,2.8,lb,short ton,0 OT,SLW,FLUIDIZED,0.28,lb,short ton,0 -OT,SLW,N/A,0.28,lb,short ton,0 +OT,SLW,N/A,2.8,lb,short ton,0 OT,SLW,OTHER,2.8,lb,short ton,0 OT,SLW,STOKER,2.8,lb,short ton,0 OT,SLW,TANGENTIAL,2.8,lb,short ton,0 @@ -1174,7 +1174,7 @@ ST,SLW,CELLBURNER,2.8,lb,short ton,0 ST,SLW,CYCLONE,2.8,lb,short ton,0 ST,SLW,DUCTBURNER,2.8,lb,short ton,0 ST,SLW,FLUIDIZED,0.28,lb,short ton,0 -ST,SLW,N/A,0.28,lb,short ton,0 +ST,SLW,N/A,2.8,lb,short ton,0 ST,SLW,OTHER,2.8,lb,short ton,0 ST,SLW,STOKER,2.8,lb,short ton,0 ST,SLW,TANGENTIAL,2.8,lb,short ton,0 @@ -1184,7 +1184,7 @@ OT,SUB,CELLBURNER,35*S,lb,short ton,1 OT,SUB,CYCLONE,35*S,lb,short ton,1 OT,SUB,DUCTBURNER,35*S,lb,short ton,1 OT,SUB,FLUIDIZED,3.5*S,lb,short ton,1 -OT,SUB,N/A,3.5*S,lb,short ton,1 +OT,SUB,N/A,35*S,lb,short ton,1 OT,SUB,OTHER,35*S,lb,short ton,1 OT,SUB,STOKER,35*S,lb,short ton,1 OT,SUB,TANGENTIAL,35*S,lb,short ton,1 @@ -1194,7 +1194,7 @@ ST,SUB,CELLBURNER,35*S,lb,short ton,1 ST,SUB,CYCLONE,35*S,lb,short ton,1 ST,SUB,DUCTBURNER,35*S,lb,short ton,1 ST,SUB,FLUIDIZED,3.5*S,lb,short ton,1 -ST,SUB,N/A,3.5*S,lb,short ton,1 +ST,SUB,N/A,35*S,lb,short ton,1 ST,SUB,OTHER,35*S,lb,short ton,1 ST,SUB,STOKER,35*S,lb,short ton,1 ST,SUB,TANGENTIAL,35*S,lb,short ton,1 @@ -1204,7 +1204,7 @@ OT,TDF,CELLBURNER,38*S,lb,short ton,1 OT,TDF,CYCLONE,38*S,lb,short ton,1 OT,TDF,DUCTBURNER,38*S,lb,short ton,1 OT,TDF,FLUIDIZED,3.8*S,lb,short ton,1 -OT,TDF,N/A,3.8*S,lb,short ton,1 +OT,TDF,N/A,38*S,lb,short ton,1 OT,TDF,OTHER,38*S,lb,short ton,1 OT,TDF,STOKER,38*S,lb,short ton,1 OT,TDF,TANGENTIAL,38*S,lb,short ton,1 @@ -1214,7 +1214,7 @@ ST,TDF,CELLBURNER,38*S,lb,short ton,1 ST,TDF,CYCLONE,38*S,lb,short ton,1 ST,TDF,DUCTBURNER,38*S,lb,short ton,1 ST,TDF,FLUIDIZED,3.8*S,lb,short ton,1 -ST,TDF,N/A,3.8*S,lb,short ton,1 +ST,TDF,N/A,38*S,lb,short ton,1 ST,TDF,OTHER,38*S,lb,short ton,1 ST,TDF,STOKER,38*S,lb,short ton,1 ST,TDF,TANGENTIAL,38*S,lb,short ton,1 @@ -1224,7 +1224,7 @@ OT,WC,CELLBURNER,30*S,lb,short ton,1 OT,WC,CYCLONE,30*S,lb,short ton,1 OT,WC,DUCTBURNER,30*S,lb,short ton,1 OT,WC,FLUIDIZED,3*S,lb,short ton,1 -OT,WC,N/A,3*S,lb,short ton,1 +OT,WC,N/A,30*S,lb,short ton,1 OT,WC,OTHER,30*S,lb,short ton,1 OT,WC,STOKER,30*S,lb,short ton,1 OT,WC,TANGENTIAL,30*S,lb,short ton,1 @@ -1234,7 +1234,7 @@ ST,WC,CELLBURNER,30*S,lb,short ton,1 ST,WC,CYCLONE,30*S,lb,short ton,1 ST,WC,DUCTBURNER,30*S,lb,short ton,1 ST,WC,FLUIDIZED,3*S,lb,short ton,1 -ST,WC,N/A,3*S,lb,short ton,1 +ST,WC,N/A,30*S,lb,short ton,1 ST,WC,OTHER,30*S,lb,short ton,1 ST,WC,STOKER,30*S,lb,short ton,1 ST,WC,TANGENTIAL,30*S,lb,short ton,1 @@ -1294,7 +1294,7 @@ OT,WDL,CELLBURNER,5.964*S,lb,barrel,1 OT,WDL,CYCLONE,5.964*S,lb,barrel,1 OT,WDL,DUCTBURNER,5.964*S,lb,barrel,1 OT,WDL,FLUIDIZED,0.5964*S,lb,barrel,1 -OT,WDL,N/A,0.5964*S,lb,barrel,1 +OT,WDL,N/A,5.964*S,lb,barrel,1 OT,WDL,OTHER,5.964*S,lb,barrel,1 OT,WDL,STOKER,5.964*S,lb,barrel,1 OT,WDL,TANGENTIAL,5.964*S,lb,barrel,1 @@ -1304,7 +1304,7 @@ ST,WDL,CELLBURNER,5.964*S,lb,barrel,1 ST,WDL,CYCLONE,5.964*S,lb,barrel,1 ST,WDL,DUCTBURNER,5.964*S,lb,barrel,1 ST,WDL,FLUIDIZED,0.5964*S,lb,barrel,1 -ST,WDL,N/A,0.5964*S,lb,barrel,1 +ST,WDL,N/A,5.964*S,lb,barrel,1 ST,WDL,OTHER,5.964*S,lb,barrel,1 ST,WDL,STOKER,5.964*S,lb,barrel,1 ST,WDL,TANGENTIAL,5.964*S,lb,barrel,1 @@ -1314,7 +1314,7 @@ OT,WDS,CELLBURNER,0.29,lb,short ton,0 OT,WDS,CYCLONE,0.29,lb,short ton,0 OT,WDS,DUCTBURNER,0.29,lb,short ton,0 OT,WDS,FLUIDIZED,0.08,lb,short ton,0 -OT,WDS,N/A,0.08,lb,short ton,0 +OT,WDS,N/A,0.29,lb,short ton,0 OT,WDS,OTHER,0.29,lb,short ton,0 OT,WDS,STOKER,0.08,lb,short ton,0 OT,WDS,TANGENTIAL,0.29,lb,short ton,0 @@ -1324,7 +1324,7 @@ ST,WDS,CELLBURNER,0.29,lb,short ton,0 ST,WDS,CYCLONE,0.29,lb,short ton,0 ST,WDS,DUCTBURNER,0.29,lb,short ton,0 ST,WDS,FLUIDIZED,0.08,lb,short ton,0 -ST,WDS,N/A,0.08,lb,short ton,0 +ST,WDS,N/A,0.29,lb,short ton,0 ST,WDS,OTHER,0.29,lb,short ton,0 ST,WDS,STOKER,0.08,lb,short ton,0 ST,WDS,TANGENTIAL,0.29,lb,short ton,0 @@ -1384,7 +1384,7 @@ OT,WO,CELLBURNER,6.174*S,lb,barrel,1 OT,WO,CYCLONE,6.174*S,lb,barrel,1 OT,WO,DUCTBURNER,6.174*S,lb,barrel,1 OT,WO,FLUIDIZED,0.6174*S,lb,barrel,1 -OT,WO,N/A,0.6174*S,lb,barrel,1 +OT,WO,N/A,6.174*S,lb,barrel,1 OT,WO,OTHER,6.174*S,lb,barrel,1 OT,WO,STOKER,6.174*S,lb,barrel,1 OT,WO,TANGENTIAL,6.174*S,lb,barrel,1 @@ -1394,7 +1394,7 @@ ST,WO,CELLBURNER,6.174*S,lb,barrel,1 ST,WO,CYCLONE,6.174*S,lb,barrel,1 ST,WO,DUCTBURNER,6.174*S,lb,barrel,1 ST,WO,FLUIDIZED,0.6174*S,lb,barrel,1 -ST,WO,N/A,0.6174*S,lb,barrel,1 +ST,WO,N/A,6.174*S,lb,barrel,1 ST,WO,OTHER,6.174*S,lb,barrel,1 ST,WO,STOKER,6.174*S,lb,barrel,1 ST,WO,TANGENTIAL,6.174*S,lb,barrel,1 diff --git a/notebooks/explore_data/explore_intermediate_outputs.ipynb b/notebooks/explore_data/explore_intermediate_outputs.ipynb index 20c90712..23b22f70 100644 --- a/notebooks/explore_data/explore_intermediate_outputs.ipynb +++ b/notebooks/explore_data/explore_intermediate_outputs.ipynb @@ -47,11 +47,39 @@ "residual_profiles = pd.read_csv(f\"{outputs_folder()}{path_prefix}/residual_profiles_{year}.csv\")\n", "shaped_eia_data = pd.read_csv(f\"{outputs_folder()}{path_prefix}/shaped_eia923_data_{year}.csv\")" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Explore Results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# load all power sector results and concat together\n", + "\n", + "resolution = \"annual\"\n", + "\n", + "all_data = []\n", + "for ba in os.listdir(results_folder(f\"2020/power_sector_data/{resolution}/us_units\")):\n", + " df = pd.read_csv(results_folder(f\"2020/power_sector_data/{resolution}/us_units/{ba}\"))\n", + " df[\"ba_code\"] = ba.split(\".\")[0]\n", + " all_data.append(df)\n", + "\n", + "all_data = pd.concat(all_data, axis=0)\n", + "\n", + "all_data[all_data[\"fuel_category\"] == \"total\"]" + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3.9.12 ('hourly_egrid')", + "display_name": "Python 3.10.4 ('open_grid_emissions')", "language": "python", "name": "python3" }, @@ -65,12 +93,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.5" + "version": "3.10.4" }, "orig_nbformat": 4, "vscode": { "interpreter": { - "hash": "4103f3cd497821eca917ea303dbe10c590d787eb7d2dc3fd4e15dec0356e7931" + "hash": "25e36f192ecdbe5da57d9bea009812e7b11ef0e0053366a845a2802aae1b29d2" } } }, diff --git a/notebooks/validation/validate_vs_egrid.ipynb b/notebooks/validation/validate_vs_egrid.ipynb index 074c2d8c..a20be21e 100644 --- a/notebooks/validation/validate_vs_egrid.ipynb +++ b/notebooks/validation/validate_vs_egrid.ipynb @@ -41,7 +41,7 @@ "metadata": {}, "outputs": [], "source": [ - "year = 2020\n" + "year = 2020" ] }, { @@ -352,6 +352,19 @@ "comparison_count\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# evaluate all plants\n", + "comparison_count, compared = validation.compare_plant_level_results_to_egrid(\n", + " annual_plant_results, egrid_plant, PLANTS_MISSING_FROM_EGRID\n", + ")\n", + "comparison_count" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -367,11 +380,14 @@ "source": [ "# specify the dataframe, metric, and status to explore\n", "comparison_df = compared\n", - "metric = \"fuel_consumed_for_electricity_mmbtu\"\n", - "status = \"-50% to -10%\"\n", + "metric = \"so2_mass_lb\"\n", + "status = \"<50%\"\n", + "\n", + "comparison_df = comparison_df.merge(egrid_plant.set_index(\"plant_id_egrid\")[[metric]], how=\"left\", left_index=True, right_index=True, suffixes=(None,\"_egrid\"))\n", + "comparison_df = comparison_df.merge(annual_plant_results.set_index(\"plant_id_egrid\")[[metric]], how=\"left\", left_index=True, right_index=True, suffixes=(None,\"_calc\"))\n", "\n", "# show the data\n", - "columns_to_show = [\"plant_name\", \"ba_code\", \"state\", metric, f\"{metric}_status\"]\n", + "columns_to_show = [\"plant_name_eia\", \"ba_code\", \"state\", metric, f\"{metric}_status\", f\"{metric}_egrid\", f\"{metric}_calc\"]\n", "comparison_df.loc[(comparison_df[f\"{metric}_status\"] == status), columns_to_show]\n" ] }, @@ -570,11 +586,8 @@ } ], "metadata": { - "interpreter": { - "hash": "4103f3cd497821eca917ea303dbe10c590d787eb7d2dc3fd4e15dec0356e7931" - }, "kernelspec": { - "display_name": "Python 3.9.12 ('hourly_egrid')", + "display_name": "Python 3.10.4 ('open_grid_emissions')", "language": "python", "name": "python3" }, @@ -588,7 +601,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.5" + "version": "3.10.4" + }, + "vscode": { + "interpreter": { + "hash": "25e36f192ecdbe5da57d9bea009812e7b11ef0e0053366a845a2802aae1b29d2" + } } }, "nbformat": 4, diff --git a/src/emissions.py b/src/emissions.py index 3b1c1fed..f87c80f2 100644 --- a/src/emissions.py +++ b/src/emissions.py @@ -1378,6 +1378,11 @@ def calculate_generator_so2_ef_per_unit_from_boiler_type( def return_monthly_plant_fuel_sulfur_content(pudl_out): + """ + Returns the month specific, plant average sulfur content. + + Sulfur content values are on a 0-100 scale (e.g. 5.2% = 5.2) + """ plant_specific_fuel_sulfur_content = pudl_out.bf_eia923().loc[ :, [ @@ -1390,11 +1395,6 @@ def return_monthly_plant_fuel_sulfur_content(pudl_out): ], ] - # divide by 100 to get decimal percent - plant_specific_fuel_sulfur_content["sulfur_content_pct"] = ( - plant_specific_fuel_sulfur_content["sulfur_content_pct"] / 100 - ) - plant_specific_fuel_sulfur_content = plant_specific_fuel_sulfur_content[ ~plant_specific_fuel_sulfur_content["energy_source_code"].isin(CLEAN_FUELS) ] diff --git a/src/validation.py b/src/validation.py index e98a67d2..ed931078 100644 --- a/src/validation.py +++ b/src/validation.py @@ -993,6 +993,8 @@ def load_egrid_plant_file(year): "PLGENATN", "PLGENATR", "PLHTIANT", + "UNNOX", + "UNSO2", "UNCO2", "UNHTIT", "UNHTIOZT", @@ -1014,11 +1016,13 @@ def load_egrid_plant_file(year): "PSTATABB": "state", "PLPRMFL": "plant_primary_fuel", "ORISPL": "plant_id_egrid", - "PNAME": "plant_name", + "PNAME": "plant_name_eia", "UNHTIT": "fuel_consumed_mmbtu", "PLHTIANT": "fuel_consumed_for_electricity_mmbtu", "UNCO2": "co2_mass_lb", # this is actually in tons, but we are converting in the next step - "PLCO2AN": "co2_mass_lb_adjusted", # this is actually in tons, but we are converting in the next step + "UNNOX": "nox_mass_lb", # this is actually in tons, but we are converting in the next step + "UNSO2": "so2_mass_lb", # this is actually in tons, but we are converting in the next step + "PLCO2AN": "co2_mass_lb_for_electricity_adjusted", # this is actually in tons, but we are converting in the next step "CHPFLAG": "chp_flag", "UNHTIOZT": "fuel_consumed_mmbtu_ozone_season", "UNHTISRC": "fuel_data_source_annual", @@ -1028,14 +1032,20 @@ def load_egrid_plant_file(year): # convert co2 mass tons to lb egrid_plant["co2_mass_lb"] = egrid_plant["co2_mass_lb"] * 2000 - egrid_plant["co2_mass_lb_adjusted"] = egrid_plant["co2_mass_lb_adjusted"] * 2000 + egrid_plant["nox_mass_lb"] = egrid_plant["nox_mass_lb"] * 2000 + egrid_plant["so2_mass_lb"] = egrid_plant["so2_mass_lb"] * 2000 + egrid_plant["co2_mass_lb_for_electricity_adjusted"] = ( + egrid_plant["co2_mass_lb_for_electricity_adjusted"] * 2000 + ) # if egrid has a missing value for co2 for a clean plant, replace with zero clean_fuels = ["SUN", "MWH", "WND", "WAT", "WH", "PUR", "NUC"] egrid_plant.loc[ - egrid_plant["plant_primary_fuel"].isin(clean_fuels), "co2_mass_lb_adjusted" + egrid_plant["plant_primary_fuel"].isin(clean_fuels), + "co2_mass_lb_for_electricity_adjusted", ] = egrid_plant.loc[ - egrid_plant["plant_primary_fuel"].isin(clean_fuels), "co2_mass_lb_adjusted" + egrid_plant["plant_primary_fuel"].isin(clean_fuels), + "co2_mass_lb_for_electricity_adjusted", ].fillna( 0 ) @@ -1053,14 +1063,16 @@ def load_egrid_plant_file(year): "ba_code", "state", "plant_id_egrid", - "plant_name", + "plant_name_eia", "plant_primary_fuel", "chp_flag", "net_generation_mwh", "fuel_consumed_mmbtu", "fuel_consumed_for_electricity_mmbtu", "co2_mass_lb", - "co2_mass_lb_adjusted", + "co2_mass_lb_for_electricity_adjusted", + "nox_mass_lb", + "so2_mass_lb", "fuel_consumed_mmbtu_ozone_season", "fuel_data_source_annual", "fuel_data_source_ozone", @@ -1124,6 +1136,15 @@ def add_egrid_plant_id(df, from_id, to_id): def compare_plant_level_results_to_egrid( plant_data, egrid_plant, PLANTS_MISSING_FROM_EGRID ): + columns_to_compare = [ + "net_generation_mwh", + "fuel_consumed_mmbtu", + "fuel_consumed_for_electricity_mmbtu", + "co2_mass_lb_for_electricity_adjusted", + "co2_mass_lb", + "so2_mass_lb", + "nox_mass_lb", + ] # standardize column names and index so that the two dfs can be divided calculated_to_compare = ( plant_data.groupby("plant_id_egrid", dropna=False) @@ -1133,25 +1154,14 @@ def compare_plant_level_results_to_egrid( # drop the plants that have no data in eGRID plants_with_no_data_in_egrid = list( - egrid_plant[ - egrid_plant[ - [ - "net_generation_mwh", - "fuel_consumed_mmbtu", - "fuel_consumed_for_electricity_mmbtu", - "co2_mass_lb", - "co2_mass_lb_adjusted", - ] - ].sum(axis=1) - == 0 - ]["plant_id_egrid"] + egrid_plant[egrid_plant[columns_to_compare].sum(axis=1) == 0]["plant_id_egrid"] ) egrid_plant = egrid_plant[ ~egrid_plant["plant_id_eia"].isin(plants_with_no_data_in_egrid) ] egrid_to_compare = egrid_plant.set_index(["plant_id_egrid"]).drop( - columns=["ba_code", "state", "plant_name", "plant_id_eia"] + columns=["ba_code", "state", "plant_name_eia", "plant_id_eia"] ) # only keep plants that are in the comparison data egrid_to_compare = egrid_to_compare[ @@ -1162,7 +1172,7 @@ def compare_plant_level_results_to_egrid( compared = ( calculated_to_compare.div(egrid_to_compare) .merge( - egrid_plant[["plant_id_egrid", "plant_name", "ba_code", "state"]], + egrid_plant[["plant_id_egrid", "plant_name_eia", "ba_code", "state"]], how="left", left_index=True, right_on="plant_id_egrid", @@ -1170,7 +1180,7 @@ def compare_plant_level_results_to_egrid( ) .set_index("plant_id_egrid") ) - compared["plant_name"] = compared["plant_name"].fillna("unknown") + compared["plant_name_eia"] = compared["plant_name_eia"].fillna("unknown") # create a dataframe that merges the two sources of data together compared_merged = calculated_to_compare.merge( @@ -1182,13 +1192,7 @@ def compare_plant_level_results_to_egrid( ) # for each column, change missing values to zero if both values are zero (only nan b/c divide by zero) - for col in [ - "net_generation_mwh", - "fuel_consumed_mmbtu", - "fuel_consumed_for_electricity_mmbtu", - "co2_mass_lb_adjusted", - "co2_mass_lb", - ]: + for col in columns_to_compare: # identify plants with zero values for both plant_ids = list( compared_merged[ @@ -1199,13 +1203,7 @@ def compare_plant_level_results_to_egrid( compared.loc[compared.index.isin(plant_ids), col] = 1 # for each column, categorize the data based on how far it is off from egrid - for col in [ - "net_generation_mwh", - "fuel_consumed_mmbtu", - "fuel_consumed_for_electricity_mmbtu", - "co2_mass_lb_adjusted", - "co2_mass_lb", - ]: + for col in columns_to_compare: # add a new column compared[f"{col}_status"] = pd.cut( x=compared[col], @@ -1247,13 +1245,7 @@ def compare_plant_level_results_to_egrid( ] = "not_in_egrid" # identify which plants are missing from egrid vs calculated values - for col in [ - "net_generation_mwh", - "fuel_consumed_mmbtu", - "fuel_consumed_for_electricity_mmbtu", - "co2_mass_lb_adjusted", - "co2_mass_lb", - ]: + for col in columns_to_compare: # identify plants that are missing in egrid plants_missing_egrid = list( compared_merged[ @@ -1307,16 +1299,10 @@ def compare_plant_level_results_to_egrid( # create a dataframe that counts how many plants are in each category comparison_count = [] - for col in [ - "net_generation_mwh", - "fuel_consumed_mmbtu", - "fuel_consumed_for_electricity_mmbtu", - "co2_mass_lb_adjusted", - "co2_mass_lb", - ]: + for col in columns_to_compare: count = ( compared.groupby(f"{col}_status", dropna=False) - .count()["plant_name"] + .count()["plant_name_eia"] .rename(col) ) count.index = count.index.rename("status") @@ -1344,7 +1330,7 @@ def identify_plants_missing_from_our_calculations( "fuel_consumed_mmbtu", "fuel_consumed_for_electricity_mmbtu", "co2_mass_lb", - "co2_mass_lb_adjusted", + "co2_mass_lb_for_electricity_adjusted", ] ].sum(axis=1) == 0 @@ -1390,8 +1376,8 @@ def identify_plants_missing_from_egrid(egrid_plant, annual_plant_results): - set(egrid_plant["plant_id_egrid"].unique()) ) - plant_names = load_data.load_pudl_table(table_name="plants_eia860", year=2020)[ - ["plant_id_eia", "plant_name_eia", "sector_name_eia"] + plant_names = load_data.load_pudl_table(table_name="plants_entity_eia")[ + ["plant_id_eia", "plant_name_eia"] ] missing_from_egrid = annual_plant_results[ annual_plant_results["plant_id_egrid"].isin(PLANTS_MISSING_FROM_EGRID) @@ -1549,7 +1535,7 @@ def compare_egrid_fuel_total(plant_data, egrid_plant_df): ] egrid_to_compare = egrid_plant_df.set_index(["plant_id_egrid"]).drop( - columns=["ba_code", "state", "plant_name", "plant_id_eia"] + columns=["ba_code", "state", "plant_name_eia", "plant_id_eia"] ) # only keep plants that are in the comparison data egrid_to_compare = egrid_to_compare[ @@ -1615,7 +1601,13 @@ def identify_potential_missing_fuel_in_egrid(pudl_out, year, egrid_plant, cems): # merge the annual EIA-923 data into the egrid data egrid_eia_comparison = ( egrid_plant[ - ["plant_id_egrid", "plant_name", "ba_code", "plant_primary_fuel", metric] + [ + "plant_id_egrid", + "plant_name_eia", + "ba_code", + "plant_primary_fuel", + metric, + ] ] .merge( gf_total[["plant_id_egrid", metric]], From aa40bc445833a1050534b75cbd49fb6a8250dd27 Mon Sep 17 00:00:00 2001 From: gailin-p Date: Tue, 6 Sep 2022 10:28:33 -0400 Subject: [PATCH 03/12] Fix frustrating sign bug --- src/consumed.py | 4 +++- src/output_data.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/consumed.py b/src/consumed.py index 6a1e957a..be5302fd 100644 --- a/src/consumed.py +++ b/src/consumed.py @@ -102,6 +102,8 @@ def get_average_emission_factors(prefix: str = "2020/", year: int = 2020): Used to fill in emissions from BAs outside of US, where we have generation by fuel (from gridemissions) but no open-grid-emissions data + We use `gridemissions` assumptions for fuel mix for non-US BAs, which are simple and not time-varying + Structure: EMISSIONS_FACTORS[poll][adjustment][fuel] """ genavg = pd.read_csv( @@ -281,7 +283,7 @@ def output_results(self): if (ba in self.import_regions) or (ba in self.generation_regions): continue self.results[ba]["net_consumed_mwh"] = ( - self.generation[ba] + self.eia930.df[KEYS["E"]["TI"] % ba] + self.generation[ba] - self.eia930.df[KEYS["E"]["TI"] % ba] )[self.generation.index] for pol in POLLUTANTS: for adj in ADJUSTMENTS: diff --git a/src/output_data.py b/src/output_data.py index d3e5b75c..22321a80 100644 --- a/src/output_data.py +++ b/src/output_data.py @@ -304,13 +304,13 @@ def round_table(table): """ Round each numeric column. All values in a column have the same rounding. - Rounding for each col is based on the smallest non-zero value: if < 1, sigfigs = 3, else 2 decimal places + Rounding for each col is based on the median non-zero value: if < 1, sigfigs = 3, else 2 decimal places """ decimals = {} # Iterate through numeric columns for c in table.select_dtypes(include=np.number).columns: # Non-zero minimum - val = table.loc[table[c] > 0, c].min() + val = table.loc[table[c] > 0, c].median() if val > 1: decimals[c] = 2 elif np.isnan( From 2b3c512f1d5741a513499077474bb1df27ad8858 Mon Sep 17 00:00:00 2001 From: gailin-p Date: Tue, 6 Sep 2022 10:31:42 -0400 Subject: [PATCH 04/12] gitignore .vscode folder --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index d2fcd043..f832638c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,9 @@ notebooks/.ipynb_checkpoints notebooks/*/.ipynb_checkpoints .hypothesis/ +# Editor settings +.vscode/* + # Mac junk .DS_Store From 96416c60053cc0052af183b075c5cd021d60ea31 Mon Sep 17 00:00:00 2001 From: gailin-p Date: Wed, 7 Sep 2022 11:19:23 -0400 Subject: [PATCH 05/12] * set negative generated rates to zero * add neg check to output_to_results * add rate columns to negative check * make negative check not error on small (small run has data issues leading to negative, caused by using subset of data) --- src/consumed.py | 36 ++++++++++++++++++------------------ src/output_data.py | 27 ++++++++++++++++++++++++++- src/validation.py | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 21 deletions(-) diff --git a/src/consumed.py b/src/consumed.py index be5302fd..872c7318 100644 --- a/src/consumed.py +++ b/src/consumed.py @@ -9,10 +9,20 @@ from output_data import ( GENERATED_EMISSION_RATE_COLS, + CONSUMED_EMISSION_RATE_COLS, output_to_results, TIME_RESOLUTIONS, ) +""" For these BAs, there are significant and systematic differences +between our net_generation_mwh and EIA-930 net generation and interchange, +so we cannot combine our net generation and 930 interchange to get net_consumed. +Instead, we use 930 demand as net_consumed. Note: there may be issues with the 930 +demand! But it is better than combining inconsistent generation and interchange, +which results in unreasonable profiles with many negative hours. +""" +BA_930_INCONSISTENCY = ["SPA", "CPLW", "GCPD", "AZPS", "EEI"] + # Defined in output_data, written to each BA file EMISSION_COLS = [ "co2_mass_lb_for_electricity", @@ -29,21 +39,6 @@ "so2_mass_lb_for_electricity_adjusted", ] -CONSUMED_EMISSION_RATE_COLS = [ - "consumed_co2_rate_lb_per_mwh_for_electricity", - "consumed_ch4_rate_lb_per_mwh_for_electricity", - "consumed_n2o_rate_lb_per_mwh_for_electricity", - "consumed_co2e_rate_lb_per_mwh_for_electricity", - "consumed_nox_rate_lb_per_mwh_for_electricity", - "consumed_so2_rate_lb_per_mwh_for_electricity", - "consumed_co2_rate_lb_per_mwh_for_electricity_adjusted", - "consumed_ch4_rate_lb_per_mwh_for_electricity_adjusted", - "consumed_n2o_rate_lb_per_mwh_for_electricity_adjusted", - "consumed_co2e_rate_lb_per_mwh_for_electricity_adjusted", - "consumed_nox_rate_lb_per_mwh_for_electricity_adjusted", - "consumed_so2_rate_lb_per_mwh_for_electricity_adjusted", -] - FUEL_TYPE_MAP = { "COL": "coal", "NG": "natural_gas", @@ -282,9 +277,14 @@ def output_results(self): for ba in self.regions: if (ba in self.import_regions) or (ba in self.generation_regions): continue - self.results[ba]["net_consumed_mwh"] = ( - self.generation[ba] - self.eia930.df[KEYS["E"]["TI"] % ba] - )[self.generation.index] + if ba in BA_930_INCONSISTENCY: + self.results[ba]["net_consumed_mwh"] = self.eia930.df[ + KEYS["E"]["D"] % ba + ][self.generation.index] + else: + self.results[ba]["net_consumed_mwh"] = ( + self.generation[ba] - self.eia930.df[KEYS["E"]["TI"] % ba] + )[self.generation.index] for pol in POLLUTANTS: for adj in ADJUSTMENTS: self.results[ba][get_column(pol, adjustment=adj)] = ( diff --git a/src/output_data.py b/src/output_data.py index 22321a80..bc0cfa65 100644 --- a/src/output_data.py +++ b/src/output_data.py @@ -23,6 +23,21 @@ "generated_so2_rate_lb_per_mwh_for_electricity_adjusted", ] +CONSUMED_EMISSION_RATE_COLS = [ + "consumed_co2_rate_lb_per_mwh_for_electricity", + "consumed_ch4_rate_lb_per_mwh_for_electricity", + "consumed_n2o_rate_lb_per_mwh_for_electricity", + "consumed_co2e_rate_lb_per_mwh_for_electricity", + "consumed_nox_rate_lb_per_mwh_for_electricity", + "consumed_so2_rate_lb_per_mwh_for_electricity", + "consumed_co2_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_ch4_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_n2o_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_co2e_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_nox_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_so2_rate_lb_per_mwh_for_electricity_adjusted", +] + UNIT_CONVERSIONS = {"lb": ("kg", 0.453592), "mmbtu": ("GJ", 1.055056)} TIME_RESOLUTIONS = {"hourly": "H", "monthly": "M", "annual": "A"} @@ -77,6 +92,8 @@ def output_intermediate_data(df, file_name, path_prefix, year, skip_outputs): def output_to_results(df, file_name, subfolder, path_prefix, skip_outputs): + # Always check columns that should not be negative. + small = "small" in path_prefix if not skip_outputs: print(f" Exporting {file_name} to data/results/{path_prefix}{subfolder}") @@ -84,6 +101,9 @@ def output_to_results(df, file_name, subfolder, path_prefix, skip_outputs): metric = round_table(metric) df = round_table(df) + # Check for negatives after rounding + validation.test_for_negative_values(df, small) + df.to_csv( results_folder(f"{path_prefix}{subfolder}us_units/{file_name}.csv"), index=False, @@ -406,7 +426,10 @@ def write_power_sector_results(ba_fuel_data, path_prefix, skip_outputs): def add_generated_emission_rate_columns(df): for emission_type in ["_for_electricity", "_for_electricity_adjusted"]: for emission in ["co2", "ch4", "n2o", "co2e", "nox", "so2"]: - df[f"generated_{emission}_rate_lb_per_mwh{emission_type}"] = ( + col_name = ( + f"generated_{emission}_rate_lb_per_mwh{emission_type}" + ) + df[col_name] = ( ( df[f"{emission}_mass_lb{emission_type}"] / df["net_generation_mwh"] @@ -415,6 +438,8 @@ def add_generated_emission_rate_columns(df): .replace(np.inf, np.NaN) .replace(-np.inf, np.NaN) ) + # Set negative rates to zero, following eGRID methodology + df.loc[df[col_name] < 0, col_name] = 0 return df # output the hourly data diff --git a/src/validation.py b/src/validation.py index ed931078..248527eb 100644 --- a/src/validation.py +++ b/src/validation.py @@ -39,7 +39,7 @@ def validate_year(year): raise UserWarning(year_warning) -def test_for_negative_values(df): +def test_for_negative_values(df, small: bool = False): """Checks that there are no unexpected negative values in the data.""" print(" Checking that fuel and emissions values are positive... ", end="") columns_that_should_be_positive = [ @@ -69,6 +69,30 @@ def test_for_negative_values(df): "co2e_mass_lb_for_electricity_adjusted", "nox_mass_lb_for_electricity_adjusted", "so2_mass_lb_for_electricity_adjusted", + "generated_co2_rate_lb_per_mwh_for_electricity", + "generated_ch4_rate_lb_per_mwh_for_electricity", + "generated_n2o_rate_lb_per_mwh_for_electricity", + "generated_co2e_rate_lb_per_mwh_for_electricity", + "generated_nox_rate_lb_per_mwh_for_electricity", + "generated_so2_rate_lb_per_mwh_for_electricity", + "generated_co2_rate_lb_per_mwh_for_electricity_adjusted", + "generated_ch4_rate_lb_per_mwh_for_electricity_adjusted", + "generated_n2o_rate_lb_per_mwh_for_electricity_adjusted", + "generated_co2e_rate_lb_per_mwh_for_electricity_adjusted", + "generated_nox_rate_lb_per_mwh_for_electricity_adjusted", + "generated_so2_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_co2_rate_lb_per_mwh_for_electricity", + "consumed_ch4_rate_lb_per_mwh_for_electricity", + "consumed_n2o_rate_lb_per_mwh_for_electricity", + "consumed_co2e_rate_lb_per_mwh_for_electricity", + "consumed_nox_rate_lb_per_mwh_for_electricity", + "consumed_so2_rate_lb_per_mwh_for_electricity", + "consumed_co2_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_ch4_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_n2o_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_co2e_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_nox_rate_lb_per_mwh_for_electricity_adjusted", + "consumed_so2_rate_lb_per_mwh_for_electricity_adjusted", ] columns_to_test = [ col for col in columns_that_should_be_positive if col in df.columns @@ -84,7 +108,12 @@ def test_for_negative_values(df): print(" ") negative_warnings += 1 if negative_warnings > 0: - raise UserWarning("The above negative values are errors and must be fixed") + if small: + print( + " Found negative values during small run, these may be fixed with full data" + ) + else: + raise UserWarning("The above negative values are errors and must be fixed") else: print("OK") return negative_test From 773a29da1dab1721f9d8c1a221a5668a006e285b Mon Sep 17 00:00:00 2001 From: gailin-p Date: Wed, 7 Sep 2022 12:07:15 -0400 Subject: [PATCH 06/12] remove duplicate from gitignore --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index b3f60ed7..2f35d2c3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,6 @@ notebooks/.ipynb_checkpoints notebooks/*/.ipynb_checkpoints .hypothesis/ -# Editor settings -.vscode/* - # Mac junk .DS_Store From 3d5cbaffbd8f5a6954883f315b512c500b4628c9 Mon Sep 17 00:00:00 2001 From: gailin-p Date: Wed, 7 Sep 2022 15:06:41 -0400 Subject: [PATCH 07/12] zip data quality metrics folders, add year to zipped file names --- src/output_data.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/output_data.py b/src/output_data.py index bc0cfa65..59529a06 100644 --- a/src/output_data.py +++ b/src/output_data.py @@ -49,7 +49,7 @@ def prepare_files_for_upload(years): This should only be run when releasing a new minor or major version of the repo. """ - zip_data_for_zenodo() + # zip_data_for_zenodo() for year in years: zip_results_for_s3(year) @@ -63,11 +63,17 @@ def zip_results_for_s3(year): for unit in ["metric_units", "us_units"]: folder = f"{results_folder()}/{year}/{data_type}/{aggregation}/{unit}" shutil.make_archive( - f"{results_folder()}/{year}/{data_type}/{data_type}_{aggregation}_{unit}", + f"{results_folder()}/{year}/{data_type}/{year}_{data_type}_{aggregation}_{unit}", "zip", root_dir=folder, # base_dir="", ) + shutil.make_archive( + f"{results_folder()}/{year}/data_quality_metrics/{year}_data_quality_metrics", + "zip", + root_dir=f"{results_folder()}/{year}/data_quality_metrics", + # base_dir="", + ) def zip_data_for_zenodo(): From d8e1203ac302cd6a9be24190dc326541e7184614 Mon Sep 17 00:00:00 2001 From: gailin-p Date: Wed, 7 Sep 2022 15:45:02 -0400 Subject: [PATCH 08/12] validate_vs_egrid notebook fix change `plant_name` to `plant_name_eia` --- notebooks/validation/validate_vs_egrid.ipynb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/notebooks/validation/validate_vs_egrid.ipynb b/notebooks/validation/validate_vs_egrid.ipynb index a20be21e..b0e08164 100644 --- a/notebooks/validation/validate_vs_egrid.ipynb +++ b/notebooks/validation/validate_vs_egrid.ipynb @@ -191,7 +191,7 @@ "metadata": {}, "outputs": [], "source": [ - "ba_code_match = egrid_plant.set_index(\"plant_id_eia\")[[\"plant_name\", \"ba_code\"]].merge(\n", + "ba_code_match = egrid_plant.set_index(\"plant_id_eia\")[[\"plant_name_eia\", \"ba_code\"]].merge(\n", " annual_plant_results.set_index(\"plant_id_eia\")[[\"ba_code\"]],\n", " how=\"inner\",\n", " left_index=True,\n", @@ -231,7 +231,7 @@ "outputs": [], "source": [ "fuel_match = egrid_plant.set_index(\"plant_id_eia\")[\n", - " [\"plant_name\", \"plant_primary_fuel\"]\n", + " [\"plant_name_eia\", \"plant_primary_fuel\"]\n", "].merge(\n", " annual_plant_results.set_index(\"plant_id_eia\")[[\"plant_primary_fuel\"]],\n", " how=\"inner\",\n", @@ -418,7 +418,7 @@ " \"fuel_consumed_mmbtu\",\n", " \"fuel_consumed_for_electricity_mmbtu\",\n", " \"co2_mass_lb\",\n", - " \"co2_mass_lb_adjusted\",\n", + " \"co2_mass_lb_for_electricity_adjusted\",\n", "]\n", "egrid_plant_ba_agg = egrid_plant.groupby([\"ba_code\"]).sum()[data_columns].reset_index()\n" ] @@ -587,7 +587,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3.10.4 ('open_grid_emissions')", + "display_name": "Python 3.10.5 ('hourly_egrid')", "language": "python", "name": "python3" }, @@ -601,11 +601,11 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.4" + "version": "3.10.5" }, "vscode": { "interpreter": { - "hash": "25e36f192ecdbe5da57d9bea009812e7b11ef0e0053366a845a2802aae1b29d2" + "hash": "65c02dfd2dc2ef471c0b5088763a28c1faaa7cad28937ca42fadf51e669fd8e8" } } }, From 556a02bcfe0be88293f7d9bd52fd91577c656cd1 Mon Sep 17 00:00:00 2001 From: gailin-p Date: Wed, 7 Sep 2022 15:45:49 -0400 Subject: [PATCH 09/12] EIA-930 interchange manual fix update Use SRP-AZPS interchange as truth, disregard AZPS-SRP interchange --- src/eia930.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/eia930.py b/src/eia930.py index 04ffc1bf..2a7e2715 100644 --- a/src/eia930.py +++ b/src/eia930.py @@ -401,6 +401,10 @@ def manual_930_adjust(raw: pd.DataFrame): - PJM-OVEC, all time. Based on OVEC demand - generation, OVEC should be a net exporter to PJM - Note: OVEC's data repeats daily starting in 2018... + - Interchange mysterious + - AZPS - SRP flips gradually in Nov 2019, then abruptly back in June 2020. + throughout, SRP - AZPS remains constant around 3000 lb imported to AZPS from SRP + We assume SRP - AZPS is correct, and assign AZPS - SRP to be the inverse - Make all start-of-hour - Generation - - 1 hour @@ -437,6 +441,13 @@ def manual_930_adjust(raw: pd.DataFrame): ovec_col = get_int_columns("PJM", raw.columns, ["OVEC"]) raw.loc[:, ovec_col] = raw.loc[:, ovec_col] * -1 + # Interchange AZPS - SRP is wonky. Use SRP - AZPS (inverted) + azps_srp = get_int_columns("AZPS", raw.columns, ["SRP"]) + srp_azps = get_int_columns("SRP", raw.columns, ["AZPS"]) + raw.loc[:, azps_srp] = (raw.loc[:, srp_azps] * (-1)).rename( + columns={srp_azps[0]: azps_srp[0]} # rename so Pandas will do the right thing + ) + # Interchange TEPC is uniformly lagged cols = get_int_columns("TEPC", raw.columns) new = raw[cols].shift(-7, freq="H") From 63765d7685828540e7c593eeb1a496f1630195cc Mon Sep 17 00:00:00 2001 From: gailin-p Date: Wed, 7 Sep 2022 15:54:53 -0400 Subject: [PATCH 10/12] uncomment --- src/output_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output_data.py b/src/output_data.py index 59529a06..f6d67c1d 100644 --- a/src/output_data.py +++ b/src/output_data.py @@ -49,7 +49,7 @@ def prepare_files_for_upload(years): This should only be run when releasing a new minor or major version of the repo. """ - # zip_data_for_zenodo() + zip_data_for_zenodo() for year in years: zip_results_for_s3(year) From 09058d9540eea551b97f725c1c3333045853473f Mon Sep 17 00:00:00 2001 From: gailin-p Date: Wed, 7 Sep 2022 16:19:35 -0400 Subject: [PATCH 11/12] * Limit interchange update to before 6/1/2020 * fix total interchange (sum of per-BA interchange) --- src/eia930.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/eia930.py b/src/eia930.py index 2a7e2715..9de8cb7e 100644 --- a/src/eia930.py +++ b/src/eia930.py @@ -441,12 +441,19 @@ def manual_930_adjust(raw: pd.DataFrame): ovec_col = get_int_columns("PJM", raw.columns, ["OVEC"]) raw.loc[:, ovec_col] = raw.loc[:, ovec_col] * -1 - # Interchange AZPS - SRP is wonky. Use SRP - AZPS (inverted) + # Interchange AZPS - SRP is wonky before 6/1/2020 7:00 UTC. Use SRP - AZPS (inverted) azps_srp = get_int_columns("AZPS", raw.columns, ["SRP"]) srp_azps = get_int_columns("SRP", raw.columns, ["AZPS"]) - raw.loc[:, azps_srp] = (raw.loc[:, srp_azps] * (-1)).rename( + replacement = (raw.loc[:, srp_azps] * (-1)).rename( columns={srp_azps[0]: azps_srp[0]} # rename so Pandas will do the right thing ) + raw.loc[raw.index < "2020-06-01T07:00+00", azps_srp] = replacement[ + raw.index < "2020-06-01T07:00+00" + ] + # Update total interchange + all_cols = [c for c in get_int_columns("AZPS", raw.columns) if "ALL" not in c] + total_col = "EBA.AZPS-ALL.TI.H" + raw.loc[:, total_col] = raw.loc[:, all_cols].sum(axis=1) # Interchange TEPC is uniformly lagged cols = get_int_columns("TEPC", raw.columns) From e0fa40cddde3f57d99d9b1a25cdc9d0ebdf79e5f Mon Sep 17 00:00:00 2001 From: gailin-p Date: Wed, 7 Sep 2022 16:24:41 -0400 Subject: [PATCH 12/12] limit total interchange fix in AZPS to before June 1 2020 --- src/eia930.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eia930.py b/src/eia930.py index 9de8cb7e..67b089fa 100644 --- a/src/eia930.py +++ b/src/eia930.py @@ -447,13 +447,13 @@ def manual_930_adjust(raw: pd.DataFrame): replacement = (raw.loc[:, srp_azps] * (-1)).rename( columns={srp_azps[0]: azps_srp[0]} # rename so Pandas will do the right thing ) - raw.loc[raw.index < "2020-06-01T07:00+00", azps_srp] = replacement[ - raw.index < "2020-06-01T07:00+00" - ] + raw.loc[:"2020-06-01T07:00+00", azps_srp] = replacement[:"2020-06-01T07:00+00"] # Update total interchange all_cols = [c for c in get_int_columns("AZPS", raw.columns) if "ALL" not in c] total_col = "EBA.AZPS-ALL.TI.H" - raw.loc[:, total_col] = raw.loc[:, all_cols].sum(axis=1) + raw.loc[:"2020-06-01T07:00+00", total_col] = raw.loc[ + :"2020-06-01T07:00+00", all_cols + ].sum(axis=1) # Interchange TEPC is uniformly lagged cols = get_int_columns("TEPC", raw.columns)