@@ -16,25 +16,21 @@ using ClimaOcean.OceanSimulations
16
16
using Oceananigans
17
17
using CairoMakie
18
18
19
- # We start by defining a grid. The ECCO2 grid is a good starting point.
20
- # The ECCO2 grid is not "immersed" by default, but we can use the ECCO mask
21
- # to define the "bathymetry" of the ECCO fields.
22
- # `ecco2_center_mask` produces a field with `true` values where data is missing (i.e., in immersed cells).
23
- # We can use this mask as an immersed boundary for our grid.
24
- # Let's create the grid and visualize the mask.
25
-
26
- mask = ecco_mask ()
19
+ # # Computing fluxes on the ECCO2 grid
20
+ #
21
+ # We start by building the ECCO2 grid, using `ECCO_mask`
22
+ # to identify missing cells.
23
+
24
+ mask = ECCO_mask ()
27
25
grid = mask. grid
28
26
grid = ImmersedBoundaryGrid (grid, GridFittedBoundary (mask))
29
27
30
28
fig = Figure ()
31
29
ax = Axis (fig[1 , 1 ])
32
30
heatmap! (ax, interior (grid. immersed_boundary. mask, :, :, grid. Nz))
31
+ save (" ECCO_continents.png" , fig) # hide
33
32
34
- save (" ecco_continents.png" , fig)
35
- nothing # hide
36
-
37
- # 
33
+ # 
38
34
39
35
# Next, we construct our atmosphere and ocean.
40
36
#
@@ -50,103 +46,50 @@ nothing #hide
50
46
#
51
47
# We invoke the constructor with only the first two time indices, corresponding to
52
48
# January 1st (at 00:00 AM and 03:00 AM).
53
- # By passing the ECCO grid, we automatically interpolate the atmospheric data onto the grid.
54
- # Note that this is recommended only for small simulations (in terms of grid size).
55
- # By omitting the grid, the interpolation will be done on the fly.
56
- #
57
- # We construct the ocean simulation without considering advection, closures, or Coriolis effects since
58
- # we will not time-step the ocean but only use it to construct the fluxes.
59
-
60
- atmosphere = JRA55_prescribed_atmosphere (1 : 2 ; backend = InMemory (), grid = grid. underlying_grid)
61
-
62
- ocean = ocean_simulation (grid; momentum_advection = nothing ,
63
- tracer_advection = nothing ,
64
- closure = nothing ,
65
- coriolis = nothing )
66
-
67
- # Now that we have an atmosphere and a container for the ocean, we need to populate
68
- # our ocean with initial conditions. To do this, we can use the ECCO2 dataset by
69
- # `set!`ting the model with the `ECCOMetadata`. If no date is specified,
70
- # the fields corresponding to January 1st, 1992 (the first available date in
71
- # ECCO2 dataset) are used.
72
- # This command will download the fields to the local machine.
73
-
74
- set! (ocean. model;
75
- T = ECCOMetadata (:temperature ),
76
- S = ECCOMetadata (:salinity ))
77
-
78
- # The final step is to construct a coupled model.
79
- # The coupled model requires an ocean, which we have just constructed and initialized,
80
- # an atmosphere, which we have downloaded from the JRA55 dataset, a sea ice model
81
- # (in this case we do not account for sea ice by defining `sea_ice = nothing`),
82
- # and a radiation model. The default radiation model assumes two spectral bands:
83
- # a shortwave band modeling visible and UV light, and a longwave band that accounts for
84
- # near, mid and far infrared (mostly far infrared given the low emission temperature).
85
- # By constructing the coupled model, the `update_state!` function, which calculates the fluxes,
86
- # will be triggered.
87
-
88
- radiation = Radiation ()
89
- sea_ice = nothing
90
- coupled_model = OceanSeaIceModel (ocean, sea_ice; atmosphere, radiation)
49
+
50
+ atmosphere = JRA55_prescribed_atmosphere (1 : 2 ; backend = InMemory ())
51
+ ocean = ocean_simulation (grid)
52
+
53
+ # Now that we have an atmosphere and ocean, we `set!` the ocean temperature and salinity
54
+ # to the ECCO2 data by first creating T, S metadata objects,
55
+
56
+ T_metadata = ECCOMetadata (:temperature )
57
+ S_metadata = ECCOMetadata (:salinity )
58
+
59
+ # Note that if a date is not provided to `ECCOMetadata`, then the default Jan 1st, 1992 is used.
60
+ # To copy the ECCO state into `ocean.model`, we use `set!`,
61
+
62
+ set! (ocean. model; T= T_metadata, S= S_metadata)
63
+
64
+ # Finally, we construct a coupled model, which will compute fluxes during construction.
65
+ # We omit `sea_ice` so the model is ocean-only, and use the default `Radiation()` that
66
+ # uses the two-band shortwave (visible and UV) + longwave (mid and far infrared)
67
+ # decomposition of the radiation spectrum.
68
+
69
+ coupled_model = OceanSeaIceModel (ocean; atmosphere, radiation= Radiation ())
91
70
92
71
# Now that the surface fluxes are computed, we can extract and visualize them.
93
72
# The turbulent fluxes are stored in `coupled_model.fluxes.turbulent`.
94
- #
95
- # Qs = coupled_model.fluxes.turbulent.fields.sensible_heat : the sensible heat flux (in Wm⁻²)
96
- # Ql = coupled_model.fluxes.turbulent.fields.latent_heat : the latent heat flux (in Wm⁻²)
97
- # τx = coupled_model.fluxes.turbulent.fields.x_momentum : the zonal wind stress (in Nm)
98
- # τy = coupled_model.fluxes.turbulent.fields.y_momentum : the meridional wind stress (in Nm)
99
- # Mv = coupled_model.fluxes.turbulent.fields.water_vapor : evaporation (in kg m⁻²s⁻¹)
100
- #
101
- # They are 2D fields (3D data structures with one point in the vertical). To extract the data, we use the
102
- # `interior` functionality from Oceananigans.
103
-
104
- turbulent_fluxes = coupled_model. fluxes. turbulent. fields
105
73
106
- Qs = interior (turbulent_fluxes. sensible_heat, :, :, 1 )
107
- Ql = interior (turbulent_fluxes. latent_heat, :, :, 1 )
108
- τx = interior (turbulent_fluxes. x_momentum, :, :, 1 )
109
- τy = interior (turbulent_fluxes. y_momentum, :, :, 1 )
110
- Mv = interior (turbulent_fluxes. water_vapor, :, :, 1 )
111
- nothing # hide
74
+ fluxes = coupled_model. fluxes. turbulent. fields
112
75
113
76
fig = Figure (size = (800 , 400 ))
114
- ax = Axis (fig[1 , 1 ], title = " Sensible heat flux (Wm⁻²)" )
115
- hm = heatmap! (ax, Qs; colormap = :bwr )
116
- hidedecorations! (ax)
117
- save (" sensible_heat_flux.png" , fig)
118
- nothing # hide
119
- # 
120
77
121
- fig = Figure (size = (800 , 400 ))
122
- ax = Axis (fig[1 , 2 ], title = " Latent heat flux (Wm⁻²)" )
123
- heatmap! (ax, Ql; colormap = :bwr )
124
- hidedecorations! (ax)
125
- save (" latent_heat_flux.png" , fig)
126
- nothing # hide
127
- # 
78
+ ax = Axis (fig[1 , 1 ], title = " Sensible heat flux (W m⁻²)" )
79
+ heatmap! (ax, fluxes. sensible_heat; colormap = :bwr )
128
80
129
- fig = Figure (size = (800 , 400 ))
130
- ax = Axis (fig[2 , 1 ], title = " Zonal wind stress (Nm)" )
131
- heatmap! (ax, τx; colormap = :bwr )
132
- hidedecorations! (ax)
133
- save (" zonal_wind_stress.png" , fig)
134
- nothing # hide
135
- # 
81
+ ax = Axis (fig[1 , 2 ], title = " Latent heat flux (W m⁻²)" )
82
+ heatmap! (ax, fluxes. latent_heat; colormap = :bwr )
136
83
137
- fig = Figure (size = (800 , 400 ))
138
- ax = Axis (fig[2 , 2 ], title = " Meridional wind stress (Nm)" )
139
- heatmap! (ax, τy; colormap = :bwr )
140
- hidedecorations! (ax)
141
- save (" meridional_wind_stress.png" , fig)
142
- nothing # hide
143
- # 
84
+ ax = Axis (fig[2 , 1 ], title = " Zonal wind stress (N m)" )
85
+ heatmap! (ax, fluxes. x_momentum; colormap = :bwr )
144
86
145
- fig = Figure (size = (800 , 400 ))
146
- ax = Axis (fig[3 , 1 ], title = " Water vapor flux (kg m⁻²s⁻¹)" )
87
+ ax = Axis (fig[2 , 2 ], title = " Meridional wind stress (N m)" )
88
+ heatmap! (ax, fluxes. y_momentum; colormap = :bwr )
89
+
90
+ ax = Axis (fig[3 , 1 ], title = " Water vapor flux (kg m⁻² s⁻¹)" )
147
91
heatmap! (ax, Mv; colormap = :bwr )
148
- hidedecorations! (ax)
149
- save (" water_vapor_flux.png" , fig)
150
- nothing # hide
151
- # 
92
+
93
+ save (" fluxes.png" , fig)
94
+ # 
152
95
0 commit comments