Skip to content

Commit 2630abf

Browse files
glwagnernavidcytomchor
authored
Call compute! in constructor for ComputedField (#4531)
* Update computed_field.jl * Update oceananigans.bib * remove obsolete compute statement * add `compute` kw and retain original behavior in output_construction * fix test plus docstrings * Update src/OutputWriters/output_construction.jl * fix doctests in operations.md * fix doctest in seawater_density * no need to compute * no need to compute! * fix docstrings --------- Co-authored-by: Navid C. Constantinou <[email protected]> Co-authored-by: tomaschor <[email protected]>
1 parent b94aa4d commit 2630abf

File tree

10 files changed

+47
-69
lines changed

10 files changed

+47
-69
lines changed

docs/oceananigans.bib

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -983,18 +983,18 @@ @article{BouZeid05
983983
}
984984

985985
@article{Lan2022,
986-
author = {Lan, Rihui and Ju, Lili and Wanh, Zhu and Gunzburger, Max and Jones, Philip},
987-
title = {High-order multirate explicit time-stepping schemes for the baroclinic-barotropic split dynamics in primitive equations},
988-
journal = {Journal of Computational Physics},
989-
volume = {457},
990-
pages = {111050},
991-
year = {2022},
992-
doi = {https://doi.org/10.1016/j.jcp.2022.111050},
986+
author = {Lan, Rihui and Ju, Lili and Wanh, Zhu and Gunzburger, Max and Jones, Philip},
987+
title = {High-order multirate explicit time-stepping schemes for the baroclinic-barotropic split dynamics in primitive equations},
988+
journal = {Journal of Computational Physics},
989+
volume = {457},
990+
pages = {111050},
991+
year = {2022},
992+
doi = {10.1016/j.jcp.2022.111050},
993993
}
994994

995995
@inproceedings{Verstappen14,
996996
title={Numerical scale separation in large-eddy simulation},
997-
author={Verstappen, RWCP and Rozema, W and Bae, HJ},
997+
author={Verstappen, Roel and Rozema, Wybe and Bae, H. Jane},
998998
booktitle={Proceedings of the Summer Program},
999999
pages={417--426},
10001000
year={2014}

docs/src/operations.md

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -245,26 +245,10 @@ set!(c, 1)
245245
├── operand: Integral of BinaryOperation at (Center, Center, Center) over dims (1, 2)
246246
├── status: time=0.0
247247
└── data: 1×1×11 OffsetArray(::Array{Float64, 3}, 1:1, 1:1, -2:8) with eltype Float64 with indices 1:1×1:1×-2:8
248-
└── max=0.0, min=0.0, mean=0.0
248+
└── max=2.55032e14, min=2.55032e14, mean=2.55032e14
249249
```
250250

251251
A few remarks: note that the `∫c` has locations `Nothing, Nothing, Center`; this is because we have integrated in the first two dimensions and thus it's `reduced over dims = (1, 2)`.
252-
Further note that `∫c` is full of zeros; its max, min, and mean values are all 0.
253-
No computation has been done yet.
254-
To compute `∫c`, we call [`compute!`](@ref),
255-
256-
```jldoctest operations_avg_int
257-
compute!(∫c)
258-
259-
# output
260-
1×1×5 Field{Nothing, Nothing, Center} reduced over dims = (1, 2) on LatitudeLongitudeGrid on CPU
261-
├── data: OffsetArrays.OffsetArray{Float64, 3, Array{Float64, 3}}, size: (1, 1, 5)
262-
├── grid: 60×10×5 LatitudeLongitudeGrid{Float64, Periodic, Bounded, Bounded} on CPU with 3×3×3 halo and with precomputed metrics
263-
├── operand: Integral of BinaryOperation at (Center, Center, Center) over dims (1, 2)
264-
├── status: time=0.0
265-
└── data: 1×1×11 OffsetArray(::Array{Float64, 3}, 1:1, 1:1, -2:8) with eltype Float64 with indices 1:1×1:1×-2:8
266-
└── max=2.55032e14, min=2.55032e14, mean=2.55032e14
267-
```
268252

269253
Above we see that the max, min and mean of the field are all the same.
270254
Let's check that these values are what we expect:
@@ -296,15 +280,14 @@ conditional_∫c = Field(Integral(c, dims=(1, 2), condition=cond)) # integrate o
296280
├── operand: Integral of ConditionalOperation of BinaryOperation at (Center, Center, Center) with condition cond (generic function with 1 method) over dims (1, 2)
297281
├── status: time=0.0
298282
└── data: 1×1×11 OffsetArray(::Array{Float64, 3}, 1:1, 1:1, -2:8) with eltype Float64 with indices 1:1×1:1×-2:8
299-
└── max=0.0, min=0.0, mean=0.0
283+
└── max=1.27516e14, min=1.27516e14, mean=1.27516e14
300284
```
301285

302286
Above we have attached a condition to the operand.
303287
Now the operand is applied only when the condition is true.
304-
Let's compute and see if we get 1/4 of the area of the sphere
288+
Let's see if that is 1/4 of the area of the sphere
305289

306290
```jldoctest operations_avg_int
307-
compute!(conditional_∫c)
308291
conditional_∫c[1, 1, 1] ≈ π * grid.radius^2 # area of spherical zone with 0ᵒ ≤ φ ≤ 30ᵒ
309292
310293
# output
@@ -319,7 +302,6 @@ cond_array[:, 1:5, :] .= false # set the first half of the latitude range to fal
319302
320303
conditional_∫c = Field(Integral(c, dims=(1, 2), condition=cond_array))
321304
322-
compute!(conditional_∫c)
323305
conditional_∫c[1, 1, 1] ≈ π * grid.radius^2 # area of spherical zone with 0ᵒ ≤ φ ≤ 30ᵒ
324306
325307
# output

docs/src/quick_start.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ using CairoMakie
3737
3838
u, v, w = model.velocities
3939
ζ = Field(∂x(v) - ∂y(u))
40-
compute!(ζ)
4140
4241
heatmap(ζ, axis=(; aspect=1))
4342
```
@@ -48,7 +47,6 @@ A few more time-steps, and it's starting to get a little diffuse!
4847
simulation.stop_iteration += 400
4948
run!(simulation)
5049
51-
compute!(ζ)
5250
heatmap(ζ, axis=(; aspect=1))
5351
```
5452

@@ -87,7 +85,6 @@ run!(simulation)
8785
8886
u, v, w = model.velocities
8987
ζ = Field(∂x(v) - ∂y(u))
90-
compute!(ζ)
9188
9289
fig = Figure(size=(1200, 600))
9390
axζ = Axis(fig[1, 1], aspect=1, title="vorticity")

examples/horizontal_convection.jl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,9 @@ nothing #hide
306306

307307
for n = 1:length(t)
308308
ke = Field(Integral(1/2 * s_timeseries[n]^2 / (Lx * H)))
309-
compute!(ke)
310309
kinetic_energy[n] = ke[1, 1, 1]
311310

312311
χ = Field(Integral(χ_timeseries[n] / (Lx * H)))
313-
compute!(χ)
314-
315312
Nu[n] = χ[1, 1, 1] / χ_diff
316313
end
317314

examples/shallow_water_Bickley_jet.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,8 @@ uh, vh, h = model.solution
9696
u = uh / h
9797
v = vh / h
9898

99-
## Build and compute mean vorticity discretely
99+
## Build mean vorticity discretely
100100
ω = Field(∂x(v) - ∂y(u))
101-
compute!(ω)
102101

103102
## Copy mean vorticity to a new field
104103
ωⁱ = Field((Face, Face, Nothing), model.grid)

src/AbstractOperations/computed_field.jl

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const ComputedField = Field{<:Any, <:Any, <:Any, <:OperationOrFunctionField}
1717
data = nothing,
1818
indices = indices(operand),
1919
boundary_conditions = FieldBoundaryConditions(operand.grid, location(operand)),
20+
compute = true,
2021
recompute_safely = true)
2122
2223
Return a field `f` where `f.data` is computed from `f.operand` by calling `compute!(f)`.
@@ -29,16 +30,20 @@ Keyword arguments
2930
3031
`boundary_conditions` (`FieldBoundaryConditions`): Boundary conditions for `f`.
3132
32-
`recompute_safely` (`Bool`): whether or not to _always_ "recompute" `f` if `f` is
33+
`recompute_safely` (`Bool`): Whether or not to _always_ "recompute" `f` if `f` is
3334
nested within another computation via an `AbstractOperation` or `FunctionField`.
34-
If `data` is not provided then `recompute_safely=false` and
35+
If `data` is not provided then `recompute_safely = false` and
3536
recomputation is _avoided_. If `data` is provided, then
3637
`recompute_safely = true` by default.
38+
39+
`compute`: If `true`, `compute!` the `Field` during construction, otherwise if `false`, initialize with zeros.
40+
Default: `true`.
3741
"""
3842
function Field(operand::OperationOrFunctionField;
3943
data = nothing,
4044
indices = indices(operand),
4145
boundary_conditions = FieldBoundaryConditions(operand.grid, location(operand)),
46+
compute = true,
4247
recompute_safely = true)
4348

4449
grid = operand.grid
@@ -54,13 +59,20 @@ function Field(operand::OperationOrFunctionField;
5459

5560
status = recompute_safely ? nothing : FieldStatus()
5661

57-
return Field(loc, grid, data, boundary_conditions, indices, operand, status)
62+
computed_field = Field(loc, grid, data, boundary_conditions, indices, operand, status)
63+
64+
if compute
65+
compute!(computed_field)
66+
end
67+
68+
return computed_field
5869
end
5970

6071
"""
61-
compute!(comp::ComputedField)
72+
compute!(comp::ComputedField, time=nothing)
6273
6374
Compute `comp.operand` and store the result in `comp.data`.
75+
If `time` then computation happens if `time != field.status.time`.
6476
"""
6577
function compute!(comp::ComputedField, time=nothing)
6678
# First compute `dependencies`:

src/Fields/scans.jl

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Base.summary(s::Scan) = string(summary(s.type), " ",
4141
function Field(scan::Scan;
4242
data = nothing,
4343
indices = indices(scan.operand),
44+
compute = true,
4445
recompute_safely = true)
4546

4647
operand = scan.operand
@@ -56,7 +57,13 @@ function Field(scan::Scan;
5657
boundary_conditions = FieldBoundaryConditions(grid, loc, indices)
5758
status = recompute_safely ? nothing : FieldStatus()
5859

59-
return Field(loc, grid, data, boundary_conditions, indices, scan, status)
60+
scan_field = Field(loc, grid, data, boundary_conditions, indices, scan, status)
61+
62+
if compute
63+
compute!(scan_field)
64+
end
65+
66+
return scan_field
6067
end
6168

6269
const ScannedComputedField = Field{<:Any, <:Any, <:Any, <:Scan}
@@ -105,7 +112,7 @@ Base.show(io::IO, s::Scan) =
105112
106113
Return a `Reduction` of `operand` with `reduce!`, where `reduce!` can be called with
107114
108-
```
115+
```julia
109116
reduce!(field, operand)
110117
```
111118
@@ -118,18 +125,12 @@ Example
118125
using Oceananigans
119126
120127
Nx, Ny, Nz = 3, 3, 3
121-
122128
grid = RectilinearGrid(size=(Nx, Ny, Nz), x=(0, 1), y=(0, 1), z=(0, 1),
123129
topology=(Periodic, Periodic, Periodic))
124130
125131
c = CenterField(grid)
126-
127132
set!(c, (x, y, z) -> x + y + z)
128-
129133
max_c² = Field(Reduction(maximum!, c^2, dims=3))
130-
131-
compute!(max_c²)
132-
133134
max_c²[1:Nx, 1:Ny]
134135
135136
# output
@@ -151,7 +152,7 @@ location(r::Reduction) = reduced_location(location(r.operand); dims=r.dims)
151152
152153
Return a `Accumulation` of `operand` with `accumulate!`, where `accumulate!` can be called with
153154
154-
```
155+
```julia
155156
accumulate!(field, operand; dims)
156157
```
157158
@@ -164,18 +165,12 @@ Example
164165
using Oceananigans
165166
166167
Nx, Ny, Nz = 3, 3, 3
167-
168168
grid = RectilinearGrid(size=(Nx, Ny, Nz), x=(0, 1), y=(0, 1), z=(0, 1),
169169
topology=(Periodic, Periodic, Periodic))
170170
171171
c = CenterField(grid)
172-
173172
set!(c, (x, y, z) -> x + y + z)
174-
175173
cumsum_c² = Field(Accumulation(cumsum!, c^2, dims=3))
176-
177-
compute!(cumsum_c²)
178-
179174
cumsum_c²[1:Nx, 1:Ny, 1:Nz]
180175
181176
# output

src/Models/seawater_density.jl

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,6 @@ julia> density_field = Field(density_operation)
106106
│ └── west: Nothing, east: Nothing, south: Nothing, north: Nothing, bottom: ZeroFlux, top: ZeroFlux, immersed: ZeroFlux
107107
├── operand: KernelFunctionOperation at (Center, Center, Center)
108108
├── status: time=0.0
109-
└── data: 1×1×106 OffsetArray(::Array{Float64, 3}, 1:1, 1:1, -2:103) with eltype Float64 with indices 1:1×1:1×-2:103
110-
└── max=0.0, min=0.0, mean=0.0
111-
112-
julia> compute!(density_field)
113-
1×1×100 Field{Center, Center, Center} on RectilinearGrid on CPU
114-
├── grid: 1×1×100 RectilinearGrid{Float64, Flat, Flat, Bounded} on CPU with 0×0×3 halo
115-
├── boundary conditions: FieldBoundaryConditions
116-
│ └── west: Nothing, east: Nothing, south: Nothing, north: Nothing, bottom: ZeroFlux, top: ZeroFlux, immersed: ZeroFlux
117-
├── operand: KernelFunctionOperation at (Center, Center, Center)
118-
├── status: time=0.0
119109
└── data: 1×1×106 OffsetArray(::Array{Float64, 3}, 1:1, 1:1, -2:103) with eltype Float64 with indices 1:1×1:1×-2:103
120110
└── max=1032.38, min=1027.73, mean=1030.06
121111
```

src/OutputWriters/output_construction.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ end
5454

5555
function construct_output(user_output::Union{AbstractField, Reduction}, grid, user_indices, with_halos)
5656
indices = output_indices(user_output, grid, user_indices, with_halos)
57-
return Field(user_output; indices)
57+
58+
# Don't compute AbstractOperations or Reductions
59+
additional_kw = user_output isa Field ? NamedTuple() : (; compute=false)
60+
61+
return Field(user_output; indices, additional_kw...)
5862
end
5963

6064
#####

test/test_field_scans.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,10 +376,12 @@ interior_array(a, i, j, k) = Array(interior(a, i, j, k))
376376
c = CenterField(grid)
377377
set!(c, (x, y, z) -> x + y + z)
378378

379-
max_c² = Field(Reduction(maximum, c^2, dims=3))
379+
max_c² = Field(Reduction(maximum!, c^2, dims=3))
380380
∫max_c² = Integral(max_c², dims=(1, 2))
381-
compute!(∫max_c²)
382381
@test ∫max_c² isa Reduction
382+
∫max_c²_field = Field(∫max_c²)
383+
@test ∫max_c²_field isa Field
384+
@test ∫max_c²_field.operand === ∫max_c²
383385

384386
@info " Testing conditional reductions of immersed Fields [$(typeof(arch))]"
385387

0 commit comments

Comments
 (0)