Working on code updates

This commit is contained in:
Alex Gebben Work 2026-02-03 17:02:46 -07:00
parent a58e82a8e1
commit 748ad694a3
2 changed files with 188 additions and 8 deletions

View File

@ -5,7 +5,7 @@ library(parallel)
library(lpSolve) #For solving discrete value maximization for the power plants
####Manual inputs
#DISCOUNT_RATE_LIST <- seq(0,1,by=0.0025)
DISCOUNT_RATE_LIST <- c(0.03,0.04,0.045,0.05,0.07,0.1)
DISCOUNT_RATE_LIST <- c(0.03,0.05,0.07,0.1)
SHIPPING_COST_PER_TON <- 1.2874*26000 #Inflation adjusted from New Mexico Report
CV1 <- 1.3074*(10607030-1060703) #Data from Texas Report, converted from 2018 to Dec 2025 dollars
CV2 <- 1.2874*(6984013-1117442) #Data from New Mexico Report, Converted from 2019 to Dec 2025
@ -14,10 +14,11 @@ CV3 <- mean(CV1,CV2) #Average of the two
###################################Cost results
#source("Cost_Data_Proc.r")
CIFS <- rbind(readRDS("Data/Cleaned_Data/Texas_CIFS_Costs.Rds"),readRDS("Data/Cleaned_Data/New_Mexico_CIFS_Costs.Rds"))
#Adjust for inflation
CIFS[,-1:-5] <- 1.2874*CIFS[,-1:-5]
COSTS <- do.call(rbind,lapply(DISCOUNT_RATE_LIST ,function(DISCOUNT){CIFS %>% group_by(Location,Capacity,Cost_Assumption) %>% mutate(NPC=Total/(1+DISCOUNT)^Year) %>% summarize(Discount=DISCOUNT,Costs=sum(NPC))})) %>% ungroup
TEMP <- COSTS%>% group_by(Location,Cost_Assumption,Discount) %>% summarize(ST_COST=min(Costs),ST_CAPACITY=min(Capacity),M_COST=(max(Costs)-min(Costs))/(max(Capacity)-min(Capacity))) %>% ungroup
CAPACITY_INCREMENT <- 5000
#rm(COST_DATA)
for(i in 1:nrow(TEMP)){
@ -34,15 +35,18 @@ for(i in 1:nrow(TEMP)){
if(!exists("COST_DATA")){COST_DATA <- C_RES}else{COST_DATA<- rbind(COST_DATA,C_RES)}
}
saveRDS(COST_DATA ,"Data/Cleaned_Data/All_CIFS_Discounted_Costs.Rds")
COST_DATA <- COST_DATA %>% filter(Cost_Assumption=='Average') %>% select(-Cost_Assumption) %>% unique
#COST_DATA <- COST_DATA %>% filter(Cost_Assumption=='Average') %>% select(-Cost_Assumption) %>% unique
COST_DATA <- COST_DATA %>% filter(Cost_Assumption=='High') %>% select(-Cost_Assumption) %>% unique
##All unique capacity levels that the revenues need to be calculated for
CAPACITY_LIST <- COST_DATA %>% pull(Capacity) %>% unique
###
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
TOTAL
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)
#!!!!!!!!!!!!#####TEST OF VARIABLITY IN CLOSING YEAR, CHANGE OR FORMALIZE LATER
#TOTAL <- TOTAL %>% mutate(CLOSE_YEAR=ifelse(CLOSE_YEAR>2018,CLOSE_YEAR+20,CLOSE_YEAR))
###########Series of functions to calculate the gross consumer surplus from a CIFS for each facility, in each year from 1960 to 2082.
@ -72,7 +76,7 @@ MULTI_DISCOUNT_RATE_NPV <- function(DISCOUNT_INCREMENT,DATA=TOTAL,YEARS=1960:208
TOTAL_VALUE_METRICS <- MULTI_DISCOUNT_RATE_NPV(DISCOUNT_RATE_LIST ,DOLLARS_SAVED_PER_YEAR=CV2)
TOTAL_VALUE_METRICS <- TOTAL_VALUE_METRICS %>% filter(!(Facility %in% c("Palo Verde","Vogtle")))#These facilities always have a negative NPV by the end date 2083
#TOTAL_VALUE_METRICS <- TOTAL_VALUE_METRICS %>% filter(!(Facility %in% c("Palo Verde","Vogtle")))#These facilities always have a negative NPV by the end date 2083
TOTAL_VALUE_METRICS <- TOTAL_VALUE_METRICS %>% left_join(read_csv("Data/Raw_Data/Curie_Spent_Fuel_Site_Totals.csv")) %>% select(Year,Facility,Discount,Total_Tons,Revenue)
#Function to find the maximum Revenue BUT it does not take dollars just relative savings
@ -96,13 +100,21 @@ YEARLY_RESULTS <- function(DATA,DISCOUNT,CAPACITY,SHIPPING_COSTS=0){
Rev_No_Shipping <- do.call(rbind,mclapply(CAPACITY_LIST,function(CAPACITY){do.call(rbind,lapply(DISCOUNT_RATE_LIST,function(x){YEARLY_RESULTS(TOTAL_VALUE_METRICS,x,CAPACITY,0)}))},mc.cores=min(length(CAPACITY_LIST),NCORES)))
Rev_No_Shipping
TEST <- Rev_No_Shipping %>% left_join(COST_DATA) %>% mutate(Profit=Revenue-Cost) %>% group_by(Discount,Capacity,Location) %>% mutate(Time_Benefit=(1-Discount)*(lead(Profit)-Profit),Op_Cost=Discount*Profit,Marginal=Time_Benefit-Op_Cost) %>% unique
TEST
TEST <- TEST %>% mutate(Current_Profit=Profit/((1+Discount)^(Year-2026))) %>% ungroup
TEST <- TEST %>% group_by(Year,Location,Discount) %>% filter(Current_Profit==max(Current_Profit)) %>% ungroup
TEST %>% select(Profit,Current_Profit,Year,Discount) %>% tail
TEST %>% group_by(Location,Discount) %>% filter(Current_Profit==max(Current_Profit))
TEST %>% group_by(Location,Discount) %>% filter(Current_Profit==max(Current_Profit)) %>% print(n=100)
TEST %>% group_by(Location,Discount) %>% filter(Discount==0.04) %>% select(Year,Capacity,Profit,Current_Profit) %>% mutate(Delay_Profit=(lead(Current_Profit)-Current_Profit)/10^6) %>% print(n=70)
ggplot(TEST ,aes(x=Year,y=Current_Profit/10^9,color=Capacity))+geom_line()+facet_wrap(Discount~Location)
ggplot(TEST %>% filter(Discount==0.03) ,aes(x=Year,y=Current_Profit/10^9,color=Capacity))+geom_line()+facet_wrap(Discount~Location,ncol=1)+scale_x_continuous(breaks=seq(1960,2083,by=5))
ggplot(TEST %>% filter(Discount==0.05) ,aes(x=Year,y=Current_Profit/10^9,color=Capacity))+geom_line()+facet_wrap(Discount~Location,ncol=1)+scale_x_continuous(breaks=seq(1960,2083,by=5))
ggplot(TEST %>% filter(Year>2000) ,aes(x=Year,y=Current_Profit/10^9,color=Capacity))+geom_line()+facet_wrap(Discount~Location,ncol=2,scales = "free_y")+scale_x_continuous(breaks=seq(1960,2083,by=5))
ggplot(TEST ,aes(x=Year,y=Current_Profit/10^9,color=Capacity))+geom_line()+facet_wrap(Discount~Location)

168
Single_Price_Data_Proc.r Normal file
View File

@ -0,0 +1,168 @@
#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
#DISCOUNT_RATE_LIST <- seq(0,1,by=0.0025)
DISCOUNT_RATE_LIST <- c(0.03,0.05,0.07,0.1)
SHIPPING_COST_PER_TON <- 1.2874*26000 #Inflation adjusted from New Mexico Report
CV1 <- 1.3074*(10607030-1060703) #Data from Texas Report, converted from 2018 to Dec 2025 dollars
CV2 <- 1.2874*(6984013-1117442) #Data from New Mexico Report, Converted from 2019 to Dec 2025
CV3 <- mean(CV1,CV2) #Average of the two
###################################Cost results
#source("Cost_Data_Proc.r")
CIFS <- rbind(readRDS("Data/Cleaned_Data/Texas_CIFS_Costs.Rds"),readRDS("Data/Cleaned_Data/New_Mexico_CIFS_Costs.Rds"))
#Adjust for inflation
CIFS[,-1:-5] <- 1.2874*CIFS[,-1:-5]
COSTS <- do.call(rbind,lapply(DISCOUNT_RATE_LIST ,function(DISCOUNT){CIFS %>% group_by(Location,Capacity,Cost_Assumption) %>% mutate(NPC=Total/(1+DISCOUNT)^Year) %>% summarize(Discount=DISCOUNT,Costs=sum(NPC))})) %>% ungroup
TEMP <- COSTS %>% group_by(Location,Cost_Assumption,Discount) %>% summarize(ST_COST=min(Costs),ST_CAPACITY=min(Capacity),M_COST=(max(Costs)-min(Costs))/(max(Capacity)-min(Capacity))) %>% ungroup
CAPACITY_INCREMENT <- 5000
#rm(COST_DATA)
for(i in 1:nrow(TEMP)){
LOC <- as.character(TEMP[i,"Location"])
COST_LEVEL <- as.character(TEMP[i,"Cost_Assumption"])
DISCOUNT <- as.numeric(TEMP[i,"Discount"])
ST_CAP <- as.numeric(TEMP[i,"ST_CAPACITY"])
ST_COST <- as.numeric(TEMP[i,"ST_COST"])
COST_SLOPE <- as.numeric(TEMP[i,]$M_COST)
CAPACITY <- seq(ST_CAP,160000,by=5000)
COST <- ST_COST+COST_SLOPE*CAPACITY_INCREMENT*(0:(length(CAPACITY)-1))
C_RES <- cbind(CAPACITY,COST) %>% as_tibble %>% mutate(Location=LOC,Cost_Assumption=COST_LEVEL,Discount=DISCOUNT) %>% select(Location,Cost_Assumption,Discount,Capacity=CAPACITY,Cost=COST)
if(!exists("COST_DATA")){COST_DATA <- C_RES}else{COST_DATA<- rbind(COST_DATA,C_RES)}
}
saveRDS(COST_DATA ,"Data/Cleaned_Data/All_CIFS_Discounted_Costs.Rds")
#COST_DATA <- COST_DATA %>% filter(Cost_Assumption=='Average') %>% select(-Cost_Assumption) %>% unique
COST_DATA <- COST_DATA %>% filter(Cost_Assumption=='High') %>% select(-Cost_Assumption) %>% unique
##All unique capacity levels that the revenues need to be calculated for
CAPACITY_LIST <- COST_DATA %>% pull(Capacity) %>% unique
###
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)
#!!!!!!!!!!!!#####TEST OF VARIABLITY IN CLOSING YEAR, CHANGE OR FORMALIZE LATER
#TOTAL <- TOTAL %>% mutate(CLOSE_YEAR=ifelse(CLOSE_YEAR>2018,CLOSE_YEAR+20,CLOSE_YEAR))
###########Series of functions to calculate the gross consumer surplus from a CIFS for each facility, in each year from 1960 to 2082.
#Function to find the net present revenue of a facility,given a discount rate, and the current year, and year the facility will close. This is the sum of discounted costs that WOULD have taken place if the facility was not built
VALUE_ADD <- function(r,CURRENT_YEAR,CLOSE_YEAR){
Years_Until_Close <- max(CLOSE_YEAR-CURRENT_YEAR+1,0)
VALUES <- (1+r)^-(1:10^4)
if(Years_Until_Close==0){return(sum(VALUES))} else{return(sum(VALUES[-1:-Years_Until_Close]))}
}
#A function to extend the revenues calculations to the closure date of all of the facilities.
VALUE_ADD_SINGLE_YEAR <- function(r,CURRENT_YEAR,CLOSE_YEARS){return(sapply(CLOSE_YEARS,function(x){VALUE_ADD(r,CURRENT_YEAR,x)}))}
#A function to extend the calculation of the net present revenues of each facility to all years of interest. That is what is the NPV of building the facility in each year, for each facility.
NPV_CALC <- function(r,DATA=TOTAL,YEARS=1960:2083){
Facility <- pull(DATA,Facility)
RES <- cbind(Facility,do.call(cbind,lapply(YEARS,function(x){VALUE_ADD_SINGLE_YEAR(r,x,DATA$CLOSE_YEAR)})))
colnames(RES) <- c("Facility",YEARS)
RES <- as_tibble(RES) %>% pivot_longer(cols=-Facility,names_to="Year",values_to="Revenue") %>% arrange(Year) %>% mutate(Year=parse_number(Year),Revenue=parse_number(Revenue),Discount=r)
return(RES)
}
#A function which returns a list, of net present revenue calculation tables (facility by year) for a range of possible discount rates. This allows for the results to be quickly looked up, when we want to adjust the time value of money. These results combine costs savings to calculate NPV
MULTI_DISCOUNT_RATE_NPV <- function(DISCOUNT_INCREMENT,DATA=TOTAL,YEARS=1960:2083,DOLLARS_SAVED_PER_YEAR){
NCORES <- detectCores()-1
RES <- mclapply(DISCOUNT_INCREMENT,NPV_CALC,mc.cores = NCORES)
RES <- do.call(rbind,RES) %>% mutate(Revenue=Revenue*DOLLARS_SAVED_PER_YEAR)
return(RES)
}
TOTAL_VALUE_METRICS <- MULTI_DISCOUNT_RATE_NPV(DISCOUNT_RATE_LIST ,DOLLARS_SAVED_PER_YEAR=CV2)
#TOTAL_VALUE_METRICS <- TOTAL_VALUE_METRICS %>% filter(!(Facility %in% c("Palo Verde","Vogtle")))#These facilities always have a negative NPV by the end date 2083
TOTAL_VALUE_METRICS <- TOTAL_VALUE_METRICS %>% left_join(read_csv("Data/Raw_Data/Curie_Spent_Fuel_Site_Totals.csv")) %>% select(Year,Facility,Discount,Total_Tons,Revenue)
#Function to find the maximum Revenue BUT it does not take dollars just relative savings
TBL <- TOTAL_VALUE_METRICS
YEAR <- 2020
CIFS_SIZE=40000
SHIPPING_COST <- 0
MAX_REV <- function(YEAR,TBL,DISCOUNT,CIFS_SIZE,SHIPPING_COST=0){
TBL <- TBL %>% filter(Year==YEAR,Discount==DISCOUNT,Revenue/Total_Tons>SHIPPING_COST)%>% mutate(Marginal=Revenue/Total_Tons)
VALUES <- TBL %>% pull(Marginal) %>% unique
RESULT <- 0
for(i in 1:length(VALUES)){
VOL <- pull(TBL[TBL$Marginal<=VALUES[i],],Total_Tons)
REV <- VALUES[i]*VOL
C_MAX_VALUE <- as.numeric(lp(direction = "max", objective.in = REV, const.mat = matrix(VOL, nrow = 1),const.dir = "<=", const.rhs = CIFS_SIZE, all.bin = TRUE)[11])
C_MAX_VALUE
RESULT <- max(RESULT,C_MAX_VALUE)
}
return(RESULT)
}
#Calculate all results for the start year to the end year. Discount rate, and capacities are fixed.
YEARLY_RESULTS <- function(DATA,DISCOUNT,CAPACITY,SHIPPING_COSTS=0){
RES <- cbind(1960:2083,sapply(1960:2083, function(x){MAX_REV(YEAR=x,TBL=DATA,DISCOUNT,CAPACITY,SHIPPING_COSTS)})) %>% as_tibble
colnames(RES) <- c("Year","Revenue")
RES <- RES %>% mutate(Discount=DISCOUNT,Capacity=CAPACITY) %>% select(Year,Discount,Capacity,Revenue) %>% mutate(Shipping_Cost_Cuttoff=SHIPPING_COSTS)
return(RES)
}
#Calculate and individual facilities rate, for all discount rates, and all years
TOTAL_VALUE_METRICS
Rev_No_Shipping <- do.call(rbind,mclapply(CAPACITY_LIST,function(CAPACITY){do.call(rbind,lapply(DISCOUNT_RATE_LIST,function(x){YEARLY_RESULTS(TOTAL_VALUE_METRICS,x,CAPACITY,0)}))},mc.cores=min(length(CAPACITY_LIST),NCORES)))
Rev_No_Shipping
TEST <- Rev_No_Shipping %>% left_join(COST_DATA) %>% mutate(Profit=Revenue-Cost) %>% group_by(Discount,Capacity,Location) %>% mutate(Time_Benefit=(1-Discount)*(lead(Profit)-Profit),Op_Cost=Discount*Profit,Marginal=Time_Benefit-Op_Cost) %>% unique
TEST
TEST <- TEST %>% mutate(Current_Profit=Profit/((1+Discount)^(Year-2026))) %>% ungroup
TEST <- TEST %>% group_by(Year,Location,Discount) %>% filter(Current_Profit==max(Current_Profit)) %>% ungroup
TEST %>% select(Profit,Current_Profit,Year,Discount) %>% tail
TEST %>% group_by(Location,Discount) %>% filter(Current_Profit==max(Current_Profit)) %>% print(n=100)
TEST %>% group_by(Location,Discount) %>% filter(Discount==0.04) %>% select(Year,Capacity,Profit,Current_Profit) %>% mutate(Delay_Profit=(lead(Current_Profit)-Current_Profit)/10^6) %>% print(n=70)
ggplot(TEST %>% filter(Discount==0.03) ,aes(x=Year,y=Current_Profit/10^9,color=Capacity))+geom_line()+facet_wrap(Discount~Location,ncol=1)+scale_x_continuous(breaks=seq(1960,2083,by=5))
ggplot(TEST %>% filter(Discount==0.05) ,aes(x=Year,y=Current_Profit/10^9,color=Capacity))+geom_line()+facet_wrap(Discount~Location,ncol=1)+scale_x_continuous(breaks=seq(1960,2083,by=5))
ggplot(TEST %>% filter(Year>2000) ,aes(x=Year,y=Current_Profit/10^9,color=Capacity))+geom_line()+facet_wrap(Discount~Location,ncol=2,scales = "free_y")+scale_x_continuous(breaks=seq(1960,2083,by=5))
ggplot(TEST ,aes(x=Year,y=Current_Profit/10^9,color=Capacity))+geom_line()+facet_wrap(Discount~Location)
TEST2 <- TEST %>% filter(Discount==0.05,Location=='Texas')
ggplot(TEST2,aes(x=Year,y=Marginal,group=as.factor(Capacity),color=as.factor(Capacity)))+geom_line()
#Calculate the net present revenue of all facilities that can CURRENTLY be shipped to the site with a profit. Note that the total Revenue is more important because most of the sites will be willing to pay for the right to CIFS storage in the future even if the shipping costs are too high presently. This result is used to show what might be the current ideal facility size, even if future expansion is expected to maximize profit.
Rev_Shipping <- do.call(rbind,mclapply(CAPACITY_LIST,function(CAPACITY){do.call(rbind,lapply(DISCOUNT_RATE_LIST,function(x){YEARLY_RESULTS(TOTAL_VALUE_METRICS,x,CAPACITY,SHIPPING_COST_PER_TON )}))},mc.cores=min(length(CAPACITY_LIST),NCORES)))
Revenue_Results <- rbind(Rev_No_Shipping,Rev_Shipping) %>% mutate(Type=ifelse(Shipping_Cost_Cuttoff==0,"Revenue","Revenue_Shipping")) %>% pivot_wider(values_from=Revenue,names_from=Type) %>% select(-Shipping_Cost_Cuttoff) %>% group_by(Year,Discount,Capacity) %>% summarize(Revenue=mean(Revenue,na.rm=TRUE),Revenue_Shipping=mean(Revenue_Shipping,na.rm=TRUE)) %>% ungroup
Revenue_Results
####################################################
COSTS <- rbind(COSTS,EXTENDED_CAPACITY_NEW_MEXICO)
COST_DATA %>% pull(Cost_Assumption) %>% unique
saveRDS(COSTS,"Data/Cleaned_Data/All_CIFS_Discounted_Costs.Rds")
COSTS %>% group_by(Location,Capac
CIFS_Data <- Revenue_Results %>% left_join(COSTS) %>% mutate(Profit=Revenue-Costs,Profit_Shipping=Revenue_Shipping-Costs) %>% select(Year,Location,Capacity,Discount,Revenue,Costs,Profit,Revenue_Shipping,Profit_Shipping,everything())
#CIFS_Data <-
CIFS_Data <- CIFS_Data %>% group_by(Location,Capacity,Discount) %>% arrange(Location,Capacity,Discount,Year) %>% mutate(Time_Benefit=lead(Profit)-Profit,Op_Cost=Profit*Discount,Marginal=Time_Benefit-Op_Cost) %>% ungroup
TEMP <- CIFS_Data %>% filter(Discount==0.05) %>% mutate(Time_Benefit=lead(Profit)-Profit,Op_Cost=Profit*Discount,Marginal=Time_Benefit-Op_Cost)
CIFS_Data <- CIFS_Data %>% group_by(Location,Phase,Capacity,Discount) %>% mutate(Time_Benefit=(1-Discount)*(lead(Profit)-Profit),Op_Cost=Profit*Discount,Marginal=Time_Benefit-Op_Cost)
((-3504542954)-(-3530861857))-0.05*(-3530861857 )
STARTING_YEARS <- CIFS_Data %>% group_by(Location,Phase,Capacity,Discount) %>% mutate(PROFITABLE=Profit>0 & Marginal<=0) %>% filter(PROFITABLE) %>% filter(Year==min(Year)) %>% select(Location,Phase,Capacity,Discount,Start_Year=Year,Profit) %>% ungroup
CIFS_Data %>% mutate(Current_Profit=Profit/((1+Discount)^(Year-2026))) %>% group_by(Location,Discount,Capacity) %>% filter(Current_Profit==max(Current_Profit)) %>% select(Start_Year=Year,Location,Phase,Capacity,Current_Profit) %>% ungroup %>% arrange(Discount,Location,desc(Current_Profit)) %>% select(Discount,Location,Phase,Start_Year,Current_Profit)
#############
ggplot(CIFS_Data ,aes(x=Year,y=Marginal/10^6,group=Capacity,color=as.factor(Capacity)))+geom_line()+facet_wrap(~Discount,ncol=1)+scale_x_continuous(breaks=seq(1960,2083,by=5))
ggplot(CIFS_Data ,aes(x=Year,y=Marginal,group=Capacity,color=as.factor(Capacity)))+geom_line()+facet_grid(~Discount)
dir.create("./Results",showWarnings=FALSE)
saveRDS(TOTAL_VALUE_METRICS,"./Results/Storage_Values_by_Facility_and_Variable_Discounts.Rds")