diff --git a/h2/app.r b/h2/app.r index da636fb..e4de19e 100644 --- a/h2/app.r +++ b/h2/app.r @@ -1,15 +1,39 @@ source("./global.r") -ui <- fluidPage( +ui <- fluidPage(theme = shinythemes::shinytheme("readable"), includeCSS("./components/layout/style copy.css"), + tags$div(class = "container", + tags$img(src = "images/earth-header.png", height = "300px", width = "100%", class = "earth", alt = "Earth's atmosphere"), + tags$div( + a( + img(src = "images/GCIMS_logo_alt.svg", class = "logo"), href = "https://gcims.pnnl.gov/", target = "_blank"), + h1("HectorUI", class = "header-text-title"), + h2("An Interactive Climate Model", class = "header-text-sub", style = "font-weight:normal; "), + ), + ), navbarPage( id = "nav", title = "", collapsible = TRUE, tabPanel(title = "Home", - includeHTML("./components/layout/homepage.html")), + fluidRow( + column(7, + includeHTML("./components/layout/homepage.html") + ), + column(4, div( + br(), + br(), + actionButton(inputId = "launch_scenario", + label = "Explore Hector", + style = "background: #4174C3; color: white; + font-size: 24px; padding: 32px 24px; + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);"), + align = "center" + )) + ) + ), tabPanel(title = "Guides"), - tabPanel(title = "Explore Hector", + tabPanel(title = "Run Hector", fluidRow( run_ui("run_1"), ) @@ -21,11 +45,14 @@ ui <- fluidPage( ), tabPanel(title = "About") ), + hr(), + includeHTML("./components/layout/footer.html") ) server <- function(input, output, session) { r6 <- HectorInputs$new() # r6 class r6_tracking <- HectorInputs$new() # separate r6 class for carbon tracking + observeEvent(input$launch_scenario, updateTabsetPanel(session, "nav", selected = "Run Hector"), ignoreInit = TRUE) run_server("run_1", r6 = r6) summary_server("summary_1", r6 = r6) diff --git a/h2/components/functions/func_graph_plots.R b/h2/components/functions/func_graph_plots.R index 4a5c104..90f4855 100644 --- a/h2/components/functions/func_graph_plots.R +++ b/h2/components/functions/func_graph_plots.R @@ -5,19 +5,19 @@ graph_plots <- function(r6) { if (r6$save == TRUE) { #browser() - {ggplot(r6$no_save_output) + - geom_line(aes(x = year, y = value, color = ssp)) + + {ggplot(last(r6$output)) + + geom_line(aes(x = year, y = value, color = Scenario)) + labs(x = "Year", y = last(r6$output)$variable[1], - title = paste0("Run Name: ", last(r6$output)$run[1], "\n", "Variable: ", last(r6$output)$variable[1])) + + title = paste0("Run Name: ", last(r6$output)$run[1], "\n", "Variable: ", last(r6$output)$variable[1],"\nPermafrost: ",r6$permafrost)) + theme(legend.position = "bottom")} %>% plotly::ggplotly() } else if(r6$save == FALSE) { {ggplot(r6$no_save_output) + - geom_line(aes(x = year, y = value, color = ssp)) + + geom_line(aes(x = year, y = value, color = Scenario)) + labs(x = "Year", y = r6$no_save_output$variable[1], - title = paste0("Run Name: Unsaved Run\n", "Variable: ", r6$no_save_output$variable[1]))} %>% + title = paste0("Run Name: Unsaved Run\n", "Variable: ", r6$no_save_output$variable[1],"\nPermafrost: ",r6$permafrost))} %>% plotly::ggplotly() %>% layout( legend = list( diff --git a/h2/components/layout/footer.html b/h2/components/layout/footer.html new file mode 100644 index 0000000..4816c9d --- /dev/null +++ b/h2/components/layout/footer.html @@ -0,0 +1 @@ + diff --git a/h2/components/layout/homepage.html b/h2/components/layout/homepage.html index a0e3718..56d2825 100644 --- a/h2/components/layout/homepage.html +++ b/h2/components/layout/homepage.html @@ -1,4 +1,4 @@ -

Welcome to the user interface for Hector: an open source, object-oriented, and interactive simple global climate carbon-cycle model. It runs essentially instantaneously while still representing the most critical global scale earth system processes, and is one of a class of models heavily used for for emulating complex climate models and uncertainty analyses. +

Welcome to the user interface for Hector: an open source, object-oriented, and interactive simple global climate carbon-cycle model. It runs essentially instantaneously while still representing the most critical global scale earth system processes, and is one of a class of models heavily used for for emulating complex climate models and uncertainty analyses.

This interactive version is built upon previous work by developers at the Joint Global Change Research Institute (JGCRI), including the development of the initial C++ version of Hector, and the follow up R Package "Hector R".

diff --git a/h2/components/layout/style copy.css b/h2/components/layout/style copy.css index fd14914..f4d24df 100644 --- a/h2/components/layout/style copy.css +++ b/h2/components/layout/style copy.css @@ -1,8 +1,110 @@ -.test { - font-family:"Barlow Regular", Sans-Serif !important; -} - h5 { font-weight: bold; } + +body +{ + font-family:"Barlow Regular", Sans-Serif !important; +} + +.about-info +{ + font-size: 12px; +} + +.c-emissions +{ + font-size: 14px; +} + +.container { + position: relative; + width:100%; +} + +.header-text-title +{ + position: absolute; + color: #FFFFFF; + top: 40%; + left: 50%; + text-align: center;!important + max-width: 120px; + margin-right: -50%; + transform: translate(-50%, -50%) +} + +.header-text-sub +{ + position: absolute; + color: #FFFFFF; + text-align: center; + font-size: 100%; + top: 60%; + left: 50%; + margin-right: -50%; + transform: translate(-50%, -50%) +} + +.home-text +{ + font-size: 16px; +} + +.hrNav +{ + font-size: 50px; +} + +.logo +{ + + position: absolute; + top: 2rem; + left: 2rem; + margin:20px; + padding:0px 8px; + width:5em; +} + +.maps +{ + font-size: 16px; +} + +.nav-tabs +{ + font-size: 14px; +} + +.output-vars +{ + font-size: 16px; +} + +.params +{ + font-size: 14px; +} + +.navbar-nav +{ + float:none; + margin:0 auto; + display: block; + text-align: center; + color: #000000; +} + +.navbar-nav > li { + display: inline-block; + float:none; + color: #000000; +} + +.sticky-footer +{ + font-size: 12px; +} +} diff --git a/h2/components/modules/mod_run.R b/h2/components/modules/mod_run.R index 6c768b9..5c0ed32 100644 --- a/h2/components/modules/mod_run.R +++ b/h2/components/modules/mod_run.R @@ -7,19 +7,12 @@ run_ui <- function(id) { tabsetPanel( tabPanel(class = "params", "Standard Scenarios", chooseSliderSkin(skin = "Flat", color = "#375a7f"), - prettyRadioButtons(ns("ssp_path"), label="Select SSP:", - choices = list("SSP 1-1.9"="input/hector_ssp119.ini", - "SSP 1-2.6"="input/hector_ssp126.ini", - "SSP 2-4.5"="input/hector_ssp245.ini", - "SSP 3-7.0"="input/hector_ssp370.ini", - "SSP 4-3.4"="input/hector_ssp434.ini", - "SSP 4-6.0"="input/hector_ssp460.ini", - "SSP 5-3.4OS"="input/hector_ssp534-over.ini", - "SSP 5-8.5"="input/hector_ssp585.ini"), - selected = "input/hector_ssp245.ini", inline=TRUE, - shape = "square", width = "80%"), + selectInput(ns("ssp_path"), label="Select SSP:", + choices = scenarios, + selected = "input/hector_ssp245.ini"), sliderInput(ns("time"), label="Select dates:", min = 1750, max = 2300, value = c(1900,2100), sep="", width = "90%", step=5), + materialSwitch(ns("permafrost"), "Include Permafrost Carbon", value = FALSE), h5("Model Parameters"), sliderInput(ns("alpha"), label="Aerosol forcing scaling factor", # AERO_SCALE() min = 0.01, max = 1, value = 1, width = "90%"), @@ -32,58 +25,57 @@ run_ui <- function(id) { sliderInput(ns("q10_rh"), label="Heterotrophic temperature sensitivity", # Q10_RH() min = 1, max = 5, value = 2, step=0.1, width = "90%"), sliderInput(ns("volscl"), label="Volcanic forcing scaling factor", # VOLCANIC_SCALE() - min = 0, max = 1, value = 1, width = "90%"), - materialSwitch(ns("savetoggle"),"Save Run", value = FALSE), - textInput(ns("run_name"), label = "Run Name", placeholder = "Run 1"), - dropdownButton(inputId = ns("dropdown"), - icon = icon("gear"), - circle = TRUE, - status = "primary", - dataTableOutput(ns("savetable")), - actionButton(ns("deleteRuns"), "Delete Selected") - ) + min = 0, max = 1, value = 1, width = "90%") ) ) ), mainPanel(width = 8, - tabsetPanel( - tabPanel(p(icon("chart-line","fa-2x"), "Scenario Output", value="outputTab"), - br(), - fluidRow( - column(4, - selectInput(ns("variable"), "Select variable:", - list("Carbon Cycle" = list("Atmospheric CO2" = CONCENTRATIONS_CO2(), - "FFI Emissions" = FFI_EMISSIONS(), - "LUC Emissions" = LUC_EMISSIONS()), - "Concentrations" = list("N2O Concentration" = CONCENTRATIONS_N2O()), - "Emissions" = list("Black Carbon Emissions" = EMISSIONS_BC(), - "Organic Carbon Emissions" = EMISSIONS_OC()), - "Forcings" = list("RF - Total" = RF_TOTAL(), - "RF - Albedo" = RF_ALBEDO(), - "RF - CO2" = RF_CO2(), - "RF - N2O" = RF_N2O(), - "RF - Black Carbon" = RF_BC(), - "RF - Organic Carbon" = RF_OC(), - "RF - Total SO2" = RF_SO2(), - "RF - Volcanic Activity" = RF_VOL(), - "RF - CH4" = RF_CH4())), - selected = "Atmospheric CO2", multiple = FALSE), - ), - column(3, - actionBttn(ns("run"),"Run", color = "primary"), - - ) - ), - fluidRow( - withSpinner(plotlyOutput(ns("graph"))) - ) + fluidRow( + column(4, + selectInput(ns("variable"), "Choose Output Variable:", + list("Carbon Cycle" = list("Atmospheric CO2" = CONCENTRATIONS_CO2(), + "FFI Emissions" = FFI_EMISSIONS(), + "LUC Emissions" = LUC_EMISSIONS()), + "Concentrations" = list("N2O Concentration" = CONCENTRATIONS_N2O()), + "Emissions" = list("Black Carbon Emissions" = EMISSIONS_BC(), + "Organic Carbon Emissions" = EMISSIONS_OC()), + "Forcings" = list("RF - Total" = RF_TOTAL(), + "RF - Albedo" = RF_ALBEDO(), + "RF - CO2" = RF_CO2(), + "RF - N2O" = RF_N2O(), + "RF - Black Carbon" = RF_BC(), + "RF - Organic Carbon" = RF_OC(), + "RF - Total SO2" = RF_SO2(), + "RF - Volcanic Activity" = RF_VOL(), + "RF - CH4" = RF_CH4())), + selected = "Atmospheric CO2", multiple = FALSE), ), - tabPanel(p(icon("globe-americas","fa-2x"), "World Maps", value="outputTab") + column(3, + materialSwitch(ns("savetoggle"), "Save Run", status = "success") ), - tabPanel(p(icon("chart-pie","fa-2x"), "Carbon Tracking", value="outputTab") + column(5, + conditionalPanel( + condition = "input.savetoggle == true", + ns = ns, + textInput(ns("run_name"), label = "Run Name", placeholder = "Run 1") + ) + ), + column(2, + dropdownButton(inputId = ns("dropdown"), + icon = icon("gear"), + circle = TRUE, + status = "primary", + dataTableOutput(ns("savetable")), + actionButton(ns("deleteRuns"), "Delete Selected") + ) ) - + ), + fluidRow( + actionBttn(ns("run"),"Run", color = "primary"), + ), + fluidRow( + withSpinner(plotlyOutput(ns("graph"))) ) ) ) @@ -96,13 +88,9 @@ run_server <- function(id, r6) { observe({ if (input$savetoggle == TRUE) { - r6$save <- TRUE - } else { - r6$save <- FALSE - } r6$selected_var <- reactive({input$variable}) @@ -114,6 +102,12 @@ run_server <- function(id, r6) { core <- reactive({newcore(r6$ini_file())}) # create core # Set parameters using inputs (function to only call setvar once in final version) + if (input$permafrost == TRUE) { + setvar(core(),0,PERMAFROST_C(),865,"Pg C") + r6$permafrost <- "On" + } else if (input$permafrost == FALSE) { + r6$permafrost <- "Off" + } setvar(core(),NA,AERO_SCALE(),input$alpha,"(unitless)") setvar(core(),NA,BETA(),input$beta,"(unitless)") setvar(core(),NA,DIFFUSIVITY(),input$diff,"cm2/s") @@ -124,16 +118,17 @@ run_server <- function(id, r6) { reset(core()) run(core()) - #browser() if (r6$save == TRUE) { r6$output[[r6$run_name()]] <- fetchvars(core(), r6$time()[1]:r6$time()[2], vars = list(r6$selected_var())) %>% - mutate(run = r6$run_name(), Scenario = input$ssp_path) + mutate(run = r6$run_name(), Scenario = names(which(scenarios == input$ssp_path, arr.ind = FALSE))) + + updateSwitchInput(session = session, "savetoggle", value = FALSE) } else if (r6$save == FALSE) { r6$no_save_output <- fetchvars(core(), r6$time()[1]:r6$time()[2], vars = list(r6$selected_var())) %>% - mutate(ssp = input$ssp_path) + mutate(Scenario = names(which(scenarios == input$ssp_path, arr.ind = FALSE))) } @@ -150,11 +145,30 @@ run_server <- function(id, r6) { }) %>% bindEvent(input$run, ignoreNULL = TRUE, ignoreInit = FALSE) - }) -} + # Clear text input for run save after toggle switch is off + observe({ + updateTextInput(session = session, "run_name", value = NA) + }) %>% + bindEvent(input$savetoggle == FALSE) + + # Create a table to show saved runs in session + observe({ -# might be worth it to just run the core with all selectable variables. how much time would that add? -# issue seems to be that mod_run goes first, so input$variable just doesn't exist yet... maybe having -# that module containing all choices is a good idea + savetable <- reactive(tibble("Run Name" = names(r6$output))) + output$savetable <- renderDataTable({savetable()}) + + }) %>% bindEvent(input$run) + + # Create delete entry in saved output list based on user-selected row + observe({ -# fetchvars(core,1745:2300,vars=list(CONCENTRATIONS_CO2(),FFI_EMISSIONS(),LUC_EMISSIONS(),CONCENTRATIONS_N2O,EMISSIONS_BC(),EMISSIONS_OC(),RF_TOTAL(),RF_ALBEDO(),RF_N2O(),RF_CO2(),RF_BC(),RF_OC(),RF_SO2(),RF_CH4(),RF_VOL())) + #this should work in theory, but savetable isn't getting passed into the observe? + delete <- savetable()$`Run Name`[input$savetable_rows_selected] + + r6$output[[delete]] <- NULL + + }) %>% bindEvent(input$deleteRuns) + + + }) +} \ No newline at end of file diff --git a/h2/global.r b/h2/global.r index 49a2a01..beaeef6 100644 --- a/h2/global.r +++ b/h2/global.r @@ -34,6 +34,7 @@ HectorInputs <- R6Class( no_save_output = NULL, no_save = NULL, run_name = NA, + permafrost = NULL, save = NULL, inputs = NULL, selected_var = NULL, @@ -50,6 +51,15 @@ HectorInputs <- R6Class( ) ) +scenarios <- list("SSP 1-1.9"="input/hector_ssp119.ini", + "SSP 1-2.6"="input/hector_ssp126.ini", + "SSP 2-4.5"="input/hector_ssp245.ini", + "SSP 3-7.0"="input/hector_ssp370.ini", + "SSP 4-3.4"="input/hector_ssp434.ini", + "SSP 4-6.0"="input/hector_ssp460.ini", + "SSP 5-3.4OS"="input/hector_ssp534-over.ini", + "SSP 5-8.5"="input/hector_ssp585.ini") + title <- list("CO2_concentration" = "Atmospheric CO2", "atmos_co2" = "Atmospheric Carbon Pool", "ffi_emissions" = "FFI Emissions", diff --git a/h2/www/images/GCIMS_logo_alt.svg b/h2/www/images/GCIMS_logo_alt.svg new file mode 100644 index 0000000..30aa3ec --- /dev/null +++ b/h2/www/images/GCIMS_logo_alt.svg @@ -0,0 +1,12 @@ + + + logo + + + + \ No newline at end of file diff --git a/h2/www/images/GitHub-logo.png b/h2/www/images/GitHub-logo.png new file mode 100644 index 0000000..41887d7 Binary files /dev/null and b/h2/www/images/GitHub-logo.png differ diff --git a/h2/www/images/Hector-sm.png b/h2/www/images/Hector-sm.png new file mode 100644 index 0000000..1bb2f06 Binary files /dev/null and b/h2/www/images/Hector-sm.png differ diff --git a/h2/www/images/earth-header.png b/h2/www/images/earth-header.png new file mode 100644 index 0000000..3c986cd Binary files /dev/null and b/h2/www/images/earth-header.png differ diff --git a/h2/www/images/hectorcal-doi.svg b/h2/www/images/hectorcal-doi.svg new file mode 100644 index 0000000..3ab99b7 --- /dev/null +++ b/h2/www/images/hectorcal-doi.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3515153 + + + 10.5281/zenodo.3515153 + + + \ No newline at end of file diff --git a/h2/www/images/line.png b/h2/www/images/line.png new file mode 100644 index 0000000..a3e282e Binary files /dev/null and b/h2/www/images/line.png differ