@@ -5,37 +5,50 @@ import ClimaComms
5
5
"""
6
6
column_integral_definite!(ϕ_top, ᶜ∂ϕ∂z, [ϕ_bot])
7
7
8
- Sets `ϕ_top```{}= \\ int_{z_{bot}}^{z_{top}}\\ ,```ᶜ∂ϕ∂z```(z)\\ ,dz +{}```ϕ_bot`,
9
- where ``z_{bot}`` and ``z_{top}`` are the values of `z` at the bottom and top of
10
- the domain, respectively. The input `ᶜ∂ϕ∂z` should be a cell-center `Field` or
11
- `AbstractBroadcasted`, and the output `ϕ_top` should be a horizontal `Field`.
12
- The default value of `ϕ_bot` is 0.
8
+ Sets `ϕ_top```{}= \\ frac{1}{ΔA(z_{bot})}\\ int_{z_{bot}}^{z_{top}}\\ ,
9
+ ```ᶜ∂ϕ∂z```(z)\\ ,ΔA(z)\\ ,dz +{}```ϕ_bot`, where ``z_{bot}`` and ``z_{top}`` are
10
+ the values of `z` at the bottom and top of the domain, and where `ΔA` is the
11
+ area differential `J/Δz`, with `J` denoting the metric Jacobian. The input
12
+ `ᶜ∂ϕ∂z` should be a cell-center `Field` or `AbstractBroadcasted`, and the output
13
+ `ϕ_top` should be a horizontal `Field`. The default value of `ϕ_bot` is 0.
13
14
"""
14
15
function column_integral_definite! (ϕ_top, ᶜ∂ϕ∂z, ϕ_bot = rzero (eltype (ϕ_top)))
15
- ᶜΔϕ = Base. Broadcast. broadcasted (⊠ , ᶜ∂ϕ∂z, Fields. Δz_field (axes (ᶜ∂ϕ∂z)))
16
+ ᶜJ = Fields. local_geometry_field (axes (ᶜ∂ϕ∂z)). J
17
+ f_space = Spaces. face_space (axes (ᶜ∂ϕ∂z))
18
+ J_bot = Fields. level (Fields. local_geometry_field (f_space). J, half)
19
+ Δz_bot = Fields. level (Fields. Δz_field (f_space), half)
20
+ ΔA_bot = Base. broadcasted (/ , J_bot, Δz_bot)
21
+ ᶜΔϕ = Base. broadcasted (⊠ , ᶜ∂ϕ∂z, Base. broadcasted (/ , ᶜJ, ΔA_bot))
16
22
column_reduce! (⊞ , ϕ_top, ᶜΔϕ; init = ϕ_bot)
17
23
end
18
24
19
25
"""
20
26
column_integral_indefinite!(ᶠϕ, ᶜ∂ϕ∂z, [ϕ_bot])
21
27
22
- Sets `ᶠϕ```(z) = \\ int_{z_{bot}}^z\\ ,```ᶜ∂ϕ∂z```(z')\\ ,dz' +{}```ϕ_bot`, where
23
- ``z_{bot}`` is the value of `z` at the bottom of the domain. The input `ᶜ∂ϕ∂z`
24
- should be a cell-center `Field` or `AbstractBroadcasted`, and the output `ᶠϕ`
25
- should be a cell-face `Field`. The default value of `ϕ_bot` is 0.
28
+ Sets `ᶠϕ```(z) = \\ frac{1}{ΔA(z_{bot})}\\ int_{z_{bot}}^z\\ ,```ᶜ∂ϕ∂z```(z')\\ ,
29
+ ΔA(z')\\ ,dz' +{}```ϕ_bot`, where ``z_{bot}`` is the value of `z` at the bottom
30
+ of the domain, and where `ΔA` is the area differential `J/Δz`, with `J` denoting
31
+ the metric Jacobian. The input `ᶜ∂ϕ∂z` should be a cell-center `Field` or
32
+ `AbstractBroadcasted`, and the output `ᶠϕ` should be a cell-face `Field`. The
33
+ default value of `ϕ_bot` is 0.
26
34
27
35
column_integral_indefinite!(∂ϕ∂z, ᶠϕ, [ϕ_bot], [rtol])
28
36
29
- Sets
30
- `ᶠϕ```(z) = \\ int_{z_{bot}}^z\\ ,```∂ϕ∂z```(```ᶠϕ```(z'), z')\\ ,dz' +{}```ϕ_bot`,
31
- where `∂ϕ∂z` can be any scalar-valued two-argument function. The output `ᶠϕ`
32
- satisfies `ᶜgradᵥ.(ᶠϕ) ≈ ∂ϕ∂z.(ᶜint.(ᶠϕ), ᶜz)`, where `ᶜgradᵥ = GradientF2C()`,
33
- `ᶜint = InterpolateF2C()`, and `ᶜz = Fields.coordinate_field(ᶜint.(ᶠϕ)).z`, and
34
- where the approximation is accurate to a relative tolerance of `rtol`. The
37
+ Sets `ᶠϕ```(z) = \\ frac{1}{ΔA(z_{bot})}\\ int_{z_{bot}}^z\\ ,
38
+ ```∂ϕ∂z```(```ᶠϕ```(z'), z')\\ ,ΔA(z')\\ ,dz' +{}```ϕ_bot`, where `∂ϕ∂z` can be
39
+ any scalar-valued two-argument function. When a shallow atmosphere approximation
40
+ is used, `ΔA = ΔA_{bot}` at all values of `z`, and the output `ᶠϕ` satisfies
41
+ `ᶜgradᵥ.(ᶠϕ) ≈ ∂ϕ∂z.(ᶜint.(ᶠϕ), ᶜz)` with a relative tolerance of `rtol`, where
42
+ `ᶜgradᵥ = GradientF2C()` and `ᶜint = InterpolateF2C()`. When a deep atmosphere
43
+ is used, the vertical gradient is replaced with an area-weighted gradient. The
35
44
default value of `ϕ_bot` is 0, and the default value of `rtol` is 0.001.
36
45
"""
37
46
function column_integral_indefinite! (ᶠϕ, ᶜ∂ϕ∂z, ϕ_bot = rzero (eltype (ᶠϕ)))
38
- ᶜΔϕ = Base. Broadcast. broadcasted (⊠ , ᶜ∂ϕ∂z, Fields. Δz_field (axes (ᶜ∂ϕ∂z)))
47
+ ᶜJ = Fields. local_geometry_field (axes (ᶜ∂ϕ∂z)). J
48
+ J_bot = Fields. level (Fields. local_geometry_field (ᶠϕ). J, half)
49
+ Δz_bot = Fields. level (Fields. Δz_field (ᶠϕ), half)
50
+ ΔA_bot = Base. broadcasted (/ , J_bot, Δz_bot)
51
+ ᶜΔϕ = Base. broadcasted (⊠ , ᶜ∂ϕ∂z, Base. broadcasted (/ , ᶜJ, ΔA_bot))
39
52
column_accumulate! (⊞ , ᶠϕ, ᶜΔϕ; init = ϕ_bot)
40
53
end
41
54
function column_integral_indefinite! (
@@ -45,26 +58,23 @@ function column_integral_indefinite!(
45
58
rtol = eltype (ᶠϕ)(0.001 ),
46
59
) where {F <: Function }
47
60
device = ClimaComms. device (ᶠϕ)
48
- face_space = axes (ᶠϕ)
49
- center_space = if face_space isa Spaces. FaceFiniteDifferenceSpace
50
- Spaces. CenterFiniteDifferenceSpace (face_space)
51
- elseif face_space isa Spaces. FaceExtrudedFiniteDifferenceSpace
52
- Spaces. CenterExtrudedFiniteDifferenceSpace (face_space)
53
- else
54
- error (" output of column_integral_indefinite! must be on cell faces" )
55
- end
56
- ᶜz = Fields. coordinate_field (center_space). z
57
- ᶜΔz = Fields. Δz_field (center_space)
58
- ᶜz_and_Δz = Base. Broadcast. broadcasted (tuple, ᶜz, ᶜΔz)
59
- column_accumulate! (ᶠϕ, ᶜz_and_Δz; init = ϕ_bot) do ϕ_prev, (z, Δz)
60
- residual (ϕ_new) = (ϕ_new - ϕ_prev) / Δz - ∂ϕ∂z ((ϕ_prev + ϕ_new) / 2 , z)
61
+ c_space = Spaces. center_space (axes (ᶠϕ))
62
+ ᶜz = Fields. coordinate_field (c_space). z
63
+ ᶜJ = Fields. local_geometry_field (c_space). J
64
+ J_bot = Fields. level (Fields. local_geometry_field (ᶠϕ). J, half)
65
+ Δz_bot = Fields. level (Fields. Δz_field (ᶠϕ), half)
66
+ ΔA_bot = Base. broadcasted (/ , J_bot, Δz_bot)
67
+ ᶜz_and_Δz = Base. broadcasted (tuple, ᶜz, Base. broadcasted (/ , ᶜJ, ΔA_bot))
68
+ column_accumulate! (ᶠϕ, ᶜz_and_Δz; init = ϕ_bot) do ϕ_prev, (z, weighted_Δz)
69
+ residual (ϕ_new) =
70
+ (ϕ_new - ϕ_prev) / weighted_Δz - ∂ϕ∂z ((ϕ_prev + ϕ_new) / 2 , z)
61
71
(; converged, root) = RootSolvers. find_zero (
62
72
residual,
63
73
RootSolvers. NewtonsMethodAD (ϕ_prev),
64
74
RootSolvers. CompactSolution (),
65
75
RootSolvers. RelativeSolutionTolerance (rtol),
66
76
)
67
- ClimaComms. @assert device converged " ∂ϕ∂z could not be integrated over \
77
+ ClimaComms. @assert device converged " unable to integrate through \
68
78
z = $z with rtol set to $rtol "
69
79
return root
70
80
end
0 commit comments