-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Climate time series #256
Comments
Just pass it as Then it should "just work". If you index with It does the time lookup each timstep so it's instant within the rule for each cell. If your time steps don't match the climate data exactly it helps to use |
Thxs! I'll try it out and see how it goes :) |
Great. If you ever feel like adding these and other things you learn to the docs somewhere it would be very much appreciated |
Sure! I'll be happy to do so when I figure out how to do it :) I'll add info on |
Did you get this working? |
Not yet. Didn't have much time this week. I'll let you know so you can
close the issue :)
Nico
…On Sat, 31 Aug 2024, 12:09 Rafael Schouten, ***@***.***> wrote:
Did you get this working?
—
Reply to this email directly, view it on GitHub
<#256 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ALXYX33WV4F5WXTZDDHGRYLZUGI6XAVCNFSM6AAAAABNH6F5L6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMRSHA2TANZRHE>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
Ok, so I've been trying to implement this but I ran into another issue that I had been ignoring so far. Since my grids hold complex objects, I've been using
Any idea on how to solve this? :) |
Sorry, not sure I get it, I need a lot more context. But a Also don't understand the "run a RasterSeries" part... A RasterSeries is basically just an array of Rasters with some nice helpers. It wont actually work as anything that can "run" in DynamicGrids, I assume you mean as "aux" data? You want to But again, I just need more code - the only way to be clear in a conversation like this is to post the code (Oh are you trying to use a RasterSeries as |
Ok! I now see what you mean. For some reason I thought However, still don't understand how I should write the instructions. Here's the code, given that Full code:
Sorry my question was not very clear :( |
Ok so seems I don't make these distinctions clear enough 😅
I'm assuming your So to rewrite: combined_raster = Rasters.combine(raster_series, Ti)[bounds...]
aux = (; combined_raster=combined_raster)
tspan = Date(2023, 1):Month(1):Date(2023, 8)
init_for_timeseries = (
state = raster_with_abundances,
state_richness = raster_richness,
)
function int_Gr_for_timeseries(state::MyStructs256, self_regulation::AbstractFloat, combined_raster::AbstractFloat)
return MyStructs256(SVector{256, Float64}(state.a .* self_regulation .* combined_raster))
end
timeseries_rule = Cell{:state, :state}() do data, state, I
combined_raster = get(data, Aux(:combined_raster), I) # Important bit here!!
merged_state = state + int_Gr_for_timeseries(state, self_regulation, combined_raster)
return MyStructs256(SVector{256, Float64}(merged_state.a))
end
array_output = ResultOutput(
init_for_timeseries; tspan = tspan,
aux = aux,
mask = raster_sum
)
@time s = sim!(array_output, Ruleset(timeseries_rule)) And ultimately to make something reusable you make this a field of your rule struct, and use this combined_raster = get(data, rule.combined_raster, I) And users can pass |
I see! I'll need some time to understand everything you just said but I get the overall functionality :) However, I just ran your code and still throws the Now is referring to not finding it in
|
I can't actually test it because its not a complete MWE ;) But maybe just a typeo somewhere or some variable not updated. If you make a full MWE I will always test my answers - but I don't have time to generate fake data to test it |
Yeah in this error you have an empty namedtuple for aux(nt::@NamedTuple{}, ::Aux{:combined_raster}) I'm not sure why |
Me neither jaja Sure, I can make a MWE, it looked like a straight error |
Ohhhh I get it sorry. Yeah this is kind of annoying. You need to pass in the aux as a variable. On GPUs we need to thin the data a lot or the kernel size overflows and wont compile. So we only pass in the things that we need for each specific rule, and we remove all grids and aux data that isn't used and send the simplest possible thing to the GPU. By putting the aux in as a variable we can find it, but we don't actually scan the code for manually defined But this should fix it: timeseries_rule = let combined_raster_aux=Aux{:combined_raster}()
Cell{:state, :state}() do data, state, I
combined_raster = get(data, combined_raster_aux, I) # Important bit here!!
merged_state = state + int_Gr_for_timeseries(state, self_regulation, combined_raster)
return MyStructs256(SVector{256, Float64}(merged_state.a))
end
end This is kind of awful actually, I didn't think about this so much when I wrote that thinning. Thats why this is in (there is some magic happening here in that any variable in the let block will be a field in the anonymous function struct made by the |
Jajaja, ok, if I was lost before, I definitely am now. But I see what you mean. Now the error switched to |
Yeah, need that MWE or there are just typos and little bugs |
By: Probably we should do that too its just a pain, you mean we should fix it? |
|
Can I send you the objects by email? github doesn't support .jls |
I mean do I just separate out the GPU code to thin Aux like that and not bother for CPU so we don't have this error... Or do I analise the function code to find if there are any |
Just make the data with (Always best everyone else reading this can see it too) |
Ok, here it is. It works fine and gives the exact same error: ######## TRYING TIME SERIES #########
using StaticArrays, Serialization, DynamicGrids, Dispersal, Rasters, Dates
struct MyStructs256{T <: AbstractFloat} <: FieldVector{2, T}
a::SVector{256, T}
b::T
# Custom constructor for automatic sum calculation
function MyStructs256(a::SVector{256, T}) where T <: AbstractFloat
new{T}(a, sum(a))
end
# Explicit constructor allowing manual setting of both `a` and `b`
MyStructs256(a::SVector{256, T}, b::T) where T <: AbstractFloat = new{T}(a, b)
end
# Define zero and oneunit for MyStructs256
Base.zero(::Type{MyStructs256{T}}) where {T <: AbstractFloat} = MyStructs256(SVector{256, T}(fill(zero(T), 256)), zero(T))
Base.zero(x::MyStructs256{T}) where {T <: AbstractFloat} = MyStructs256(SVector{256, T}(fill(zero(T), 256)), zero(T))
Base.oneunit(::Type{MyStructs256{T}}) where {T <: AbstractFloat} = MyStructs256(fill(oneunit(T), 256), oneunit(T))
# Comparison based on 'b' field
Base.isless(x::MyStructs256, y::MyStructs256) = isless(x.b, y.b)
Base.isless(x::MyStructs256, y::AbstractFloat) = isless(x.b, y)
# Element-wise arithmetic operations ensuring 'b' is recalculated correctly
Base.:+(x::MyStructs256, y::MyStructs256) = MyStructs256(x.a .+ y.a, sum(x.a .+ y.a))
Base.:-(x::MyStructs256, y::MyStructs256) = MyStructs256(x.a .- y.a, sum(x.a .- y.a))
Base.:*(x::MyStructs256, scalar::Real) = MyStructs256(x.a .* scalar, sum(x.a .* scalar))
Base.:/(x::MyStructs256, scalar::Real) = MyStructs256(x.a ./ scalar, sum(x.a ./ scalar))
Base.:-(x::MyStructs256, scalar::Real) = MyStructs256(x.a .- scalar, x.b - scalar * 256)
Base.:+(x::MyStructs256, scalar::Real) = MyStructs256(x.a .+ scalar, x.b + scalar * 256)
# Define what a NaN is for MyStructs256
Base.isnan(x::MyStructs256) = isnan(x.b) || any(isnan, x.a)
# Adding a method in the sum function for MyStructs256
function Base.sum(structs::MyStructs256...)
# Sum the 'a' vectors
summed_a = sum([s.a for s in structs])
# Sum the 'b' values
summed_b = sum([s.b for s in structs])
# Create a new MyStructs256 instance with the summed results
return MyStructs256(summed_a, summed_b)
end
# Adding a method to maximum
# Define maximum for MyStructs256
function Base.maximum(a::MyStructs256, b::MyStructs256)
return MyStructs256(max.(a.a, b.a))
end
# Define maximum for MyStructs256 with a scalar
function Base.maximum(a::MyStructs256, b::AbstractFloat)
return MyStructs256(max.(a.a, b))
end
# Define maximum for a scalar with MyStructs256
function Base.maximum(a::AbstractFloat, b::MyStructs256)
return MyStructs256(max.(a, b.a))
end
# Define maximum for MyStructs256
function Base.maximum(a::MyStructs256)
return maximum(a.a)
end
# Define maximum for a matrix of MyStructs256
function Base.maximum(a::Matrix{MyStructs256{AbstractFloat}})
# Extract all `b` values from each MyStructs256 element in the matrix and find the maximum
return maximum(map(x -> x.b, a))
end
########### CREATING DATA ##########
######### raster_with_abundances ########
# Define the size of the raster
size_x, size_y = 125, 76
# Define the x and y dimensions directly
x_dim = X(1:size_x)
y_dim = Y(1:size_y)
# A 125x76 grid of random MyStructs256
raster_matrix = reshape([MyStructs256(SVector{256, Float64}(rand(256))) for _ in 1:(size_x * size_y)], size_x, size_y)
raster_with_abundances = Raster(raster_matrix, dims=(x_dim, y_dim))
######### raster_sum ########
# Create a 125x76 grid of Bool values with first and last rows as false, others true
sum_matrix = [i == 1 || i == size_x ? false : true for i in 1:size_x, j in 1:size_y]
# Create the Bool raster with the specified dimensions
raster_sum = Raster(sum_matrix, dims=(x_dim, y_dim))
######## combined_raster ########
time_dim = Ti([Date(2023, i, 1) for i in 1:8]) # 8 time points
# Create 8 individual rasters with random Int16 values
raster_layers = [
Raster(rand(Int16, size_x, size_y), dims=(x_dim, y_dim)) for _ in 1:8
]
# Set the first and last rows to -32768 to represent missing values
for raster in raster_layers
raster[1, :] .= -32768 # First row
raster[end, :] .= -32768 # Last row
end
# Combine the rasters into a 3D raster
combined_raster = Raster(cat(raster_layers..., dims=3), dims=(x_dim, y_dim, time_dim))
######### HERE STARTS THE RELEVANT PART #############
aux = (; combined_raster=combined_raster)
tspan = Date(2023, 1):Month(1):Date(2023, 8)
init_for_timeseries = (
state = raster_with_abundances
)
self_regulation = 0.01
function int_Gr_for_timeseries(state::MyStructs256, self_regulation::AbstractFloat, combined_raster::AbstractFloat)
return MyStructs256(SVector{256, Float64}(state.a .* self_regulation .* combined_raster))
end
timeseries_rule = let combined_raster_aux=Aux{:combined_raster}()
Cell{:state, :state}() do data, state, I
combined_raster = get(data, combined_raster_aux, I) # Important bit here!!
merged_state = state + int_Gr_for_timeseries(state, self_regulation, combined_raster)
return MyStructs256(SVector{256, Float64}(merged_state.a))
end
end
array_output = ResultOutput(
init_for_timeseries; tspan = tspan,
aux = aux,
mask = raster_sum
)
@time s = sim!(array_output, Ruleset(timeseries_rule)) |
Ok thats an easy one! By deleting the second argument this is no longer a namedtuple, its just an array: init_for_timeseries = (
state = raster_with_abundances
) And of course you can just pass a single array as Personally I always use init_for_timeseries = (; # this makes all the difference
state = raster_with_abundances
) |
And finally for the simulation to run you need this: function int_Gr_for_timeseries(state::MyStructs256, self_regulation::AbstractFloat, combined_raster)
return MyStructs256(SVector{256, Float64}(state.a .* self_regulation .* combined_raster))
end Because |
And maybe you notice I made your code block colorful... it helps to use ```julia as the start fence so github knows to use julia colors. Much easier to read that way |
We could have better errors like "Youre rule $ruletype wants a grid called And the same for |
Ok! Finally! It worked. Thank you very much Raf, really appreciate your patience :) |
Once I understand the structure behind all you told me, I'm happy to PR #260 if you don't have time. Or perhaps it's very straight forward for you and it'll only take you a sec :) I'm diving into the GPU part of DG these days so it'll be useful for me to understand it anyway. |
So in the DynamicGrids.jl/src/simulationdata.jl Lines 268 to 284 in 2c2acf0
We could conditionally just use all the Then, making It needs cleaning up anyway its kind of a mess. |
Hey there,
Would you mind pointing me out what would be the way of using a climate series in a simulation? I mean, let's say I have a RasterSeries of a climate variable across time. And I want to run a simulation that runs through this climate variation. What'd be the way of implementing this (if feasible)?
Thxs :)
Nico
The text was updated successfully, but these errors were encountered: