List of submissions

It follows the code and plot of the RainGauge of all RainMaker submissions to /submissions sorted in alphabetical order of the filename.

Chris Rackauckas: Global BBO optimization

path: /submissions/chris_global_bbo.jl

rank: 1. of 12 submissions

author = "Chris Rackauckas"
description = "Global BBO optimization"

#=

using SpeedyWeather
using RainMaker
using Optimization, OptimizationBBO

const PARAMETER_KEYS = (
    :orography_scale,           # [1],      default: 1, scale of global orography
    :mountain_height,           # [m],      default: 0, height of an additional azores mountain
    :mountain_size,             # [˚],      default: 1, horizontal size of an additional azores mountain
    :mountain_lon,              # [˚E],     default: -27.25, longitude of an additional azores mountain
    :mountain_lat,              # [˚N],     default: 38.7, latitude of an additional azores mountain
    :temperature_equator,       # [K],      default: 300, sea surface temperature at the equator
    :temperature_pole,          # [K],      default: 273, sea surfaec temperature at the poles
    :temperature_atlantic,      # [K],      default: 0, sea surface temperature anomaly in the atlantic
    :temperature_azores,        # [K],      default: 0, sea surface temperature anomaly at the azores
    :zonal_wind,                # [m/s],    default: 35, zonal wind speed
    :rotation,                  # [],       default: 7.9e-5, Earth rotation
    :ocean_temp,                # [K],      default: 175,
)

function calc_precip(u)
    best_param_sample = u

    # wrap into named tuple
    parameters = NamedTuple{PARAMETER_KEYS}(best_param_sample)

    # define resolution. Use trunc=42, 63, 85, 127, ... for higher resolution, cubically slower
    spectral_grid = SpectralGrid(trunc=31, nlayers=8)

    # Define AquaPlanet ocean, for idealised sea surface temperatures
    # but don't change land-sea mask = retain real ocean basins
    ocean = AquaPlanet(spectral_grid,
                temp_equator=parameters.temperature_equator,
                temp_poles=parameters.temperature_pole)

    # add initial conditions with a stronger zonal wind matching temperature
    initial_conditions = InitialConditions(
        vordiv = ZonalWind(u₀=parameters.zonal_wind),
        temp = JablonowskiTemperature(u₀=parameters.zonal_wind),
        pres = PressureOnOrography(),
        humid = ConstantRelativeHumidity())

    # Earth's orography but scaled
    orography = EarthOrography(spectral_grid, scale=parameters.orography_scale)

    # construct model
    model = PrimitiveWetModel(spectral_grid; ocean, initial_conditions, orography, planet=Earth(Float32, rotation=parameters.rotation))

    # Add rain gauge, locate on Terceira Island
    rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
    add!(model, rain_gauge)

    # Initialize
    simulation = initialize!(model, time=DateTime(2025, 1, 10))

    # Add additional  mountain
    H = parameters.mountain_height
    λ₀, φ₀, σ = parameters.mountain_lon, parameters.mountain_lat, parameters.mountain_size
    set!(model, orography=(λ,φ) -> H*exp(-spherical_distance((λ,φ), (λ₀,φ₀), radius=360/2π)^2/2σ^2), add=true)

    set!(simulation, temp = (λ, ϕ, σ) -> parameters.ocean_temp)

    # set sea surface temperature anomalies
    # 1. Atlantic
    set!(simulation, sea_surface_temperature=
        (λ, φ) -> (30 < φ < 60) && (270 < λ < 360) ? parameters.temperature_atlantic : 0, add=true)

    # 2. Azores
    A = parameters.temperature_azores
    λ_az, φ_az, σ_az = -27.25, 38.7, 4    # location [˚], size [˚] of Azores
    set!(simulation, sea_surface_temperature=
        (λ, φ) -> A*exp(-spherical_distance((λ, φ), (λ_az, φ_az), radius=360/2π)^2/2σ_az^2), add=true)

    # Run simulation for 20 days, maybe longer for more stable statistics? Could be increased to 30, 40, ... days ?
    run!(simulation, period=Day(20))
    skip!(rain_gauge, Day(5))
    maximum(rain_gauge.accumulated_rain_convection + rain_gauge.accumulated_rain_large_scale)
end

loss(u,p) = -Float64(calc_precip(u))
f = OptimizationFunction(loss)
lb = [0, -2000, 0, -180, -90, 270, 270, -5, -5, 5, 0.0 ,0.0]
ub = [2, 5000, 30, 180, 90, 300, 300, 5, 5, 50, 1e-4, 305]
x0 = (lb .+ ub) ./ 2
prob = Optimization.OptimizationProblem(f, x0; lb, ub)

function callback(state, l) #callback function to observe training
    display(l)
    return false
end

