@@ -49,7 +49,8 @@ module model_mod
49
49
50
50
use obs_kind_mod, only : get_index_for_quantity, QTY_U_CURRENT_COMPONENT, &
51
51
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
53
54
54
55
use ensemble_manager_mod, only : ensemble_type
55
56
@@ -220,25 +221,27 @@ end function get_model_size
220
221
! 0 unless there is some problem in computing the interpolation in
221
222
! which case a positive istatus should be returned.
222
223
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 )
224
225
225
226
226
227
type (ensemble_type), intent (in ) :: state_handle
227
228
integer , intent (in ) :: ens_size
228
229
type (location_type), intent (in ) :: location
229
- integer , intent (in ) :: qty
230
+ integer , intent (in ) :: qty_in
230
231
real (r8 ), intent (out ) :: expected_obs(ens_size) ! < array of interpolated values
231
232
integer , intent (out ) :: istatus(ens_size)
232
233
234
+ integer :: qty ! local qty
233
235
integer :: which_vert, four_ilons(4 ), four_ilats(4 ), lev(ens_size,2 )
234
236
integer :: locate_status, quad_status
235
237
real (r8 ) :: lev_fract(ens_size)
236
238
real (r8 ) :: lon_lat_vert(3 )
237
239
real (r8 ) :: quad_vals(4 , ens_size)
238
240
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)
239
242
type (quad_interp_handle) :: interp
240
243
integer :: varid, i, e, thick_id
241
- integer (i8) :: th_indx, indx(ens_size)
244
+ integer (i8) :: th_indx
242
245
real (r8 ) :: depth_at_x(ens_size), thick_at_x(ens_size) ! depth, layer thickness at obs lat lon
243
246
logical :: found(ens_size)
244
247
@@ -247,6 +250,16 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
247
250
expected_obs(:) = MISSING_R8
248
251
istatus(:) = 1
249
252
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
+
250
263
varid = get_varid_from_kind(dom_id, qty)
251
264
if (varid < 0 ) then ! not in state
252
265
istatus = NOT_IN_STATE
@@ -338,6 +351,66 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
338
351
return
339
352
endif
340
353
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
+
341
414
do i = 1 , 2
342
415
! HK which corner of the quad is which?
343
416
! corner1
@@ -371,27 +444,15 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
371
444
quad_vals, & ! 4 corners x ens_size
372
445
expected(:,i), &
373
446
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
380
448
381
449
enddo
382
450
383
451
! Interpolate between levels
384
452
! expected_obs = bot_val + lev_fract * (top_val - bot_val)
385
453
expected_obs = expected(:,1 ) + lev_fract(:) * (expected(:,2 ) - expected(:,1 ))
386
454
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
395
456
396
457
!- -----------------------------------------------------------------
397
458
! Returns the smallest increment in time that the model is capable
@@ -897,6 +958,63 @@ function get_interp_handle(qty)
897
958
898
959
end function
899
960
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
900
1018
901
1019
!- -----------------------------------------------------------------
902
1020
! Verify that the namelist was filled in correctly, and check
0 commit comments