Working on timing optimization
This commit is contained in:
parent
3cecb59560
commit
71af838e03
@ -1,4 +1,5 @@
|
||||
library(tidyverse)
|
||||
library(lpSolve)
|
||||
##Value from table C-2 of Holtec report, cost categories
|
||||
#"Initial Annual Estimated Costs and 2019 Constant Dollar Values for the Various Activities for the Proposed CISF and the No-Action Alternative"
|
||||
|
||||
@ -8,21 +9,31 @@ library(tidyverse)
|
||||
#PHASE_SIZE <- 5000
|
||||
#ST_CAP <- 8680
|
||||
#TRANSPORT_COST_RATIO <- 155462880/5000 # or 269883561/8680 since transportation cost scale linearly
|
||||
#VOLUME <- 10^5/2+480
|
||||
#VOLUME <- 10
|
||||
#TRANS_CONSTRAINT <- (ST_CAP+5000*19)/19
|
||||
#PHASES_ADDED <- max(ceiling((VOLUME-ST_CAP)/PHASE_SIZE),0) #Make sure added phases are not negative
|
||||
|
||||
#STARTING_VOLUME=8680
|
||||
#PHASE_CONST_COST=103399272
|
||||
#DISCOUNT <- 0.05
|
||||
#VOLUME <- 8660+5000
|
||||
#PHASES_ADDED <- 1
|
||||
#DECOM_COST_PER_TON =24822656/5000
|
||||
#155462880/10^9
|
||||
OPTIMAL_COST <- function(PHASES_ADDED,VOLUME,CURRENT_YEAR,DISCOUNT=0.05,STARTING_VOLUME=8680,PHASE_SIZE=5000,END_YEAR=40,PHASE_CONST_COST=103399272,TRANSPORT_COST_RATIO=155462880/5000,TRANS_CONSTRAINT =(8680+5000*19)/19,DECOM_COST_PER_TON =24822656/5000,INFLATION_ADJUST=1.2874){
|
||||
ADDED_VOLUME=max(VOLUME-STARTING_VOLUME,0)
|
||||
ADDED_VOLUME
|
||||
STARTING_VOLUME
|
||||
VOLUME
|
||||
if(ADDED_VOLUME/PHASE_SIZE>PHASES_ADDED){stop("Not enough capacity for the requested volume")}
|
||||
###Construction Cost to cover supplied SNF volume
|
||||
CONSTRUCT_COST <- PHASES_ADDED*PHASE_CONST_COST
|
||||
#Cost to transport SNF from reactors to the CIFS in the current year and to repository at end of project period
|
||||
SHIPPING_TIME<- VOLUME/TRANS_CONSTRAINT
|
||||
VOLUME/TRANS_CONSTRAINT
|
||||
SHIPPING_YEARS <- ceiling(SHIPPING_TIME )
|
||||
if(SHIPPING_YEARS>END_YEAR-CURRENT_YEAR){stop("Not enough time to ship the requested SNF volume")}
|
||||
AT_CAPACITY_VOLUME <- TRANS_CONSTRAINT*floor(SHIPPING_TIME )
|
||||
UNDER_CAPACITY_VOLUME <- VOLUME-AT_CAPACITY_VOLUME
|
||||
AT_CAPACITY_VOLUME <- TRANS_CONSTRAINT
|
||||
UNDER_CAPACITY_VOLUME <- VOLUME-(SHIPPING_YEARS-1)*AT_CAPACITY_VOLUME
|
||||
SHIPPING_SCHEDULE_OUT <- rep(AT_CAPACITY_VOLUME,SHIPPING_YEARS)
|
||||
if(UNDER_CAPACITY_VOLUME!=0){SHIPPING_SCHEDULE_OUT[1] <- UNDER_CAPACITY_VOLUME}
|
||||
SHIPPING_SCHEDULE_OUT <- TRANSPORT_COST_RATIO*SHIPPING_SCHEDULE_OUT
|
||||
@ -40,7 +51,6 @@ if(ADDED_VOLUME/PHASE_SIZE>PHASES_ADDED){stop("Not enough capacity for the reque
|
||||
TOTAL_COST <- TOTAL_COST*INFLATION_ADJUST
|
||||
return(TOTAL_COST)
|
||||
}
|
||||
OPTIMAL_COST(20,10^4,20)
|
||||
|
||||
CHECK_FEASIBLE_SHIPPING <- function(VOLUME,ST_YEAR){
|
||||
RESULT <- try(OPTIMAL_COST(10^5,VOLUME,ST_YEAR),silent=TRUE)
|
||||
@ -60,11 +70,6 @@ FIND_FEASIBLE_LIMIT <- function(STARTING_TIME){
|
||||
}
|
||||
SHIPPING_CAPACITY_LIMITS <- cbind(1:40,sapply(1:40,FIND_FEASIBLE_LIMIT)) %>% as_tibble %>% rename(Year=V1,Max_Capacity=V2)
|
||||
SHIPPING_CAPACITY_LIMITS %>% print(n=100)
|
||||
REACTOR_VALUES <- readRDS("Data/Cleaned_Data/Reactor_Values.Rds")
|
||||
C_VALUES <- REACTOR_VALUES %>% filter(Year==2026+40,Discount==0.05)
|
||||
C_VALUES
|
||||
TBL <- CURRENT
|
||||
CIFS_SIZE <- ST_CAP
|
||||
MAX_REV <- function(TBL,CIFS_SIZE){
|
||||
# TBL <- TBL %>% filter(Year==YEAR,Discount==DISCOUNT,Revenue/Total_Tons>SHIPPING_COST)
|
||||
REV <- TBL %>% pull(Revenue)
|
||||
@ -72,11 +77,7 @@ MAX_REV <- function(TBL,CIFS_SIZE){
|
||||
RES <- lp(direction = "max", objective.in = REV, const.mat = matrix(VOL, nrow = 1,byrow=TRUE),const.dir = "<=", const.rhs = CIFS_SIZE, all.bin = TRUE)
|
||||
return(RES)
|
||||
}
|
||||
ST_CAP <- 8680
|
||||
PHASE_SIZE <- 5000
|
||||
|
||||
RES <-
|
||||
names(RES)
|
||||
PROFIT_EST <- function(ADDED_PHASES,ST_YEAR,YEARS_AHEAD,DATA=REACTOR_VALUES,DISCOUNT_RATE=0.05,ST_CAP=8680,PHASE_SIZE=5000){
|
||||
CURRENT <- DATA%>% filter(Year==ST_YEAR+YEARS_AHEAD,Discount==DISCOUNT_RATE)
|
||||
RES <- MAX_REV(CURRENT,ST_CAP+PHASE_SIZE*ADDED_PHASES)
|
||||
@ -85,19 +86,54 @@ PROFIT_EST <- function(ADDED_PHASES,ST_YEAR,YEARS_AHEAD,DATA=REACTOR_VALUES,DISC
|
||||
PROFIT <- rbind(REVENUE,OPTIMAL_COST(ADDED_PHASES,TONS_STORED,YEARS_AHEAD))
|
||||
return(PROFIT)
|
||||
}
|
||||
MAX_REV(CURRENT,ST_CAP+PHASE_SIZE*1)
|
||||
|
||||
OPTIMAL_COST(0,TONS_STORED,YEARS_AHEAD)
|
||||
t(sapply(0:3,PROFIT_EST,ST_YEAR=2026,YEARS_AHEAD=15)/10^6) %>% as_tibble %>% rename(Rev=V1,Cost=V2) %>% mutate(Profit=Rev-Cost)
|
||||
REACTOR_VALUES <- readRDS("Data/Cleaned_Data/Reactor_Values.Rds")
|
||||
#ADDED <- 1
|
||||
#ADD_RES <- MAX_REV(CURRENT,8680+5000*ADDED)
|
||||
#REACTOR_DATA <- CURRENT
|
||||
#STARTING_YEAR <- 2026
|
||||
#YEARS_AHEAD=20
|
||||
#STARTING_CAP=8680
|
||||
#SINGLE_PHASE_CAP=5000
|
||||
#ADDED_UNITS <- 1
|
||||
#Find the optimal profit and cost, plus if the capacity constraint of an addtion in binding.
|
||||
ADDITION_CHECK <- function(REACTOR_DATA,ADDED_UNITS,YEARS_AHEAD,Discount_Rate=0.05,STARTING_CAP=8680,SINGLE_PHASE_CAP=5000){
|
||||
OPTIM_GUESS <- MAX_REV(REACTOR_DATA,STARTING_CAP+SINGLE_PHASE_CAP*ADDED_UNITS)
|
||||
SELECTED_REACTORS <- REACTOR_DATA[which(ADD_RES$solution==1),]%>% mutate(MARGINAL_VALUE=Revenue/Total_Tons)
|
||||
FOUND_VOLUME <- OPTIM_GUESS$constraint[76]
|
||||
LOWEST_VALUE_REACTOR <-SELECTED_REACTORS[SELECTED_REACTORS$MARGINAL_VALUE== min(SELECTED_REACTORS$MARGINAL_VALUE),]
|
||||
MARGINAL_VALUE <- LOWEST_VALUE_REACTOR$MARGINAL_VALUE
|
||||
FULL_COST_AT_CAPACITY <- OPTIMAL_COST(ADDED_UNITS,FOUND_VOLUME,YEARS_AHEAD)
|
||||
MARGINAL_COST <- FULL_COST_AT_CAPACITY -OPTIMAL_COST(ADDED_UNITS,FOUND_VOLUME-1,YEARS_AHEAD)
|
||||
BOUNDED <- MARGINAL_VALUE>MARGINAL_COST
|
||||
if(BOUNDED){
|
||||
FOUND_VOLUME <- FOUND_VOLUME-STARTING_CAP
|
||||
State <- "Capacity Constrainted"
|
||||
Optimal_Rev <- OPTIM_GUESS$objval
|
||||
Optimal_Cost <- FULL_COST_AT_CAPACITY
|
||||
}
|
||||
else {
|
||||
HIGHEST_VALUE_REACTOR <-SELECTED_REACTORS[SELECTED_REACTORS$MARGINAL_VALUE== max(SELECTED_REACTORS$MARGINAL_VALUE),]
|
||||
MARGINAL_VALUE <- unique(HIGHEST_VALUE_REACTOR$MARGINAL_VALUE)
|
||||
if(MARGINAL_VALUE>=MARGINAL_COST){
|
||||
State <- "Not a Profitable Phase"
|
||||
FOUND_VOLUME <- 0
|
||||
OPTIM_STARTING <- MAX_REV(REACTOR_DATA,STARTING_CAP)
|
||||
Optimal_Rev <- OPTIM_STARTING$objval
|
||||
Optimal_Cost <- OPTIMAL_COST(0,STARTING_CAP,YEARS_AHEAD)
|
||||
}else{
|
||||
State <- "No Binding Constraints"
|
||||
FOUND_VOLUME <- NA
|
||||
Optimal_Rev <- NA
|
||||
Optimal_Cost <- NA
|
||||
|
||||
RES$solution
|
||||
names(RES)
|
||||
length(RES$objective)
|
||||
|
||||
CURRENT[RES[[9]],]
|
||||
CURRENT[-RES[[9]],]
|
||||
|
||||
REACTOR_VALUES %>% filter(Year=[RES[[9]],]
|
||||
}
|
||||
|
||||
}
|
||||
Profit <- Optimal_Rev-Optimal_Cost
|
||||
return(c(ADDED_UNITS,State,FOUND_VOLUME,Profit,Optimal_Rev,Optimal_Cost))
|
||||
}
|
||||
#Note for self: By running addition's from 1 to 20 (Roughly) at the same number of years ahead the number of 5000 unit addtions which maximizes profit in that year can be found. It looks like at least 22 units will be built which is enough for the whole US, but the timing of addtions needs to be worked out by backwards induction using the years.
|
||||
ADDITION_CHECK(CURRENT,22,1)
|
||||
|
||||
|
||||
68
Scripts/Reactor_Clean.r
Normal file
68
Scripts/Reactor_Clean.r
Normal file
@ -0,0 +1,68 @@
|
||||
#A script which attempts to pull in all data, and create a data frame with the maximum revenue values for each facility, year and discount rate. The output can then be used to make figures and graphs
|
||||
library(tidyverse)
|
||||
library(parallel)
|
||||
NCORES <- detectCores()-1
|
||||
library(lpSolve) #For solving discrete value maximization for the power plants
|
||||
####Manual inputs
|
||||
#Range of discount rates to calculate in the model. Each facility will have each rate calculated, so more values slows the results but allows for more discount rates to be reported in the findings.
|
||||
DISCOUNT_RATE_LIST <- seq(0.01,0.15,by=0.0025)
|
||||
#The cost per ton of shipping uranium, used to see what can be shipped on day one of the project.
|
||||
CV <- 1.2874*(6984013) #Data from New Mexico Report, Converted from 2019 to Dec 2025
|
||||
#Locations to save results
|
||||
SAVE_DIR <- "./Data/Cleaned_Data/"
|
||||
#Create any need save locations
|
||||
dir.create(SAVE_DIR,recursive=TRUE,showWarnings=FALSE)
|
||||
TOTAL <- read_csv("Data/Raw_Data/Curie_Spent_Fuel_Site_Totals.csv") %>% mutate(OP_YEAR=year(Op_Date_Min),CLOSE_YEAR=year(Close_Date_Max))%>% select(Facility,Total_Assemblies,Total_Tons,OP_YEAR,CLOSE_YEAR)
|
||||
FACILITY_LIST <- TOTAL %>% pull(Facility)
|
||||
#https://www.nrc.gov/reactors/operating/licensing/renewal/subsequent-license-renewal
|
||||
SUBMITTED <-rbind(c(FACILITY_LIST[str_detect(FACILITY_LIST,"Duane*" )],2025),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Nine Mile*" )],2026),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Ginna*" )],2026),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Cooper*" )],2026),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Farley*" )],2027),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Prairie*" )],2027),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Brunswick*" )],2027),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Cook" )],2027),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Hope" )],2027),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Salem" )],2027),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Perry" )],2027),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Millstone" )],2028),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Palisades" )],2028),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Beaver" )],2028),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Callaway" )],2029),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Three Mile Island" )],2029),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Davis-Besse" )],2029),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Wolf" )],2030),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Lucie" )],2021),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Robinson" )],2025),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Hatch" )],2025))
|
||||
SUBMITTED <- SUBMITTED %>% as_tibble
|
||||
colnames(SUBMITTED ) <- c("Facility","App_Date","Status")
|
||||
SUBMITTED <- SUBMITTED%>% mutate(Status="Applied",App_Date=as.numeric(App_Date)) %>% select(Facility,Status,App_Date)
|
||||
|
||||
#Issued
|
||||
RENEWED <- rbind(c(FACILITY_LIST[str_detect(FACILITY_LIST,"Turkey" )],"Granted",2018,2033),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Peach" )],"Granted",2019,2034),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Surry" )],"Granted",2020,2033),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"North" )],"Granted",2021,2040),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Monticello" )],"Granted",2024,2030),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Oconee" )],"Granted",2025,2034),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Summer" )],"Granted",2025,2042),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Beach" )],"Granted",2025,2033),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Browns" )],"Granted",2025,2036),
|
||||
c(FACILITY_LIST[str_detect(FACILITY_LIST,"Dresden" )],"Granted",2025,2031))
|
||||
RENEWED <- RENEWED %>% as_tibble
|
||||
colnames(RENEWED) <- c("Facility","Status","App_Date","Op_Date")
|
||||
RENEWED <- RENEWED %>% mutate(Op_Date=as.numeric(Op_Date),App_Date=as.numeric(App_Date))
|
||||
AVG_LENGTH <- RENEWED %>% mutate(DIFF=Op_Date-App_Date) %>% pull(DIFF) %>% mean %>% round
|
||||
SUBMITTED <- SUBMITTED %>% mutate(Op_Date=App_Date+AVG_LENGTH)
|
||||
UPDATE <- rbind(RENEWED,SUBMITTED )
|
||||
TOTAL_ORIG <- TOTAL
|
||||
TOTAL <- TOTAL %>% left_join(UPDATE) %>% mutate(CLOSE_YEAR=ifelse(Op_Date>CLOSE_YEAR & !is.na(Status),Op_Date,CLOSE_YEAR)) %>% select(-Status,-App_Date,-Op_Date)
|
||||
source("./Scripts/Functions/NPV_Functions.r")
|
||||
TOTAL_VALUE_METRICS <- MULTI_DISCOUNT_RATE_NPV(DISCOUNT_RATE_LIST,TOTAL ,DOLLARS_SAVED_PER_YEAR=CV)%>% left_join(read_csv("Data/Raw_Data/Curie_Spent_Fuel_Site_Totals.csv")) %>% select(Year,Facility,Discount,Total_Tons,Revenue)
|
||||
TOTAL_VALUE_METRICS_ORIG <- MULTI_DISCOUNT_RATE_NPV(DISCOUNT_RATE_LIST,TOTAL_ORIG ,DOLLARS_SAVED_PER_YEAR=CV) %>% left_join(read_csv("Data/Raw_Data/Curie_Spent_Fuel_Site_Totals.csv")) %>% select(Year,Facility,Discount,Total_Tons,Revenue)
|
||||
TOTAL_VALUE_METRICS_ORIG
|
||||
saveRDS(TOTAL_VALUE_METRICS ,paste0(SAVE_DIR,"Reactor_Values.Rds"))
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user