sol = solve(prob, BBO_adaptive_de_rand_1_bin_radiuslimited(), maxiters = 10000,
    maxtime = 10000.0, callback = callback)

loss(sol.u, nothing)
=#

using SpeedyWeather
using RainMaker

PARAMETER_KEYS = (
    :orography_scale,           # [1],      default: 1, scale of global orography
    :mountain_height,           # [m],      default: 0, height of an additional azores mountain
    :mountain_size,             # [˚],      default: 1, horizontal size of an additional azores mountain
    :mountain_lon,              # [˚E],     default: -27.25, longitude of an additional azores mountain
    :mountain_lat,              # [˚N],     default: 38.7, latitude of an additional azores mountain
    :temperature_equator,       # [K],      default: 300, sea surface temperature at the equator
    :temperature_pole,          # [K],      default: 273, sea surfaec temperature at the poles
    :temperature_atlantic,      # [K],      default: 0, sea surface temperature anomaly in the atlantic
    :temperature_azores,        # [K],      default: 0, sea surface temperature anomaly at the azores
    :zonal_wind,                # [m/s],    default: 35, zonal wind speed
    :rotation,                  # [],       default: 7.9e-5, Earth rotation
    :ocean_temp,                # [K],      default: 175,
)

# output from the surrogate model
best_param_sample = [
  1.1225500464800942,
  220.31392224420077,
  12.01763511440397,
  -15.841509987790861,
  -86.12422836923388,
  288.90809710269053,
  298.96513672809175,
  4.925009771675318,
  3.5009899916848117,
  6.871195942673129,
  3.0197768190150545e-5,
  173.24948639303884
]

parameters = NamedTuple{PARAMETER_KEYS}(best_param_sample)

# define resolution. Use trunc=42, 63, 85, 127, ... for higher resolution, cubically slower
spectral_grid = SpectralGrid(trunc=31, nlayers=8)

# Define AquaPlanet ocean, for idealised sea surface temperatures
# but don't change land-sea mask = retain real ocean basins
ocean = AquaPlanet(spectral_grid,
            temp_equator=parameters.temperature_equator,
            temp_poles=parameters.temperature_pole)

# add initial conditions with a stronger zonal wind matching temperature
initial_conditions = InitialConditions(
    vordiv = ZonalWind(u₀=parameters.zonal_wind),
    temp = JablonowskiTemperature(u₀=parameters.zonal_wind),
    pres = PressureOnOrography(),
    humid = ConstantRelativeHumidity())

# Earth's orography but scaled
orography = EarthOrography(spectral_grid, scale=parameters.orography_scale)

# construct model
model = PrimitiveWetModel(spectral_grid; ocean, initial_conditions, orography, planet=Earth(Float32, rotation=parameters.rotation))

# Add rain gauge, locate on Terceira Island
rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

# Initialize
simulation = initialize!(model, time=DateTime(2025, 1, 10))

# Add additional  mountain
H = parameters.mountain_height
λ₀, φ₀, σ = parameters.mountain_lon, parameters.mountain_lat, parameters.mountain_size
set!(model, orography=(λ,φ) -> H*exp(-spherical_distance((λ,φ), (λ₀,φ₀), radius=360/2π)^2/2σ^2), add=true)

set!(simulation, temp = (λ, ϕ, σ) -> parameters.ocean_temp)

# set sea surface temperature anomalies
# 1. Atlantic
set!(simulation, sea_surface_temperature=
    (λ, φ) -> (30 < φ < 60) && (270 < λ < 360) ? parameters.temperature_atlantic : 0, add=true)

# 2. Azores
A = parameters.temperature_azores
λ_az, φ_az, σ_az = -27.25, 38.7, 4    # location [˚], size [˚] of Azores
set!(simulation, sea_surface_temperature=
    (λ, φ) -> A*exp(-spherical_distance((λ, φ), (λ_az, φ_az), radius=360/2π)^2/2σ_az^2), add=true)

# Run simulation for 20 days, maybe longer for more stable statistics? Could be increased to 30, 40, ... days ?
run!(simulation, period=Day(20))

submission: chris_global_bbo

Simone: A veeery cold atmosphere

path: /submissions/simone_submission.jl

rank: 2. of 12 submissions

author = "Simone"
description = "A veeery cold atmosphere"

using SpeedyWeather
using RainMaker
using Dates

# define resolution. Use trunc=42, 63, 85, 127, ... for higher resolution, cubically slower
spectral_grid = SpectralGrid(trunc=31, nlayers=8)

# Define AquaPlanet ocean, for idealised sea surface temperatures
# but don't change land-sea mask = retain real ocean basins
ocean = AquaPlanet(spectral_grid)

# add initial conditions with a stronger zonal wind matching temperature
initial_conditions = InitialConditions(
    vordiv = ZonalWind(u₀=50),
    temp   = JablonowskiTemperature(),
    pres   = PressureOnOrography(),
    humid  = ConstantRelativeHumidity())

