@@ -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
@@ -113,8 +114,8 @@ module model_mod
113
114
integer , parameter :: NOT_IN_STATE = 12
114
115
integer , parameter :: THICKNESS_NOT_IN_STATE = 13
115
116
integer , parameter :: QUAD_LOCATE_FAILED = 14
116
- integer , parameter :: THICKNESS_QUAD_EVALUTATE_FAILED = 15
117
- integer , parameter :: QUAD_EVALUTATE_FAILED = 16
117
+ integer , parameter :: THICKNESS_QUAD_EVALUATE_FAILED = 15
118
+ integer , parameter :: QUAD_EVALUATE_FAILED = 16
118
119
integer , parameter :: QUAD_ON_LAND = 17
119
120
integer , parameter :: QUAD_ON_BASIN_EDGE = 18
120
121
integer , parameter :: OBS_ABOVE_SURFACE = 20
@@ -220,25 +221,29 @@ 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
+ real (r8 ), parameter :: CONCENTRATION_TO_PPT = 1000.0_r8
235
+
236
+ integer :: qty ! local qty
233
237
integer :: which_vert, four_ilons(4 ), four_ilats(4 ), lev(ens_size,2 )
234
238
integer :: locate_status, quad_status
235
239
real (r8 ) :: lev_fract(ens_size)
236
240
real (r8 ) :: lon_lat_vert(3 )
237
241
real (r8 ) :: quad_vals(4 , ens_size)
238
242
real (r8 ) :: expected(ens_size, 2 ) ! level below and above obs
243
+ real (r8 ) :: expected_pot_temp(ens_size), expected_salinity(ens_size), pressure_dbars(ens_size)
239
244
type (quad_interp_handle) :: interp
240
245
integer :: varid, i, e, thick_id
241
- integer (i8) :: th_indx, indx(ens_size)
246
+ integer (i8) :: th_indx
242
247
real (r8 ) :: depth_at_x(ens_size), thick_at_x(ens_size) ! depth, layer thickness at obs lat lon
243
248
logical :: found(ens_size)
244
249
@@ -247,6 +252,16 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
247
252
expected_obs(:) = MISSING_R8
248
253
istatus(:) = 1
249
254
255
+ if (qty_in == QTY_TEMPERATURE) then
256
+ qty = QTY_POTENTIAL_TEMPERATURE ! model has potential temperature
257
+ if (get_varid_from_kind(dom_id, QTY_SALINITY) < 0 ) then ! Require salinity to convert to temperature
258
+ istatus = NOT_IN_STATE
259
+ return
260
+ end if
261
+ else
262
+ qty = qty_in
263
+ endif
264
+
250
265
varid = get_varid_from_kind(dom_id, qty)
251
266
if (varid < 0 ) then ! not in state
252
267
istatus = NOT_IN_STATE
@@ -310,7 +325,7 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
310
325
thick_at_x, &
311
326
quad_status)
312
327
if (quad_status /= 0 ) then
313
- istatus(:) = THICKNESS_QUAD_EVALUTATE_FAILED
328
+ istatus(:) = THICKNESS_QUAD_EVALUATE_FAILED
314
329
return
315
330
endif
316
331
@@ -338,6 +353,66 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
338
353
return
339
354
endif
340
355
356
+
357
+ select case (qty_in)
358
+ case (QTY_TEMPERATURE)
359
+ ! convert from potential temperature to temperature
360
+
361
+ 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)
362
+ if (quad_status /= 0 ) then
363
+ istatus(:) = QUAD_EVALUATE_FAILED
364
+ return
365
+ endif
366
+ 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)
367
+ if (quad_status /= 0 ) then
368
+ istatus(:) = QUAD_EVALUATE_FAILED
369
+ return
370
+ endif
371
+
372
+ pressure_dbars = 0.059808_r8 * (exp (- 0.025_r8 * depth_at_x) - 1.0_r8 ) &
373
+ + 0.100766_r8 * depth_at_x + 2.28405e-7_r8 * lon_lat_vert(3 )** 2
374
+ expected_obs = sensible_temp(expected_pot_temp, expected_salinity, pressure_dbars)
375
+
376
+ case (QTY_SALINITY) ! convert from g of salt per kg of seawater (model) to kg of salt per kg of seawater (observation)
377
+ call state_on_quad(four_ilons, four_ilats, lon_lat_vert, ens_size, lev, lev_fract, interp, state_handle, varid, expected_obs, quad_status)
378
+ if (quad_status /= 0 ) then
379
+ istatus(:) = QUAD_EVALUATE_FAILED
380
+ return
381
+ endif
382
+ expected_obs = expected_obs/ CONCENTRATION_TO_PPT
383
+
384
+ case default
385
+ call state_on_quad(four_ilons, four_ilats, lon_lat_vert, ens_size, lev, lev_fract, interp, state_handle, varid, expected_obs, quad_status)
386
+ if (quad_status /= 0 ) then
387
+ istatus(:) = QUAD_EVALUATE_FAILED
388
+ return
389
+ endif
390
+ end select
391
+
392
+ istatus(:) = 0
393
+
394
+ end subroutine model_interpolate
395
+
396
+ !- -----------------------------------------------------------------
397
+ ! Interpolate on the quad, between two levels
398
+ subroutine state_on_quad (four_ilons , four_ilats , lon_lat_vert , ens_size , lev , lev_fract , interp , state_handle , varid , expected_obs , quad_status )
399
+
400
+ integer , intent (in ) :: four_ilons(4 ), four_ilats(4 ) ! indices into lon, lat
401
+ real (r8 ), intent (in ) :: lon_lat_vert(3 ) ! lon, lat, vert of obs
402
+ integer , intent (in ) :: ens_size
403
+ integer , intent (in ) :: lev(ens_size,2 ) ! levels below and above obs
404
+ real (r8 ), intent (in ) :: lev_fract(ens_size)
405
+ type (quad_interp_handle), intent (in ) :: interp
406
+ type (ensemble_type), intent (in ) :: state_handle
407
+ integer , intent (in ) :: varid ! which state variable
408
+ real (r8 ), intent (out ) :: expected_obs(ens_size)
409
+ integer , intent (out ) :: quad_status
410
+
411
+ integer :: i, e
412
+ integer (i8) :: indx(ens_size)
413
+ real (r8 ) :: quad_vals(4 , ens_size)
414
+ real (r8 ) :: expected(ens_size, 2 ) ! state value at level below and above obs
415
+
341
416
do i = 1 , 2
342
417
! HK which corner of the quad is which?
343
418
! corner1
@@ -371,27 +446,15 @@ subroutine model_interpolate(state_handle, ens_size, location, qty, expected_obs
371
446
quad_vals, & ! 4 corners x ens_size
372
447
expected(:,i), &
373
448
quad_status)
374
- if (quad_status /= 0 ) then
375
- istatus(:) = QUAD_EVALUTATE_FAILED
376
- return
377
- else
378
- istatus = 0
379
- endif
449
+ if (quad_status /= 0 ) return
380
450
381
451
enddo
382
452
383
453
! Interpolate between levels
384
454
! expected_obs = bot_val + lev_fract * (top_val - bot_val)
385
455
expected_obs = expected(:,1 ) + lev_fract(:) * (expected(:,2 ) - expected(:,1 ))
386
456
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
-
457
+ end subroutine state_on_quad
395
458
396
459
!- -----------------------------------------------------------------
397
460
! Returns the smallest increment in time that the model is capable
@@ -627,28 +690,28 @@ subroutine read_horizontal_grid()
627
690
mask_v(:,:) = .false.
628
691
call nc_get_attribute_from_variable(ncid, ' geolon' , ' _FillValue' , fillval)
629
692
where (geolon == fillval) mask = .true.
630
- where (geolon == fillval) geolon = 72.51
631
- where (geolat == fillval) geolat = 42.56
693
+ where (geolon == fillval) geolon = 72.51_r8
694
+ where (geolat == fillval) geolat = 42.56_r8
632
695
633
696
call nc_get_attribute_from_variable(ncid, ' geolon_u' , ' _FillValue' , fillval)
634
697
where (geolon_u == fillval) mask_u = .true.
635
- where (geolon_u == fillval) geolon_u = 72.51
636
- where (geolat_u == fillval) geolat_u = 42.56
698
+ where (geolon_u == fillval) geolon_u = 72.51_r8
699
+ where (geolat_u == fillval) geolat_u = 42.56_r8
637
700
638
701
call nc_get_attribute_from_variable(ncid, ' geolon_v' , ' _FillValue' , fillval)
639
702
where (geolon_v == fillval) mask_v = .true.
640
- where (geolon_v == fillval) geolon_v = 72.51
641
- where (geolat_v == fillval) geolat_v = 42.56
703
+ where (geolon_v == fillval) geolon_v = 72.51_r8
704
+ where (geolat_v == fillval) geolat_v = 42.56_r8
642
705
643
706
! mom6 example files have longitude > 360 and longitudes < 0
644
707
! DART uses [0,360]
645
- geolon = mod (geolon, 360.0 )
646
- geolon_u = mod (geolon_u, 360.0 )
647
- geolon_v = mod (geolon_v, 360.0 )
708
+ geolon = mod (geolon, 360.0_r8 )
709
+ geolon_u = mod (geolon_u, 360.0_r8 )
710
+ geolon_v = mod (geolon_v, 360.0_r8 )
648
711
649
- where (geolon < 0.0 ) geolon = geolon + 360
650
- where (geolon_u < 0.0 ) geolon_u = geolon_u + 360
651
- where (geolon_v < 0.0 ) geolon_v = geolon_v + 360
712
+ where (geolon < 0.0 ) geolon = geolon + 360.0_r8
713
+ where (geolon_u < 0.0 ) geolon_u = geolon_u + 360.0_r8
714
+ where (geolon_v < 0.0 ) geolon_v = geolon_v + 360.0_r8
652
715
653
716
call nc_close_file(ncid)
654
717
@@ -897,6 +960,63 @@ function get_interp_handle(qty)
897
960
898
961
end function
899
962
963
+ !- -----------------------------------------------------------
964
+ ! calculate sensible (in-situ) temperature from
965
+ ! local pressure, salinity, and potential temperature
966
+ elemental function sensible_temp (potemp , s , lpres )
967
+
968
+ real (r8 ), intent (in ) :: potemp ! potential temperature in C
969
+ real (r8 ), intent (in ) :: s ! salinity Practical Salinity Scale 1978 (PSS-78)
970
+ real (r8 ), intent (in ) :: lpres ! pressure in decibars
971
+ real (r8 ) :: sensible_temp ! in-situ (sensible) temperature (C)
972
+
973
+ integer :: i,j,n
974
+ real (r8 ) :: dp,p,q,r1,r2,r3,r4 ,r5,s1,t,x
975
+
976
+ s1 = s - 35.0_r8
977
+ p = 0.0_r8
978
+ t = potemp
979
+
980
+ dp = lpres - p
981
+ n = int (abs (dp)/ 1000.0_r8 ) + 1
982
+ dp = dp/ n
983
+
984
+ do i= 1 ,n
985
+ do j= 1 ,4
986
+
987
+ r1 = ((- 2.1687e-16_r8 * t + 1.8676e-14_r8 ) * t - 4.6206e-13_r8 ) * p
988
+ r2 = (2.7759e-12_r8 * t - 1.1351e-10_r8 ) * s1
989
+ r3 = ((- 5.4481e-14_r8 * t + 8.733e-12_r8 ) * t - 6.7795e-10_r8 ) * t
990
+ r4 = (r1 + (r2 + r3 + 1.8741e-8_r8 )) * p + (- 4.2393e-8_r8 * t+1.8932e-6_r8 ) * s1
991
+ r5 = r4 + ((6.6228e-10_r8 * t-6.836e-8_r8 ) * t + 8.5258e-6_r8 ) * t + 3.5803e-5_r8
992
+
993
+ x = dp* r5
994
+
995
+ if (j == 1 ) then
996
+ t = t + 0.5_r8 * x
997
+ q = x
998
+ p = p + 0.5_r8 * dp
999
+
1000
+ else if (j == 2 ) then
1001
+ t = t + 0.29298322_r8 * (x- q)
1002
+ q = 0.58578644_r8 * x + 0.121320344_r8 * q
1003
+
1004
+ else if (j == 3 ) then
1005
+ t = t + 1.707106781_r8 * (x- q)
1006
+ q = 3.414213562_r8 * x - 4.121320344_r8 * q
1007
+ p = p + 0.5_r8 * dp
1008
+
1009
+ else ! j must == 4
1010
+ t = t + (x - 2.0_r8 * q) / 6.0_r8
1011
+
1012
+ endif
1013
+
1014
+ enddo ! j loop
1015
+ enddo ! i loop
1016
+
1017
+ sensible_temp = t
1018
+
1019
+ end function sensible_temp
900
1020
901
1021
!- -----------------------------------------------------------------
902
1022
! Verify that the namelist was filled in correctly, and check
0 commit comments