Skip to content

Commit a612e81

Browse files
feat: model_interpolate for QTY_TEMPERATURE
fixes #773 Converts potential_temp (model) to in-situ temp (obs) Following method in POP model_mod: #773 (comment) Uses element function - need to check with fortran standard has elemental.
1 parent bddda57 commit a612e81

File tree

1 file changed

+136
-18
lines changed

1 file changed

+136
-18
lines changed

models/MOM6/model_mod.f90

+136-18
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,66 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
338351
return
339352
endif
340353

354+
355+
select case (qty_in)
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*lon_lat_vert(3)**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) then
377+
istatus(:) = QUAD_EVALUTATE_FAILED
378+
return
379+
endif
380+
expected_obs = expected_obs/1000.0_r8
381+
382+
case default
383+
call state_on_quad(four_ilons, four_ilats, lon_lat_vert, ens_size, lev, lev_fract, interp, state_handle, varid, expected_obs, quad_status)
384+
if (quad_status /= 0) then
385+
istatus(:) = QUAD_EVALUTATE_FAILED
386+
return
387+
endif
388+
end select
389+
390+
istatus(:) = 0
391+
392+
end subroutine model_interpolate
393+
394+
!------------------------------------------------------------------
395+
! Interpolate on the quad, between two levels
396+
subroutine state_on_quad(four_ilons, four_ilats, lon_lat_vert, ens_size, lev, lev_fract, interp, state_handle, varid, expected_obs, quad_status)
397+
398+
integer, intent(in) :: four_ilons(4), four_ilats(4) ! indices into lon, lat
399+
real(r8), intent(in) :: lon_lat_vert(3) ! lon, lat, vert of obs
400+
integer, intent(in) :: ens_size
401+
integer, intent(in) :: lev(ens_size,2) ! levels below and above obs
402+
real(r8), intent(in) :: lev_fract(ens_size)
403+
type(quad_interp_handle), intent(in) :: interp
404+
type(ensemble_type), intent(in) :: state_handle
405+
integer, intent(in) :: varid ! which state variable
406+
real(r8), intent(out) :: expected_obs(ens_size)
407+
integer, intent(out) :: quad_status
408+
409+
integer :: i, e
410+
integer(i8) :: indx(ens_size)
411+
real(r8) :: quad_vals(4, ens_size)
412+
real(r8) :: expected(ens_size, 2) ! state value at level below and above obs
413+
341414
do i = 1, 2
342415
!HK which corner of the quad is which?
343416
! corner1
@@ -371,27 +444,15 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
371444
quad_vals, & ! 4 corners x ens_size
372445
expected(:,i), &
373446
quad_status)
374-
if (quad_status /= 0) then
375-
istatus(:) = QUAD_EVALUTATE_FAILED
376-
return
377-
else
378-
istatus = 0
379-
endif
447+
if (quad_status /= 0) return
380448

381449
enddo
382450

383451
! Interpolate between levels
384452
! expected_obs = bot_val + lev_fract * (top_val - bot_val)
385453
expected_obs = expected(:,1) + lev_fract(:) * (expected(:,2) - expected(:,1))
386454

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-
455+
end subroutine state_on_quad
395456

396457
!------------------------------------------------------------------
397458
! Returns the smallest increment in time that the model is capable
@@ -897,6 +958,63 @@ function get_interp_handle(qty)
897958

898959
end function
899960

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

9011019
!------------------------------------------------------------------
9021020
! Verify that the namelist was filled in correctly, and check

0 commit comments

Comments
 (0)