# Earth's orography but scaled
orography = EarthOrography(spectral_grid, scale=0.25)

# Let's reduce the rotation rate to make the planet run slower
model = PrimitiveWetModel(spectral_grid; ocean, initial_conditions, orography, planet=Earth(Float32, rotation=1e-5))

# Pick the location of the Azores (Terceira Island)
λₒ = -27.25
φ₀ = 38.7

# Add rain gauge, locate on Terceira Island
rain_gauge = RainGauge(spectral_grid, lond=λₒ, latd=φ₀)
add!(model, rain_gauge)

# Initialize
simulation = initialize!(model, time=DateTime(2025, 1, 10))

# A hot ocean under a veeeeeeeeery cold atmosphere
set!(simulation, sea_surface_temperature=(λ, φ)->305)
set!(simulation, temp=(λ, ϕ, σ)->175)

run!(simulation, period=Day(20))

# Plot the results (not needed for submission but doesn't hurt!)
using CairoMakie
# heatmap(model.orography.orography, title="My orogoraphy [m]") # check orography
RainMaker.plot(rain_gauge, rate_Δt=Hour(1), skip=Day(5))

submission: simone_submission

Anas: Surrogate best parameters

path: /submissions/anas_surrogate.jl

rank: 3. of 12 submissions

author = "Anas"
description = "Surrogate best parameters"

using SpeedyWeather
using RainMaker

PARAMETER_KEYS = (
    :orography_scale,           # [1],      default: 1, scale of global orography
    :mountain_height,           # [m],      default: 0, height of an additional azores mountain
    :mountain_size,             # [˚],      default: 1, horizontal size of an additional azores mountain
    :mountain_lon,              # [˚E],     default: -27.25, longitude of an additional azores mountain
    :mountain_lat,              # [˚N],     default: 38.7, latitude of an additional azores mountain
    :temperature_equator,       # [K],      default: 300, sea surface temperature at the equator
    :temperature_pole,          # [K],      default: 273, sea surfaec temperature at the poles
    :temperature_atlantic,      # [K],      default: 0, sea surface temperature anomaly in the atlantic
    :temperature_azores,        # [K],      default: 0, sea surface temperature anomaly at the azores
    :zonal_wind,                # [m/s],    default: 35, zonal wind speed
)

# output from the surrogate model
best_param_sample = [
    0.243467,
    3456.64,
    21.2324,
    -90.1826,
    58.4064,
    287.617,
    295.99,
    4.98632,
    3.45722,
    50.0179,
]

# wrap into named tuple
parameters = NamedTuple{PARAMETER_KEYS}(best_param_sample)

# define resolution. Use trunc=42, 63, 85, 127, ... for higher resolution, cubically slower
spectral_grid = SpectralGrid(trunc=31, nlayers=8)

# Define AquaPlanet ocean, for idealised sea surface temperatures
# but don't change land-sea mask = retain real ocean basins
ocean = AquaPlanet(spectral_grid,
            temp_equator=parameters.temperature_equator,
            temp_poles=parameters.temperature_pole)

# add initial conditions with a stronger zonal wind matching temperature
initial_conditions = InitialConditions(
    vordiv = ZonalWind(u₀=parameters.zonal_wind),
    temp = JablonowskiTemperature(u₀=parameters.zonal_wind),
    pres = PressureOnOrography(),
    humid = ConstantRelativeHumidity())

# Earth's orography but scaled
orography = EarthOrography(spectral_grid, scale=parameters.orography_scale)

# construct model
model = PrimitiveWetModel(spectral_grid; ocean, initial_conditions, orography)

# Add rain gauge, locate on Terceira Island
rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

# Initialize
simulation = initialize!(model, time=DateTime(2025, 1, 10))

# Add additional  mountain
H = parameters.mountain_height
λ₀, φ₀, σ = parameters.mountain_lon, parameters.mountain_lat, parameters.mountain_size
set!(model, orography=(λ,φ) -> H*exp(-spherical_distance((λ,φ), (λ₀,φ₀), radius=360/2π)^2/2σ^2), add=true)

# set sea surface temperature anomalies
# 1. Atlantic
set!(simulation, sea_surface_temperature=
    (λ, φ) -> (30 < φ < 60) && (270 < λ < 360) ? parameters.temperature_atlantic : 0, add=true)

# 2. Azores
A = parameters.temperature_azores
λ_az, φ_az, σ_az = -27.25, 38.7, 4    # location [˚], size [˚] of Azores
set!(simulation, sea_surface_temperature=
    (λ, φ) -> A*exp(-spherical_distance((λ, φ), (λ_az, φ_az), radius=360/2π)^2/2σ_az^2), add=true)

