# | (C) 2006-2019 Potsdam Institute for Climate Impact Research (PIK) # | authors, and contributors see CITATION.cff file. This file is part # | of REMIND and licensed under AGPL-3.0-or-later. Under Section 7 of # | AGPL-3.0, you are granted additional permissions described in the # | REMIND License Exception, version 1.0 (see LICENSE file). # | Contact: remind@pik-potsdam.de library(lucode, quietly = TRUE,warn.conflicts =FALSE) library(dplyr, quietly = TRUE,warn.conflicts =FALSE) require(gdx) # Function to create the levs.gms, fixings.gms, and margs.gms files, used in # delay scenarios. create_fixing_files <- function(cfg, input_ref_file = "input_ref.gdx") { # Start the clock. begin <- Sys.time() # Extract data from input_ref.gdx file and store in levs_margs_ref.gms. system(paste("gdxdump", input_ref_file, "Format=gamsbas Delim=comma FilterDef=N Output=levs_margs_ref.gms", sep = " ")) # Read data from levs_margs_ref.gms. ref_gdx_data <- suppressWarnings(readLines("levs_margs_ref.gms")) # Create fixing files. cat("\n") create_standard_fixings(cfg, ref_gdx_data) # Stop the clock. cat("Time it took to create the fixing files: ") manipulate_runtime <- Sys.time()-begin print(manipulate_runtime) cat("\n") # Delete file. file.remove("levs_margs_ref.gms") } # Function to create the levs.gms, fixings.gms, and margs.gms files, used in # the standard (i.e. the non-macro stand-alone) delay scenarios. create_standard_fixings <- function(cfg, ref_gdx_data) { # Declare empty lists to hold the strings for the 'manipulateFile' functions. full_manipulateThis <- NULL levs_manipulateThis <- NULL fixings_manipulateThis <- NULL margs_manipulateThis <- NULL str_years <- c() no_years <- (cfg$gms$cm_startyear - 2005) / 5 # Write level values to file levs <- c() for (i in 1:no_years) { str_years[i] <- paste("L \\('", 2000 + i * 5, sep = "") levs <- c(levs, grep(str_years[i], ref_gdx_data, value = TRUE)) } writeLines(levs, "levs.gms") # Replace fixing.gms with level values file.copy("levs.gms", "fixings.gms", overwrite = TRUE) fixings_manipulateThis <- c(fixings_manipulateThis, list(c(".L ", ".FX "))) #cb q_co2eq is only "static" equation to be active before cm_startyear, as multigasscen could be different from a scenario to another that is fixed on the first #cb therefore, vm_co2eq cannot be fixed, otherwise infeasibilities would result. vm_co2eq.M is meaningless, is never used in the code (a manipulateFile delete line command would be even better) # manipulateFile("fixings.gms", list(c("vm_co2eq.FX ", "vm_co2eq.M "))) # Write marginal values to file margs <- c() str_years <- c() for (i in 1:no_years) { str_years[i] <- paste("M \\('", 2000 + i * 5, sep = "") margs <- c(margs, grep(str_years[i], ref_gdx_data, value = TRUE)) } writeLines(margs, "margs.gms") # temporary fix so that you can use older gdx for fixings - will become obsolete in the future and can be deleted once the next variable name change is done margs_manipulateThis <- c(margs_manipulateThis, list(c("q_taxrev","q21_taxrev"))) # fixing for SPA runs based on ModPol input data margs_manipulateThis <- c(margs_manipulateThis, list(c("q41_emitrade_restr_mp.M", "!!q41_emitrade_restr_mp.M")), list(c("q41_emitrade_restr_mp2.M", "!!q41_emitrade_restr_mp2.M"))) #AJS this symbol is not known and crashes the run - is it depreciated? TODO levs_manipulateThis <- c(levs_manipulateThis, list(c("vm_pebiolc_price_base.L", "!!vm_pebiolc_price_base.L"))) #AJS filter out nash marginals in negishi case, as they would lead to a crash when trying to fix on them: if(cfg$gms$optimization == 'negishi'){ margs_manipulateThis <- c(margs_manipulateThis, list(c("q80_costAdjNash.M", "!!q80_costAdjNash.M"))) } if(cfg$gms$subsidizeLearning == 'off'){ levs_manipulateThis <- c(levs_manipulateThis, list(c("v22_costSubsidizeLearningForeign.L", "!!v22_costSubsidizeLearningForeign.L"))) margs_manipulateThis <- c(margs_manipulateThis, list(c("q22_costSubsidizeLearning.M", "!!q22_costSubsidizeLearning.M")), list(c("v22_costSubsidizeLearningForeign.M", "!!v22_costSubsidizeLearningForeign.M")), list(c("q22_costSubsidizeLearningForeign.M", "!!q22_costSubsidizeLearningForeign.M"))) fixings_manipulateThis <- c(fixings_manipulateThis, list(c("v22_costSubsidizeLearningForeign.FX", "!!v22_costSubsidizeLearningForeign.FX"))) } #JH filter out negishi marginals in nash case, as they would lead to a crash when trying to fix on them: if(cfg$gms$optimization == 'nash'){ margs_manipulateThis <- c(margs_manipulateThis, list(c("q80_balTrade.M", "!!q80_balTrade.M")), list(c("q80_budget_helper.M", "!!q80_budget_helper.M"))) } #RP filter out module 40 techpol fixings if(cfg$gms$techpol == 'none'){ margs_manipulateThis <- c(margs_manipulateThis, list(c("q40_NewRenBound.M", "!!q40_NewRenBound.M")), list(c("q40_CoalBound.M", "!!q40_CoalBound.M")), list(c("q40_LowCarbonBound.M", "!!q40_LowCarbonBound.M")), list(c("q40_FE_RenShare.M", "!!q40_FE_RenShare.M")), list(c("q40_trp_bound.M", "!!q40_trp_bound.M")), list(c("q40_TechBound.M", "!!q40_TechBound.M")), list(c("q40_ElecBioBound.M", "!!q40_ElecBioBound.M")), list(c("q40_PEBound.M", "!!q40_PEBound.M")), list(c("q40_PEcoalBound.M", "!!q40_PEcoalBound.M")), list(c("q40_PEgasBound.M", "!!q40_PEgasBound.M")), list(c("q40_PElowcarbonBound.M", "!!q40_PElowcarbonBound.M")), list(c("q40_EV_share.M", "!!q40_EV_share.M")), list(c("q40_TrpEnergyRed.M", "!!q40_TrpEnergyRed.M")), list(c("q40_El_RenShare.M", "!!q40_El_RenShare.M")), list(c("q40_BioFuelBound.M", "!!q40_BioFuelBound.M"))) } if(cfg$gms$techpol == 'NPi2018'){ margs_manipulateThis <- c(margs_manipulateThis, list(c("q40_El_RenShare.M", "!!q40_El_RenShare.M")), list(c("q40_CoalBound.M", "!!q40_CoalBound.M"))) } # Include fixings (levels) and marginals in full.gms at predefined position # in core/loop.gms. full_manipulateThis <- c(full_manipulateThis, list(c("cb20150605readinpositionforlevelfile", paste("first offlisting inclusion of levs.gms so that level value can be accessed", "$offlisting", "$include \"levs.gms\";", "$onlisting", sep = "\n")))) full_manipulateThis <- c(full_manipulateThis, list(c("cb20140305readinpositionforfinxingfiles", paste("offlisting inclusion of levs.gms, fixings.gms, and margs.gms", "$offlisting", "$include \"levs.gms\";", "$include \"fixings.gms\";", "$include \"margs.gms\";", "$onlisting", sep = "\n")))) # Perform actual manipulation on levs.gms, fixings.gms, and margs.gms in # single, respective, parses of the texts. manipulateFile("levs.gms", levs_manipulateThis) manipulateFile("fixings.gms", fixings_manipulateThis) manipulateFile("margs.gms", margs_manipulateThis) # Perform actual manipulation on full.gms, in single parse of the text. manipulateFile("full.gms", full_manipulateThis) } # Set value source_include so that loaded scripts know, that they are # included as source (instead a load from command line) source_include <- TRUE # unzip all .gz files system("gzip -d -f *.gz") # Load REMIND run configuration load("config.Rdata") #AJS set MAGCFG file magcfgFile = paste0('./magicc/MAGCFG_STORE/','MAGCFG_USER_',toupper(cfg$gms$cm_magicc_config),'.CFG') if(!file.exists(magcfgFile)){ stop(paste('ERROR in MAGGICC configuration: Could not find file ',magcfgFile)) } system(paste0('cp ',magcfgFile,' ','./magicc/MAGCFG_USER.CFG')) # Change flag "cm_compile_main" from TRUE to FALSE since we are not compiling # main.gms but executing full.gms and therefore want to load some data from the # input.gdx files. manipulateFile("full.gms", list(c("\\$setglobal cm_compile_main *TRUE", "\\$setglobal cm_compile_main FALSE"))) # Prepare the files containing the fixings for delay scenarios (for fixed runs) if ( cfg$gms$cm_startyear > 2005 & (!file.exists("levs.gms.gz") | !file.exists("levs.gms"))) { create_fixing_files(cfg = cfg, input_ref_file = "input_ref.gdx") } # Store REMIND directory and output file names maindir <- cfg$remind_folder REMIND_mif_name <- paste("REMIND_generic_", cfg$title, ".mif", sep = "") # Print message cat("\nStarting REMIND...\n") # Save start time begin <- Sys.time() # Call GAMS if (cfg$gms$CES_parameters == "load") { system(paste0(cfg$gamsv, " full.gms -errmsg=1 -a=", cfg$action, " -ps=0 -pw=185 -gdxcompress=1 -logoption=", cfg$logoption)) } else if (cfg$gms$CES_parameters == "calibrate") { # Remember file modification time of fulldata.gdx to see if it changed fulldata_m_time <- Sys.time(); # Save original input file.copy("input.gdx", "input_00.gdx", overwrite = TRUE) # Iterate calibration algorithm for (cal_itr in 1:cfg$gms$c_CES_calibration_iterations) { cat("CES calibration iteration: ", cal_itr, "\n") # Update calibration iteration in GAMS file system(paste0("sed -i 's/^\\(\\$setglobal c_CES_calibration_iteration ", "\\).*/\\1", cal_itr, "/' full.gms")) system(paste0(cfg$gamsv, " full.gms -errmsg=1 -a=", cfg$action, " -ps=0 -pw=185 -gdxcompress=1 -logoption=", cfg$logoption)) # If GAMS found a solution if ( file.exists("fulldata.gdx") && file.info("fulldata.gdx")$mtime > fulldata_m_time) { #create the file to be used in the load mode getLoadFile <- function(){ file_name = paste0(cfg$gms$cm_CES_configuration,"_ITERATION_",cal_itr,".inc") ces_in = system("gdxdump fulldata.gdx symb=in NoHeader Format=CSV", intern = TRUE) %>% gsub("\"","",.) #" This comment is just to obtain correct syntax highlighting expr_ces_in = paste0("(",paste(ces_in, collapse = "|") ,")") tmp = system("gdxdump fulldata.gdx symb=pm_cesdata", intern = TRUE)[-(1:2)] %>% grep("(quantity|price|eff|effgr|xi|rho|offset_quantity|compl_coef)", x = ., value = TRUE) tmp = tmp %>% grep(expr_ces_in,x = ., value = T) tmp %>% sub("'([^']*)'.'([^']*)'.'([^']*)'.'([^']*)' (.*)[ ,][ /];?", "pm_cesdata(\"\\1\",\"\\2\",\"\\3\",\"\\4\") = \\5;", x = .) %>% write(file_name) pm_cesdata_putty = system("gdxdump fulldata.gdx symb=pm_cesdata_putty", intern = TRUE) if (length(pm_cesdata_putty) == 2){ tmp_putty = gsub("^Parameter *([A-z_(,)])+cesParameters\\).*$",'\\1"quantity") = 0;', pm_cesdata_putty[2]) } else { tmp_putty = pm_cesdata_putty[-(1:2)] %>% grep("quantity", x = ., value = TRUE) %>% grep(expr_ces_in,x = ., value = T) } tmp_putty %>% sub("'([^']*)'.'([^']*)'.'([^']*)'.'([^']*)' (.*)[ ,][ /];?", "pm_cesdata_putty(\"\\1\",\"\\2\",\"\\3\",\"\\4\") = \\5;", x = .)%>% write(file_name,append =T) } getLoadFile() # Store all the interesting output file.copy("full.lst", sprintf("full_%02i.lst", cal_itr), overwrite = TRUE) file.copy("full.log", sprintf("full_%02i.log", cal_itr), overwrite = TRUE) file.copy("fulldata.gdx", "input.gdx", overwrite = TRUE) file.copy("fulldata.gdx", sprintf("input_%02i.gdx", cal_itr), overwrite = TRUE) # Update file modification time fulldata_m_time <- file.info("fulldata.gdx")$mtime } else { break } } } else { stop("unknown realisation of 29_CES_parameters") } # Calculate run time gams_runtime <- Sys.time() - begin # If REMIND actually did run if (cfg$action == "ce" && cfg$gms$c_skip_output != "on") { # Print Message cat("\nREMIND run finished!\n") # Create solution report for Nash runs if (cfg$gms$optimization == "nash" && cfg$gms$cm_nash_mode != "debug" && file.exists("fulldata.gdx")) { system("gdxdump fulldata.gdx Format=gamsbas Delim=comma Output=output_nash.gms") file.append("full.lst", "output_nash.gms") file.remove("output_nash.gms") } } # Collect and submit run statistics to central data base lucode::runstatistics(file = "runstatistics.rda", modelstat = readGDX(gdx="fulldata.gdx","o_modelstat", format="first_found"), config = cfg, runtime = gams_runtime, setup_info = lucode::setup_info(), submit = cfg$runstatistics) # Compress files with the fixing-information if (cfg$gms$cm_startyear > 2005) system("gzip -f levs.gms margs.gms fixings.gms") # go up to the main folder, where the cfg files for subsequent runs are stored setwd(cfg$remind_folder) #====================== Subsequent runs =========================== # 1. Save the path to the fulldata.gdx of the current run to the cfg files # of the runs that use it as 'input_bau.gdx' # Use the name to check whether it is a coupled run (TRUE if the name ends with "-rem-xx") coupled_run <- grepl("-rem-[0-9]{1,2}$",cfg$title) no_ref_runs <- identical(cfg$RunsUsingTHISgdxAsBAU,character(0)) | all(is.na(cfg$RunsUsingTHISgdxAsBAU)) | coupled_run if(!no_ref_runs) { source("scripts/start_functions.R") # Save the current cfg settings into a different data object, so that they are not overwritten cfg_main <- cfg for(run in seq(1,length(cfg_main$RunsUsingTHISgdxAsBAU))){ # for each of the runs that use this gdx as bau, read in the cfg, ... cat("Writing the path for input_bau.gdx to ",paste0(cfg_main$RunsUsingTHISgdxAsBAU[run],".RData"),"\n") load(paste0(cfg_main$RunsUsingTHISgdxAsBAU[run],".RData")) # ...change the path_gdx_bau field of the subsequent run to the fulldata gdx of the current run ... cfg$files2export$start['input_bau.gdx'] <- paste0(cfg_main$remind_folder,"/",cfg_main$results_folder,"/fulldata.gdx") save(cfg, file = paste0(cfg_main$RunsUsingTHISgdxAsBAU[run],".RData")) } # Set cfg back to original cfg <- cfg_main } # 2. Save the path to the fulldata.gdx of the current run to the cfg files # of the subsequent runs that use it as 'input_ref.gdx' and start these runs no_subsequent_runs <- identical(cfg$subsequentruns,character(0)) | identical(cfg$subsequentruns,NULL) | coupled_run if(no_subsequent_runs){ cat('\nNo subsequent run was set for this scenario\n') } else { # Save the current cfg settings into a different data object, so that they are not overwritten cfg_main <- cfg source("scripts/start_functions.R") for(run in seq(1,length(cfg_main$subsequentruns))){ # for each of the subsequent runs, read in the cfg, ... cat("Writing the path for input_ref.gdx to ",paste0(cfg_main$subsequentruns[run],".RData"),"\n") load(paste0(cfg_main$subsequentruns[run],".RData")) # ...change the path_gdx_ref field of the subsequent run to the fulldata gdx of the current (preceding) run ... cfg$files2export$start['input_ref.gdx'] <- paste0(cfg_main$remind_folder,"/",cfg_main$results_folder,"/fulldata.gdx") save(cfg, file = paste0(cfg_main$subsequentruns[run],".RData")) # Subsequent runs will be started in submit.R using the RData files written above # after the current run has finished. cat("Starting subsequent run ",cfg_main$subsequentruns[run],"\n") start_run(cfg) } # Set cfg back to original cfg <- cfg_main } # 3. Create script file that can be used later to restart the subsequent runs manually. # In case there are no subsequent runs (or it's coupled runs), the file contains only # a small message. subseq_start_file <- paste0(cfg$results_folder,"/start_subsequentruns.R") if(no_subsequent_runs){ write("cat('\nNo subsequent run was set for this scenario\n')",file=subseq_start_file) } else { # go up to the main folder, where the cfg. files for subsequent runs are stored filetext <- paste0("setwd('",cfg$remind_folder,"')\n") filetext <- paste0(filetext,"source('scripts/start_functions.R')\n") for(run in seq(1,length(cfg$subsequentruns))){ filetext <- paste0(filetext,"\n") filetext <- paste0(filetext,"load('",cfg$subsequentruns[run],".RData')\n") filetext <- paste0(filetext,"cat('",cfg$subsequentruns[run],"')\n") filetext <- paste0(filetext,"start_run(cfg)\n") } # Write the text to the file write(filetext,file=subseq_start_file) } #=================== END - Subsequent runs ======================== # Print REMIND runtime cat("\n gams_runtime is ", gams_runtime, "\n") # Copy important files into output_folder (after REMIND execution) for (file in cfg$files2export$end) file.copy(file, cfg$results_folder, overwrite = TRUE) # Postprocessing / Output Generation output <- cfg$output outputdir <- cfg$results_folder sys.source("output.R",envir=new.env())