From a0ce091e728b201f70e677a8f0138ef5789776fb Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:06:09 -0500 Subject: [PATCH 01/21] add decommissioning function --- scripts/deployment_script.py | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 scripts/deployment_script.py diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py new file mode 100644 index 00000000..ef020499 --- /dev/null +++ b/scripts/deployment_script.py @@ -0,0 +1,44 @@ +# These functions outline different reactor deployment algorithms, +# and metrics for analyzing the final product. + +import pandas as pd +import numpy as np +import math # for rounding ceiling and floor +from datetime import datetime # for random seed generation + + + + +# # # # # # # # # # # # Constituent Functions # # # # # # # # # # # + +def direct_decom(df, ar_dict): + """ + This function assumes that every time a reactor model is decommissioned it + is replaced by a new version of itself. + + Parameters + ---------- + df: pandas dataframe + The dataframe of capacity information + ar_dict: dictionary + A dictionary of reactors with information of the form: + {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]} + """ + + # now we are going to note when reactors are decommissioned + for reactor in ar_dict.keys(): + # create a decommissioning column + df[f'{reactor}Decom'] = 0 + for year in range(len(df['Year'])): + decom_year = year + ar_dict[reactor][2] + if decom_year >= len(df['Year']): + pass + else: + # tracks the number of decommissioned reactors + df.loc[decom_year, f'{reactor}Decom'] += df.loc[year, f'num_{reactor}'] + + # construct new reactors to replace the decommissioned ones + df.loc[decom_year, f'num_{reactor}'] += df.loc[year, f'num_{reactor}'] + + return df + From 9b0072d13bf7d6727c68c343f427e11bb101d192 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:07:01 -0500 Subject: [PATCH 02/21] add reactor number to capacity function --- scripts/deployment_script.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index ef020499..92cc84df 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -42,3 +42,36 @@ def direct_decom(df, ar_dict): return df +def num_react_to_cap(df, ar_dict): + """ + This function takes in a dataframe and the dictionary of reactors, + and converts the number of reactors columns to a capacity from each reactor + and a total capacity column. + + Parameters + ---------- + df: pandas dataframe + The dataframe of capacity information + ar_dict: dictionary + A dictionary of reactors with information of the form: + {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]} + """ + + if 'total_cap' not in df: + df[f'total_cap'] = 0 + # Create a column for the new capacity each year. + df['new_cap'] = 0 + else: + pass + + for reactor in ar_dict.keys(): + # New capacity calculations. + df[f'new_{reactor}_cap'] = (df[f'num_{reactor}'] - df[f'{reactor}Decom']) * ar_dict[f'{reactor}'][0] + df['new_cap'] += df[f'new_{reactor}_cap'] + + # Total capacity calculations. + df[f'{reactor}_cap'] = df[f'num_{reactor}'] * ar_dict[f'{reactor}'][0] + df['total_cap'] += df[f'{reactor}_cap'] + + return df + From cfa8b42c1f093d087e71505f28068710674d6c30 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:08:00 -0500 Subject: [PATCH 03/21] add greedy description function and function summaries --- scripts/deployment_script.py | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index 92cc84df..c2ae04e1 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -75,3 +75,62 @@ def num_react_to_cap(df, ar_dict): return df + +# # # # # # # # # # # # Deployment Functions # # # # # # # # # # # +# 1. Greedy Algorithm: deploy the largest reactor first at each time step, fill +# in the remaining capacity with the next smallest, and so on. +# 2. Pre-determined distributions: one or more reactors have a preset +# distribution, and a smaller capacity model fills in the gaps. +# 2.b Deployment Cap [extension of 2]: there is a single-number capacity for +# one or more of the reactor models. * there is no function for this, just use +# a constant distribution. +# 3. Random Deployment: uses a date and hour as seed to randomly sample the +# reactors list. +# 4. Initially Random, Greedy: randomly deploys reactors until a reactor bigger +# than the remaining capacity is proposed for each year, then fills remaining +# capacity with a greedy algorithm. + +def greedy_deployment(df, base_col, ar_dict): + """ + In this greedy deployment, we will deploy the largest capacity reactor first until another deployment will exceed the desired capacity then the next largest capacity reactor is deployed and so on. + + Parameters + ---------- + df: pandas dataframe + The dataframe of capacity information + base_col: str + The string name corresponding to the column of capacity that the algorithm is deploying reactors to meet + ar_dict: dictionary + A dictionary of reactors with information of the form: + {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]} + """ + + for reactor in ar_dict.keys(): + if f'num_{reactor}' not in df: + df[f'num_{reactor}'] = 0 + else: + pass + + for year in range(len(df[base_col])): + remaining_cap = df[base_col][year].copy() + for reactor in ar_dict.keys(): + if ar_dict[reactor][0] > remaining_cap: + reactor_div = 0 + else: + # find out how many of this reactor to deploy + reactor_div = math.floor(remaining_cap / ar_dict[reactor][0]) + # remaining capacity to meet + remaining_cap -= reactor_div * ar_dict[reactor][0] + df.loc[year, f'num_{reactor}'] += reactor_div + + # account for decommissioning with a direct replacement + df = direct_decom(df, ar_dict) + + # Now calculate the total capacity each year (includes capacity from a + # replacement reactor that is new that year, but not new overall because it + # is replacing itself). + df = num_react_to_cap(df, ar_dict) + + return df + + From 78a13b86283f9742c930260af4aec8954142c2e2 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:08:49 -0500 Subject: [PATCH 04/21] add pre determined deployment --- scripts/deployment_script.py | 99 ++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index c2ae04e1..b4d54091 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -134,3 +134,102 @@ def greedy_deployment(df, base_col, ar_dict): return df +def pre_det_deployment(df, base_col, ar_dict, greedy=True): + """ + This function allows the user to specify a distribution for reactor + deployment for specific models. + + There are two implementations: + 1) greedy (greedy=True): wherein the largest reactor is deployed up till + its cap, then the next largest and so on. + 2) linear (greedy=False): wherein the capped reactors are cyclically + deployed until they hit their individual cap. + + df: pandas dataframe + The dataframe of capacity information. + base_col: str + The string name corresponding to the column of capacity that the + algorithm is deploying reactors to meet. + ar_dict: dictionary + A dictionary of reactors with information of the form: + {reactor: [Power (MWe), capacity_factor (%), lifetime (yr), + [distribution]]}. + * The distribution must be the same length as the capacity you are + matching. + * The function assumes that the distribution is at the third index + (i.e., fourth spot). + greedy: bool + A True/False value that determines whether the initial deployment is + greedy or linear. + """ + # initialize the number of reactor columns + for reactor in ar_dict.keys(): + if f'num_{reactor}' not in df: + df[f'num_{reactor}'] = 0 + else: + pass + + if greedy == True: + for year in range(len(df[base_col])): + cap_difference = df[base_col][year].copy() + for reactor in ar_dict.keys(): + # The number of reactors you'd need to meet the remaining + # capacity. + most_reactors = math.floor(cap_difference/ar_dict[reactor][0]) + # If there is a distribution we'll use it. Otherwise, we + # will use a greedy deployment. + if type(ar_dict[reactor][3]) == list: + # Check if the desired amount is greater than the cap. + if most_reactors >= ar_dict[reactor][3][year]: + # If so, we will only deploy up to the cap. + cap_difference -= ar_dict[reactor][3][year] * ar_dict[reactor][0] + df.loc[year, f'num_{reactor}'] += ar_dict[reactor][3][year] + # If the desired is less than the cap, then we'll deploy a + # greedy amount of reactors. + else: + cap_difference -= most_reactors * ar_dict[reactor][0] + df.loc[year, f'num_{reactor}'] += most_reactors + # If there's no cap then we'll deploy a greedy amount of + # reactors. + else: + cap_difference -= most_reactors * ar_dict[reactor][0] + df.loc[year, f'num_{reactor}'] += most_reactors + # Not greedy. + else: + for year in range(len(df[base_col])): + cap_difference = df[base_col][year].copy() + while cap_difference > 0: + for reactor in ar_dict.keys(): + # Check if the next reactor will exceed or equal the + # desired capacity. + next_difference = cap_difference - ar_dict[reactor][0] + # Set the limit one of the smallest reactors below zero + # so the while loop can end. + if next_difference <= -(ar_dict[reactor][0] + 1): + continue + else: + # Check if a cap exists. + if type(ar_dict[reactor][3]) == list: + # Check if the cap will be exceeded by adding + # another reactor. + if ar_dict[reactor][3][year] >= (df.loc[year,f'num_{reactor}'] + 1): + df.loc[year, f'num_{reactor}'] += 1 + # Update remaining capacity to be met. + cap_difference -= ar_dict[reactor][0] + # If there isn't a cap add another reactor. + else: + df.loc[year, f'num_{reactor}'] += 1 + # Update remaining capacity to be met. + cap_difference -= ar_dict[reactor][0] + + # account for decommissioning with a direct replacement + df = direct_decom(df, ar_dict) + + # Now calculate the total capacity each year (includes capacity from a + # replacement reactor that is new that year, but not new overall because it + # is replacing itself). + df = num_react_to_cap(df, ar_dict) + + return df + + From 4b49b9bd1252ee1bde2d02c682422f42ae7f9c79 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:09:20 -0500 Subject: [PATCH 05/21] add random deployment function --- scripts/deployment_script.py | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index b4d54091..573450e3 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -233,3 +233,84 @@ def pre_det_deployment(df, base_col, ar_dict, greedy=True): return df +def rand_deployment(df, base_col, ar_dict, set_seed=False, rough=True, tolerance=5): + """ + This function randomly deploys reactors from the dictionary of reactors to meet a capacity need. + + There are two implementations: + 1) rough (rough=True): if a reactor greater than the remaining capacity is proposed, the deployment ends. + 2) [IN-PROGRESS] complete (rough=False): the algorithm keeps trying to deploy randomly selected reactors until the capacity demand has been met. + + Parameters + ---------- + df: pandas dataframe + The dataframe of capacity information. + base_col: str + The string name corresponding to the column of capacity that the + algorithm is deploying reactors to meet. + ar_dict: dictionary + A dictionary of reactors with information of the form: + {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]}. + set_seed: bool + A True/False value that determines whether the seed used for the random + number is set or varies based on time. + rough: bool + A True/False value that determines whether the initial deployment is + rough or complete. + tolerance: float/int + The capacity tolerance to which reactors are deployed in the complete + deployment case (i.e., when rough=False). Without this, convergence + is tricky to achieve. + """ + + # initialize the number of reactor columns + for reactor in ar_dict.keys(): + if f'num_{reactor}' not in df: + df[f'num_{reactor}'] = 0 + else: + pass + + for year in range(len(df[base_col])): + years_capacity = df[base_col][year] + # I set the limit this way so that something close to 0 could still + # deploy the smallest reactor. + + if set_seed == False: + # sample random number based on time + c = datetime.now() + real_seed = int(c.strftime('%y%m%d%H%M%S')) + else: + real_seed = 20240527121205 + + rng = np.random.default_rng(seed=real_seed) + + while years_capacity > -(ar_dict[list(ar_dict.keys())[-1]][0] + 1): + rand_reactor = rng.integers(0,len(ar_dict.keys())) + + # identify random reactor + deployed = list(ar_dict.keys())[rand_reactor] + + if ar_dict[deployed][0] > years_capacity: + if rough is True: + # for a much rougher check, use break + break + elif rough is False: + # for a more accurate, but much much longer run + # todo, finish this ensuring it can converge + print('This feature is unstable.') + continue + else: + df.loc[year, f'num_{deployed}'] += 1 + years_capacity -= ar_dict[deployed][0] + + # account for decommissioning with a direct replacement + df = direct_decom(df, ar_dict) + + # Now calculate the total capacity each year (includes capacity from a + # replacement reactor that is new that year, but not new overall because it + # is replacing itself). + df = num_react_to_cap(df, ar_dict) + + return df + + From b31e616596c14aafd55c81967c9e81f7b958fe38 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:09:56 -0500 Subject: [PATCH 06/21] add random + greedy deployment function --- scripts/deployment_script.py | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index 573450e3..080727b8 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -314,3 +314,54 @@ def rand_deployment(df, base_col, ar_dict, set_seed=False, rough=True, tolerance return df +def rand_greedy_deployment(df, base_col, ar_dict, set_seed): + """ + This function combines the rough random and greedy deployments to fill in any gaps caused by the roughness. + + Parameters + ---------- + df: pandas dataframe + The dataframe of capacity information. + base_col: str + The string name corresponding to the column of capacity that the + algorithm is deploying reactors to meet. + ar_dict: dictionary + A dictionary of reactors with information of the form: + {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]}. + set_seed: bool + A True/False value that determines whether the seed used for the random + number is set or varies based on time. + """ + # Initialize the number of reactor columns. + for reactor in ar_dict.keys(): + if f'num_{reactor}' not in df: + df[f'num_{reactor}'] = 0 + else: + pass + + # First we will apply the rough random. + df = rand_deployment(df, base_col, ar_dict, set_seed, rough=True) + + # Now we will make a remaining cap column. + df['remaining_cap'] = df[base_col] - df['new_cap'] + + # make columns for the randomly deployed reactors and the greedy reactors + for reactor in ar_dict.keys(): + df[f'greedy_num_{reactor}'] = 0 + df[f'rand_num_{reactor}'] = df[f'num_{reactor}'] + + # Now we will use the remaining cap column with a greedy deployment. + df = greedy_deployment(df, 'remaining_cap', ar_dict) + + #reset the total capacity column + df['new_cap'] = 0 + + # populate the greedy reactor column + for year in range(len(df[base_col])): + for reactor in ar_dict.keys(): + df.loc[year,f'greedy_num_{reactor}'] = df.loc[year,f'num_{reactor}'] - df.loc[year,f'rand_num_{reactor}'] + df.loc[year, f'new_cap'] += df.loc[year,f'{reactor}_cap'] + + return df + + From 9fcdef7626020b0d7b3b7c3f7d3e3195d5c5fd89 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:10:18 -0500 Subject: [PATCH 07/21] add analysis function and helper functions --- scripts/deployment_script.py | 111 +++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index 080727b8..3de9c053 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -365,3 +365,114 @@ def rand_greedy_deployment(df, base_col, ar_dict, set_seed): return df +# # # # # # # # # # # # Analysis Functions # # # # # # # # # # # # +# analyze how well each method did with the amount and percent of over/ +# under-prediction. + +def simple_diff(df, base, proj): + """ + Calculate the difference between the projected and base capacities. + + Parameters + ---------- + df: pd.DataFrame + The output pandas DataFrame from the deployment functions. + base: str + The name of the base capacity column in the DataFrame. + proj: str + The name of the projected capacity column in the DataFrame. + """ + return df[proj] - df[base] + + + +def calc_percentage(df, base): + """ + Calculate the percentage difference between proj and base. + + Parameters + ---------- + df: pd.DataFrame + The output pandas DataFrame from the deployment functions. + base: str + The name of the base capacity column in the DataFrame. + """ + return (df['difference'] / df[base]) * 100 + + + +def analyze_algorithm(df, base, proj, ar_dict): + """ + This function takes in a DataFrame output of the deployment functions + above, and returns a series of metrics so you can compare different + deployments. + + Parameters + ---------- + df: pd.DataFrame + The output pandas DataFrame from the deployment functions. + base: str + The name of the base capacity column in the DataFrame. + proj: str + The name of the projected capacity column in the DataFrame. + ar_dict: dictionary + A dictionary of reactors with information of the form: + {reactor: [Power (MWe), capacity_factor (%), lifetime (yr), + [distribution]]}. + + Returns + ------- + above_count: int + The number of times the deployed capacity exceeds the desired capacity. + below_count: int + The number of times the deployed capacity is below the desired capacity. + equal_count: int + The number of times the deployed capacity equals the desired capacity. + above_percentage: float + The percent of times the deployed capacity exceeds the desired capacity. + below_percentage: float + The percent of times the deployed capacity is below the desired + capacity. + total_above: int + The excess of deployed capacity. + total_below: int + The dearth of deployed capacity. + percent_provided: dict + The percent of the deployed capacity that comes from each reactor. + """ + + df['difference'] = df.apply(simple_diff, base=base, proj=proj, axis=1) + df['percentage'] = df.apply(calc_percentage, base=base, axis=1) + + above_count = (df['difference'] > 0).sum() + below_count = (df['difference'] < 0).sum() + equal_count = (df['difference'] == 0).sum() + + above_percentage = (above_count / len(df)) * 100 + below_percentage = (below_count / len(df)) * 100 + + total_above = df['difference'][df['difference'] > 0].sum() + total_below = df['difference'][df['difference'] < 0].sum() + + # Now we will calculate the percent of the total capacity coming from each + # reactor. + percent_provided = {} + + total_cap_sum = df['total_cap'].sum() + for reactor in ar_dict.keys(): + total_reactor_cap = df[f'{reactor}_cap'].sum() + percent_reactor_cap = (1 - (total_cap_sum - total_reactor_cap)/total_cap_sum) * 100 + percent_provided[reactor] = percent_reactor_cap + + results = { + 'above_count': above_count, + 'below_count': below_count, + 'equal_count': equal_count, + 'above_percentage': above_percentage, + 'below_percentage': below_percentage, + 'total_above': total_above, + 'total_below': total_below, + 'percent_provided': percent_provided + } + + return results \ No newline at end of file From 15ea5e69d577849d791b97348ab1fb16df7e3b93 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:11:43 -0500 Subject: [PATCH 08/21] start test_deployment_script and add helper functions --- scripts/tests/test_deployment_script.py | 50 +++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 scripts/tests/test_deployment_script.py diff --git a/scripts/tests/test_deployment_script.py b/scripts/tests/test_deployment_script.py new file mode 100644 index 00000000..13e09078 --- /dev/null +++ b/scripts/tests/test_deployment_script.py @@ -0,0 +1,50 @@ +import os +import sys +import pytest +import numpy as np +import pandas as pd +path = os.path.realpath(__file__) +sys.path.append(os.path.dirname(os.path.dirname(path))) +import deployment_scripts as dep + +ad_reactors = { + 'ReactorBig': [80, 1, 6, [1,2,1,2,1,2,1,2,1]], + 'ReactorMedium':[20,1,4,'no_dist'], + 'ReactorSmall': [5, 1, 2, 'no_dist']} +# {reactor: [Power (MWe), capacity_factor (%), +# lifetime (yr), distribution (default='no_dist')]} + +test_dict = { + 'Year':[2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], + 'test_cap': [20, 79, 80, 81, 220, 640, 693, 950, 700]} +test_df = pd.DataFrame.from_dict(test_dict) + + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # Helper Functions # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +def test_direct_decom(): + # Decommissioning test dictionary + # Based on the greedy algorithm + decom_df = { + 'Year': [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], + 'manual_decom': [0, 0, 0, 0, 0, 0, 0, 0, 1], + # manual calculation based on greedy algorithm + 'ReactorBigDecom': [0, 0, 0, 0, 0, 0, 0, 0, 1]} + # result of greedy function using the direct_decom function + + assert all(decom_df['manual_decom'][i] == decom_df['ReactorBigDecom'][i] for i in range(len(decom_df['manual_decom']))) + + +def test_num_react_to_cap(): + # Reactors to capacity test dictionary + # Based on the greedy algorithm + react_to_cap_df = { + 'Year': [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], + 'manual_cap': [0, 0, 80, 80, 160, 640, 640, 880, 720], + 'new_cap': [0, 0, 80, 80, 160, 640, 640, 880, 720]} + + assert all(react_to_cap_df['manual_cap'][i] == react_to_cap_df['new_cap'][i] for i in range(len(react_to_cap_df['manual_cap']))) + + From 145282cb76378bfae4a1cca95e3484b846b78728 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:12:18 -0500 Subject: [PATCH 09/21] add deployment function tests --- scripts/tests/test_deployment_script.py | 117 ++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/scripts/tests/test_deployment_script.py b/scripts/tests/test_deployment_script.py index 13e09078..72ef4438 100644 --- a/scripts/tests/test_deployment_script.py +++ b/scripts/tests/test_deployment_script.py @@ -48,3 +48,120 @@ def test_num_react_to_cap(): assert all(react_to_cap_df['manual_cap'][i] == react_to_cap_df['new_cap'][i] for i in range(len(react_to_cap_df['manual_cap']))) +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # Deployment Functions # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +def test_greedy_deployment(): + # Greedy distribution dictionary + greedy_dist_df = { + 'Year': [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], + 'test_cap': [20, 79, 80, 81, 220, 640, 693, 950, 700], + 'manual_cap': [20, 75, 80, 80, 220, 640, 690, 950, 700]} + + # Convert to DataFrame for comparison + greedy_dist_df = pd.DataFrame(greedy_dist_df) + + calculated_greedy_df = dep.greedy_deployment( + test_df, 'test_cap', ad_reactors) + + # Ensure 'new_cap' column exists in the result + assert 'new_cap' in calculated_greedy_df.columns, "The 'new_cap' column is missing in the calculated results." + + # Test the 'manual_cap' values against 'new_cap' + for i in range(len(greedy_dist_df)): + assert greedy_dist_df['manual_cap'][i] == calculated_greedy_df['new_cap'][i], f"Failed at index {i}: {greedy_dist_df['manual_cap'][i]} != {calculated_greedy_df['new_cap'][i]}" + + print("Greedy tests passed.") + + +def test_pre_det_deployment_greedy(): + # Define the expected DataFrame for the greedy case + manual_pre_det_greedy_df = { + 'Year': [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], + 'test_cap': [20, 79, 80, 81, 220, 640, 693, 950, 700], + 'total_cap': [20, 75, 80, 95, 240, 715, 690, 965, 950], + 'manual_cap': [20, 75, 80, 80, 220, 640, 690, 950, 700] + } + manual_pre_det_greedy_df = pd.DataFrame(manual_pre_det_greedy_df) + + # Create a copy of test_df to pass to the function + pre_det_dep_df_greedy = test_df.copy() + + # Call the pre_det_deployment function with greedy=True + result_df = dep.pre_det_deployment(pre_det_dep_df_greedy, 'test_cap', ad_reactors, greedy=True) + + # Check that 'new_cap' matches 'manual_cap' + assert result_df['new_cap'].equals(manual_pre_det_greedy_df['manual_cap']) + + print("Greedy pre-determined distribution test passed.") + + +def test_pre_det_deployment_linear(): + # Define the expected DataFrame for the linear case + pre_det_linear_df = { + 'Year': [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], + 'test_cap': [20, 79, 80, 81, 220, 640, 693, 950, 700], + 'total_cap': [80, 80, 100, 100, 225, 655, 825, 1150, 1050], + 'manual_cap': [80, 80, 100, 100, 225, 655, 700, 955, 705] + } + pre_det_linear_df = pd.DataFrame(pre_det_linear_df) + + # Create a copy of test_df to pass to the function + pre_det_dep_df_linear = test_df.copy() + + # Call the pre_det_deployment function with greedy=False + result_df = dep.pre_det_deployment(pre_det_dep_df_linear, 'test_cap', ad_reactors, greedy=False) + + # Check that 'new_cap' matches 'manual_cap' + assert result_df['new_cap'].equals(pre_det_linear_df['manual_cap']) + + print("Linear pre-determined distribution test passed.") + + +def test_rand_deployment(): + # Define the expected DataFrame for the random function + manual_rand_df = { + 'Year': [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], + 'test_cap': [20, 79, 80, 81, 220, 640, 693, 950, 700], + 'total_cap': [0, 0, 80, 80, 205, 615, 620, 915, 835], + 'manual_cap': [0, 0, 80, 80, 205, 615, 615, 900, 695] + } + + manual_rand_df = pd.DataFrame(manual_rand_df) + + # Create a copy of test_df to pass to the function + rand_dep_df = test_df.copy() + + # Call the rand_deployment function + result_df = dep.rand_deployment(rand_dep_df, 'test_cap', ad_reactors, set_seed=True) + + # Check that 'new_cap' matches 'manual_cap' + assert result_df['new_cap'].equals(manual_rand_df['manual_cap']) + + print("Random deployment test passed.") + + +def test_rand_greedy_deployment(): + # Define the expected DataFrame for the random greedy function + manual_rand_greedy_df = { + 'Year': [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], + 'test_cap': [20, 79, 80, 81, 220, 640, 693, 950, 700], + 'total_cap': [20, 75, 80, 95, 240, 715, 690, 965, 950], + 'manual_cap': [20, 75, 80, 80, 220, 640, 690, 950, 700] + } + + manual_rand_greedy_df = pd.DataFrame(manual_rand_greedy_df) + + # Create a copy of test_df to pass to the function + rand_greedy_dep_df = test_df.copy() + + # Call the rand_deployment function + result_df = dep.rand_greedy_deployment(rand_greedy_dep_df, 'test_cap', ad_reactors, set_seed=True) + + # Check that 'new_cap' matches 'manual_cap' + assert result_df['new_cap'].equals(manual_rand_greedy_df['manual_cap']) + + print("Random greedy deployment test passed.") + + From f0427226a056d4aafc2689f3de40c5f1f3134df8 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:12:40 -0500 Subject: [PATCH 10/21] add analysis test function --- scripts/tests/test_deployment_script.py | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/scripts/tests/test_deployment_script.py b/scripts/tests/test_deployment_script.py index 72ef4438..ab15c429 100644 --- a/scripts/tests/test_deployment_script.py +++ b/scripts/tests/test_deployment_script.py @@ -165,3 +165,33 @@ def test_rand_greedy_deployment(): print("Random greedy deployment test passed.") +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # Analysis Functions # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + +def test_analyze_algorithm(): + # Create a sample DataFrame for testing + data = { + 'Year': [2016, 2017, 2018], + 'proj_cap': [110, 160, 190], + 'total_cap': [105, 160, 195], + 'ReactorBig_cap': [80, 160, 80], + 'ReactorMedium_cap': [20, 0, 80], + 'ReactorSmall_cap': [5, 0, 35] + } + df = pd.DataFrame(data) + + # Call the analyze_algorithm function + results = dep.analyze_algorithm(df, 'total_cap', 'proj_cap', ad_reactors) + + # Check the expected results + assert results['above_count'] == 1 + assert results['below_count'] == 1 + assert results['equal_count'] == 1 + assert results['above_percentage'] == 33.33333333333333 + assert results['below_percentage'] == 33.33333333333333 + assert results['total_above'] == 5 + assert results['total_below'] == -5 + assert results['percent_provided'] == {'ReactorBig': 69.56521739130434, + 'ReactorMedium': 21.739130434782606, + 'ReactorSmall': 8.695652173913048} From 1b84e912ded818735d33f374de776db297e4bfe0 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:28:02 -0500 Subject: [PATCH 11/21] create autodoc page for deployment script --- docs/deployment_script_doc.rst | 7 +++++++ docs/index.md | 1 + 2 files changed, 8 insertions(+) create mode 100644 docs/deployment_script_doc.rst diff --git a/docs/deployment_script_doc.rst b/docs/deployment_script_doc.rst new file mode 100644 index 00000000..156da622 --- /dev/null +++ b/docs/deployment_script_doc.rst @@ -0,0 +1,7 @@ +Deployment Script +----------------- + +.. automodule:: scripts.deployment_script + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 0232e4c1..53ca1b72 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,6 +14,7 @@ create_ar_deployinst_doc create_cyclus_input_doc dakota_input_doc dataframe_analysis_doc +deployment_script_doc merge_coordinates_doc output_metrics_doc predicting_the_past_import_doc From bcaa19ef97d6c66be6797df25fbfbab17e8a0cd4 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Tue, 27 Aug 2024 14:28:35 -0500 Subject: [PATCH 12/21] pep8 updates for test_deployment_script --- scripts/tests/test_deployment_script.py | 40 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/scripts/tests/test_deployment_script.py b/scripts/tests/test_deployment_script.py index ab15c429..9f565359 100644 --- a/scripts/tests/test_deployment_script.py +++ b/scripts/tests/test_deployment_script.py @@ -1,15 +1,15 @@ +path = os.path.realpath(__file__) +sys.path.append(os.path.dirname(os.path.dirname(path))) +import deployment_script as dep import os import sys import pytest import numpy as np import pandas as pd -path = os.path.realpath(__file__) -sys.path.append(os.path.dirname(os.path.dirname(path))) -import deployment_scripts as dep ad_reactors = { - 'ReactorBig': [80, 1, 6, [1,2,1,2,1,2,1,2,1]], - 'ReactorMedium':[20,1,4,'no_dist'], + 'ReactorBig': [80, 1, 6, [1, 2, 1, 2, 1, 2, 1, 2, 1]], + 'ReactorMedium':[20, 1, 4, 'no_dist'], 'ReactorSmall': [5, 1, 2, 'no_dist']} # {reactor: [Power (MWe), capacity_factor (%), # lifetime (yr), distribution (default='no_dist')]} @@ -32,9 +32,11 @@ def test_direct_decom(): 'manual_decom': [0, 0, 0, 0, 0, 0, 0, 0, 1], # manual calculation based on greedy algorithm 'ReactorBigDecom': [0, 0, 0, 0, 0, 0, 0, 0, 1]} - # result of greedy function using the direct_decom function + # result of greedy function using the direct_decom function - assert all(decom_df['manual_decom'][i] == decom_df['ReactorBigDecom'][i] for i in range(len(decom_df['manual_decom']))) + assert all(decom_df['manual_decom'][i] == \ + decom_df['ReactorBigDecom'][i] \ + for i in range(len(decom_df['manual_decom']))) def test_num_react_to_cap(): @@ -45,7 +47,9 @@ def test_num_react_to_cap(): 'manual_cap': [0, 0, 80, 80, 160, 640, 640, 880, 720], 'new_cap': [0, 0, 80, 80, 160, 640, 640, 880, 720]} - assert all(react_to_cap_df['manual_cap'][i] == react_to_cap_df['new_cap'][i] for i in range(len(react_to_cap_df['manual_cap']))) + assert all(react_to_cap_df['manual_cap'][i] == \ + react_to_cap_df['new_cap'][i] \ + for i in range(len(react_to_cap_df['manual_cap']))) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -66,11 +70,15 @@ def test_greedy_deployment(): test_df, 'test_cap', ad_reactors) # Ensure 'new_cap' column exists in the result - assert 'new_cap' in calculated_greedy_df.columns, "The 'new_cap' column is missing in the calculated results." + assert 'new_cap' in calculated_greedy_df.columns, \ + "The 'new_cap' column is missing in the calculated results." # Test the 'manual_cap' values against 'new_cap' for i in range(len(greedy_dist_df)): - assert greedy_dist_df['manual_cap'][i] == calculated_greedy_df['new_cap'][i], f"Failed at index {i}: {greedy_dist_df['manual_cap'][i]} != {calculated_greedy_df['new_cap'][i]}" + assert greedy_dist_df['manual_cap'][i] == \ + calculated_greedy_df['new_cap'][i], f"Failed at index {i}:\ + {greedy_dist_df['manual_cap'][i]} != \ + {calculated_greedy_df['new_cap'][i]}" print("Greedy tests passed.") @@ -89,7 +97,8 @@ def test_pre_det_deployment_greedy(): pre_det_dep_df_greedy = test_df.copy() # Call the pre_det_deployment function with greedy=True - result_df = dep.pre_det_deployment(pre_det_dep_df_greedy, 'test_cap', ad_reactors, greedy=True) + result_df = dep.pre_det_deployment(pre_det_dep_df_greedy, 'test_cap', + ad_reactors, greedy=True) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(manual_pre_det_greedy_df['manual_cap']) @@ -111,7 +120,8 @@ def test_pre_det_deployment_linear(): pre_det_dep_df_linear = test_df.copy() # Call the pre_det_deployment function with greedy=False - result_df = dep.pre_det_deployment(pre_det_dep_df_linear, 'test_cap', ad_reactors, greedy=False) + result_df = dep.pre_det_deployment(pre_det_dep_df_linear, 'test_cap', + ad_reactors, greedy=False) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(pre_det_linear_df['manual_cap']) @@ -134,7 +144,8 @@ def test_rand_deployment(): rand_dep_df = test_df.copy() # Call the rand_deployment function - result_df = dep.rand_deployment(rand_dep_df, 'test_cap', ad_reactors, set_seed=True) + result_df = dep.rand_deployment(rand_dep_df, 'test_cap', + ad_reactors, set_seed=True) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(manual_rand_df['manual_cap']) @@ -157,7 +168,8 @@ def test_rand_greedy_deployment(): rand_greedy_dep_df = test_df.copy() # Call the rand_deployment function - result_df = dep.rand_greedy_deployment(rand_greedy_dep_df, 'test_cap', ad_reactors, set_seed=True) + result_df = dep.rand_greedy_deployment(rand_greedy_dep_df, 'test_cap', + ad_reactors, set_seed=True) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(manual_rand_greedy_df['manual_cap']) From 7446ce57cece35fda62f461e0cb5f39382517177 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Wed, 28 Aug 2024 08:05:38 -0500 Subject: [PATCH 13/21] pep8 updates to test dep --- scripts/deployment_script.py | 24 ++++++++++--------- scripts/tests/test_deployment_script.py | 31 +++++++++++++------------ 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index 3de9c053..e32ab31e 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -359,8 +359,10 @@ def rand_greedy_deployment(df, base_col, ar_dict, set_seed): # populate the greedy reactor column for year in range(len(df[base_col])): for reactor in ar_dict.keys(): - df.loc[year,f'greedy_num_{reactor}'] = df.loc[year,f'num_{reactor}'] - df.loc[year,f'rand_num_{reactor}'] - df.loc[year, f'new_cap'] += df.loc[year,f'{reactor}_cap'] + df.loc[year,f'greedy_num_{reactor}'] = df.loc[year, \ + f'num_{reactor}'] \ + - df.loc[year,f'rand_num_{reactor}'] + df.loc[year, f'new_cap'] += df.loc[year, f'{reactor}_cap'] return df @@ -385,7 +387,6 @@ def simple_diff(df, base, proj): return df[proj] - df[base] - def calc_percentage(df, base): """ Calculate the percentage difference between proj and base. @@ -400,7 +401,6 @@ def calc_percentage(df, base): return (df['difference'] / df[base]) * 100 - def analyze_algorithm(df, base, proj, ar_dict): """ This function takes in a DataFrame output of the deployment functions @@ -423,15 +423,15 @@ def analyze_algorithm(df, base, proj, ar_dict): Returns ------- above_count: int - The number of times the deployed capacity exceeds the desired capacity. + The number of times the deployed capacity exceeds desired capacity. below_count: int - The number of times the deployed capacity is below the desired capacity. + The number of times the deployed capacity is below desired capacity. equal_count: int - The number of times the deployed capacity equals the desired capacity. + The number of times the deployed capacity equals desired capacity. above_percentage: float - The percent of times the deployed capacity exceeds the desired capacity. + The percent of times the deployed capacity exceeds desired capacity. below_percentage: float - The percent of times the deployed capacity is below the desired + The percent of times the deployed capacity is below desired capacity. total_above: int The excess of deployed capacity. @@ -461,7 +461,8 @@ def analyze_algorithm(df, base, proj, ar_dict): total_cap_sum = df['total_cap'].sum() for reactor in ar_dict.keys(): total_reactor_cap = df[f'{reactor}_cap'].sum() - percent_reactor_cap = (1 - (total_cap_sum - total_reactor_cap)/total_cap_sum) * 100 + percent_reactor_cap = (1 - \ + (total_cap_sum - total_reactor_cap)/total_cap_sum) * 100 percent_provided[reactor] = percent_reactor_cap results = { @@ -475,4 +476,5 @@ def analyze_algorithm(df, base, proj, ar_dict): 'percent_provided': percent_provided } - return results \ No newline at end of file + return results + diff --git a/scripts/tests/test_deployment_script.py b/scripts/tests/test_deployment_script.py index 9f565359..254c268b 100644 --- a/scripts/tests/test_deployment_script.py +++ b/scripts/tests/test_deployment_script.py @@ -1,21 +1,22 @@ -path = os.path.realpath(__file__) -sys.path.append(os.path.dirname(os.path.dirname(path))) -import deployment_script as dep import os import sys import pytest import numpy as np import pandas as pd +path = os.path.realpath(__file__) +sys.path.append(os.path.dirname(os.path.dirname(path))) +import deployment_script as dep + ad_reactors = { 'ReactorBig': [80, 1, 6, [1, 2, 1, 2, 1, 2, 1, 2, 1]], - 'ReactorMedium':[20, 1, 4, 'no_dist'], + 'ReactorMedium': [20, 1, 4, 'no_dist'], 'ReactorSmall': [5, 1, 2, 'no_dist']} # {reactor: [Power (MWe), capacity_factor (%), # lifetime (yr), distribution (default='no_dist')]} test_dict = { - 'Year':[2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], + 'Year': [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024], 'test_cap': [20, 79, 80, 81, 220, 640, 693, 950, 700]} test_df = pd.DataFrame.from_dict(test_dict) @@ -34,9 +35,9 @@ def test_direct_decom(): 'ReactorBigDecom': [0, 0, 0, 0, 0, 0, 0, 0, 1]} # result of greedy function using the direct_decom function - assert all(decom_df['manual_decom'][i] == \ - decom_df['ReactorBigDecom'][i] \ - for i in range(len(decom_df['manual_decom']))) + assert all(decom_df['manual_decom'][i] == + decom_df['ReactorBigDecom'][i] + for i in range(len(decom_df['manual_decom']))) def test_num_react_to_cap(): @@ -47,9 +48,9 @@ def test_num_react_to_cap(): 'manual_cap': [0, 0, 80, 80, 160, 640, 640, 880, 720], 'new_cap': [0, 0, 80, 80, 160, 640, 640, 880, 720]} - assert all(react_to_cap_df['manual_cap'][i] == \ - react_to_cap_df['new_cap'][i] \ - for i in range(len(react_to_cap_df['manual_cap']))) + assert all(react_to_cap_df['manual_cap'][i] == + react_to_cap_df['new_cap'][i] + for i in range(len(react_to_cap_df['manual_cap']))) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -98,7 +99,7 @@ def test_pre_det_deployment_greedy(): # Call the pre_det_deployment function with greedy=True result_df = dep.pre_det_deployment(pre_det_dep_df_greedy, 'test_cap', - ad_reactors, greedy=True) + ad_reactors, greedy=True) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(manual_pre_det_greedy_df['manual_cap']) @@ -121,7 +122,7 @@ def test_pre_det_deployment_linear(): # Call the pre_det_deployment function with greedy=False result_df = dep.pre_det_deployment(pre_det_dep_df_linear, 'test_cap', - ad_reactors, greedy=False) + ad_reactors, greedy=False) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(pre_det_linear_df['manual_cap']) @@ -145,7 +146,7 @@ def test_rand_deployment(): # Call the rand_deployment function result_df = dep.rand_deployment(rand_dep_df, 'test_cap', - ad_reactors, set_seed=True) + ad_reactors, set_seed=True) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(manual_rand_df['manual_cap']) @@ -169,7 +170,7 @@ def test_rand_greedy_deployment(): # Call the rand_deployment function result_df = dep.rand_greedy_deployment(rand_greedy_dep_df, 'test_cap', - ad_reactors, set_seed=True) + ad_reactors, set_seed=True) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(manual_rand_greedy_df['manual_cap']) From 4cee712ea6653e2c3950c03c81a373b8cceba21b Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Wed, 28 Aug 2024 08:09:00 -0500 Subject: [PATCH 14/21] indentation pep8 fixes test dep --- scripts/tests/test_deployment_script.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/tests/test_deployment_script.py b/scripts/tests/test_deployment_script.py index 254c268b..0aa453fe 100644 --- a/scripts/tests/test_deployment_script.py +++ b/scripts/tests/test_deployment_script.py @@ -36,8 +36,8 @@ def test_direct_decom(): # result of greedy function using the direct_decom function assert all(decom_df['manual_decom'][i] == - decom_df['ReactorBigDecom'][i] - for i in range(len(decom_df['manual_decom']))) + decom_df['ReactorBigDecom'][i] + for i in range(len(decom_df['manual_decom']))) def test_num_react_to_cap(): @@ -49,8 +49,8 @@ def test_num_react_to_cap(): 'new_cap': [0, 0, 80, 80, 160, 640, 640, 880, 720]} assert all(react_to_cap_df['manual_cap'][i] == - react_to_cap_df['new_cap'][i] - for i in range(len(react_to_cap_df['manual_cap']))) + react_to_cap_df['new_cap'][i] + for i in range(len(react_to_cap_df['manual_cap']))) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -99,7 +99,7 @@ def test_pre_det_deployment_greedy(): # Call the pre_det_deployment function with greedy=True result_df = dep.pre_det_deployment(pre_det_dep_df_greedy, 'test_cap', - ad_reactors, greedy=True) + ad_reactors, greedy=True) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(manual_pre_det_greedy_df['manual_cap']) @@ -122,7 +122,7 @@ def test_pre_det_deployment_linear(): # Call the pre_det_deployment function with greedy=False result_df = dep.pre_det_deployment(pre_det_dep_df_linear, 'test_cap', - ad_reactors, greedy=False) + ad_reactors, greedy=False) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(pre_det_linear_df['manual_cap']) @@ -170,7 +170,7 @@ def test_rand_greedy_deployment(): # Call the rand_deployment function result_df = dep.rand_greedy_deployment(rand_greedy_dep_df, 'test_cap', - ad_reactors, set_seed=True) + ad_reactors, set_seed=True) # Check that 'new_cap' matches 'manual_cap' assert result_df['new_cap'].equals(manual_rand_greedy_df['manual_cap']) From 1f0f2d85c854414c59ec2197f249e060e1bd0105 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Wed, 28 Aug 2024 08:23:18 -0500 Subject: [PATCH 15/21] pep8 updates dep --- scripts/deployment_script.py | 75 ++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index e32ab31e..4c92bb45 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -7,10 +7,9 @@ from datetime import datetime # for random seed generation - - # # # # # # # # # # # # Constituent Functions # # # # # # # # # # # + def direct_decom(df, ar_dict): """ This function assumes that every time a reactor model is decommissioned it @@ -35,13 +34,16 @@ def direct_decom(df, ar_dict): pass else: # tracks the number of decommissioned reactors - df.loc[decom_year, f'{reactor}Decom'] += df.loc[year, f'num_{reactor}'] + df.loc[decom_year, f'{reactor}Decom'] += \ + df.loc[year, f'num_{reactor}'] # construct new reactors to replace the decommissioned ones - df.loc[decom_year, f'num_{reactor}'] += df.loc[year, f'num_{reactor}'] + df.loc[decom_year, f'num_{reactor}'] += \ + df.loc[year, f'num_{reactor}'] return df + def num_react_to_cap(df, ar_dict): """ This function takes in a dataframe and the dictionary of reactors, @@ -66,7 +68,9 @@ def num_react_to_cap(df, ar_dict): for reactor in ar_dict.keys(): # New capacity calculations. - df[f'new_{reactor}_cap'] = (df[f'num_{reactor}'] - df[f'{reactor}Decom']) * ar_dict[f'{reactor}'][0] + df[f'new_{reactor}_cap'] = (df[f'num_{reactor}'] - + df[f'{reactor}Decom']) * \ + ar_dict[f'{reactor}'][0] df['new_cap'] += df[f'new_{reactor}_cap'] # Total capacity calculations. @@ -82,8 +86,8 @@ def num_react_to_cap(df, ar_dict): # 2. Pre-determined distributions: one or more reactors have a preset # distribution, and a smaller capacity model fills in the gaps. # 2.b Deployment Cap [extension of 2]: there is a single-number capacity for -# one or more of the reactor models. * there is no function for this, just use -# a constant distribution. +# one or more of the reactor models. * there is no function for this, just +# use a constant distribution. # 3. Random Deployment: uses a date and hour as seed to randomly sample the # reactors list. # 4. Initially Random, Greedy: randomly deploys reactors until a reactor bigger @@ -92,14 +96,17 @@ def num_react_to_cap(df, ar_dict): def greedy_deployment(df, base_col, ar_dict): """ - In this greedy deployment, we will deploy the largest capacity reactor first until another deployment will exceed the desired capacity then the next largest capacity reactor is deployed and so on. + In this greedy deployment, we will deploy the largest capacity reactor + first until another deployment will exceed the desired capacity then the + next largest capacity reactor is deployed and so on. Parameters ---------- df: pandas dataframe The dataframe of capacity information base_col: str - The string name corresponding to the column of capacity that the algorithm is deploying reactors to meet + The string name corresponding to the column of capacity that the + algorithm is deploying reactors to meet ar_dict: dictionary A dictionary of reactors with information of the form: {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]} @@ -129,7 +136,7 @@ def greedy_deployment(df, base_col, ar_dict): # Now calculate the total capacity each year (includes capacity from a # replacement reactor that is new that year, but not new overall because it # is replacing itself). - df = num_react_to_cap(df, ar_dict) + df = num_react_to_cap(df, ar_dict) return df @@ -169,7 +176,7 @@ def pre_det_deployment(df, base_col, ar_dict, greedy=True): else: pass - if greedy == True: + if greedy is True: for year in range(len(df[base_col])): cap_difference = df[base_col][year].copy() for reactor in ar_dict.keys(): @@ -182,8 +189,10 @@ def pre_det_deployment(df, base_col, ar_dict, greedy=True): # Check if the desired amount is greater than the cap. if most_reactors >= ar_dict[reactor][3][year]: # If so, we will only deploy up to the cap. - cap_difference -= ar_dict[reactor][3][year] * ar_dict[reactor][0] - df.loc[year, f'num_{reactor}'] += ar_dict[reactor][3][year] + cap_difference -= ar_dict[reactor][3][year] \ + * ar_dict[reactor][0] + df.loc[year, f'num_{reactor}'] += \ + ar_dict[reactor][3][year] # If the desired is less than the cap, then we'll deploy a # greedy amount of reactors. else: @@ -212,7 +221,8 @@ def pre_det_deployment(df, base_col, ar_dict, greedy=True): if type(ar_dict[reactor][3]) == list: # Check if the cap will be exceeded by adding # another reactor. - if ar_dict[reactor][3][year] >= (df.loc[year,f'num_{reactor}'] + 1): + if ar_dict[reactor][3][year] >= \ + (df.loc[year, f'num_{reactor}'] + 1): df.loc[year, f'num_{reactor}'] += 1 # Update remaining capacity to be met. cap_difference -= ar_dict[reactor][0] @@ -228,18 +238,23 @@ def pre_det_deployment(df, base_col, ar_dict, greedy=True): # Now calculate the total capacity each year (includes capacity from a # replacement reactor that is new that year, but not new overall because it # is replacing itself). - df = num_react_to_cap(df, ar_dict) + df = num_react_to_cap(df, ar_dict) return df -def rand_deployment(df, base_col, ar_dict, set_seed=False, rough=True, tolerance=5): +def rand_deployment(df, base_col, ar_dict, + set_seed=False, rough=True, tolerance=5): """ - This function randomly deploys reactors from the dictionary of reactors to meet a capacity need. + This function randomly deploys reactors from the dictionary of + reactors to meet a capacity need. There are two implementations: - 1) rough (rough=True): if a reactor greater than the remaining capacity is proposed, the deployment ends. - 2) [IN-PROGRESS] complete (rough=False): the algorithm keeps trying to deploy randomly selected reactors until the capacity demand has been met. + 1) rough (rough=True): if a reactor greater than the remaining + capacity is proposed, the deployment ends. + 2) [IN-PROGRESS] complete (rough=False): the algorithm keeps + trying to deploy randomly selected reactors until the capacity demand + has been met. Parameters ---------- @@ -275,7 +290,7 @@ def rand_deployment(df, base_col, ar_dict, set_seed=False, rough=True, tolerance # I set the limit this way so that something close to 0 could still # deploy the smallest reactor. - if set_seed == False: + if set_seed is False: # sample random number based on time c = datetime.now() real_seed = int(c.strftime('%y%m%d%H%M%S')) @@ -285,7 +300,7 @@ def rand_deployment(df, base_col, ar_dict, set_seed=False, rough=True, tolerance rng = np.random.default_rng(seed=real_seed) while years_capacity > -(ar_dict[list(ar_dict.keys())[-1]][0] + 1): - rand_reactor = rng.integers(0,len(ar_dict.keys())) + rand_reactor = rng.integers(0, len(ar_dict.keys())) # identify random reactor deployed = list(ar_dict.keys())[rand_reactor] @@ -309,14 +324,15 @@ def rand_deployment(df, base_col, ar_dict, set_seed=False, rough=True, tolerance # Now calculate the total capacity each year (includes capacity from a # replacement reactor that is new that year, but not new overall because it # is replacing itself). - df = num_react_to_cap(df, ar_dict) + df = num_react_to_cap(df, ar_dict) return df def rand_greedy_deployment(df, base_col, ar_dict, set_seed): """ - This function combines the rough random and greedy deployments to fill in any gaps caused by the roughness. + This function combines the rough random and greedy deployments + to fill in any gaps caused by the roughness. Parameters ---------- @@ -353,15 +369,15 @@ def rand_greedy_deployment(df, base_col, ar_dict, set_seed): # Now we will use the remaining cap column with a greedy deployment. df = greedy_deployment(df, 'remaining_cap', ar_dict) - #reset the total capacity column + # reset the total capacity column df['new_cap'] = 0 # populate the greedy reactor column for year in range(len(df[base_col])): for reactor in ar_dict.keys(): - df.loc[year,f'greedy_num_{reactor}'] = df.loc[year, \ - f'num_{reactor}'] \ - - df.loc[year,f'rand_num_{reactor}'] + df.loc[year, f'greedy_num_{reactor}'] = \ + df.loc[year, f'num_{reactor}'] \ + - df.loc[year, f'rand_num_{reactor}'] df.loc[year, f'new_cap'] += df.loc[year, f'{reactor}_cap'] return df @@ -461,8 +477,9 @@ def analyze_algorithm(df, base, proj, ar_dict): total_cap_sum = df['total_cap'].sum() for reactor in ar_dict.keys(): total_reactor_cap = df[f'{reactor}_cap'].sum() - percent_reactor_cap = (1 - \ - (total_cap_sum - total_reactor_cap)/total_cap_sum) * 100 + percent_reactor_cap = (1 - + (total_cap_sum - total_reactor_cap)/ + total_cap_sum) * 100 percent_provided[reactor] = percent_reactor_cap results = { From f880dc612b12f8e07b6c86c31184c296a571da60 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Wed, 28 Aug 2024 08:25:57 -0500 Subject: [PATCH 16/21] pep8 indendation fixes dep script --- scripts/deployment_script.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index 4c92bb45..14b9cd6f 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -222,7 +222,7 @@ def pre_det_deployment(df, base_col, ar_dict, greedy=True): # Check if the cap will be exceeded by adding # another reactor. if ar_dict[reactor][3][year] >= \ - (df.loc[year, f'num_{reactor}'] + 1): + (df.loc[year, f'num_{reactor}'] + 1): df.loc[year, f'num_{reactor}'] += 1 # Update remaining capacity to be met. cap_difference -= ar_dict[reactor][0] @@ -478,7 +478,7 @@ def analyze_algorithm(df, base, proj, ar_dict): for reactor in ar_dict.keys(): total_reactor_cap = df[f'{reactor}_cap'].sum() percent_reactor_cap = (1 - - (total_cap_sum - total_reactor_cap)/ + (total_cap_sum - total_reactor_cap) / total_cap_sum) * 100 percent_provided[reactor] = percent_reactor_cap @@ -494,4 +494,3 @@ def analyze_algorithm(df, base, proj, ar_dict): } return results - From 653c58367b320957c26a45ba0d43f80ed94396ba Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Wed, 28 Aug 2024 08:28:15 -0500 Subject: [PATCH 17/21] pep8 indendation dep script --- scripts/deployment_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/deployment_script.py b/scripts/deployment_script.py index 14b9cd6f..385c5bfc 100644 --- a/scripts/deployment_script.py +++ b/scripts/deployment_script.py @@ -222,7 +222,7 @@ def pre_det_deployment(df, base_col, ar_dict, greedy=True): # Check if the cap will be exceeded by adding # another reactor. if ar_dict[reactor][3][year] >= \ - (df.loc[year, f'num_{reactor}'] + 1): + (df.loc[year, f'num_{reactor}'] + 1): df.loc[year, f'num_{reactor}'] += 1 # Update remaining capacity to be met. cap_difference -= ar_dict[reactor][0] From aeeae01efb58568d11eb2d05e9271ccdef788dc5 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Wed, 28 Aug 2024 09:14:40 -0500 Subject: [PATCH 18/21] add reactor deployment to scripts readme --- docs/index.md | 2 +- ...ipt_doc.rst => reactor_deployment_doc.rst} | 0 ...oyment_script.py => reactor_deployment.py} | 0 scripts/scripts_README.md | 95 ++++++++++--------- ...t_script.py => test_reactor_deployment.py} | 0 5 files changed, 53 insertions(+), 44 deletions(-) rename docs/{deployment_script_doc.rst => reactor_deployment_doc.rst} (100%) rename scripts/{deployment_script.py => reactor_deployment.py} (100%) rename scripts/tests/{test_deployment_script.py => test_reactor_deployment.py} (100%) diff --git a/docs/index.md b/docs/index.md index 53ca1b72..ba60ecc4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -14,7 +14,7 @@ create_ar_deployinst_doc create_cyclus_input_doc dakota_input_doc dataframe_analysis_doc -deployment_script_doc +reactor_deployment_doc merge_coordinates_doc output_metrics_doc predicting_the_past_import_doc diff --git a/docs/deployment_script_doc.rst b/docs/reactor_deployment_doc.rst similarity index 100% rename from docs/deployment_script_doc.rst rename to docs/reactor_deployment_doc.rst diff --git a/scripts/deployment_script.py b/scripts/reactor_deployment.py similarity index 100% rename from scripts/deployment_script.py rename to scripts/reactor_deployment.py diff --git a/scripts/scripts_README.md b/scripts/scripts_README.md index ed6983c0..ba00a687 100644 --- a/scripts/scripts_README.md +++ b/scripts/scripts_README.md @@ -4,7 +4,7 @@ input files and analyze CYCLUS output files. ### analysis.py -Input : CYCLUS output file (.sqlite) +Input : CYCLUS output file (.sqlite) ``` python analysis.py [outputfile] ``` @@ -13,51 +13,51 @@ Most functions return a dictionary of lists (timeseries of a value) that can be used to plot a stacked bar chart or a line plot. ### create_input.py -Python script to create CYCLUS input files from PRIS Year-end Reator Status -Reports. Once the Report is downloaded from the PRIS Database, it must be +Python script to create CYCLUS input files from PRIS Year-end Reator Status +Reports. Once the Report is downloaded from the PRIS Database, it must be saved as ``database/Year-end Reactor Status_####.csv``, in which the ``####`` -is the four digit year the data is pulled from. Creates multiple files that -are used for a CYCLUS simulation, using functions contained in -``predicting_the_past_import.py``. Due to relative path dependancies in this +is the four digit year the data is pulled from. Creates multiple files that +are used for a CYCLUS simulation, using functions contained in +``predicting_the_past_import.py``. Due to relative path dependancies in this script, it **must** be run from the ``scripts`` directory. Input : None -User Specifications : -- line 7 : ``data_year`` (int) -- four digit year the data is pulled from, must match +User Specifications : +- line 7 : ``data_year`` (int) -- four digit year the data is pulled from, must match the year in the Year-end Reactor Status file -- line 8 : ``start_year`` (int) -- four digit year for the simulation to start on. The +- line 8 : ``start_year`` (int) -- four digit year for the simulation to start on. The simulation will start in January of that year -- line 9 : ``region`` (str) -- Region to include reactors from. Possible regions are +- line 9 : ``region`` (str) -- Region to include reactors from. Possible regions are Asia, United States, Europe, South America, North America, Africa, and All Currently, only one region can be accepted at a time - line 10 : ``project`` (str) -- directory name in ``/input/`` to contain all of the CYCLUS input files created -- line 35 : ``burnup`` (list of ints) -- list of burnup values to be used in CYCLUS simulation. +- line 35 : ``burnup`` (list of ints) -- list of burnup values to be used in CYCLUS simulation. - line 46 : cycle length of reactors (int) -- input to ``import_data.write_reactors()`` - line 47 : refueling length of reactor (int) -- input to ``import_data.write_reactors()`` -- line 58 : simulation duration (int) -- duration of simulation in months; dafault value of +- line 58 : simulation duration (int) -- duration of simulation in months; dafault value of 780 months (65 years) - line 58 : burnup of reactors in CYCLUS simulation (int) -- must be a value in ``burnups``, so that recipe files are present; default of 50 GWd/MTU -Outputs : -- ``database/reactors_pris_####.csv`` : ``.csv`` file of condensed PRIS year-end Reactor +Outputs : +- ``database/reactors_pris_####.csv`` : ``.csv`` file of condensed PRIS year-end Reactor Status information, in which ``####`` is the four digit year the data is pulled from -- ``input/project/inputs/region.xml`` : CYCLUS input file, in which ``project`` and ``region`` +- ``input/project/inputs/region.xml`` : CYCLUS input file, in which ``project`` and ``region`` are user specifications -- ``input/project/inputs/region/recipes/`` : directory containing recipe files that are read into +- ``input/project/inputs/region/recipes/`` : directory containing recipe files that are read into the CYCLUS input file, in which ``project`` and ``region`` are user specifications -- ``input/project/inputs/region/reactors'`` : directory containing input files for each of the -reactors in the selected region. Each reactor will be a separate ``.xml`` input file that -will be read into the CYCLUS input file, in which ``project`` and ``region`` are user +- ``input/project/inputs/region/reactors'`` : directory containing input files for each of the +reactors in the selected region. Each reactor will be a separate ``.xml`` input file that +will be read into the CYCLUS input file, in which ``project`` and ``region`` are user specifications - ``input/project/inputs/region/buildtimes/inclusions.xml`` : Input file that contains links -to the reactors in the region to be included in the CYLCUS simulation, in which ``project`` +to the reactors in the region to be included in the CYLCUS simulation, in which ``project`` and ``region`` are user specifications -- ``input/project/inputs/region/buildtimes/country/deployinst.xml`` : Input file of the -``DeployInst`` institution for the specified ``country`` that is read into the CYCLUS +- ``input/project/inputs/region/buildtimes/country/deployinst.xml`` : Input file of the +``DeployInst`` institution for the specified ``country`` that is read into the CYCLUS input file, in which ``project`` and ``region`` are user specifications To run: @@ -65,29 +65,38 @@ To run: python create_input.py ``` +### reactor_deployment.py +This script holds schemes to deploy reactors to meet a need over time. They do +not create cyclus input files, the outputs are dataframes. This script is not +intended to be run as a whole, the individual functions are meant to be called +in your analysis. + +Usage: + import reactor_deployment as dep + ### merge_coordinates.py -Reads in a PRIS data base, adds columns for the latitude and longitude for each -reactor with available data from the coordinates database. Reactors that do not -have available coordinates are left blank. The available database is +Reads in a PRIS data base, adds columns for the latitude and longitude for each +reactor with available data from the coordinates database. Reactors that do not +have available coordinates are left blank. The available database is ``database/coordinates.sqlite`` To run: ``` python merge_coordinates.py [pris_link] [webscrape_link] ``` -Inputs: +Inputs: - ``pris_link``: ``.csv`` file of raw reactor data -- ``webscrape_link``: SQLite data base of coordinates of reactor locations +- ``webscrape_link``: SQLite data base of coordinates of reactor locations -Outputs: -- ``reactors_pris_2016.csv`` : ``.csv`` file of reactor data, including the latitude and +Outputs: +- ``reactors_pris_2016.csv`` : ``.csv`` file of reactor data, including the latitude and longitude coordinates ### predicting_the_past_import.py -Contains functions used to create ``.xml`` input files for a CYCLUS simulation. +Contains functions used to create ``.xml`` input files for a CYCLUS simulation. To run: -``` +``` python predicting_the_past.py ``` Inputs: None @@ -95,8 +104,8 @@ Inputs: None Outputs: None ### random_lifetime_extensions.py -Function to apply lifetime extensions to reactors in a CYCLUS input, based on a Gaussian -distribution (mean = 10, standard deviation = 3 years). +Function to apply lifetime extensions to reactors in a CYCLUS input, based on a Gaussian +distribution (mean = 10, standard deviation = 3 years). To run: ``` @@ -110,30 +119,30 @@ Outputs: None Simple Cyclus output for testing purposes. ### tests/test_analysis.py -testfile for analysis.py. -To run: +testfile for analysis.py. +To run: ``` python test_analysis.py -``` +``` ### tests/test_transition_metrics.py -testfile for transition_metrics.py. -To run: +testfile for transition_metrics.py. +To run: ``` pytest test_transition_metrics.py ``` ### tests/transition_metrics_decommission_test.py -testfile for transition_metrics, with the simulation -designed to have facilities decommissioned. +testfile for transition_metrics, with the simulation +designed to have facilities decommissioned. ### tests/transition_metrics_nodecommission_test.py -testfile for transition_metrics, with the simulation -designed to not have facilities decommissioned. +testfile for transition_metrics, with the simulation +designed to not have facilities decommissioned. ### transition_metrics.py -Functions to plot and analyze data for the results in ```input/haleu```. +Functions to plot and analyze data for the results in ```input/haleu```. To run: ``` diff --git a/scripts/tests/test_deployment_script.py b/scripts/tests/test_reactor_deployment.py similarity index 100% rename from scripts/tests/test_deployment_script.py rename to scripts/tests/test_reactor_deployment.py From 6e4431927d523f9eed53791ef5d189b377e769e3 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Wed, 28 Aug 2024 09:18:23 -0500 Subject: [PATCH 19/21] fix reactor deployment import in test --- scripts/tests/test_reactor_deployment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/test_reactor_deployment.py b/scripts/tests/test_reactor_deployment.py index 0aa453fe..afef3569 100644 --- a/scripts/tests/test_reactor_deployment.py +++ b/scripts/tests/test_reactor_deployment.py @@ -5,7 +5,7 @@ import pandas as pd path = os.path.realpath(__file__) sys.path.append(os.path.dirname(os.path.dirname(path))) -import deployment_script as dep +import reactor_deployment as dep ad_reactors = { From 702554c9dbeb19aa05052b05958b1c70a96bb7bc Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Fri, 30 Aug 2024 12:33:29 -0500 Subject: [PATCH 20/21] address @LukeSeifert comments --- scripts/reactor_deployment.py | 133 +++++++++++++++++++++++----------- 1 file changed, 92 insertions(+), 41 deletions(-) diff --git a/scripts/reactor_deployment.py b/scripts/reactor_deployment.py index 385c5bfc..cbc564c1 100644 --- a/scripts/reactor_deployment.py +++ b/scripts/reactor_deployment.py @@ -22,15 +22,23 @@ def direct_decom(df, ar_dict): ar_dict: dictionary A dictionary of reactors with information of the form: {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]} + + Returns + ------- + df: pandas dataframe + The dataframe of capacity information with the decommissioned reactors. """ + # define number of years + num_years = len(df['Year']) + # now we are going to note when reactors are decommissioned for reactor in ar_dict.keys(): # create a decommissioning column df[f'{reactor}Decom'] = 0 - for year in range(len(df['Year'])): + for year in range(num_years): decom_year = year + ar_dict[reactor][2] - if decom_year >= len(df['Year']): + if decom_year >= num_years: pass else: # tracks the number of decommissioned reactors @@ -57,6 +65,11 @@ def num_react_to_cap(df, ar_dict): ar_dict: dictionary A dictionary of reactors with information of the form: {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]} + + Returns + ------- + df: pandas dataframe + The dataframe of capacity information with the new columns. """ if 'total_cap' not in df: @@ -80,6 +93,35 @@ def num_react_to_cap(df, ar_dict): return df +def reactor_columns(df, ar_dict): + """ + This function takes in a dataframe and the dictionary of reactors, + and creates columns for each reactor. + + Parameters + ---------- + df: pandas dataframe + The dataframe of capacity information. + ar_dict: dictionary + A dictionary of reactors with information of the form: + {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]} + + Returns + ------- + df: pandas dataframe + The dataframe of capacity information with columns for each reactor. + """ + + # Initialize the number of reactor columns. + for reactor in ar_dict.keys(): + if f'num_{reactor}' not in df: + df[f'num_{reactor}'] = 0 + else: + pass + + return df + + # # # # # # # # # # # # Deployment Functions # # # # # # # # # # # # 1. Greedy Algorithm: deploy the largest reactor first at each time step, fill # in the remaining capacity with the next smallest, and so on. @@ -110,13 +152,15 @@ def greedy_deployment(df, base_col, ar_dict): ar_dict: dictionary A dictionary of reactors with information of the form: {reactor: [Power (MWe), capacity_factor (%), lifetime (yr)]} + + Returns + ------- + df: pandas dataframe + The dataframe of capacity information with the deployed reactors. """ - for reactor in ar_dict.keys(): - if f'num_{reactor}' not in df: - df[f'num_{reactor}'] = 0 - else: - pass + # Initialize the number of reactor columns. + df = reactor_columns(df, ar_dict) for year in range(len(df[base_col])): remaining_cap = df[base_col][year].copy() @@ -152,6 +196,8 @@ def pre_det_deployment(df, base_col, ar_dict, greedy=True): 2) linear (greedy=False): wherein the capped reactors are cyclically deployed until they hit their individual cap. + Parameters + ---------- df: pandas dataframe The dataframe of capacity information. base_col: str @@ -168,13 +214,14 @@ def pre_det_deployment(df, base_col, ar_dict, greedy=True): greedy: bool A True/False value that determines whether the initial deployment is greedy or linear. + + Returns + ------- + df: pandas dataframe + The dataframe of capacity information with the deployed reactors. """ # initialize the number of reactor columns - for reactor in ar_dict.keys(): - if f'num_{reactor}' not in df: - df[f'num_{reactor}'] = 0 - else: - pass + df = reactor_columns(df, ar_dict) if greedy is True: for year in range(len(df[base_col])): @@ -276,14 +323,15 @@ def rand_deployment(df, base_col, ar_dict, The capacity tolerance to which reactors are deployed in the complete deployment case (i.e., when rough=False). Without this, convergence is tricky to achieve. + + Returns + ------- + df: pandas dataframe + The dataframe of capacity information with the deployed reactors. """ # initialize the number of reactor columns - for reactor in ar_dict.keys(): - if f'num_{reactor}' not in df: - df[f'num_{reactor}'] = 0 - else: - pass + df = reactor_columns(df, ar_dict) for year in range(len(df[base_col])): years_capacity = df[base_col][year] @@ -312,7 +360,7 @@ def rand_deployment(df, base_col, ar_dict, elif rough is False: # for a more accurate, but much much longer run # todo, finish this ensuring it can converge - print('This feature is unstable.') + raise NotImplementedError('This feature is unstable.') continue else: df.loc[year, f'num_{deployed}'] += 1 @@ -329,7 +377,7 @@ def rand_deployment(df, base_col, ar_dict, return df -def rand_greedy_deployment(df, base_col, ar_dict, set_seed): +def rand_greedy_deployment(df, base_col, ar_dict, set_seed=False): """ This function combines the rough random and greedy deployments to fill in any gaps caused by the roughness. @@ -347,13 +395,14 @@ def rand_greedy_deployment(df, base_col, ar_dict, set_seed): set_seed: bool A True/False value that determines whether the seed used for the random number is set or varies based on time. + + Returns + ------- + df: pandas dataframe + The dataframe of capacity information with the deployed reactors. """ # Initialize the number of reactor columns. - for reactor in ar_dict.keys(): - if f'num_{reactor}' not in df: - df[f'num_{reactor}'] = 0 - else: - pass + df = reactor_columns(df, ar_dict) # First we will apply the rough random. df = rand_deployment(df, base_col, ar_dict, set_seed, rough=True) @@ -438,23 +487,25 @@ def analyze_algorithm(df, base, proj, ar_dict): Returns ------- - above_count: int - The number of times the deployed capacity exceeds desired capacity. - below_count: int - The number of times the deployed capacity is below desired capacity. - equal_count: int - The number of times the deployed capacity equals desired capacity. - above_percentage: float - The percent of times the deployed capacity exceeds desired capacity. - below_percentage: float - The percent of times the deployed capacity is below desired - capacity. - total_above: int - The excess of deployed capacity. - total_below: int - The dearth of deployed capacity. - percent_provided: dict - The percent of the deployed capacity that comes from each reactor. + results: dict + A dictionary of the results of the analysis. + above_count: int + The number of times the deployed capacity exceeds desired capacity. + below_count: int + The number of times the deployed capacity is below desired capacity. + equal_count: int + The number of times the deployed capacity equals desired capacity. + above_percentage: float + The percent of times the deployed capacity exceeds desired capacity. + below_percentage: float + The percent of times the deployed capacity is below desired + capacity. + total_above: int + The excess of deployed capacity. + total_below: int + The dearth of deployed capacity. + percent_provided: dict + The percent of the deployed capacity that comes from each reactor. """ df['difference'] = df.apply(simple_diff, base=base, proj=proj, axis=1) From 33740d44d443a4b2871a5550c95ee5e29e211dc2 Mon Sep 17 00:00:00 2001 From: Nathan Ryan Date: Fri, 30 Aug 2024 12:40:46 -0500 Subject: [PATCH 21/21] pep8 line shortening --- scripts/reactor_deployment.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/reactor_deployment.py b/scripts/reactor_deployment.py index cbc564c1..ec46e49e 100644 --- a/scripts/reactor_deployment.py +++ b/scripts/reactor_deployment.py @@ -492,11 +492,13 @@ def analyze_algorithm(df, base, proj, ar_dict): above_count: int The number of times the deployed capacity exceeds desired capacity. below_count: int - The number of times the deployed capacity is below desired capacity. + The number of times the deployed capacity is below + desired capacity. equal_count: int The number of times the deployed capacity equals desired capacity. above_percentage: float - The percent of times the deployed capacity exceeds desired capacity. + The percent of times the deployed capacity exceeds + desired capacity. below_percentage: float The percent of times the deployed capacity is below desired capacity.