# Run simulation for 20 days, maybe longer for more stable statistics? Could be increased to 30, 40, ... days ?
run!(simulation, period=Day(20))

submission: anas_surrogate

Chris Rackauckas: XGBoost surrogate, global BBO optimization

path: /submissions/chris_xgboost_global.jl

rank: 4. of 12 submissions

author = "Chris Rackauckas"
description = "XGBoost surrogate, global BBO optimization"

#=
# Same data as the neural network, just a dead simple surrogate

using JLSO
cd(raw"/Users/chrisrackauckas/.julia/external/speedier_speedyweather_juliaEO25")
data = JLSO.load("10kdata.jlso")[:d]
X = data.inputs'
y = data.outputs

Xtrain = X[1:2:end, :]
Xtest  = X[2:2:end, :]
ytrain = y[1:2:end]
ytest  = y[2:2:end]

using XGBoost, Statistics

bst = xgboost((Xtrain, ytrain), num_round=1000, max_depth=7, objective="reg:squarederror")
# obtain model predictions
ŷ = predict(bst, Xtest)
mean(abs2,ŷ - ytest)

evaluate(x) = predict(bst, reshape(x,1,10))[1]

using Optimization, OptimizationBBO
function loss(x,p)
    -Float64(evaluate(x))
end
f = OptimizationFunction(loss)
lb = [0, -2000, 0, -180, -90, 270, 270, -5, -5, 5]
ub = [2, 5000, 30, 180, 90, 300, 300, 5, 5, 50]
x0 = Xtest[1,:]
prob = Optimization.OptimizationProblem(f, x0; lb, ub)

function callback(state, l) #callback function to observe training
    display(l)
    return false
end

sol = solve(prob, BBO_adaptive_de_rand_1_bin_radiuslimited(), maxiters = 100000,
    maxtime = 1000.0, callback = callback)
=#

using SpeedyWeather
using RainMaker

PARAMETER_KEYS = (
    :orography_scale,           # [1],      default: 1, scale of global orography
    :mountain_height,           # [m],      default: 0, height of an additional azores mountain
    :mountain_size,             # [˚],      default: 1, horizontal size of an additional azores mountain
    :mountain_lon,              # [˚E],     default: -27.25, longitude of an additional azores mountain
    :mountain_lat,              # [˚N],     default: 38.7, latitude of an additional azores mountain
    :temperature_equator,       # [K],      default: 300, sea surface temperature at the equator
    :temperature_pole,          # [K],      default: 273, sea surfaec temperature at the poles
    :temperature_atlantic,      # [K],      default: 0, sea surface temperature anomaly in the atlantic
    :temperature_azores,        # [K],      default: 0, sea surface temperature anomaly at the azores
    :zonal_wind,                # [m/s],    default: 35, zonal wind speed
)

# output from the surrogate model
best_param_sample = [0.35952993077958434,
  3703.1625800261263,
  26.34236279617161,
  -68.84186967475854,
  75.45866186852497,
  298.51854709388454,
  296.03786989719214,
  4.737936621135976,
  4.397474802331573,
  46.17772842581346
]

# wrap into named tuple
parameters = NamedTuple{PARAMETER_KEYS}(best_param_sample)

# define resolution. Use trunc=42, 63, 85, 127, ... for higher resolution, cubically slower
spectral_grid = SpectralGrid(trunc=31, nlayers=8)

# Define AquaPlanet ocean, for idealised sea surface temperatures
# but don't change land-sea mask = retain real ocean basins
ocean = AquaPlanet(spectral_grid,
            temp_equator=parameters.temperature_equator,
            temp_poles=parameters.temperature_pole)

# add initial conditions with a stronger zonal wind matching temperature
initial_conditions = InitialConditions(
    vordiv = ZonalWind(u₀=parameters.zonal_wind),
    temp = JablonowskiTemperature(u₀=parameters.zonal_wind),
    pres = PressureOnOrography(),
    humid = ConstantRelativeHumidity())

# Earth's orography but scaled
orography = EarthOrography(spectral_grid, scale=parameters.orography_scale)

# construct model
model = PrimitiveWetModel(spectral_grid; ocean, initial_conditions, orography)

# Add rain gauge, locate on Terceira Island
rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

# Initialize
simulation = initialize!(model, time=DateTime(2025, 1, 10))

# Add additional  mountain
H = parameters.mountain_height
λ₀, φ₀, σ = parameters.mountain_lon, parameters.mountain_lat, parameters.mountain_size
set!(model, orography=(λ,φ) -> H*exp(-spherical_distance((λ,φ), (λ₀,φ₀), radius=360/2π)^2/2σ^2), add=true)

# set sea surface temperature anomalies
# 1. Atlantic
set!(simulation, sea_surface_temperature=
    (λ, φ) -> (30 < φ < 60) && (270 < λ < 360) ? parameters.temperature_atlantic : 0, add=true)

