diff --git a/landbosse/model/ErectionCost.py b/landbosse/model/ErectionCost.py index 53257d6c..d2059a32 100644 --- a/landbosse/model/ErectionCost.py +++ b/landbosse/model/ErectionCost.py @@ -865,9 +865,10 @@ def aggregate_erection_costs(self): Returns ------- - (pd.DataFrame, pd.DataFrame) - Two dataframes: First, utilizing the same crane for base and topping. - Second, utilizing separate cranes for base and topping + Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame] + Two dataframes: First, utilizing the separate cranes for base and topping. + Second, utilizing same crane for base and topping, + Third is crew cost. """ join_wind_operation = self.output_dict['join_wind_operation'] overtime_multiplier = self.input_dict['overtime_multiplier'] @@ -925,6 +926,7 @@ def aggregate_erection_costs(self): crew_cost_grouped = crew_cost.groupby(['Crew type ID', 'Operation']).sum().reset_index() # merge crane data with grouped crew costs + possible_crane_cost = pd.merge(possible_crane_cost, crew_cost_grouped, on=['Crew type ID', 'Operation']) # calculate labor costs diff --git a/post_processing_scripts/extract_crane_choice.py b/post_processing_scripts/extract_crane_choice.py new file mode 100644 index 00000000..417f5d1f --- /dev/null +++ b/post_processing_scripts/extract_crane_choice.py @@ -0,0 +1,119 @@ +import pandas as pd + +# The extended_landbosse_details dataframe includes all the details along side +# all the project list inputs +print("Reading extended details...") +df = pd.read_csv("extended_landbosse_details.csv") + +# Extract the crane choice data +print("Selecting erection data...") +erection_df = df.query("`Module` == 'ErectionCost'")[[ + "Project ID with serial", + "Variable name", + "Numeric value", + "Non-numeric value", + "Number of turbines", + "Turbine rating MW", + "Hub height m", + "Labor cost multiplier", + "Crane breakdown fraction", + "Breakpoint between base and topping (percent)", + "Total project construction time (months)" +]] + +aligned_erection_rows = [] + +print("Selecting unique projects...") +unique_project_id_with_serial = erection_df['Project ID with serial'].unique() + +print("Rearranging crane detail data from rows into columns...") +for project_id_with_serial in unique_project_id_with_serial: + print(f"\t{project_id_with_serial}") + + # Crane data output + crane_data_df = erection_df.query( + "`Project ID with serial` == @project_id_with_serial and `Variable name` == 'crane_data_output: crane_boom_operation_concat - variable - value'" + ) + top_wind_multiplier_row = crane_data_df[crane_data_df["Non-numeric value"].str.contains("Top - Wind multiplier")] + base_wind_multiplier_row = crane_data_df[crane_data_df["Non-numeric value"].str.contains("Base - Wind multiplier")] + offload_wind_multiplier_row = crane_data_df[crane_data_df["Non-numeric value"].str.contains("Offload - Wind multiplier")] + top_wind_multiplier = top_wind_multiplier_row["Numeric value"].values[0] + offload_wind_multiplier = offload_wind_multiplier_row["Numeric value"].values[0] + if len(base_wind_multiplier_row) > 0: + base_wind_multiplier = base_wind_multiplier_row["Numeric value"].values[0] + else: + base_wind_multiplier = None + + # Re-using crane_data_df from above, operation time for all turbines + top_operation_time_hours_row = crane_data_df[ + crane_data_df["Non-numeric value"].str.contains("Top - Operation time all turbines hrs")] + offload_operation_time_hours_row = crane_data_df[ + crane_data_df["Non-numeric value"].str.contains("Offload - Operation time all turbines hrs")] + base_operation_time_hours_row = crane_data_df[ + crane_data_df["Non-numeric value"].str.contains("Base - Operation time all turbines hrs")] + top_operation_time_hours = top_operation_time_hours_row["Numeric value"].values[0] + offload_operation_time_hours = offload_operation_time_hours_row["Numeric value"].values[0] + if len(base_operation_time_hours_row) > 0: + base_operation_time_hours = base_operation_time_hours_row["Numeric value"].values[0] + else: + base_operation_time_hours = None + + # Crane cost details + crane_cost_df = erection_df.query( + "`Project ID with serial` == @project_id_with_serial and `Variable name` == 'crane_cost_details: Operation ID - Type of cost - Cost'" + ) + top_total_cost_row = crane_cost_df[crane_cost_df["Non-numeric value"].str.contains("Top - Total cost USD")] + base_total_cost_row = crane_cost_df[crane_cost_df["Non-numeric value"].str.contains("Base - Total cost USD")] + offload_total_cost_row = crane_cost_df[crane_cost_df["Non-numeric value"].str.contains("Offload - Total cost USD")] + top_total_cost = top_total_cost_row["Numeric value"].values[0] + offload_total_cost = offload_total_cost_row["Numeric value"].values[0] + if len(base_total_cost_row) > 0: + base_total_cost = base_total_cost_row["Numeric value"].values[0] + else: + base_total_cost = None + + # Crane choice + crane_choice_rows_df = erection_df.query( + "`Project ID with serial` == @project_id_with_serial and `Variable name` == 'crane_choice: Crew name - Boom system - Operation'" + ) + top_row = crane_choice_rows_df[crane_choice_rows_df["Non-numeric value"].str.contains("Top")] + base_row = crane_choice_rows_df[crane_choice_rows_df["Non-numeric value"].str.contains("Base")] + offload_row = crane_choice_rows_df[crane_choice_rows_df["Non-numeric value"].str.contains("Offload")] + offload = " ".join(offload_row["Non-numeric value"].values[0].split(" - ")[:-1]) + top = " ".join(top_row["Non-numeric value"].values[0].split(" - ")[:-1]) + if len(base_row) > 0: + base = " ".join(base_row["Non-numeric value"].values[0].split(" - ")[:-1]) + else: + base = None + + aligned_erection_row = { + "Project ID with serial": project_id_with_serial, + "Number of turbines": top_row["Number of turbines"].values[0], + "Breakpoint between base and topping (percent)": \ + top_row["Breakpoint between base and topping (percent)"].values[0], + "Turbine rating MW": top_row["Turbine rating MW"].values[0], + "Crane breakdown fraction": top_row["Crane breakdown fraction"].values[0], + "Labor cost multiplier": top_row["Labor cost multiplier"].values[0], + "Hub height m": top_row["Hub height m"].values[0], + "Base crane choice": base, + "Offload crane choice": offload, + "Top crane choice": top, + "Base total cost": + round(float(base_total_cost), 0) if base_total_cost is not None else None, + "Offload total cost": round(float(offload_total_cost), 0), + "Top total cost": round(float(top_total_cost), 0), + "Base wind multiplier": + round(float(base_wind_multiplier), 2) if base_wind_multiplier is not None else None, + "Offload wind multiplier": round(float(offload_wind_multiplier), 2), + "Top wind multiplier": round(float(top_wind_multiplier), 2), + "Base operation time all turbines (hours)": + round(float(base_operation_time_hours), 0) if base_operation_time_hours is not None else None, + "Offload operation time all turbines (hours)": round(float(offload_operation_time_hours), 0), + "Top operation time all turbines (hours)": round(float(top_operation_time_hours), 0) + } + + aligned_erection_rows.append(aligned_erection_row) + +print("Writing crane choices...") +aligned_crane_choice_df = pd.DataFrame(aligned_erection_rows) +aligned_crane_choice_df.to_csv("crane_details.csv", index=False) diff --git a/post_processing_scripts/sql_queries/everything_against_baseline.sql b/post_processing_scripts/sql_queries/everything_against_baseline.sql deleted file mode 100644 index 77d5e20c..00000000 --- a/post_processing_scripts/sql_queries/everything_against_baseline.sql +++ /dev/null @@ -1,47 +0,0 @@ -WITH baseline AS (SELECT - "Project ID with serial" AS "Baseline project ID with serial", - "Module", - "Type of cost", - ROUND("Cost per turbine"::numeric, 0) AS "Baseline $/turbine", - ROUND("Cost per project"::numeric, 0) AS "Baseline $/project", - ROUND("Cost per kW"::numeric, 0) AS "Baseline $/kW", - "Turbine rating MW" AS "Baseline turbine rating (MW)", - "Hub height m" AS "Baseline hub height", - "Labor cost multiplier" AS "Baseline labor cost multiplier", - "Crane breakdown fraction" AS "Baseline crane breakdown fraction", - ROUND("Number of turbines"::numeric * "Turbine rating MW"::numeric, -1) AS "Baseline plant size (MW)" -FROM - landbosse_costs -WHERE - ROUND("Number of turbines"::numeric * "Turbine rating MW"::numeric, -1) = 150 - AND "Hub height m" = 90 - AND "Turbine rating MW" = 2.5 - AND "Crane breakdown fraction" = 0 - AND "Labor cost multiplier" = 1.0 -ORDER BY 1, 2, 3) - -SELECT - lc."Project ID with serial", - lc."Module", - lc."Type of cost", - ROUND(lc."Cost per turbine"::numeric, 0) AS "$/turbine", - ROUND(lc."Cost per project"::numeric, 0) AS "$/project", - ROUND(lc."Cost per kW"::numeric, 0) AS "$/kW", - b."Baseline $/turbine", - b."Baseline $/project", - b."Baseline $/kW", - lc."Turbine rating MW" AS "Turbine rating (MW)", - lc."Hub height m", - lc."Labor cost multiplier", - lc."Crane breakdown fraction", - ROUND(lc."Number of turbines"::numeric * lc."Turbine rating MW"::numeric, -1) AS "Plant size (MW)", - b."Baseline turbine rating (MW)", - b."Baseline hub height", - b."Baseline labor cost multiplier", - b."Baseline crane breakdown fraction", - b."Baseline plant size (MW)" -FROM landbosse_costs lc -JOIN baseline b - ON b."Module" = lc."Module" - AND b."Type of cost" = lc."Type of cost" -ORDER BY 1, 2, 3; \ No newline at end of file diff --git a/setup.py b/setup.py index 5677de0b..477a0c94 100644 --- a/setup.py +++ b/setup.py @@ -28,8 +28,6 @@ 'scipy', 'xlsxwriter', 'xlrd', - 'psycopg2-binary', - 'sqlalchemy', 'pytest' ], command_options={