Skip to content

Commit 59f1c95

Browse files
feat: model_interpolate for QTY_TEMPERATURE
fixes #773 untested, also need to check with fortran standard has elemental.
1 parent bddda57 commit 59f1c95

File tree

1 file changed

+129
-18
lines changed

1 file changed

+129
-18
lines changed

models/MOM6/model_mod.f90

Lines changed: 129 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ module model_mod
4949

5050
use obs_kind_mod, only : get_index_for_quantity, QTY_U_CURRENT_COMPONENT, &
5151
QTY_V_CURRENT_COMPONENT, QTY_LAYER_THICKNESS, &
52-
QTY_DRY_LAND, QTY_SALINITY
52+
QTY_DRY_LAND, QTY_SALINITY, QTY_TEMPERATURE, &
53+
QTY_POTENTIAL_TEMPERATURE
5354

5455
use ensemble_manager_mod, only : ensemble_type
5556

@@ -220,25 +221,27 @@ end function get_model_size
220221
! 0 unless there is some problem in computing the interpolation in
221222
! which case a positive istatus should be returned.
222223

223-
subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs, istatus)
224+
subroutine model_interpolate(state_handle, ens_size, location, qty_in, expected_obs, istatus)
224225

225226

226227
type(ensemble_type), intent(in) :: state_handle
227228
integer, intent(in) :: ens_size
228229
type(location_type), intent(in) :: location
229-
integer, intent(in) :: qty
230+
integer, intent(in) :: qty_in
230231
real(r8), intent(out) :: expected_obs(ens_size) !< array of interpolated values
231232
integer, intent(out) :: istatus(ens_size)
232233

234+
integer :: qty ! local qty
233235
integer :: which_vert, four_ilons(4), four_ilats(4), lev(ens_size,2)
234236
integer :: locate_status, quad_status
235237
real(r8) :: lev_fract(ens_size)
236238
real(r8) :: lon_lat_vert(3)
237239
real(r8) :: quad_vals(4, ens_size)
238240
real(r8) :: expected(ens_size, 2) ! level below and above obs
241+
real(r8) :: expected_pot_temp(ens_size), expected_salinity(ens_size), pressure_dbars(ens_size)
239242
type(quad_interp_handle) :: interp
240243
integer :: varid, i, e, thick_id
241-
integer(i8) :: th_indx, indx(ens_size)
244+
integer(i8) :: th_indx
242245
real(r8) :: depth_at_x(ens_size), thick_at_x(ens_size) ! depth, layer thickness at obs lat lon
243246
logical :: found(ens_size)
244247

@@ -247,6 +250,16 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
247250
expected_obs(:) = MISSING_R8
248251
istatus(:) = 1
249252

253+
if (qty_in == QTY_TEMPERATURE) then
254+
qty = QTY_POTENTIAL_TEMPERATURE ! model has potential temperature
255+
if (get_varid_from_kind(dom_id, QTY_SALINITY) < 0) then ! Require salinity to convert to temperature
256+
istatus = NOT_IN_STATE
257+
return
258+
end if
259+
else
260+
qty = qty_in
261+
endif
262+
250263
varid = get_varid_from_kind(dom_id, qty)
251264
if (varid < 0) then ! not in state
252265
istatus = NOT_IN_STATE
@@ -338,6 +351,59 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
338351
return
339352
endif
340353

354+
355+
select case (qty)
356+
case (QTY_TEMPERATURE)
357+
! convert from potential temperature to temperature
358+
359+
call state_on_quad(four_ilons, four_ilats, lon_lat_vert, ens_size, lev, lev_fract, interp, state_handle, varid, expected_pot_temp, quad_status)
360+
if (quad_status /= 0) then
361+
istatus(:) = QUAD_EVALUTATE_FAILED
362+
return
363+
endif
364+
call state_on_quad(four_ilons, four_ilats, lon_lat_vert, ens_size, lev, lev_fract, interp, state_handle, get_varid_from_kind(dom_id, QTY_SALINITY), expected_salinity, quad_status)
365+
if (quad_status /= 0) then
366+
istatus(:) = QUAD_EVALUTATE_FAILED
367+
return
368+
endif
369+
370+
pressure_dbars = 0.059808_r8*(exp(-0.025_r8*depth_at_x) - 1.0_r8) &
371+
+ 0.100766_r8*depth_at_x + 2.28405e-7_r8*depth_at_x**2
372+
expected_obs = sensible_temp(expected_pot_temp, expected_salinity, pressure_dbars)
373+
374+
case (QTY_SALINITY) ! convert from PSU (model) to MSU (obersvation)
375+
call state_on_quad(four_ilons, four_ilats, lon_lat_vert, ens_size, lev, lev_fract, interp, state_handle, varid, expected_obs, quad_status)
376+
if (quad_status /= 0) istatus(:) = QUAD_EVALUTATE_FAILED
377+
expected_obs = expected_obs/1000.0_r8
378+
379+
case default
380+
call state_on_quad(four_ilons, four_ilats, lon_lat_vert, ens_size, lev, lev_fract, interp, state_handle, varid, expected_obs, quad_status)
381+
if (quad_status /= 0) istatus(:) = QUAD_EVALUTATE_FAILED
382+
383+
end select
384+
385+
end subroutine model_interpolate
386+
387+
!------------------------------------------------------------------
388+
! Interpolate on the quad, between two levels
389+
subroutine state_on_quad(four_ilons, four_ilats, lon_lat_vert, ens_size, lev, lev_fract, interp, state_handle, varid, expected_obs, quad_status)
390+
391+
integer, intent(in) :: four_ilons(4), four_ilats(4) ! indices into lon, lat
392+
real(r8), intent(in) :: lon_lat_vert(3) ! lon, lat, vert of obs
393+
integer, intent(in) :: ens_size
394+
integer, intent(in) :: lev(ens_size,2) ! levels below and above obs
395+
real(r8), intent(in) :: lev_fract(ens_size)
396+
type(quad_interp_handle), intent(in) :: interp
397+
type(ensemble_type), intent(in) :: state_handle
398+
integer, intent(in) :: varid ! which state variable
399+
real(r8), intent(out) :: expected_obs(ens_size)
400+
integer, intent(out) :: quad_status
401+
402+
integer :: i, e
403+
integer(i8) :: indx(ens_size)
404+
real(r8) :: quad_vals(4, ens_size)
405+
real(r8) :: expected(ens_size, 2) ! state value at level below and above obs
406+
341407
do i = 1, 2
342408
!HK which corner of the quad is which?
343409
! corner1
@@ -371,27 +437,15 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
371437
quad_vals, & ! 4 corners x ens_size
372438
expected(:,i), &
373439
quad_status)
374-
if (quad_status /= 0) then
375-
istatus(:) = QUAD_EVALUTATE_FAILED
376-
return
377-
else
378-
istatus = 0
379-
endif
440+
if (quad_status /= 0) return
380441