# 2. Azores
A = parameters.temperature_azores
λ_az, φ_az, σ_az = -27.25, 38.7, 4    # location [˚], size [˚] of Azores
set!(simulation, sea_surface_temperature=
    (λ, φ) -> A*exp(-spherical_distance((λ, φ), (λ_az, φ_az), radius=360/2π)^2/2σ_az^2), add=true)

# Run simulation for 20 days, maybe longer for more stable statistics? Could be increased to 30, 40, ... days ?
run!(simulation, period=Day(20))

submission: chris_xgboost_global

Chris Rackauckas: Global BBO optimization with hot water

path: /submissions/chris_global_bbo_hotwater.jl

rank: 5. of 12 submissions

author = "Chris Rackauckas"
description = "Global BBO optimization with hot water"

#=

using SpeedyWeather
using RainMaker
using Optimization, OptimizationBBO

PARAMETER_KEYS = (
    :orography_scale,           # [1],      default: 1, scale of global orography
    :mountain_height,           # [m],      default: 0, height of an additional azores mountain
    :mountain_size,             # [˚],      default: 1, horizontal size of an additional azores mountain
    :mountain_lon,              # [˚E],     default: -27.25, longitude of an additional azores mountain
    :mountain_lat,              # [˚N],     default: 38.7, latitude of an additional azores mountain
    :temperature_equator,       # [K],      default: 300, sea surface temperature at the equator
    :temperature_pole,          # [K],      default: 273, sea surfaec temperature at the poles
    :sea_surface_temperature,   # [K],      default: 273, sea surface temperature anomaly in the atlantic
    :zonal_wind,                # [m/s],    default: 35, zonal wind speed
    :rotation,                  # [],       default: 7.9e-5, Earth rotation
    :ocean_temp,                # [K],      default: 175,
)

function calc_precip(u)
    best_param_sample = u

    # wrap into named tuple
    parameters = NamedTuple{PARAMETER_KEYS}(best_param_sample)

    # define resolution. Use trunc=42, 63, 85, 127, ... for higher resolution, cubically slower
    spectral_grid = SpectralGrid(trunc=31, nlayers=8)

    # Define AquaPlanet ocean, for idealised sea surface temperatures
    # but don't change land-sea mask = retain real ocean basins
    ocean = AquaPlanet(spectral_grid,
                temp_equator=parameters.temperature_equator,
                temp_poles=parameters.temperature_pole)

    # add initial conditions with a stronger zonal wind matching temperature
    initial_conditions = InitialConditions(
        vordiv = ZonalWind(u₀=parameters.zonal_wind),
        temp = JablonowskiTemperature(u₀=parameters.zonal_wind),
        pres = PressureOnOrography(),
        humid = ConstantRelativeHumidity())

    # Earth's orography but scaled
    orography = EarthOrography(spectral_grid, scale=parameters.orography_scale)

    # construct model
    model = PrimitiveWetModel(spectral_grid; ocean, initial_conditions, orography, planet=Earth(Float32, rotation=parameters.rotation))

    # Add rain gauge, locate on Terceira Island
    rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
    add!(model, rain_gauge)

    # Initialize
    simulation = initialize!(model, time=DateTime(2025, 1, 10))

    # Add additional  mountain
    H = parameters.mountain_height
    λ₀, φ₀, σ = parameters.mountain_lon, parameters.mountain_lat, parameters.mountain_size
    set!(model, orography=(λ,φ) -> H*exp(-spherical_distance((λ,φ), (λ₀,φ₀), radius=360/2π)^2/2σ^2), add=true)

    set!(simulation, temp = (λ, ϕ, σ) -> parameters.ocean_temp)
    set!(simulation, sea_surface_temperature = (λ, φ) -> parameters.sea_surface_temperature)

    # Run simulation for 20 days, maybe longer for more stable statistics? Could be increased to 30, 40, ... days ?
    run!(simulation, period=Day(20))
    skip!(rain_gauge, Day(5))
    maximum(rain_gauge.accumulated_rain_convection + rain_gauge.accumulated_rain_large_scale)
end

loss(u,p) = -Float64(calc_precip(u))
f = OptimizationFunction(loss)
lb = [0, -2000, 0, -180, -90, 270, 270, 280, 5, 0.0 ,0.0]
ub = [2, 5000, 30, 180, 90, 300, 300, 305, 50, 1e-4, 305]
x0 = (lb .+ ub) ./ 2
prob = Optimization.OptimizationProblem(f, x0; lb, ub)

function callback(state, l) #callback function to observe training
    display(l)
    return false
end

sol = solve(prob, BBO_adaptive_de_rand_1_bin_radiuslimited(), maxiters = 10000,
    maxtime = 10000.0, callback = callback)

