MOM6
ocn_cap_methods.F90
Go to the documentation of this file.
2 
3  use esmf, only: esmf_clock, esmf_time, esmf_clockget, esmf_timeget
6  use mom_grid, only: ocean_grid_type
7  use mom_domains, only: pass_var
9  use mpp_domains_mod, only: mpp_get_compute_domain
11 
12  implicit none
13  private
14 
15  public :: ocn_import
16  public :: ocn_export
17 
18  logical, parameter :: debug=.false.
19 
20 !=======================================================================
21 contains
22 !=======================================================================
23 
24 !> Maps incomping ocean data to MOM6 data structures
25 subroutine ocn_import(x2o, ind, grid, ice_ocean_boundary, ocean_public, logunit, Eclock, c1, c2, c3, c4)
26  real(kind=8) , intent(in) :: x2o(:,:) !< incoming data
27  type(cpl_indices_type) , intent(in) :: ind !< Structure with MCT attribute vects and indices
28  type(ocean_grid_type) , intent(in) :: grid !< Ocean model grid
29  type(ice_ocean_boundary_type) , intent(inout) :: ice_ocean_boundary !< Ocean boundary forcing
30  type(ocean_public_type) , intent(in) :: ocean_public !< Ocean surface state
31  integer , intent(in) :: logunit !< Unit for stdout output
32  type(esmf_clock) , intent(in) :: eclock !< Time and time step ? \todo Why must this
33  real(kind=8), optional , intent(in) :: c1, c2, c3, c4 !< Coeffs. used in the shortwave decomposition
34 
35  ! Local variables
36  integer :: i, j, isc, iec, jsc, jec ! Grid indices
37  integer :: k
38  integer :: day, secs, rc
39  type(esmf_time) :: currtime
40  character(*), parameter :: f01 = "('(ocn_import) ',a,4(i6,2x),d21.14)"
41  !-----------------------------------------------------------------------
42 
43  isc = grid%isc; iec = grid%iec ; jsc = grid%jsc; jec = grid%jec
44 
45  k = 0
46  do j = jsc, jec
47  do i = isc, iec
48  k = k + 1 ! Increment position within gindex
49 
50  ! rotate taux and tauy from true zonal/meridional to local coordinates
51  ! taux
52  ice_ocean_boundary%u_flux(i,j) = grid%cos_rot(i,j) * x2o(ind%x2o_Foxx_taux,k) &
53  - grid%sin_rot(i,j) * x2o(ind%x2o_Foxx_tauy,k)
54 
55  ! tauy
56  ice_ocean_boundary%v_flux(i,j) = grid%cos_rot(i,j) * x2o(ind%x2o_Foxx_tauy,k) &
57  + grid%sin_rot(i,j) * x2o(ind%x2o_Foxx_taux,k)
58 
59  ! liquid precipitation (rain)
60  ice_ocean_boundary%lprec(i,j) = x2o(ind%x2o_Faxa_rain,k)
61 
62  ! frozen precipitation (snow)
63  ice_ocean_boundary%fprec(i,j) = x2o(ind%x2o_Faxa_snow,k)
64 
65  ! longwave radiation, sum up and down (W/m2)
66  ice_ocean_boundary%lw_flux(i,j) = (x2o(ind%x2o_Faxa_lwdn,k) + x2o(ind%x2o_Foxx_lwup,k))
67 
68  ! specific humitidy flux
69  ice_ocean_boundary%q_flux(i,j) = x2o(ind%x2o_Foxx_evap,k)
70 
71  ! sensible heat flux (W/m2)
72  ice_ocean_boundary%t_flux(i,j) = x2o(ind%x2o_Foxx_sen,k)
73 
74  ! snow&ice melt heat flux (W/m^2)
75  ice_ocean_boundary%seaice_melt_heat(i,j) = x2o(ind%x2o_Fioi_melth,k)
76 
77  ! water flux from snow&ice melt (kg/m2/s)
78  ice_ocean_boundary%seaice_melt(i,j) = x2o(ind%x2o_Fioi_meltw,k)
79 
80  ! liquid runoff
81  ice_ocean_boundary%rofl_flux(i,j) = x2o(ind%x2o_Foxx_rofl,k) * grid%mask2dT(i,j)
82 
83  ! ice runoff
84  ice_ocean_boundary%rofi_flux(i,j) = x2o(ind%x2o_Foxx_rofi,k) * grid%mask2dT(i,j)
85 
86  ! surface pressure
87  ice_ocean_boundary%p(i,j) = x2o(ind%x2o_Sa_pslv,k) * grid%mask2dT(i,j)
88 
89  ! salt flux
90  ice_ocean_boundary%salt_flux(i,j) = x2o(ind%x2o_Fioi_salt,k) * grid%mask2dT(i,j)
91 
92  ! 1) visible, direct shortwave (W/m2)
93  ! 2) visible, diffuse shortwave (W/m2)
94  ! 3) near-IR, direct shortwave (W/m2)
95  ! 4) near-IR, diffuse shortwave (W/m2)
96  if (present(c1) .and. present(c2) .and. present(c3) .and. present(c4)) then
97  ! Use runtime coefficients to decompose net short-wave heat flux into 4 components
98  ice_ocean_boundary%sw_flux_vis_dir(i,j) = x2o(ind%x2o_Foxx_swnet,k) * c1 * grid%mask2dT(i,j)
99  ice_ocean_boundary%sw_flux_vis_dif(i,j) = x2o(ind%x2o_Foxx_swnet,k) * c2 * grid%mask2dT(i,j)
100  ice_ocean_boundary%sw_flux_nir_dir(i,j) = x2o(ind%x2o_Foxx_swnet,k) * c3 * grid%mask2dT(i,j)
101  ice_ocean_boundary%sw_flux_nir_dif(i,j) = x2o(ind%x2o_Foxx_swnet,k) * c4 * grid%mask2dT(i,j)
102  else
103  ice_ocean_boundary%sw_flux_vis_dir(i,j) = x2o(ind%x2o_Faxa_swvdr,k) * grid%mask2dT(i,j)
104  ice_ocean_boundary%sw_flux_vis_dif(i,j) = x2o(ind%x2o_Faxa_swvdf,k) * grid%mask2dT(i,j)
105  ice_ocean_boundary%sw_flux_nir_dir(i,j) = x2o(ind%x2o_Faxa_swndr,k) * grid%mask2dT(i,j)
106  ice_ocean_boundary%sw_flux_nir_dif(i,j) = x2o(ind%x2o_Faxa_swndf,k) * grid%mask2dT(i,j)
107  endif
108  enddo
109  enddo
110 
111  if (debug .and. is_root_pe()) then
112  call esmf_clockget(eclock, currtime=currtime, rc=rc)
113  call esmf_timeget(currtime, d=day, s=secs, rc=rc)
114 
115  do j = grid%jsc, grid%jec
116  do i = grid%isc, grid%iec
117  write(logunit,f01)'import: day, secs, j, i, u_flux = ',day,secs,j,i,ice_ocean_boundary%u_flux(i,j)
118  write(logunit,f01)'import: day, secs, j, i, v_flux = ',day,secs,j,i,ice_ocean_boundary%v_flux(i,j)
119  write(logunit,f01)'import: day, secs, j, i, lprec = ',day,secs,j,i,ice_ocean_boundary%lprec(i,j)
120  write(logunit,f01)'import: day, secs, j, i, lwrad = ',day,secs,j,i,ice_ocean_boundary%lw_flux(i,j)
121  write(logunit,f01)'import: day, secs, j, i, q_flux = ',day,secs,j,i,ice_ocean_boundary%q_flux(i,j)
122  write(logunit,f01)'import: day, secs, j, i, t_flux = ',day,secs,j,i,ice_ocean_boundary%t_flux(i,j)
123  write(logunit,f01)'import: day, secs, j, i, seaice_melt_heat = ',&
124  day,secs,j,i,ice_ocean_boundary%seaice_melt_heat(i,j)
125  write(logunit,f01)'import: day, secs, j, i, seaice_melt = ',&
126  day,secs,j,i,ice_ocean_boundary%seaice_melt(i,j)
127  write(logunit,f01)'import: day, secs, j, i, runoff = ',&
128  day,secs,j,i,ice_ocean_boundary%rofl_flux(i,j) + ice_ocean_boundary%rofi_flux(i,j)
129  write(logunit,f01)'import: day, secs, j, i, psurf = ',&
130  day,secs,j,i,ice_ocean_boundary%p(i,j)
131  write(logunit,f01)'import: day, secs, j, i, salt_flux = ',&
132  day,secs,j,i,ice_ocean_boundary%salt_flux(i,j)
133  write(logunit,f01)'import: day, secs, j, i, sw_flux_vis_dir = ',&
134  day,secs,j,i,ice_ocean_boundary%sw_flux_vis_dir(i,j)
135  write(logunit,f01)'import: day, secs, j, i, sw_flux_vis_dif = ',&
136  day,secs,j,i,ice_ocean_boundary%sw_flux_vis_dif(i,j)
137  write(logunit,f01)'import: day, secs, j, i, sw_flux_nir_dir = ',&
138  day,secs,j,i,ice_ocean_boundary%sw_flux_nir_dir(i,j)
139  write(logunit,f01)'import: day, secs, j, i, sw_flux_nir_dif = ',&
140  day,secs,j,i,ice_ocean_boundary%sw_flux_nir_dir(i,j)
141  enddo
142  enddo
143  endif
144 
145 end subroutine ocn_import
146 
147 !=======================================================================
148 
149 !> Maps outgoing ocean data to MCT attribute vector real array
150 subroutine ocn_export(ind, ocn_public, grid, o2x, dt_int, ncouple_per_day)
151  type(cpl_indices_type), intent(inout) :: ind !< Structure with coupler indices and vectors
152  type(ocean_public_type), intent(in) :: ocn_public !< Ocean surface state
153  type(ocean_grid_type), intent(in) :: grid !< Ocean model grid
154  real(kind=8), intent(inout) :: o2x(:,:) !< MCT outgoing bugger
155  real(kind=8), intent(in) :: dt_int !< Amount of time over which to advance the
156  !! ocean (ocean_coupling_time_step), in sec
157  integer, intent(in) :: ncouple_per_day !< Number of ocean coupling calls per day
158 
159  ! Local variables
160  real, dimension(grid%isd:grid%ied,grid%jsd:grid%jed) :: ssh !< Local copy of sea_lev with updated halo
161  real, dimension(grid%isd:grid%ied,grid%jsd:grid%jed) :: sshx!< Zonal SSH gradient, local coordinate.
162  real, dimension(grid%isd:grid%ied,grid%jsd:grid%jed) :: sshy!< Meridional SSH gradient, local coordinate.
163  integer :: i, j, n, ig, jg !< Grid indices
164  real :: slp_l, slp_r, slp_c, slope, u_min, u_max
165  real :: i_time_int !< The inverse of coupling time interval [s-1].
166 
167  !-----------------------------------------------------------------------
168 
169  ! Use Adcroft's rule of reciprocals; it does the right thing here.
170  i_time_int = 0.0 ; if (dt_int > 0.0) i_time_int = 1.0 / dt_int
171 
172  ! Copy from ocn_public to o2x. ocn_public uses global indexing with no halos.
173  ! The mask comes from "grid" that uses the usual MOM domain that has halos
174  ! and does not use global indexing.
175 
176  n = 0
177  do j=grid%jsc, grid%jec
178  jg = j + grid%jdg_offset
179  do i=grid%isc,grid%iec
180  n = n+1
181  ig = i + grid%idg_offset
182  ! surface temperature in Kelvin
183  o2x(ind%o2x_So_t, n) = ocn_public%t_surf(ig,jg) * grid%mask2dT(i,j)
184  o2x(ind%o2x_So_s, n) = ocn_public%s_surf(ig,jg) * grid%mask2dT(i,j)
185  ! rotate ocn current from local tripolar grid to true zonal/meridional (inverse transformation)
186  o2x(ind%o2x_So_u, n) = (grid%cos_rot(i,j) * ocn_public%u_surf(ig,jg) + &
187  grid%sin_rot(i,j) * ocn_public%v_surf(ig,jg)) * grid%mask2dT(i,j)
188  o2x(ind%o2x_So_v, n) = (grid%cos_rot(i,j) * ocn_public%v_surf(ig,jg) - &
189  grid%sin_rot(i,j) * ocn_public%u_surf(ig,jg)) * grid%mask2dT(i,j)
190 
191  ! boundary layer depth (m)
192  o2x(ind%o2x_So_bldepth, n) = ocn_public%OBLD(ig,jg) * grid%mask2dT(i,j)
193  ! ocean melt and freeze potential (o2x_Fioo_q), W m-2
194  if (ocn_public%frazil(ig,jg) > 0.0) then
195  ! Frazil: change from J/m^2 to W/m^2
196  o2x(ind%o2x_Fioo_q, n) = ocn_public%frazil(ig,jg) * grid%mask2dT(i,j) * i_time_int
197  else
198  ! Melt_potential: change from J/m^2 to W/m^2
199  o2x(ind%o2x_Fioo_q, n) = -ocn_public%melt_potential(ig,jg) * grid%mask2dT(i,j) * i_time_int !* ncouple_per_day
200  ! make sure Melt_potential is always <= 0
201  if (o2x(ind%o2x_Fioo_q, n) > 0.0) o2x(ind%o2x_Fioo_q, n) = 0.0
202  endif
203  ! Make a copy of ssh in order to do a halo update. We use the usual MOM domain
204  ! in order to update halos. i.e. does not use global indexing.
205  ssh(i,j) = ocn_public%sea_lev(ig,jg)
206  enddo
207  enddo
208 
209  ! Update halo of ssh so we can calculate gradients
210  call pass_var(ssh, grid%domain)
211 
212  ! d/dx ssh
213  do j=grid%jsc, grid%jec ; do i=grid%isc,grid%iec
214  ! This is a simple second-order difference
215  ! o2x(ind%o2x_So_dhdx, n) = 0.5 * (ssh(i+1,j) - ssh(i-1,j)) * grid%US%m_to_L*grid%IdxT(i,j) * grid%mask2dT(i,j)
216  ! This is a PLM slope which might be less prone to the A-grid null mode
217  slp_l = (ssh(i,j) - ssh(i-1,j)) * grid%mask2dCu(i-1,j)
218  if (grid%mask2dCu(i-1,j)==0.) slp_l = 0.
219  slp_r = (ssh(i+1,j) - ssh(i,j)) * grid%mask2dCu(i,j)
220  if (grid%mask2dCu(i+1,j)==0.) slp_r = 0.
221  slp_c = 0.5 * (slp_l + slp_r)
222  if ( (slp_l * slp_r) > 0.0 ) then
223  ! This limits the slope so that the edge values are bounded by the
224  ! two cell averages spanning the edge.
225  u_min = min( ssh(i-1,j), ssh(i,j), ssh(i+1,j) )
226  u_max = max( ssh(i-1,j), ssh(i,j), ssh(i+1,j) )
227  slope = sign( min( abs(slp_c), 2.*min( ssh(i,j) - u_min, u_max - ssh(i,j) ) ), slp_c )
228  else
229  ! Extrema in the mean values require a PCM reconstruction avoid generating
230  ! larger extreme values.
231  slope = 0.0
232  endif
233  sshx(i,j) = slope * grid%US%m_to_L*grid%IdxT(i,j) * grid%mask2dT(i,j)
234  if (grid%mask2dT(i,j)==0.) sshx(i,j) = 0.0
235  enddo; enddo
236 
237  ! d/dy ssh
238  do j=grid%jsc, grid%jec ; do i=grid%isc,grid%iec
239  ! This is a simple second-order difference
240  ! o2x(ind%o2x_So_dhdy, n) = 0.5 * (ssh(i,j+1) - ssh(i,j-1)) * grid%US%m_to_L*grid%IdyT(i,j) * grid%mask2dT(i,j)
241  ! This is a PLM slope which might be less prone to the A-grid null mode
242  slp_l = ssh(i,j) - ssh(i,j-1) * grid%mask2dCv(i,j-1)
243  if (grid%mask2dCv(i,j-1)==0.) slp_l = 0.
244 
245  slp_r = ssh(i,j+1) - ssh(i,j) * grid%mask2dCv(i,j)
246  if (grid%mask2dCv(i,j+1)==0.) slp_r = 0.
247 
248  slp_c = 0.5 * (slp_l + slp_r)
249  if ((slp_l * slp_r) > 0.0) then
250  ! This limits the slope so that the edge values are bounded by the
251  ! two cell averages spanning the edge.
252  u_min = min( ssh(i,j-1), ssh(i,j), ssh(i,j+1) )
253  u_max = max( ssh(i,j-1), ssh(i,j), ssh(i,j+1) )
254  slope = sign( min( abs(slp_c), 2.*min( ssh(i,j) - u_min, u_max - ssh(i,j) ) ), slp_c )
255  else
256  ! Extrema in the mean values require a PCM reconstruction avoid generating
257  ! larger extreme values.
258  slope = 0.0
259  endif
260  sshy(i,j) = slope * grid%US%m_to_L*grid%IdyT(i,j) * grid%mask2dT(i,j)
261  if (grid%mask2dT(i,j)==0.) sshy(i,j) = 0.0
262  enddo; enddo
263 
264  ! rotate ssh gradients from local coordinates to true zonal/meridional (inverse transformation)
265  n = 0
266  do j=grid%jsc, grid%jec ; do i=grid%isc,grid%iec
267  n = n+1
268  o2x(ind%o2x_So_dhdx, n) = grid%cos_rot(i,j) * sshx(i,j) + grid%sin_rot(i,j) * sshy(i,j)
269  o2x(ind%o2x_So_dhdy, n) = grid%cos_rot(i,j) * sshy(i,j) - grid%sin_rot(i,j) * sshx(i,j)
270  enddo; enddo
271 
272 end subroutine ocn_export
273 
274 end module ocn_cap_methods
ocn_cap_methods::ocn_import
subroutine, public ocn_import(x2o, ind, grid, ice_ocean_boundary, ocean_public, logunit, Eclock, c1, c2, c3, c4)
Maps incomping ocean data to MOM6 data structures.
Definition: ocn_cap_methods.F90:26
mom_domains::pass_var
Do a halo update on an array.
Definition: MOM_domains.F90:49
ocn_cap_methods::ocn_export
subroutine, public ocn_export(ind, ocn_public, grid, o2x, dt_int, ncouple_per_day)
Maps outgoing ocean data to MCT attribute vector real array.
Definition: ocn_cap_methods.F90:151
mom_domains
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
ocn_cap_methods::debug
logical, parameter debug
Definition: ocn_cap_methods.F90:18
ocn_cpl_indices
Definition: ocn_cpl_indices.F90:1
mom_ocean_model_mct::ocean_state_type
The ocean_state_type contains all information about the state of the ocean, with a format that is pri...
Definition: mom_ocean_model_mct.F90:134
ocn_cpl_indices::cpl_indices_type
Structure with indices needed for MCT attribute vectors.
Definition: ocn_cpl_indices.F90:10
mom_grid
Provides the ocean grid type.
Definition: MOM_grid.F90:2
mom_surface_forcing_mct::ice_ocean_boundary_type
Structure corresponding to forcing, but with the elements, units, and conventions that exactly confor...
Definition: mom_surface_forcing_mct.F90:147
mom_error_handler::is_root_pe
logical function, public is_root_pe()
This returns .true. if the current PE is the root PE.
Definition: MOM_error_handler.F90:44
mom_ocean_model_mct::ocean_public_type
This type is used for communication with other components via the FMS coupler. The element names and ...
Definition: mom_ocean_model_mct.F90:88
mom_surface_forcing_mct
Definition: mom_surface_forcing_mct.F90:1
mom_ocean_model_mct
Top-level module for the MOM6 ocean model in coupled mode.
Definition: mom_ocean_model_mct.F90:2
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
ocn_cap_methods
Definition: ocn_cap_methods.F90:1
mom_grid::ocean_grid_type
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26