381442
enddo
382443

383444
! Interpolate between levels
384445
! expected_obs = bot_val + lev_fract * (top_val - bot_val)
385446
expected_obs = expected(:,1) + lev_fract(:) * (expected(:,2) - expected(:,1))
386447

387-
if (qty == QTY_SALINITY) then ! convert from PSU (model) to MSU (obersvation)
388-
expected_obs = expected_obs/1000.0_r8
389-
endif
390-
391-
392-
end subroutine model_interpolate
393-
394-
448+
end subroutine state_on_quad
395449

396450
!------------------------------------------------------------------
397451
! Returns the smallest increment in time that the model is capable
@@ -897,6 +951,63 @@ function get_interp_handle(qty)
897951

898952
end function
899953

954+
!------------------------------------------------------------
955+
! calculate sensible (in-situ) temperature from
956+
! local pressure, salinity, and potential temperature
957+
elemental function sensible_temp(potemp, s, lpres)
958+
959+
real(r8), intent(in) :: potemp ! potential temperature in C
960+
real(r8), intent(in) :: s ! salinity Practical Salinity Scale 1978 (PSS-78)
961+
real(r8), intent(in) :: lpres ! pressure in decibars
962+
real(r8) :: sensible_temp ! in-situ (sensible) temperature (C)
963+
964+
integer :: i,j,n
965+
real(r8) :: dp,p,q,r1,r2,r3,r4,r5,s1,t,x
966+
967+
s1 = s - 35.0_r8
968+
p = 0.0_r8
969+
t = potemp
970+
971+
dp = lpres - p
972+
n = int (abs(dp)/1000.0_r8) + 1
973+
dp = dp/n
974+
975+
do i=1,n
976+
do j=1,4
977+
978+
r1 = ((-2.1687e-16_r8 * t + 1.8676e-14_r8) * t - 4.6206e-13_r8) * p
979+
r2 = (2.7759e-12_r8*t - 1.1351e-10_r8) * s1
980+
r3 = ((-5.4481e-14_r8 * t + 8.733e-12_r8) * t - 6.7795e-10_r8) * t
981+
r4 = (r1 + (r2 + r3 + 1.8741e-8_r8)) * p + (-4.2393e-8_r8 * t+1.8932e-6_r8) * s1
982+
r5 = r4 + ((6.6228e-10_r8 * t-6.836e-8_r8) * t + 8.5258e-6_r8) * t + 3.5803e-5_r8
983+
984+
x = dp*r5
985+
986+
if (j == 1) then
987+
t = t + 0.5_r8 * x
988+
q = x
989+
p = p + 0.5_r8 * dp
990+
991+
else if (j == 2) then
992+
t = t + 0.29298322_r8 * (x-q)
993+
q = 0.58578644_r8 * x + 0.121320344_r8 * q
994+
995+
else if (j == 3) then
996+
t = t + 1.707106781_r8 * (x-q)
997+
q = 3.414213562_r8*x - 4.121320344_r8*q
998+
p = p + 0.5_r8*dp
999+
1000+
else ! j must == 4
1001+
t = t + (x - 2.0_r8 * q) / 6.0_r8
1002+
1003+
endif
1004+
1005+
enddo ! j loop
1006+
enddo ! i loop
1007+
1008+
sensible_temp = t
1009+
1010+
end function sensible_temp
9001011

9011012
!------------------------------------------------------------------
9021013
! Verify that the namelist was filled in correctly, and check

0 commit comments

Comments
 (0)