loss(sol.u, nothing)

julia> @show sol.u
sol.u = [0.35189195474845386, -777.7890066578076, 14.561382886621368, 151.4405147870285, -0.8557381444610144, 296.3475643734993, 277.9450731849207, 304.0433587248594, 31.637335763119115, 6.329669836967033e-6, 169.16288037057643]
=#

using SpeedyWeather
using RainMaker

PARAMETER_KEYS = (
    :orography_scale,           # [1],      default: 1, scale of global orography
    :mountain_height,           # [m],      default: 0, height of an additional azores mountain
    :mountain_size,             # [˚],      default: 1, horizontal size of an additional azores mountain
    :mountain_lon,              # [˚E],     default: -27.25, longitude of an additional azores mountain
    :mountain_lat,              # [˚N],     default: 38.7, latitude of an additional azores mountain
    :temperature_equator,       # [K],      default: 300, sea surface temperature at the equator
    :temperature_pole,          # [K],      default: 273, sea surfaec temperature at the poles
    :sea_surface_temperature,   # [K],      default: 273, sea surface temperature anomaly in the atlantic
    :zonal_wind,                # [m/s],    default: 35, zonal wind speed
    :rotation,                  # [],       default: 7.9e-5, Earth rotation
    :ocean_temp,                # [K],      default: 175,
)

# output from the surrogate model
best_param_sample = [0.35189195474845386,
      -777.7890066578076,
      14.561382886621368,
      151.4405147870285,
      -0.8557381444610144,
      296.3475643734993,
      277.9450731849207,
      304.0433587248594,
      31.637335763119115,
      6.329669836967033e-6,
      169.16288037057643
]

# wrap into named tuple
parameters = NamedTuple{PARAMETER_KEYS}(best_param_sample)

# define resolution. Use trunc=42, 63, 85, 127, ... for higher resolution, cubically slower
spectral_grid = SpectralGrid(trunc=31, nlayers=8)

# Define AquaPlanet ocean, for idealised sea surface temperatures
# but don't change land-sea mask = retain real ocean basins
ocean = AquaPlanet(spectral_grid,
            temp_equator=parameters.temperature_equator,
            temp_poles=parameters.temperature_pole)

# add initial conditions with a stronger zonal wind matching temperature
initial_conditions = InitialConditions(
    vordiv = ZonalWind(u₀=parameters.zonal_wind),
    temp = JablonowskiTemperature(u₀=parameters.zonal_wind),
    pres = PressureOnOrography(),
    humid = ConstantRelativeHumidity())

# Earth's orography but scaled
orography = EarthOrography(spectral_grid, scale=parameters.orography_scale)

# construct model
model = PrimitiveWetModel(spectral_grid; ocean, initial_conditions, orography, planet=Earth(Float32, rotation=parameters.rotation))

# Add rain gauge, locate on Terceira Island
rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

# Initialize
simulation = initialize!(model, time=DateTime(2025, 1, 10))

# Add additional  mountain
H = parameters.mountain_height
λ₀, φ₀, σ = parameters.mountain_lon, parameters.mountain_lat, parameters.mountain_size
set!(model, orography=(λ,φ) -> H*exp(-spherical_distance((λ,φ), (λ₀,φ₀), radius=360/2π)^2/2σ^2), add=true)

set!(simulation, temp = (λ, ϕ, σ) -> parameters.ocean_temp)
set!(simulation, sea_surface_temperature = (λ, φ) -> parameters.sea_surface_temperature)

# Run simulation for 20 days, maybe longer for more stable statistics? Could be increased to 30, 40, ... days ?
run!(simulation, period=Day(20))

submission: chris_global_bbo_hotwater

Chris Rackauckas: XGBoost surrogate, best parameters

path: /submissions/chris_xgboost.jl

rank: 6. of 12 submissions

author = "Chris Rackauckas"
description = "XGBoost surrogate, best parameters"

#=
# Same data as the neural network, just a dead simple surrogate

using JLSO
cd(raw"/Users/chrisrackauckas/.julia/external/speedier_speedyweather_juliaEO25")
data = JLSO.load("10kdata.jlso")[:d]
X = data.inputs'
y = data.outputs

Xtrain = X[1:2:end, :]
Xtest  = X[2:2:end, :]
ytrain = y[1:2:end]
ytest  = y[2:2:end]

using XGBoost, Statistics

bst = xgboost((Xtrain, ytrain), num_round=1000, max_depth=7, objective="reg:squarederror")
# obtain model predictions
ŷ = predict(bst, Xtest)
mean(abs2,ŷ - ytest)

evaluate(x) = predict(bst, reshape(x,1,10))[1]

using Optimization, OptimizationBBO
function loss(x,p)
    -Float64(evaluate(x))
