-
Notifications
You must be signed in to change notification settings - Fork 238
(0.96.30) Fix vector rotation operation #4560
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
Changes from 13 commits
d62bad6
ed02bf8
50a478d
f3b26be
8f4ae83
fc442a9
6248cfe
57bb82a
32a841b
67a5031
33203b6
9cf7842
98d7d2f
2f618c1
5afa53a
36d366c
26950af
6a13ba5
531e594
f9f99d6
300c7af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -67,8 +67,11 @@ _intrinsic_ coordinate systems are equivalent. However, for other grids (e.g., f | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Δxᶜᶠᵃ⁺ = Δxᶜᶠᶜ(i, j+1, 1, grid) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Δxᶜᶠᵃ⁻ = Δxᶜᶠᶜ(i, j, 1, grid) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cosθ₁ = ifelse(Δyᶠᶜᵃ⁺ == 0, zero(grid), deg2rad(φᶠᶠᵃ⁺⁺ - φᶠᶠᵃ⁺⁻) / Δyᶠᶜᵃ⁺) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cosθ₂ = ifelse(Δyᶠᶜᵃ⁻ == 0, zero(grid), deg2rad(φᶠᶠᵃ⁻⁺ - φᶠᶠᵃ⁻⁻) / Δyᶠᶜᵃ⁻) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# θᵢ is the rotation angle between intrinsic and extrinsic reference frame | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Rcosθ = (deg2rad(φᶠᶠᵃ⁺⁺ - φᶠᶠᵃ⁺⁻) / Δyᶠᶜᵃ⁺ + deg2rad(φᶠᶠᵃ⁻⁺ - φᶠᶠᵃ⁻⁻) / Δyᶠᶜᵃ⁻) / 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Rcosθ = (cosθ₁ + cosθ₂) / 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Rsinθ = - (deg2rad(φᶠᶠᵃ⁺⁺ - φᶠᶠᵃ⁻⁺) / Δxᶜᶠᵃ⁺ + deg2rad(φᶠᶠᵃ⁺⁻ - φᶠᶠᵃ⁻⁻) / Δxᶜᶠᵃ⁻) / 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Normalization for the rotation angles | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -80,8 +83,8 @@ _intrinsic_ coordinate systems are equivalent. However, for other grids (e.g., f | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cosθ = Rcosθ / R | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sinθ = Rsinθ / R | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uᵢ = u * cosθ + v * sinθ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vᵢ = - u * sinθ + v * cosθ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uᵢ = u * cosθ - v * sinθ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vᵢ = u * sinθ + v * cosθ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return uᵢ, vᵢ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -108,8 +111,11 @@ end | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Δxᶜᶠᵃ⁺ = Δxᶜᶠᶜ(i, j+1, 1, grid) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Δxᶜᶠᵃ⁻ = Δxᶜᶠᶜ(i, j, 1, grid) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cosθ₁ = ifelse(Δyᶠᶜᵃ⁺ == 0, zero(grid), deg2rad(φᶠᶠᵃ⁺⁺ - φᶠᶠᵃ⁺⁻) / Δyᶠᶜᵃ⁺) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cosθ₂ = ifelse(Δyᶠᶜᵃ⁻ == 0, zero(grid), deg2rad(φᶠᶠᵃ⁻⁺ - φᶠᶠᵃ⁻⁻) / Δyᶠᶜᵃ⁻) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# θᵢ is the rotation angle between intrinsic and extrinsic reference frame | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Rcosθ = (deg2rad(φᶠᶠᵃ⁺⁺ - φᶠᶠᵃ⁺⁻) / Δyᶠᶜᵃ⁺ + deg2rad(φᶠᶠᵃ⁻⁺ - φᶠᶠᵃ⁻⁻) / Δyᶠᶜᵃ⁻) / 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Rcosθ = (cosθ₁ + cosθ₂) / 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Rsinθ = - (deg2rad(φᶠᶠᵃ⁺⁺ - φᶠᶠᵃ⁻⁺) / Δxᶜᶠᵃ⁺ + deg2rad(φᶠᶠᵃ⁺⁻ - φᶠᶠᵃ⁻⁻) / Δxᶜᶠᵃ⁻) / 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
# Normalization for the rotation angles | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -121,8 +127,8 @@ end | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cosθ = Rcosθ / R | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sinθ = Rsinθ / R | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uₑ = u * cosθ - v * sinθ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vₑ = u * sinθ + v * cosθ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
uₑ = + u * cosθ + v * sinθ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vₑ = - u * sinθ + v * cosθ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+128
to
+129
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @siddharthabishnu are you suggesting that there is a mistake in what @simone-silvestri proposed? I mean, is what you point out what you reckon is the right expression? (I'm only asking because you didn't include it as a suggestion so I just want to ensure that I understand properly your comment.) I'll double check the calculation here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the expression was like that before. The change in this PR is indeed changing uₑ = + u * cosθ - v * sinθ
vₑ = u * sinθ + v * cosθ to uₑ = + u * cosθ + v * sinθ
vₑ = - u * sinθ + v * cosθ This is because in the In the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @simone-silvestri, can you clarify if the frame of reference containing the intrinsic vector is rotated counterclockwise relative to the frame containing the extrinsic vector by an angle θ? If so, my suggestion is correct else your implementation is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The frame of reference containing the intrinsic vector is rotated clockwise relative to frame containing the extrinsic vector. Or better put, the angle that we compute is positive if the intrinsic frame is clockwise rotated with respect to the extrinsic frame, and negative in the case that the intrinsic frame is rotated counterclockwise with respect to the extrinsic frame There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @siddharthabishnu, have a look at the docstring of the Oceananigans.jl/src/Operators/vector_rotation_operators.jl Lines 52 to 85 in 300c7af
Does this clarify your concerns and do you agree now that the PR changes in the rotation are correct (or at least consistent with the definition of the angle as per the docstring)? We added also a test at Oceananigans.jl/test/test_vector_rotation_operators.jl Lines 85 to 125 in 300c7af
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
the angle θ is the angle we need to rotate the intrinsic system to match the extrinsic that is, the intrinsic system is rotated by an angle -θ compared to the extrinsic one that's why I think it the PR is correct. But @siddharthabishnu, I admit it wasn't as clear before and I was also confused by that; I added the docstring on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @simone-silvestri and @navidcy, thank you both for the detailed explanations, which along with the docstring and the new test, helped clarify my confusion. I was unsure about the relative orientation of the intrinsic and extrinsic reference frames, and I always associate a positive angle with counterclockwise rotation by default, which is what led to my misunderstanding. It's all clear now, and I agree that the PR implementation is correct and consistent with the documentation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cool I'll merge if/when tests pass |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return uₑ, vₑ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -134,4 +140,4 @@ end | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
wₑ = getvalue(wᵢ, i, j, k, grid) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return uₑ, vₑ, wₑ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,163 +16,73 @@ using Oceananigans.Operators | |
@inline extrinsic_vector_y_component(i, j, k, grid, uᵢ, vᵢ) = | ||
@inbounds extrinsic_vector(i, j, k, grid, uᵢ, vᵢ)[2] | ||
|
||
@inline function kinetic_energyᶜᶜᶜ(i, j, k, grid, uᶜᶜᶜ, vᶜᶜᶜ) | ||
@inbounds u² = uᶜᶜᶜ[i, j, k]^2 | ||
@inbounds v² = vᶜᶜᶜ[i, j, k]^2 | ||
return (u² + v²) / 2 | ||
end | ||
|
||
function kinetic_energy(u, v) | ||
grid = u.grid | ||
ke_op = KernelFunctionOperation{Center, Center, Center}(kinetic_energyᶜᶜᶜ, grid, u, v) | ||
ke = Field(ke_op) | ||
return compute!(ke) | ||
end | ||
|
||
function pointwise_approximate_equal(field, val) | ||
CPU_field = on_architecture(CPU(), field) | ||
@test all(interior(CPU_field) .≈ val) | ||
end | ||
|
||
# A purely zonal flow with an west-east velocity > 0 | ||
# on a cubed sphere in an intrinsic coordinate system | ||
# has the following properties: | ||
function test_purely_zonal_flow(uᵢ, vᵢ, grid) | ||
c1 = maximum(uᵢ) ≈ - minimum(vᵢ) | ||
c2 = minimum(uᵢ) ≈ - maximum(vᵢ) | ||
c3 = mean(uᵢ) ≈ - mean(vᵢ) | ||
c4 = mean(uᵢ) > 0 # The mean value should be positive) | ||
|
||
return c1 & c2 & c3 & c4 | ||
end | ||
|
||
# A purely meridional flow with a south-north velocity > 0 | ||
# on a cubed sphere in an intrinsic coordinate system | ||
# has the following properties: | ||
function test_purely_meridional_flow(uᵢ, vᵢ, grid) | ||
c1 = maximum(uᵢ) ≈ maximum(vᵢ) | ||
c2 = minimum(uᵢ) ≈ minimum(vᵢ) | ||
c3 = mean(uᵢ) ≈ mean(vᵢ) | ||
c4 = mean(vᵢ) > 0 # The mean value should be positive | ||
|
||
return c1 & c2 & c3 & c4 | ||
function pointwise_approximate_equal(field1, field2) | ||
CPU_field1 = on_architecture(CPU(), field1) | ||
CPU_field2 = on_architecture(CPU(), field2) | ||
@test all(interior(CPU_field1) .≈ interior(CPU_field2)) | ||
end | ||
|
||
# Test vector invariants i.e. | ||
# -> dot product of two vectors | ||
# -> cross product of two vectors | ||
function test_vector_rotation(grid) | ||
u = CenterField(grid) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have dropped this test because it was weirdly concocted, and most likely grid dependent. The new test is grid independent and tests only that the invariants of a vector remain invariant when moving to the intrinsic frame and return equal to the extrinsic components once transformed back. I think this is the only objective test we need for vector rotation. |
||
v = CenterField(grid) | ||
|
||
# Purely longitudinal flow in the extrinsic coordinate system | ||
fill!(u, 1) | ||
fill!(v, 0) | ||
|
||
# Convert it to an "Instrinsic" reference frame | ||
uᵢ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_x_component, grid, u, v) | ||
vᵢ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_y_component, grid, u, v) | ||
|
||
uᵢ = compute!(Field(uᵢ)) | ||
vᵢ = compute!(Field(vᵢ)) | ||
|
||
# The extrema of u and v, as well as their mean value should | ||
# be equivalent on an "intrinsic" frame | ||
@test test_purely_zonal_flow(uᵢ, vᵢ, grid) | ||
|
||
# Kinetic energy should remain the same | ||
KE = kinetic_energy(uᵢ, vᵢ) | ||
@apply_regionally pointwise_approximate_equal(KE, 0.5) | ||
|
||
# Convert it back to a purely zonal velocity (vₑ == 0) | ||
uₑ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_x_component, grid, uᵢ, vᵢ) | ||
vₑ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_y_component, grid, uᵢ, vᵢ) | ||
|
||
uₑ = compute!(Field(uₑ)) | ||
vₑ = compute!(Field(vₑ)) | ||
|
||
# Make sure that the flow was converted back to a | ||
# purely zonal flow in the extrensic frame (v ≈ 0) | ||
if architecture(grid) isa CPU | ||
# Note that on the GPU, there are (apparently?) larger numerical errors | ||
# which lead to -1e-17 < vₑ < 1e-17 for which this test fails. | ||
@apply_regionally pointwise_approximate_equal(vₑ, 0) | ||
end | ||
|
||
@apply_regionally pointwise_approximate_equal(uₑ, 1) | ||
|
||
# Purely meridional flow in the extrinsic coordinate system | ||
fill!(u, 0) | ||
fill!(v, 1) | ||
|
||
# Convert it to an "Instrinsic" reference frame | ||
uᵢ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_x_component, grid, u, v) | ||
vᵢ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_y_component, grid, u, v) | ||
|
||
uᵢ = compute!(Field(uᵢ)) | ||
vᵢ = compute!(Field(vᵢ)) | ||
|
||
# The extrema of u and v, as well as their mean value should | ||
# be equivalent on an "intrinsic" frame | ||
@test test_purely_meridional_flow(uᵢ, vᵢ, grid) | ||
|
||
# Kinetic energy should remain the same | ||
KE = kinetic_energy(uᵢ, vᵢ) | ||
@apply_regionally pointwise_approximate_equal(KE, 0.5) | ||
|
||
# Convert it back to a purely zonal velocity (vₑ == 0) | ||
uₑ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_x_component, grid, uᵢ, vᵢ) | ||
vₑ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_y_component, grid, uᵢ, vᵢ) | ||
|
||
uₑ = compute!(Field(uₑ)) | ||
vₑ = compute!(Field(vₑ)) | ||
|
||
# Make sure that the flow was converted back to a | ||
# purely zonal flow in the extrensic frame (v ≈ 0) | ||
@apply_regionally pointwise_approximate_equal(vₑ, 1) | ||
|
||
if architecture(grid) isa CPU | ||
# Note that on the GPU, there are (apparently?) larger numerical errors | ||
# which lead to - 4e-17 < uₑ < 4e-17 for which this test fails. | ||
@apply_regionally pointwise_approximate_equal(uₑ, 0) | ||
end | ||
|
||
# Mixed zonal and meridional flow. | ||
fill!(u, 0.5) | ||
fill!(v, 0.5) | ||
|
||
# Convert it to an "Instrinsic" reference frame | ||
uᵢ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_x_component, grid, u, v) | ||
vᵢ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_y_component, grid, u, v) | ||
|
||
uᵢ = compute!(Field(uᵢ)) | ||
vᵢ = compute!(Field(vᵢ)) | ||
|
||
# The extrema of u and v, should be equivalent on an "intrinsic" frame | ||
# when u == v on an extrinsic frame | ||
@test maximum(uᵢ) ≈ maximum(vᵢ) | ||
@test minimum(uᵢ) ≈ minimum(vᵢ) | ||
|
||
# Kinetic energy should remain the same | ||
KE = kinetic_energy(uᵢ, vᵢ) | ||
@apply_regionally pointwise_approximate_equal(KE, 0.25) | ||
|
||
# Convert it back to a purely zonal velocity (vₑ == 0) | ||
uₑ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_x_component, grid, uᵢ, vᵢ) | ||
vₑ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_y_component, grid, uᵢ, vᵢ) | ||
|
||
uₑ = compute!(Field(uₑ)) | ||
vₑ = compute!(Field(vₑ)) | ||
|
||
# Make sure that the flow was converted back to a | ||
# purely zonal flow in the extrensic frame (v ≈ 0) | ||
@apply_regionally pointwise_approximate_equal(vₑ, 0.5) | ||
@apply_regionally pointwise_approximate_equal(uₑ, 0.5) | ||
x₁ = CenterField(grid) | ||
y₁ = CenterField(grid) | ||
x₂ = CenterField(grid) | ||
y₂ = CenterField(grid) | ||
|
||
set!(x₁, (x, y, z) -> rand()) | ||
set!(y₁, (x, y, z) -> rand()) | ||
set!(x₂, (x, y, z) -> rand()) | ||
set!(y₂, (x, y, z) -> rand()) | ||
|
||
fill_halo_regions!((x₁, y₁, x₂, y₂)) | ||
|
||
d = compute!(Field(x₁ * x₂ + y₁ * y₂)) | ||
c = compute!(Field(x₁ * y₂ - y₁ * x₂)) | ||
|
||
@info " Testing the conversion of a vector between to the Intrinsice reference frame on $(summary(grid))" | ||
xᵢ₁ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_x_component, grid, x₁, y₁) | ||
yᵢ₁ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_y_component, grid, x₁, y₁) | ||
xᵢ₂ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_x_component, grid, x₂, y₂) | ||
yᵢ₂ = KernelFunctionOperation{Center, Center, Center}(intrinsic_vector_y_component, grid, x₂, y₂) | ||
|
||
xᵢ₁ = compute!(Field(xᵢ₁)) | ||
yᵢ₁ = compute!(Field(yᵢ₁)) | ||
xᵢ₂ = compute!(Field(xᵢ₂)) | ||
yᵢ₂ = compute!(Field(yᵢ₂)) | ||
|
||
dᵢ = compute!(Field(xᵢ₁ * xᵢ₂ + yᵢ₁ * yᵢ₂)) | ||
cᵢ = compute!(Field(xᵢ₁ * yᵢ₂ - yᵢ₁ * xᵢ₂)) | ||
|
||
@apply_regionally pointwise_approximate_equal(dᵢ, d) | ||
@apply_regionally pointwise_approximate_equal(cᵢ, c) | ||
|
||
xₑ₁ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_x_component, grid, xᵢ₁, yᵢ₁) | ||
yₑ₁ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_y_component, grid, xᵢ₁, yᵢ₁) | ||
xₑ₂ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_x_component, grid, xᵢ₂, yᵢ₂) | ||
yₑ₂ = KernelFunctionOperation{Center, Center, Center}(extrinsic_vector_y_component, grid, xᵢ₂, yᵢ₂) | ||
|
||
xₑ₁ = compute!(Field(xₑ₁)) | ||
yₑ₁ = compute!(Field(yₑ₁)) | ||
xₑ₂ = compute!(Field(xₑ₂)) | ||
yₑ₂ = compute!(Field(yₑ₂)) | ||
|
||
@info " Testing the conversion of a vector between to the Extrinsic reference frame on $(summary(grid))" | ||
@apply_regionally pointwise_approximate_equal(xₑ₁, x₁) | ||
@apply_regionally pointwise_approximate_equal(xₑ₁, x₁) | ||
@apply_regionally pointwise_approximate_equal(yₑ₂, y₂) | ||
@apply_regionally pointwise_approximate_equal(yₑ₂, y₂) | ||
end | ||
|
||
@testset "Vector rotation" begin | ||
for arch in archs | ||
@testset "Conversion from Intrinsic to Extrinsic reference frame [$(typeof(arch))]" begin | ||
@info " Testing the conversion of a vector between the Intrinsic and Extrinsic reference frame" | ||
grid = ConformalCubedSphereGrid(arch; panel_size=(10, 10, 1), z=(-1, 0)) | ||
test_vector_rotation(grid) | ||
cubed_sphere_grid = ConformalCubedSphereGrid(arch; panel_size=(10, 10, 1), z=(-1, 0)) | ||
tripolar_grid = TripolarGrid(arch; size = (40, 40, 1), z=(-1, 0)) | ||
test_vector_rotation(cubed_sphere_grid) | ||
test_vector_rotation(tripolar_grid) | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@siddharthabishnu are you suggesting that there is a mistake in what @simone-silvestri proposed? I mean, is what you point out what you reckon is the right expression? (I'm only asking because you didn't include it as a suggestion so I just want to ensure that I understand properly your comment.)
I'll double check the calculation here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@navidcy, apologies for not providing a more detailed explanation earlier. Instead of using a rotation matrix, I sketched the setup by hand and resolved the components of a vector along the new directions of the rotated frame. I realized that my suggestion holds only if the frame containing the intrinsic vector is rotated counterclockwise relative to the frame with the extrinsic vector by an angle θ. If the rotation is in the opposite direction, then @simone-silvestri’s implementation is correct.