From bc31b4813749e93e7656e8e07dd985427b2c8e8b Mon Sep 17 00:00:00 2001 From: Jago Stong-Wright Date: Fri, 22 Mar 2024 10:28:40 -0400 Subject: [PATCH 01/10] added property to `ScaleNegativeTracers` to not fill with NaNs if total tracer content is less than 0 --- src/Utils/negative_tracers.jl | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Utils/negative_tracers.jl b/src/Utils/negative_tracers.jl index 21dbc6761..cdca05605 100644 --- a/src/Utils/negative_tracers.jl +++ b/src/Utils/negative_tracers.jl @@ -33,21 +33,23 @@ end ##### Infastructure to rescale negative values ##### -struct ScaleNegativeTracers{FA, SA, W} - tracers :: FA - scalefactors :: SA - warn :: W - - ScaleNegativeTracers(tracers::FA, scalefactors::SA, warn::W) where {FA, SA, W} = - warn ? error("Warning not currently implemented") : new{FA, SA, W}(tracers, scalefactors, warn) +struct ScaleNegativeTracers{FA, SA, FV, W} + tracers :: FA + scalefactors :: SA + nan_fill_value :: FV + warn :: W + + ScaleNegativeTracers(tracers::FA, scalefactors::SA, warn::W, nan_fill_value::FV) where {FA, SA, FV, W} = + warn ? error("Warning not currently implemented") : new{FA, SA, W}(tracers, scalefactors, nan_fill_value, warn) end adapt_structure(to, snt::ScaleNegativeTracers) = ScaleNegativeTracers(adapt(to, snt.tracers), adapt(to, snt.scalefactors), + adapt(to, snt.nan_fill_value), adapt(to, snt.warn)) """ - ScaleNegativeTracers(; tracers, scalefactors = ones(length(tracers)), warn = false) + ScaleNegativeTracers(; tracers, scalefactors = ones(length(tracers)), warn = false, nan_fill_value = NaN) Constructs a modifier to scale `tracers` so that none are negative. Use like: ```julia @@ -60,14 +62,17 @@ github](https://github.com/OceanBioME/OceanBioME.jl/discussions/48). Future plans include implement a positivity-preserving timestepping scheme as the ideal alternative. -If `warn` is true then scaling will raise a warning. +~~If `warn` is true then scaling will raise a warning.~~ + +`nan_fill_value` specifies the value to set the total cell content to if the total is less than 0 +(meaning that total tracer conservation can not be enforced). """ -function ScaleNegativeTracers(tracers; scalefactors = ones(length(tracers)), warn = false) +function ScaleNegativeTracers(tracers; scalefactors = ones(length(tracers)), nan_fill_value = NaN, warn = false) if length(scalefactors) != length(tracers) error("Incorrect number of scale factors provided") end - return ScaleNegativeTracers(tracers, scalefactors, warn) + return ScaleNegativeTracers(tracers, scalefactors, nan_fill_value, warn) end """ @@ -77,11 +82,11 @@ Construct a modifier to scale the conserved tracers in `model`. If `warn` is true then scaling will raise a warning. """ -function ScaleNegativeTracers(bgc::AbstractBiogeochemistry, grid; warn = false) +function ScaleNegativeTracers(bgc::AbstractBiogeochemistry, grid; nan_fill_value = NaN, warn = false) tracers = conserved_tracers(bgc) scalefactors = on_architecture(architecture(grid), ones(length(tracers))) - return ScaleNegativeTracers(tracers, scalefactors, warn) + return ScaleNegativeTracers(tracers, scalefactors, nan_fill_value, warn) end summary(scaler::ScaleNegativeTracers) = string("Mass conserving negative scaling of $(scaler.tracers)") From 3878cca8a3be5626ee227fb2dfa9d5de74f64c22 Mon Sep 17 00:00:00 2001 From: Jago Stong-Wright Date: Fri, 22 Mar 2024 10:30:31 -0400 Subject: [PATCH 02/10] corrections --- src/Utils/negative_tracers.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Utils/negative_tracers.jl b/src/Utils/negative_tracers.jl index cdca05605..985292112 100644 --- a/src/Utils/negative_tracers.jl +++ b/src/Utils/negative_tracers.jl @@ -39,8 +39,8 @@ struct ScaleNegativeTracers{FA, SA, FV, W} nan_fill_value :: FV warn :: W - ScaleNegativeTracers(tracers::FA, scalefactors::SA, warn::W, nan_fill_value::FV) where {FA, SA, FV, W} = - warn ? error("Warning not currently implemented") : new{FA, SA, W}(tracers, scalefactors, nan_fill_value, warn) + ScaleNegativeTracers(tracers::FA, scalefactors::SA, nan_fill_value::FV, warn::W) where {FA, SA, W, FV} = + warn ? error("Warning not currently implemented") : new{FA, SA, FV, W}(tracers, scalefactors, nan_fill_value, warn) end adapt_structure(to, snt::ScaleNegativeTracers) = ScaleNegativeTracers(adapt(to, snt.tracers), From 6afee8301a5bf8c8a3d7fc22b37d4be8184cf30e Mon Sep 17 00:00:00 2001 From: Jago Stong-Wright Date: Fri, 22 Mar 2024 10:32:23 -0400 Subject: [PATCH 03/10] added `nan_fill_value` passing to NPZD --- src/Models/AdvectedPopulations/NPZD.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Models/AdvectedPopulations/NPZD.jl b/src/Models/AdvectedPopulations/NPZD.jl index 4bb2a2a28..79dd85b6c 100644 --- a/src/Models/AdvectedPopulations/NPZD.jl +++ b/src/Models/AdvectedPopulations/NPZD.jl @@ -174,6 +174,7 @@ function NutrientPhytoplanktonZooplanktonDetritus(; grid, open_bottom::Bool = true, scale_negatives = false, + nan_fill_value = NaN, particles::P = nothing, modifiers::M = nothing) where {FT, LA, S, P, M} @@ -195,7 +196,7 @@ function NutrientPhytoplanktonZooplanktonDetritus(; grid, sinking_velocities) if scale_negatives - scaler = ScaleNegativeTracers(underlying_biogeochemistry, grid) + scaler = ScaleNegativeTracers(underlying_biogeochemistry, grid; nan_fill_value) modifiers = isnothing(modifiers) ? scaler : (modifiers..., scaler) end From cb863cf638179fc8da1d7d8475a5d5e016dbe1ec Mon Sep 17 00:00:00 2001 From: Jago Stong-Wright Date: Fri, 22 Mar 2024 16:27:35 -0400 Subject: [PATCH 04/10] rename to `invalid_fill_value` --- src/Models/AdvectedPopulations/NPZD.jl | 4 ++-- src/Utils/negative_tracers.jl | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Models/AdvectedPopulations/NPZD.jl b/src/Models/AdvectedPopulations/NPZD.jl index 79dd85b6c..0ef700267 100644 --- a/src/Models/AdvectedPopulations/NPZD.jl +++ b/src/Models/AdvectedPopulations/NPZD.jl @@ -174,7 +174,7 @@ function NutrientPhytoplanktonZooplanktonDetritus(; grid, open_bottom::Bool = true, scale_negatives = false, - nan_fill_value = NaN, + invalid_fill_value = NaN, particles::P = nothing, modifiers::M = nothing) where {FT, LA, S, P, M} @@ -196,7 +196,7 @@ function NutrientPhytoplanktonZooplanktonDetritus(; grid, sinking_velocities) if scale_negatives - scaler = ScaleNegativeTracers(underlying_biogeochemistry, grid; nan_fill_value) + scaler = ScaleNegativeTracers(underlying_biogeochemistry, grid; invalid_fill_value) modifiers = isnothing(modifiers) ? scaler : (modifiers..., scaler) end diff --git a/src/Utils/negative_tracers.jl b/src/Utils/negative_tracers.jl index 985292112..dc4185623 100644 --- a/src/Utils/negative_tracers.jl +++ b/src/Utils/negative_tracers.jl @@ -36,20 +36,20 @@ end struct ScaleNegativeTracers{FA, SA, FV, W} tracers :: FA scalefactors :: SA - nan_fill_value :: FV + invalid_fill_value :: FV warn :: W - ScaleNegativeTracers(tracers::FA, scalefactors::SA, nan_fill_value::FV, warn::W) where {FA, SA, W, FV} = - warn ? error("Warning not currently implemented") : new{FA, SA, FV, W}(tracers, scalefactors, nan_fill_value, warn) + ScaleNegativeTracers(tracers::FA, scalefactors::SA, invalid_fill_value::FV, warn::W) where {FA, SA, W, FV} = + warn ? error("Warning not currently implemented") : new{FA, SA, FV, W}(tracers, scalefactors, invalid_fill_value, warn) end adapt_structure(to, snt::ScaleNegativeTracers) = ScaleNegativeTracers(adapt(to, snt.tracers), adapt(to, snt.scalefactors), - adapt(to, snt.nan_fill_value), + adapt(to, snt.invalid_fill_value), adapt(to, snt.warn)) """ - ScaleNegativeTracers(; tracers, scalefactors = ones(length(tracers)), warn = false, nan_fill_value = NaN) + ScaleNegativeTracers(; tracers, scalefactors = ones(length(tracers)), warn = false, invalid_fill_value = NaN) Constructs a modifier to scale `tracers` so that none are negative. Use like: ```julia @@ -64,15 +64,15 @@ Future plans include implement a positivity-preserving timestepping scheme as th ~~If `warn` is true then scaling will raise a warning.~~ -`nan_fill_value` specifies the value to set the total cell content to if the total is less than 0 +`invalid_fill_value` specifies the value to set the total cell content to if the total is less than 0 (meaning that total tracer conservation can not be enforced). """ -function ScaleNegativeTracers(tracers; scalefactors = ones(length(tracers)), nan_fill_value = NaN, warn = false) +function ScaleNegativeTracers(tracers; scalefactors = ones(length(tracers)), invalid_fill_value = NaN, warn = false) if length(scalefactors) != length(tracers) error("Incorrect number of scale factors provided") end - return ScaleNegativeTracers(tracers, scalefactors, nan_fill_value, warn) + return ScaleNegativeTracers(tracers, scalefactors, invalid_fill_value, warn) end """ @@ -82,11 +82,11 @@ Construct a modifier to scale the conserved tracers in `model`. If `warn` is true then scaling will raise a warning. """ -function ScaleNegativeTracers(bgc::AbstractBiogeochemistry, grid; nan_fill_value = NaN, warn = false) +function ScaleNegativeTracers(bgc::AbstractBiogeochemistry, grid; invalid_fill_value = NaN, warn = false) tracers = conserved_tracers(bgc) scalefactors = on_architecture(architecture(grid), ones(length(tracers))) - return ScaleNegativeTracers(tracers, scalefactors, nan_fill_value, warn) + return ScaleNegativeTracers(tracers, scalefactors, invalid_fill_value, warn) end summary(scaler::ScaleNegativeTracers) = string("Mass conserving negative scaling of $(scaler.tracers)") From 24224c98415c063a1066e6a57a42e0a069fae21b Mon Sep 17 00:00:00 2001 From: Jago Stong-Wright Date: Fri, 22 Mar 2024 18:09:34 -0400 Subject: [PATCH 05/10] trying to prevent some strange behaviour --- src/Models/AdvectedPopulations/LOBSTER/LOBSTER.jl | 3 ++- src/OceanBioME.jl | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Models/AdvectedPopulations/LOBSTER/LOBSTER.jl b/src/Models/AdvectedPopulations/LOBSTER/LOBSTER.jl index a3818a8cf..949c29d7c 100644 --- a/src/Models/AdvectedPopulations/LOBSTER/LOBSTER.jl +++ b/src/Models/AdvectedPopulations/LOBSTER/LOBSTER.jl @@ -298,6 +298,7 @@ function LOBSTER(; grid, open_bottom::Bool = true, scale_negatives = false, + invalid_fill_value = NaN, particles::P = nothing, modifiers::M = nothing) where {FT, LA, S, P, M} @@ -345,7 +346,7 @@ function LOBSTER(; grid, sinking_velocities) if scale_negatives - scaler = ScaleNegativeTracers(underlying_biogeochemistry, grid) + scaler = ScaleNegativeTracers(underlying_biogeochemistry, grid; invalid_fill_value) if isnothing(modifiers) modifiers = scaler elseif modifiers isa Tuple diff --git a/src/OceanBioME.jl b/src/OceanBioME.jl index be3e4c15e..7bb9c5d6c 100644 --- a/src/OceanBioME.jl +++ b/src/OceanBioME.jl @@ -126,6 +126,7 @@ update_tendencies!(bgc, modifiers::Tuple, model) = [update_tendencies!(bgc, modi function update_biogeochemical_state!(bgc::Biogeochemistry, model) update_biogeochemical_state!(model, bgc.modifiers) + synchronize(device(architecture(model))) update_biogeochemical_state!(model, bgc.light_attenuation) end From e2188be2a12dbcdd08598b080b75c0630037b74d Mon Sep 17 00:00:00 2001 From: Jago Stong-Wright Date: Sun, 24 Mar 2024 19:48:53 -0400 Subject: [PATCH 06/10] forgot to actually put the value in the thing --- src/Utils/negative_tracers.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Utils/negative_tracers.jl b/src/Utils/negative_tracers.jl index dc4185623..b946c37c4 100644 --- a/src/Utils/negative_tracers.jl +++ b/src/Utils/negative_tracers.jl @@ -36,7 +36,7 @@ end struct ScaleNegativeTracers{FA, SA, FV, W} tracers :: FA scalefactors :: SA - invalid_fill_value :: FV +invalid_fill_value :: FV warn :: W ScaleNegativeTracers(tracers::FA, scalefactors::SA, invalid_fill_value::FV, warn::W) where {FA, SA, W, FV} = @@ -102,10 +102,10 @@ function update_biogeochemical_state!(model, scale::ScaleNegativeTracers) tracers_to_scale = Tuple(model.tracers[tracer_name] for tracer_name in keys(scale.tracers)) - scale_for_negs_kernel!(tracers_to_scale, scale.scalefactors) + scale_for_negs_kernel!(tracers_to_scale, scale.scalefactors, scale.invalid_fill_value) end -@kernel function scale_for_negs!(tracers, scalefactors) +@kernel function scale_for_negs!(tracers, scalefactors, invalid_fill_value) i, j, k = @index(Global, NTuple) t, p = 0.0, 0.0 @@ -120,7 +120,7 @@ end end end - t < 0 && (t = NaN) + t < 0 && (t = invalid_fill_value) for tracer in tracers value = @inbounds tracer[i, j, k] From 773de716472a736a46577a055b1a8dac39bb8a04 Mon Sep 17 00:00:00 2001 From: Jago Stong-Wright Date: Mon, 25 Mar 2024 12:20:06 -0400 Subject: [PATCH 07/10] expanded docstring to discuss how other ESMs handel negatives --- src/Utils/negative_tracers.jl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Utils/negative_tracers.jl b/src/Utils/negative_tracers.jl index b946c37c4..2c1053489 100644 --- a/src/Utils/negative_tracers.jl +++ b/src/Utils/negative_tracers.jl @@ -65,7 +65,16 @@ Future plans include implement a positivity-preserving timestepping scheme as th ~~If `warn` is true then scaling will raise a warning.~~ `invalid_fill_value` specifies the value to set the total cell content to if the total is less than 0 -(meaning that total tracer conservation can not be enforced). +(meaning that total tracer conservation can not be enforced). If the value is set to anything other than +`NaN` this scheme no longer conserves mass. While this may be useful to prevent spurious numerics leading +to crashing care should be taken that the mass doesn't deviate too much. + +This scheme is similar to that used by [NEMO-PISCES](https://www.nemo-ocean.eu/), although they scale the +tendency rather than the value, while other Earth system models simply set negative tracers to zero, for +example [NCAR's MARBL](https://marbl-ecosys.github.io/versions/latest_release/index.html) and +[NEMO-TOPAZ2](https://zenodo.org/records/2648099). More complicated schemes exist, for example +[ROMS-BECS](https://zenodo.org/records/3988618) uses an implicite-itterative approach where each component +is updated in sequence to garantee mass conservation, possibly at the expense of numerical precision. """ function ScaleNegativeTracers(tracers; scalefactors = ones(length(tracers)), invalid_fill_value = NaN, warn = false) if length(scalefactors) != length(tracers) From b150232ff4c5c6eb09e66a1f4caaca2b96c2acba Mon Sep 17 00:00:00 2001 From: Jago Stong-Wright Date: Mon, 25 Mar 2024 12:20:44 -0400 Subject: [PATCH 08/10] again --- src/Utils/negative_tracers.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Utils/negative_tracers.jl b/src/Utils/negative_tracers.jl index 2c1053489..498130dcc 100644 --- a/src/Utils/negative_tracers.jl +++ b/src/Utils/negative_tracers.jl @@ -72,9 +72,10 @@ to crashing care should be taken that the mass doesn't deviate too much. This scheme is similar to that used by [NEMO-PISCES](https://www.nemo-ocean.eu/), although they scale the tendency rather than the value, while other Earth system models simply set negative tracers to zero, for example [NCAR's MARBL](https://marbl-ecosys.github.io/versions/latest_release/index.html) and -[NEMO-TOPAZ2](https://zenodo.org/records/2648099). More complicated schemes exist, for example -[ROMS-BECS](https://zenodo.org/records/3988618) uses an implicite-itterative approach where each component -is updated in sequence to garantee mass conservation, possibly at the expense of numerical precision. +[NEMO-TOPAZ2](https://zenodo.org/records/2648099), which does not conserve mass. More complicated schemes +exist, for example [ROMS-BECS](https://zenodo.org/records/3988618) uses an implicite-itterative +approach where each component is updated in sequence to garantee mass conservation, possibly at the +expense of numerical precision. """ function ScaleNegativeTracers(tracers; scalefactors = ones(length(tracers)), invalid_fill_value = NaN, warn = false) if length(scalefactors) != length(tracers) From 6897c8c192ac7822f1782ae0e0fb5bccd1ca7444 Mon Sep 17 00:00:00 2001 From: "Navid C. Constantinou" Date: Tue, 26 Mar 2024 06:57:28 +0200 Subject: [PATCH 09/10] don't actually re-install Oceananigans --- docs/src/index.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index e45a91ddc..89c295cc0 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -25,11 +25,15 @@ julia> Pkg.add("OceanBioME") ## Running your first model -As a simple example lets run a Nutrient-Phytoplankton-Zooplankton-Detritus (NPZD) model in a two-dimensional simulation of a buoyancy front. This example requires Oceananigans, so we install that first: +As a simple example lets run a Nutrient-Phytoplankton-Zooplankton-Detritus (NPZD) model in a two-dimensional simulation of a buoyancy front. This example requires Oceananigans, so we install that first via: -```@example quickstart +```julia using Pkg; Pkg.add("Oceananigans") +``` +and then: + +```@example quickstart using OceanBioME, Oceananigans using Oceananigans.Units From de524f7e67248a0115725e374f1a9317e82ed9fc Mon Sep 17 00:00:00 2001 From: Jago Strong-Wright Date: Tue, 26 Mar 2024 10:33:55 -0400 Subject: [PATCH 10/10] Bump patch number --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c441af5a5..5eb89c2a2 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "OceanBioME" uuid = "a49af516-9db8-4be4-be45-1dad61c5a376" authors = ["Jago Strong-Wright and contributors"] -version = "0.10.1" +version = "0.10.2" [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"