end
f = OptimizationFunction(loss)
lb = [0, -2000, 0, -180, -90, 270, 270, -5, -5, 5]
ub = [2, 5000, 30, 180, 90, 300, 300, 5, 5, 50]
x0 = Xtest[1,:]
prob = Optimization.OptimizationProblem(f, x0; lb, ub)

function callback(state, l) #callback function to observe training
    display(l)
    return false
end

sol = solve(prob, BBO_adaptive_de_rand_1_bin_radiuslimited(), maxiters = 100000,
    maxtime = 1000.0, callback = callback)
=#

using SpeedyWeather
using RainMaker

PARAMETER_KEYS = (
    :orography_scale,           # [1],      default: 1, scale of global orography
    :mountain_height,           # [m],      default: 0, height of an additional azores mountain
    :mountain_size,             # [˚],      default: 1, horizontal size of an additional azores mountain
    :mountain_lon,              # [˚E],     default: -27.25, longitude of an additional azores mountain
    :mountain_lat,              # [˚N],     default: 38.7, latitude of an additional azores mountain
    :temperature_equator,       # [K],      default: 300, sea surface temperature at the equator
    :temperature_pole,          # [K],      default: 273, sea surfaec temperature at the poles
    :temperature_atlantic,      # [K],      default: 0, sea surface temperature anomaly in the atlantic
    :temperature_azores,        # [K],      default: 0, sea surface temperature anomaly at the azores
    :zonal_wind,                # [m/s],    default: 35, zonal wind speed
)

# output from the surrogate model
best_param_sample = [0.3705309673344287,
  3693.5996052143146,
  26.3392947114213,
  -68.49507115449609,
  75.0016456129241,
  295.8298679043166,
  296.00395874468376,
  4.7262056077412495,
  4.371020708252552,
  46.16767297988565
]

# wrap into named tuple
parameters = NamedTuple{PARAMETER_KEYS}(best_param_sample)

# define resolution. Use trunc=42, 63, 85, 127, ... for higher resolution, cubically slower
spectral_grid = SpectralGrid(trunc=31, nlayers=8)

# Define AquaPlanet ocean, for idealised sea surface temperatures
# but don't change land-sea mask = retain real ocean basins
ocean = AquaPlanet(spectral_grid,
            temp_equator=parameters.temperature_equator,
            temp_poles=parameters.temperature_pole)

# add initial conditions with a stronger zonal wind matching temperature
initial_conditions = InitialConditions(
    vordiv = ZonalWind(u₀=parameters.zonal_wind),
    temp = JablonowskiTemperature(u₀=parameters.zonal_wind),
    pres = PressureOnOrography(),
    humid = ConstantRelativeHumidity())

# Earth's orography but scaled
orography = EarthOrography(spectral_grid, scale=parameters.orography_scale)

# construct model
model = PrimitiveWetModel(spectral_grid; ocean, initial_conditions, orography)

# Add rain gauge, locate on Terceira Island
rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

# Initialize
simulation = initialize!(model, time=DateTime(2025, 1, 10))

# Add additional  mountain
H = parameters.mountain_height
λ₀, φ₀, σ = parameters.mountain_lon, parameters.mountain_lat, parameters.mountain_size
set!(model, orography=(λ,φ) -> H*exp(-spherical_distance((λ,φ), (λ₀,φ₀), radius=360/2π)^2/2σ^2), add=true)

# set sea surface temperature anomalies
# 1. Atlantic
set!(simulation, sea_surface_temperature=
    (λ, φ) -> (30 < φ < 60) && (270 < λ < 360) ? parameters.temperature_atlantic : 0, add=true)

# 2. Azores
A = parameters.temperature_azores
λ_az, φ_az, σ_az = -27.25, 38.7, 4    # location [˚], size [˚] of Azores
set!(simulation, sea_surface_temperature=
    (λ, φ) -> A*exp(-spherical_distance((λ, φ), (λ_az, φ_az), radius=360/2π)^2/2σ_az^2), add=true)

# Run simulation for 20 days, maybe longer for more stable statistics? Could be increased to 30, 40, ... days ?
run!(simulation, period=Day(20))

submission: chris_xgboost

Shirin Ermis: Aqua-planet simulation with a mountain

path: /submissions/aquaplanet_mountain.jl

rank: 7. of 12 submissions

author = "Shirin Ermis"
description = "Aqua-planet simulation with a mountain"

using SpeedyWeather, RainMaker

spectral_grid = SpectralGrid(trunc=31, nlayers=10)
model = PrimitiveWetModel(spectral_grid)

# Set up aqauaplanet but add large mountain in "North Sea" after initialization!
ocean = AquaPlanet(spectral_grid, temp_equator=302, temp_poles=300)
land_sea_mask = AquaPlanetMask(spectral_grid)
model = PrimitiveWetModel(spectral_grid; ocean, land_sea_mask)

