-
Notifications
You must be signed in to change notification settings - Fork 195
/
immersed_reductions.jl
86 lines (65 loc) · 4.12 KB
/
immersed_reductions.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using Oceananigans.Fields: AbstractField, indices
import Oceananigans.AbstractOperations: ConditionalOperation, evaluate_condition
import Oceananigans.Fields: condition_operand, conditional_length
#####
##### Reduction operations involving immersed boundary grids exclude the immersed periphery,
##### which includes both external nodes and nodes on the immersed interface.
#####
@inline truefunc(args...) = true
struct NotImmersed{F} <: Function
func :: F
end
# ImmersedField
const IF = AbstractField{<:Any, <:Any, <:Any, <:ImmersedBoundaryGrid}
@inline condition_operand(func::Function, op::IF, cond, mask) = ConditionalOperation(op; func, condition=NotImmersed(cond), mask)
@inline condition_operand(func::Function, op::IF, ::Nothing, mask) = ConditionalOperation(op; func, condition=NotImmersed(truefunc), mask)
@inline condition_operand(func::typeof(identity), op::IF, ::Nothing, mask) = ConditionalOperation(op; func, condition=NotImmersed(truefunc), mask)
@inline function condition_operand(func::Function, op::IF, cond::AbstractArray, mask)
arch = architecture(op.grid)
arch_condition = on_architecture(arch, cond)
ni_condition = NotImmersed(arch_condition)
return ConditionalOperation(op; func, condition=ni_condition, mask)
end
@inline conditional_length(c::IF) = conditional_length(condition_operand(identity, c, nothing, 0))
@inline conditional_length(c::IF, dims) = conditional_length(condition_operand(identity, c, nothing, 0), dims)
@inline function evaluate_condition(condition::NotImmersed, i, j, k, ibg, co::ConditionalOperation, args...)
ℓx, ℓy, ℓz = map(instantiate, location(co))
immersed = immersed_peripheral_node(i, j, k, ibg, ℓx, ℓy, ℓz) | inactive_node(i, j, k, ibg, ℓx, ℓy, ℓz)
return !immersed & evaluate_condition(condition.func, i, j, k, ibg, args...)
end
#####
##### Reduction operations on Reduced Fields test the immersed condition on the entirety of the immersed direction
#####
struct NotImmersedColumn{IC, F} <:Function
immersed_column :: IC
func :: F
end
using Oceananigans.Fields: reduced_dimensions, OneField
using Oceananigans.AbstractOperations: ConditionalOperation
# ImmersedReducedFields
const XIRF = AbstractField{Nothing, <:Any, <:Any, <:ImmersedBoundaryGrid}
const YIRF = AbstractField{<:Any, Nothing, <:Any, <:ImmersedBoundaryGrid}
const ZIRF = AbstractField{<:Any, <:Any, Nothing, <:ImmersedBoundaryGrid}
const YZIRF = AbstractField{<:Any, Nothing, Nothing, <:ImmersedBoundaryGrid}
const XZIRF = AbstractField{Nothing, <:Any, Nothing, <:ImmersedBoundaryGrid}
const XYIRF = AbstractField{Nothing, Nothing, <:Any, <:ImmersedBoundaryGrid}
const XYZIRF = AbstractField{Nothing, Nothing, Nothing, <:ImmersedBoundaryGrid}
const IRF = Union{XIRF, YIRF, ZIRF, YZIRF, XZIRF, XYIRF, XYZIRF}
@inline condition_operand(func::Function, op::IRF, cond, mask) = ConditionalOperation(op; func, condition=NotImmersedColumn(immersed_column(op), cond ), mask)
@inline condition_operand(func::Function, op::IRF, ::Nothing, mask) = ConditionalOperation(op; func, condition=NotImmersedColumn(immersed_column(op), truefunc), mask)
@inline condition_operand(func::typeof(identity), op::IRF, ::Nothing, mask) = ConditionalOperation(op; func, condition=NotImmersedColumn(immersed_column(op), truefunc), mask)
@inline function immersed_column(field::IRF)
grid = field.grid
reduced_dims = reduced_dimensions(field)
LX, LY, LZ = map(center_to_nothing, location(field))
one_field = ConditionalOperation{LX, LY, LZ}(OneField(Int), identity, grid, NotImmersed(truefunc), zero(grid))
return sum(one_field, dims=reduced_dims)
end
@inline center_to_nothing(::Type{Face}) = Face
@inline center_to_nothing(::Type{Center}) = Center
@inline center_to_nothing(::Type{Nothing}) = Center
@inline function evaluate_condition(condition::NotImmersedColumn, i, j, k, ibg, co::ConditionalOperation, args...)
LX, LY, LZ = location(co)
return evaluate_condition(condition.func, i, j, k, ibg, args...) & !(is_immersed_column(i, j, k, condition.immersed_column))
end
@inline is_immersed_column(i, j, k, column) = @inbounds column[i, j, k] == 0