@@ -7,116 +7,121 @@ using Oceananigans
77using Oceananigans: field
88using Oceananigans. Architectures: array_type
99using Oceananigans: RectilinearGrid
10+
1011
11- mutable struct GrayRadiationModel{FT, DA, SLVLW, SLVSW, AS, OTP} <: AbstractRadiationModel
12+ """
13+ GrayRadiationModel stores state and solver handles for a gray-band radiative
14+ transfer setup.
15+
16+ Field conventions (array shapes):
17+ - cos_zenith_angle: (Nx, Ny) — cos of zenith angle on the horizontal grid
18+ - sfc_emissivity: (Nbnd, Nx, Ny) — surface emissivity per band
19+ - sfc_albedo_direct: (Nbnd, Nx, Ny) — direct-beam surface albedo per band
20+ - sfc_albedo_diffuse: (Nbnd, Nx, Ny) — diffuse surface albedo per band
21+ - sw_toa_flux_inc: (Nx, Ny) — incoming shortwave flux at TOA
22+ - sw_inc_flux_diffuse: (Nx, Ny) or nothing — optional diffuse SW incoming flux
23+ - lw_toa_inc_flux: (Nx, Ny) or nothing — optional incoming LW flux at TOA
24+ """
25+ mutable struct GrayRadiationModel{FT, AS, SLVLW, SLVSW, OTP} <: AbstractRadiationModel
1226 atmospheric_state :: AS
1327 slv_lw :: SLVLW
1428 slv_sw :: SLVSW
1529 optical_properties :: OTP
16- cos_zenith_angle :: DA {FT}
17- sfc_emissivity :: DA {FT}
18- sfc_albedo_direct :: DA {FT}
19- sfc_albedo_diffuse :: DA {FT}
20- sw_toa_flux_inc :: DA {FT}
21- sw_inc_flux_diffuse :: Union{Nothing, DA {FT}}
22- lw_toa_inc_flux :: Union{Nothing, DA {FT}}
30+ cos_zenith_angle :: AbstractArray {FT}
31+ sfc_emissivity :: AbstractArray {FT}
32+ sfc_albedo_direct :: AbstractArray {FT}
33+ sfc_albedo_diffuse :: AbstractArray {FT}
34+ sw_toa_flux_inc :: AbstractArray {FT}
35+ sw_inc_flux_diffuse :: Union{Nothing, AbstractArray {FT}}
36+ lw_toa_inc_flux :: Union{Nothing, AbstractArray {FT}}
2337end
2438
39+ """
40+ GrayRadiationModel(grid; atmospheric_state,
41+ zenith_angle, sfc_emissivity, sfc_albedo_direct,
42+ sfc_albedo_diffuse, sw_flux_inc_toa;
43+ sw_flux_inc_toa_diffusive=nothing,
44+ lw_flux_inc_toa=nothing,
45+ optical_properties=nothing)
46+
47+ Construct a gray-band model using a precomputed atmospheric state.
48+ Inputs may be scalars or arrays and are normalized to device arrays.
49+ """
2550function GrayRadiationModel (
26- grid;
27- temperature,
51+ grid;
52+ temperature,
2853 pressure,
29- cos_zenith_angle ,
54+ zenith_angle ,
3055 sfc_emissivity,
3156 sfc_albedo_direct,
3257 sfc_albedo_diffuse,
3358 sw_flux_inc_toa,
34- sw_flux_inc_toa_diffusive,
35- lw_flux_inc_toa,
59+ sw_flux_inc_toa_diffusive= nothing ,
60+ lw_flux_inc_toa= nothing ,
3661 optical_properties= GrayOpticalThicknessSchneider2004 (FT),
37- lat_center= 0
38- )
39- # We assemble objects required for RRTMGP to work.
62+ lat_center= 0 ,
63+ )
64+ DA = array_type (grid. architecture)
65+ FT = eltype (grid)
66+ Nx, Ny = grid. Nx, grid. Ny
67+ Nbnd = 1
68+
69+ # Create atmospheric state from provided Fields (generic library behavior)
4070 atmospheric_state = GrayAtmosphericState (
41- grid;
42- temperature,
43- pressure,
44- otp= optical_properties,
45- lat_center= lat_center
71+ grid;
72+ temperature,
73+ pressure,
74+ otp= optical_properties,
75+ lat_center= lat_center,
4676 )
77+
78+ # Helper functions
79+ to_grid_array (val) = val isa AbstractArray ? DA (val) : (A = DA {FT} (undef, Nx, Ny); fill! (A, FT (val)))
80+ to_banded_array (val) = val isa AbstractArray ? DA (val) : (A = DA {FT} (undef, Nbnd, Nx, Ny); fill! (A, FT (val)))
81+ to_optional_grid_array (val) = val === nothing ? nothing : to_grid_array (val)
82+
83+ # Bring arrays to the correct shape for RRTMGP.jl interface
84+ cos_zenith = if zenith_angle isa AbstractArray
85+ DA (cos .(FT (π / 180 ) .* zenith_angle))
86+ else
87+ A = DA {FT} (undef, Nx, Ny)
88+ fill! (A, FT (cos (FT (π / 180 ) * zenith_angle)))
89+ end
90+ sfc_emission = to_banded_array (sfc_emissivity)
91+ sfc_alb_direct = to_banded_array (sfc_albedo_direct)
92+ sfc_alb_diffuse = to_banded_array (sfc_albedo_diffuse)
93+ toa_flux = to_grid_array (sw_flux_inc_toa)
94+ inc_flux_diffuse = to_optional_grid_array (sw_flux_inc_toa_diffusive)
95+ lw_toa_inc_flux = to_optional_grid_array (lw_flux_inc_toa)
96+
97+ # Build solvers using the high-level wrappers (they reshape internally)
4798 SLVLW = TwoStreamLWRTE
4899 SLVSW = TwoStreamSWRTE
49100 lw_params = (
50- sfc_emission = sfc_emissivity,
51- lw_inc_flux = lw_flux_inc_toa ,
101+ sfc_emission = sfc_emission,
102+ lw_inc_flux = lw_toa_inc_flux ,
52103 )
53104 sw_params = (
54- cos_zenith = cos_zenith_angle,
55- toa_flux = sw_flux_inc_toa ,
56- sfc_alb_direct = sfc_albedo_diffuse ,
57- inc_flux_diffuse = sw_flux_inc_toa_diffusive ,
58- sfc_alb_diffuse = sfc_albedo_diffuse ,
105+ cos_zenith = cos_zenith,
106+ toa_flux = toa_flux ,
107+ sfc_alb_direct = sfc_alb_direct ,
108+ inc_flux_diffuse = inc_flux_diffuse ,
109+ sfc_alb_diffuse = sfc_alb_diffuse ,
59110 )
60111 slv_lw = SLVLW (grid; lw_params... )
61112 slv_sw = SLVSW (grid; sw_params... )
62-
63- if sfc_emissivity isa DA
64-
65- elseif sfc_emissivity isa AbstractFloat
66-
67- end
68113
69114 return GrayRadiationModel (
70115 atmospheric_state,
71- slv_lw,
116+ slv_lw,
72117 slv_sw,
73118 optical_properties,
74- cos_zenith_angle ,
119+ cos_zenith ,
75120 sfc_emission,
76- sfc_albedo_direct ,
77- sfc_albedo_diffuse ,
78- sw_flux_inc_toa,
79- sw_flux_inc_toa_diffusive ,
80- lw_flux_inc_toa ,
121+ sfc_alb_direct ,
122+ sfc_alb_diffuse ,
123+ toa_flux,
124+ inc_flux_diffuse ,
125+ lw_toa_inc_flux ,
81126 )
82127end
83-
84- function GrayRadiationModel (
85- grid;
86- temperature :: Field ,
87- pressure :: Field ,
88- zenith_angle :: FT ,
89- sfc_emissivity :: FT ,
90- sfc_albedo_direct :: FT ,
91- sfc_albedo_diffuse :: FT ,
92- sw_flux_inc_toa :: FT ,
93- sw_flux_inc_toa_diffusive :: Union{Nothing, FT} ,
94- lw_flux_inc_toa :: Union{Nothing, FT} ,
95- optical_properties= GrayOpticalThicknessSchneider2004 (FT),
96- lat_center= 0
97- )
98- FT = eltype (grid)
99- DA = device_array (grid. architecture)
100- Nx, Ny, Nz = grid. Nx, grid. Ny, grid. Nz
101- Nbnd = 1
102-
103-
104- sfc_emission = DA {FT} (undef, Nbnd, Nx, Ny)
105- sfc_alb_direct = DA {FT} (undef, Nbnd, Nx, Ny)
106- sfc_alb_diffuse = DA {FT} (undef, Nbnd, Nx, Ny)
107- cos_zenith = DA {FT} (undef, Nx, Ny)
108- toa_flux = DA {FT} (undef, Nx, Ny)
109- lw_toa_inc_flux = nothing
110- inc_flux_diffuse = nothing
111- fill! (sfc_emission, FT (sfc_emissivity))
112- fill! (sfc_alb_direct, FT (albedo_direct))
113- fill! (sfc_alb_diffuse, FT (albedo_diffuse))
114- fill! (cos_zenith, FT (cos (deg2rad * zenith_angle)))
115- fill! (toa_flux, FT (sw_inc_flux))
116- end
117-
118- function (rad:: GrayRadiationModel )(:: Val{:ρe} , temperature, pressure)
119- update_atmospheric_state (rad, temperature, pressure)
120- solve_lw! (rad. slv_lw, rad. atmospheric_state)
121- solve_sw! (rad. slv_sw, rad. atmospheric_state)
122- end
0 commit comments