# Add rain gauge
rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

# Initialize and run simulation
simulation = initialize!(model, time=DateTime(2000, 9, 1))

# Add mountain now! details for mountain
H, λ₀, φ₀, σ = 4000, 2, 51, 5     # height, lon, lat position, and width
set!(model, orography=(λ,φ) -> H*exp(-spherical_distance((λ,φ), (λ₀,φ₀), radius=360/2π)^2/2σ^2))

# Run simulation for 20 days
run!(simulation, period=Day(20))

# Plot the results (not needed for submission but doesn't hurt!)
using CairoMakie
# heatmap(model.orography.orography, title="My orogoraphy [m]") # check orography
RainMaker.plot(rain_gauge, rate_Δt=Hour(1))

submission: aquaplanet_mountain

Milan: Aquaplanet

path: /submissions/aquaplanet.jl

rank: 8. of 12 submissions

author = "Milan"
description = "Aquaplanet"

using SpeedyWeather, RainMaker

spectral_grid = SpectralGrid(trunc=31, nlayers=8)

# define aquaplanet
ocean = AquaPlanet(spectral_grid, temp_equator=302, temp_poles=273)
land_sea_mask = AquaPlanetMask(spectral_grid)
orography = NoOrography(spectral_grid)
model = PrimitiveWetModel(spectral_grid; ocean, land_sea_mask, orography)

rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

simulation = initialize!(model)
run!(simulation, period=Day(20))

submission: aquaplanet

Iga: Just playing around

path: /submissions/iga_model.jl

rank: 9. of 12 submissions

author = "Iga"
description = "Just playing around"

using SpeedyWeather    # v0.13 (or #main)
using RainMaker        # v0.2 (or #main)

spectral_grid = SpectralGrid(trunc=31, nlayers=8)

model = PrimitiveWetModel(spectral_grid)
rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)
simulation = initialize!(model, time=DateTime(2000, 2, 1))

H = 8000           # height [m]
λ_azores = -27.25  # longitude [˚E]
φ_azores = 37.3   # latitude [˚N]
σ = 4             # size [˚]

# define bigger azores as anonymous function, Gaussian mountain, use radius=360/2π for distance in [˚]
bigger_azores = (λ, φ) -> H*exp(-spherical_distance((λ, φ), (λ_azores, φ_azores), radius=360/2π)^2/2σ^2)

# add to default orography, don't replace
set!(model, orography=bigger_azores, land_sea_mask=0, add=true)
set!(simulation, temp=0, sea_surface_temperature=(λ, φ) -> (30 < φ < 60) && (270 < λ < 360) ? 2 : 0, add=true)

run!(simulation, period=Day(20))

submission: iga_model

Tim Reichelt: North Sea mountain

path: /submissions/north_sea_mountain.jl

rank: 10. of 12 submissions

author = "Tim Reichelt"
description = "North Sea mountain"

using SpeedyWeather, RainMaker

spectral_grid = SpectralGrid(trunc=31, nlayers=8)
model = PrimitiveWetModel(spectral_grid)

rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

simulation = initialize!(model)

# add a massive mountain at 51.75°N, 0°W, *after* model initialization
# using spherical_distance for geodesic distances, use radius=360/2π for distance in degrees
H, λ₀, φ₀, σ = 4000, 2, 51, 5     # height, lon, lat position, and width
set!(model, orography=(λ,φ) -> H*exp(-spherical_distance((λ,φ), (λ₀,φ₀), radius=360/2π)^2/2σ^2))

run!(simulation, period=Day(20))

submission: north_sea_mountain

Milan: default

path: /submissions/default.jl

rank: 11. of 12 submissions

author = "Milan"
description = "default"

using SpeedyWeather, RainMaker

spectral_grid = SpectralGrid(trunc=31, nlayers=8)
model = PrimitiveWetModel(spectral_grid)

rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

simulation = initialize!(model)
run!(simulation, period=Day(20))

submission: default

Milan: Atlantic mountain

path: /submissions/atlantic_mountain.jl

rank: 12. of 12 submissions

author = "Milan"
description = "Atlantic mountain"

using SpeedyWeather, RainMaker

spectral_grid = SpectralGrid(trunc=31, nlayers=8)
model = PrimitiveWetModel(spectral_grid)

rain_gauge = RainGauge(spectral_grid, lond=-27.25, latd=38.7)
add!(model, rain_gauge)

simulation = initialize!(model)

# add a massive mountain at 50°N, 35°W, *after* model initialization
H, λ₀, φ₀, σ = 4000, 325, 50, 5     # height, lon, lat position, and width
set!(model, orography=(λ,φ) -> H*exp((-(λ-λ₀)^2 - (φ-φ₀)^2)/2σ^2), add=true)

run!(simulation, period=Day(20))

submission: atlantic_mountain