Skip to content

Commit

Permalink
finish readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Datseris committed Feb 20, 2024
1 parent 46a6963 commit d1f873a
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 59 deletions.
44 changes: 31 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
# EnergyBalanceModels.jl

Any quantity that may potentially be a dynamic (state) variable, or an explicit function of time, is defined in `src/variables.jl` and must have a default value when defined. They should also be exported and in the rest of the source code they are accessed from the module-level scope. _TODO: Example here_.
Variables that may be dynamic (state) variables must also obtain limits in the `physicall_plausible_limits` function which is in the same file.
Variables that can never be dynamic but are guaranteed to be observed, such as the outgoing longwave radiation, should be preferably defined in the same file but without a default value or limits.
[![docsdev](https://img.shields.io/badge/docs-dev-lightblue.svg)](https://juliadynamics.github.io/ProcessBasedModelling,jl/dev/)
[![docsstable](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliadynamics.github.io/EnergyBalanceModels.jl/stable/)
[![CI](https://github.com/JuliaDynamics/EnergyBalanceModels.jl/workflows/CI/badge.svg)](https://github.com/JuliaDynamics/EnergyBalanceModels.jl/actions?query=workflow%3ACI)
[![codecov](https://codecov.io/gh/JuliaDynamics/EnergyBalanceModels.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/JuliaDynamics/EnergyBalanceModels.jl)
[![Package Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/ProcessBasedModelling)](https://pkgs.genieframework.com?packages=ProcessBasedModelling)

# TODO:
explain that all processes by default use the global variables,
which is why docstrings are written this way.
EnergyBalanceModels.jl is a Julia package for creating and analyzing conceptual
models of climate, such as energy balance models or climate tipping models.
Such conceptual models are simplified representation of basic climate components,
and the processes that connect them, such as flows of energy or mass.
Within this context such models are typically coupled ordinary differential
equations (with partial or stochastic DEs also being possible).

EnergyBalanceModels
EnergyBalanceModels.jl accelerates both modelling and analysis aspects of working
with such models by:

"""
module defining various equations and models representing energy balance
processes. It utilizes ModelingToolkit.jl to create a flexible framework
for adding or remove dynamical state variables and adding or removing
equations that represent various processes in the earth system.
"""
- Building upon [ModelingToolkit.jl](https://docs.sciml.ai/ModelingToolkit/stable/)
for creating equations from _symbolic expressions_.
- Utilizing [ProcessBasedModelling.jl](https://github.com/JuliaDynamics/ProcessBasedModelling.jl?tab=readme-ov-file)
to provide a field-specific framework that allows easily testing different physical
hypotheses regarding how climate variables couple to each
other, or how climate processes are represented by equations.
- Offering many predefined processes from current literature and ongoing research.
- Being easy to extend with more climate variables or physical processes.
- Allowing the straightforward coupling of different conceptual models with each other.
- Automating the naming of custom parameters relating to existing climate processes.
- Integrating with [DynamicalSystems.jl](https://juliadynamics.github.io/DynamicalSystemsDocs.jl/dynamicalsystems/dev/)
to automate the start-up phase of typical nonlinear dynamics based workflows.

To install it, run `import Pkg; Pkg.add("EnergyBalanceModels")`.

All further information is provided in the documentation, which you can either find
[online](https://juliadynamics.github.io/EnergyBalanceModels.jl/stable/) or build
locally by running the `docs/make.jl` file.
23 changes: 18 additions & 5 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
# EnergyBalanceModels.jl



## [Premade symbolic variable instances](@id global_vars)

For convenience, EnergyBalanceModels.jl defines and exports some symbolic variables. These are used throughout the library as the default variables in [implemented processes](@id processes).
For convenience, EnergyBalanceModels.jl defines and exports some symbolic variables
that we [list below](@ref list_vars). These are used throughout the library as the
default variables in [implemented processes](@id processes).
When going through documentation strings of processes, such as [`BasicRadiationBalance`](@ref),
you will notice that the function call signature is like:

```julia
BasicRadiationBalance(; T=T, kwargs...)
```

This `T=T` means that the keyword argument `T`, which represents the "temperature variable", takes the value of `EnergyBalanceModels.T`, which itself is a premade symbolic variable instance that is exported by EnergyBalanceModels.jl. You can pass in your own variables instead, by doing
This `T=T` means that the keyword argument `T`, which represents the
"temperature variable", takes the value of `EnergyBalanceModels.T`,
which itself is a premade symbolic variable instance that is exported by
EnergyBalanceModels.jl. You can pass in your own variables instead, by doing
```julia
@variables T1_tropics = 310.0
@variables begin
(T1_tropics(t) = 290.0), [bounds = (200.0, 350.0), description = "temperature in tropical box 1, in Kelvin"]
end
BasicRadiationBalance(; T=T1_tropics, kwargs...)
```
_(you would also need to give `T1_tropics` to all other processes that utilize temperature)_

Defining variables with the extra `bounds, description` annotations is
useful for integrating with the rest of the functionality of the library.

The exported symbolic variables are:
### [List of premade variables](@id list_vars)

```@example MAIN
using EnergyBalanceModels
Expand All @@ -28,7 +41,7 @@ PREDEFINED_EBM_VARIABLES
All [exported symbolic variable instances](@ref) are defiled with a default value and have plausible physical limits that can be obtained with the following function:

```@docs
physically_plausible_limits(::String)
physically_plausible_limits(::Any)
```

e.g.,
Expand Down
8 changes: 1 addition & 7 deletions docs/src/processes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@

Predefined processes are provided in this page.
Those extracted by the literature cite their according resource.
Note that by default all processes utilize the globally-exported [predefined variables](@ref variables) of EnergyBalanceModels.jl.
This is conveyed in the documentation strings by writing something like
```
f(; T = T, kw...)
```
this means that the variable representing "T" will be by default the global symbolic variable `T`. You could of course provide any other variable, such as `T1` or `T2` if you have two "boxes" with different temperatures for example.
Note that by default all processes utilize the globally-exported [predefined variables](@ref global_vars) of EnergyBalanceModels.jl.

## Temperature

Expand Down Expand Up @@ -58,6 +53,5 @@ CO2Forcing
```@docs
CloudAlbedoExponential
CloudAlbedoLinear
EmissivityCumulativeSubtraction
BudykoOLR
```
7 changes: 3 additions & 4 deletions src/statespace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ The states need to be named as the limits are deduced from the function
`physically_plausible_limits(varname::String)`.
"""
function physically_plausible_limits(ds::DynamicalSystem)
sys = referrenced_sciml_model(ds)
vars = ModelingToolkit.states(sys)
varstrings = @. string(ModelingToolkit.getname(vars))
minmax = physically_plausible_limits.(varstrings)
model = referrenced_sciml_model(ds)
vars = ModelingToolkit.states(model)
minmax = physically_plausible_limits.(vars)
return minmax
end

Expand Down
51 changes: 21 additions & 30 deletions src/variables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,39 @@
# will exist in the equations.

const PREDEFINED_EBM_VARIABLES = @variables begin
T(t) = 290.0 # [description = "temperature, in Kelvin"]
S(t) = 1.0 # [description = "insolation in units relative to solar constant"]
f(t) = 0.0 # [description = "external forcing, normalized to units of the solar constant"]
α(t) = 0.3 # [description = "planetary albedo, unitless"]
α_ice(t) = 0.05 # [description = "albedo of ice, unitless"]
α_cloud(t) = 0.1 # [description = "albedo of clouds, unitless"]
ΔT(t) = 17.0 # [description = "equator to pole temperature difference, in Kelvin"]
ε(t) = 0.5 # [description = "planetary effective emissivity, unitless"]
C(t) = 0.6744 # [description = "cloud fraction, unitless"]
(t) = 0.8 # [description = "sine of latitude of ice-line"]
CO2(t) = 400 # [description = "CO2 concentration, in ppm"]
(T(t) = 290.0), [bounds = (200.0, 350.0), description = "temperature, in Kelvin"]
(S(t) = 1.0), [bounds = (0.8, 1.2), description = "insolation, normalized to units of the solar constant"]
(f(t) = 0.0), [bounds = (-0.1, 0.1), description = "external forcing, normalized to units of the solar constant"]
(α(t) = 0.3), [bounds = (0.0, 1.0), description = "planetary albedo, unitless"]
(α_ice(t) = 0.05), [bounds = (0.0, 1.0), description = "albedo of ice, unitless"]
(α_cloud(t) = 0.1), [bounds = (0.0, 1.0), description = "albedo of clouds, unitless"]
(ΔT(t) = 17.0), [bounds = (0.0, 60.0), description = "equator to pole temperature difference, in Kelvin"]
(ε(t) = 0.5), [bounds = (0.0, 1.0), description = "planetary effective emissivity, unitless"]
(C(t) = 0.6744), [bounds = (0.0, 1.0), description = "cloud fraction, unitless"]
((t) = 0.8), [bounds = (0.0, 1.0), description = "sine of latitude of ice-line"]
(CO2(t) = 400), [bounds = (200.0, 1800.0), description = "CO2 concentration, in ppm"]
# Observables that can never be dynamic variables and hence have no default value:
OLR(t) # [description = "outgoing longwave radiation"]
ASR(t) # [description = "absorved shortwave radiation"]
(OLR(t)), [description = "outgoing longwave radiation"]
(ASR(t)), [description = "absorved shortwave radiation"]
end

# TODO: Should we do this export...?
export T, S, f, α, α_ice, α_cloud, ΔT, ε, ℓ, C, CO2, OLR, ASR

# This function is only meaningful for dynamic variables!
"""
physically_plausible_limits(x)
Return a tuple (min, max) of limiting values for the variable `x`.
Return a tuple (min, max) of plausible limiting values for the variable `x`.
"""
function physically_plausible_limits(var::String)::Tuple{Float64, Float64}
if var[1] == 'T'
return (200, 350)
elseif var == "α_ice" || var == "α_clouds"
return (0, 0.5)
elseif var[1] == 'α' || var[1] == 'ε' || var[1] == 'C' || var[1] == ''
return (0, 1)
elseif var == "ΔT"
return (5.0, 60.0)
elseif var == "CO2"
return (200.0, 1600.0)
function physically_plausible_limits(var)
if ModelingToolkit.hasbounds(var)
return getbounds(var)
elseif !isnothing(default_value(var))
return (0.8default_value(var), 1.2default_value(var))
else
error("Unpsecified plausible physical limits for $(var) or no default value. "*
"Please edit function `physically_plausible_limits` and add one.")
error("""
Unpsecified plausible physical limits for $(var): it has no defined bounds or
a default variable. You need to redefine the variable to have either of the two.
""")
end
end

physically_plausible_limits(var) = physically_plausible_limits(string(ModelingToolkit.getname(var)))

0 comments on commit d1f873a

Please sign in to comment.