-
Notifications
You must be signed in to change notification settings - Fork 9
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
Unintuitive behavior of sum
#943
Comments
117: transition to using new bucket model version r=kmdeck a=kmdeck # PULL REQUEST ## Purpose and Content This PR updates the coupler driver file and other helper files so that the coupled runs work with the new version of the bucket model (with snow, and with a multi layer heat equation). To do: followup on CliMA/ClimaCore.jl#943 ## Benefits and Risks The benefit of this is that our AMIP model will be slightly more realistic. ## Linked Issues (Provide references to any link issues. Use closes #issuenum to automatically close an open issue) - Fixes #118 - Closes #118 ## PR Checklist - [X] This PR has a corresponding issue OR is linked to an SDI. - [X] I have followed CliMA's codebase [contribution](https://clima.github.io/ClimateMachine.jl/latest/Contributing/) and [style](https://clima.github.io/ClimateMachine.jl/latest/DevDocs/CodeStyle/) guidelines OR N/A. - [X] I have followed CliMA's [documentation policy](https://github.com/CliMA/policies/wiki/Documentation-Policy). - [X] I have checked all issues and PRs and I certify that this PR does not duplicate an open PR. - [x] I linted my code on my local machine prior to submission OR N/A. - [X] Unit tests are included OR N/A. - [X] Code used in an integration test OR N/A. - [x] All tests ran successfully on my local machine OR N/A. - [X] All classes, modules, and function contain docstrings OR N/A. - [X] Documentation has been added/updated OR N/A. Co-authored-by: kmdeck <[email protected]>
This one has bothered me as well: I admit I don't have a good solution. |
Is sum actually doing an integral over the domain? Maybe it would be clearer if there was a formula showing what sum was computing, and then a user could see how it reduces in some case to the integral and some cases not? Im not sure. I dont know what it is doing under the hood. |
@kmdeck yes, my understanding is that So to address your second bullet point, yes, we should expect For the first bullet point, is it due to the fact that we use the "shallow-atmosphere" approximation for our 3D sphere? See for instance this comment in this test. |
Hi @valeriabarra - thank you! It does make sense that we need the Jacobian in the integral. That said, the results from I dont think that the issue in the first test/bullet point is because of the shallow-atmosphere approx. The as a comment - making the shallow approximation makes a lot of sense for the globe, but there is no restriction on what the user can pass in for (Also note the funny behavior with |
962: Add support for definite column integrals r=simonbyrne a=charleskawczynski This PR adds `column_integral_definite!`, a non-allocating definite integral for columns. The idea is that it will replace the existing (allocating) definite integral [here](https://github.com/CliMA/ClimaAtmos.jl/blob/44cee55def2a51433c5dcdcdae010b7777cd741b/examples/hybrid/sphere/baroclinic_wave_utilities.jl#L167-L186). However, this implementation has several advantages: - It's compatible with `bycolumn`, so the computation can occur in parallel - It's allocation-free - It's _tested_ on single column and sphere configurations Looking at the flame graph for allocations (using the Julia 1.8 Allocs module with `sample_rate=1`), this is responsible for most of the remaining allocations in ClimaAtmos: <img width="1993" alt="Screen Shot 2022-09-26 at 7 57 05 AM" src="https://user-images.githubusercontent.com/1880641/192353757-03101c41-2c0b-4ccb-a8b9-43faa78680f8.png"> The interface for the added function captures two cases: ```julia function column_integral_definite!(col∫field::Field, field::Field) bycolumn(axes(field)) do colidx column_integral_definite!(col∫field[colidx], field[colidx]) nothing end return nothing end ``` and ```julia function column_integral_definite!( col∫field::PointField, field::ColumnField, ) `@inbounds` col∫field[] = column_integral_definite(field) return nothing end ``` A step towards closing #943, #748, [CA#686](CliMA/ClimaAtmos.jl#686). ## A note on an alternative approach Ideally, we would write this function as `column_integral_definite!(fn, args...)` where we might be able to write a broadcast statement like: ```julia `@.` f2D = column_integral_definite(f3D) do z f3D.x * z^2 end ``` however, this would require us to define broadcasting between planar and 3D domains, which is not trivial (or maybe not possible) because of ambiguities. The ambiguities arise because (2D, 3D) broadcasting may want different things in different cases, for example: - (f2D, f3D) -> f3D: mul full 3D field by planar surface value - (f2D, f3D) -> f2D: perform reduction over z-coordinate to yield 2D field The situation is similar when thinking about what happens when we make views. For example, ```julia Fields.bycolumn(axes(f3D)) do colidx `@.` f2D[colidx] = column_integral_definite(f3D[colidx]) do z f3D[colidx].x * z^2 end end ``` Now, we have to define how `DataF` data layouts broadcast with `VF`. Again, we have two cases: - (f0D, f1D) -> f1D: mul full 1D field by 0D field - (f0D, f1D) -> f0D: perform reduction over z-coordinate to yield 0D field My vote/preference is to support the first cases (which is partially supported already) and write custom functions (e.g., reductions) that operate on single fields for the second case. Co-authored-by: Charles Kawczynski <[email protected]> Co-authored-by: Simon Byrne <[email protected]>
962: Add support for definite column integrals r=charleskawczynski a=charleskawczynski This PR adds `column_integral_definite!`, a non-allocating definite integral for columns. The idea is that it will replace the existing (allocating) definite integral [here](https://github.com/CliMA/ClimaAtmos.jl/blob/44cee55def2a51433c5dcdcdae010b7777cd741b/examples/hybrid/sphere/baroclinic_wave_utilities.jl#L167-L186). However, this implementation has several advantages: - It's compatible with `bycolumn`, so the computation can occur in parallel - It's allocation-free - It's _tested_ on single column and sphere configurations Looking at the flame graph for allocations (using the Julia 1.8 Allocs module with `sample_rate=1`), this is responsible for most of the remaining allocations in ClimaAtmos: <img width="1993" alt="Screen Shot 2022-09-26 at 7 57 05 AM" src="https://user-images.githubusercontent.com/1880641/192353757-03101c41-2c0b-4ccb-a8b9-43faa78680f8.png"> The interface for the added function captures two cases: ```julia function column_integral_definite!(col∫field::Field, field::Field) bycolumn(axes(field)) do colidx column_integral_definite!(col∫field[colidx], field[colidx]) nothing end return nothing end ``` and ```julia function column_integral_definite!( col∫field::PointField, field::ColumnField, ) `@inbounds` col∫field[] = column_integral_definite(field) return nothing end ``` A step towards closing #943, #748, [CA#686](CliMA/ClimaAtmos.jl#686). ## A note on an alternative approach Ideally, we would write this function as `column_integral_definite!(fn, args...)` where we might be able to write a broadcast statement like: ```julia `@.` f2D = column_integral_definite(f3D) do z f3D.x * z^2 end ``` however, this would require us to define broadcasting between planar and 3D domains, which is not trivial (or maybe not possible) because of ambiguities. The ambiguities arise because (2D, 3D) broadcasting may want different things in different cases, for example: - (f2D, f3D) -> f3D: mul full 3D field by planar surface value - (f2D, f3D) -> f2D: perform reduction over z-coordinate to yield 2D field The situation is similar when thinking about what happens when we make views. For example, ```julia Fields.bycolumn(axes(f3D)) do colidx `@.` f2D[colidx] = column_integral_definite(f3D[colidx]) do z f3D[colidx].x * z^2 end end ``` Now, we have to define how `DataF` data layouts broadcast with `VF`. Again, we have two cases: - (f0D, f1D) -> f1D: mul full 1D field by 0D field - (f0D, f1D) -> f0D: perform reduction over z-coordinate to yield 0D field My vote/preference is to support the first cases (which is partially supported already) and write custom functions (e.g., reductions) that operate on single fields for the second case. A step towards closing [CA#686](CliMA/ClimaAtmos.jl#686) Co-authored-by: Charles Kawczynski <[email protected]>
FWIW, I would expect the integral over a point-space to be non-zero (in general), but it should be decreasing as the resolution increases. |
One reason why I think it's somewhat dangerous/unintuitive to define |
Here is an updated reproducer: using ClimaCore.CommonSpaces
using ClimaCore: Spaces
using ClimaCore: Spaces
using ClimaCore: Utilities
using ClimaCore: Fields
using ClimaCore
using Test
@testset "Spherical Shell" begin
FT = Float32
radius = FT(10.0)
height = FT(2.0)
n_quad_points = 3
hv_center_space = ExtrudedCubedSphereSpace(FT;
z_elem = 10,
z_min = 0,
z_max = height,
radius = 10,
h_elem = 10,
n_quad_points = 4,
staggering = CellCenter()
)
hv_face_space = Spaces.face_space(hv_center_space)
# Sum behavior
ones_volume = ones(hv_center_space)
hspace = Spaces.horizontal_space(hv_center_space)
ones_horizontal_space = ones(Spaces.horizontal_space(hv_center_space))
ones_bottom_space_level = ones(Spaces.level(hv_face_space, Utilities.PlusHalf(0)))
ones_top_space_level = ones(Spaces.level(hv_face_space, Utilities.PlusHalf(10)))
# Passing tests
@test sum(ones_volume) ≈ FT(4.0*π)*radius^2.0*height
@test sum(ones_horizontal_space) ≈ FT(4.0*π)*radius^2.0
# Not passing
@test sum(ones_bottom_space_level) ≈ FT(4.0*π)*radius^2.0
@test sum(ones_top_space_level) ≈ FT(4.0*π)*(radius+height)^2.0
column_integrals = zeros(hspace)
Fields.bycolumn(hspace) do colidx
column_integrals[colidx] .= sum(ones_volume[colidx])
end
# Expect this should be ∫dz for each element? = height?
@test sum(parent(column_integrals .- height))≈ FT(0.0)
end
@testset "Column" begin
FT = Float32
center_space = ColumnSpace(FT;
z_elem = 20,
z_min = 0,
z_max = 10,
staggering = CellCenter()
)
face_space = Spaces.face_space(center_space)
bottom_space = Spaces.level(face_space, Utilities.PlusHalf(0))
ones_column = ones(center_space)
ones_point_bottom = ones(bottom_space)
#Passes
@test sum(ones_column) ≈ FT(10)
# Does not pass
@test sum(ones_point_bottom) ≈ FT(0) #∫dx over a point is zero
end |
Describe the bug
I am trying to use
sum
to compute integrals of different fields over different spaces. In particular, I am takingsum(ones(space))
- which should be volume or area or column or "point" integrals. But,level
of the 3d space vs the horizontal space for the spherical shell. For example, I would expect that \int (ones(horizontal_space)) = 4pi R^2, and that \int ones(level) = 4pi(R+z)^2, where z is the height of the level. What \int ones(level) returns - for any level, at any height - is 4\pi R^2 dz/2, where dz is the discretization of the vertical.by column
to take a column integral over each column of the spherical shell - returning something that lives on the horizontal space - also seemed to give unintuitive results.To Reproduce
MWE below
System details
Any relevant system information:
The text was updated successfully, but these errors were encountered: