1module gps_mod
2 ! MODULE gps_mod (prefix='gps' category='5. Observation operators')
3 !
4 !:Purpose: Code related to GPS-RO and ground-based GPS observation operators.
5 !
6 use midasMpi_mod
7 use utilities_mod
8 use mathPhysConstants_mod
9 use earthConstants_mod
10 implicit none
11 save
12 private
13
14 ! public types
15 public :: gps_profile, gps_profilezd, gps_diff
16
17 ! public variables
18 public :: gps_numROProfiles, gps_vRO_IndexPrf
19 public :: gps_Level_RO, gps_RO_MAXPRFSIZE, gps_SURFMIN, gps_HSFMIN, gps_HTPMAX, gps_HTPMAXER, gps_BGCKBAND, gps_WGPS
20 public :: gps_roError, gps_roBNorm, gps_roNsigma
21 public :: gps_gravitysrf, gps_gb_maxdata, gps_gb_dzmin
22 public :: gps_gb_ltestop, gps_gb_llblmet, gps_gb_lbevis, gps_gb_irefopt, gps_gb_iztdop, gps_gb_lassmet, gps_gb_l1obs, gps_gb_yzderrwgt, gps_gb_numztd
23 public :: gps_ZTD_Index, gps_ncvmx, gps_gb_dzmax, gps_gb_yztderr, gps_gb_ysferrwgt
24
25 ! public procedures
26 public :: gps_setupro, gps_iprofile_from_index
27 public :: gps_setupgb, gps_iztd_from_index
28 public :: gps_struct1sw, gps_struct1sw_v2, gps_bndopv1, gps_refopv, gps_structztd_v2, gps_ztdopv, gps_pw
29 public :: gps_geopotential
30
31 ! public constants
32 integer, parameter, public :: gps_Level_RO_Bnd = 1
33 integer, parameter, public :: gps_Level_RO_Ref = 2
34 integer, parameter, public :: gps_Level_RO_BndandRef = 3
35 public :: gps_p_md, gps_p_mw, gps_p_wa, gps_p_wb
36
37!modgps00base
38
39 ! 32-bit integers
40 integer, parameter :: i4 = selected_int_kind(9)
41
42 ! Short floats
43 integer, parameter :: sp = selected_real_kind(6)
44
45 ! Long floats
46 integer, parameter :: dp = selected_real_kind(12)
47
48 ! Maximum number of gps levels:
49 integer(i4), parameter :: ngpssize = 100
50
51 ! Maximum number of gps extra fictitious low levels:
52 integer(i4), parameter :: ngpsxlow = 20
53
54 ! Associated maximum number of control variables:
55 integer(i4), parameter :: gps_ncvmx = 4*ngpssize
56
57!modgps01ctphys
58
59 ! Avogadro constant:
60 real(dp), parameter :: p_Avog = 6.02214129e23_dp ! From CODATA
61
62 ! Boltzmann constant:
63 real(dp), parameter :: p_Boltz = 1.3806488e-23_dp ! From CODATA
64
65 ! Air properties (public):
66 real(dp), parameter :: gps_p_md = 28.965516_dp ! From Aparicio(2011)
67 real(dp), parameter :: gps_p_mw = 18.015254_dp ! From Aparicio(2011)
68 real(dp), parameter :: gps_p_wa = gps_p_md/gps_p_mw
69 real(dp), parameter :: gps_p_wb = (gps_p_md-gps_p_mw)/gps_p_mw
70
71 ! Gas constants:
72 real(dp), parameter :: p_R = p_Avog*p_Boltz ! per mol
73 real(dp), parameter :: p_Rd = p_Avog*p_Boltz/(1.e-3_dp*gps_p_md) ! per air mass
74
75!modgps03diff
76
77 type gps_diff
78 real(dp) :: Var
79 real(dp) :: DVar(gps_ncvmx)
80 end type gps_diff
81
82 interface assignment(=)
83 module procedure gpsdiffasfd, gpsdiffasff
84 end interface
85
86 interface operator(+)
87 module procedure gpsdiffsmfd, gpsdiffsmdf, gpsdiffsmfi, gpsdiffsmif, gpsdiffsmff
88 end interface
89
90 interface operator(-)
91 module procedure gpsdiffsbfd, gpsdiffsbdf, gpsdiffsbfi, gpsdiffsbif, gpsdiffsbff
92 end interface
93
94 interface operator(*)
95 module procedure gpsdiffmlfd, gpsdiffmldf, gpsdiffmlfi, gpsdiffmlif, gpsdiffmlff
96 end interface
97
98 interface operator(/)
99 module procedure gpsdiffdvfd, gpsdiffdvdf, gpsdiffdvfi, gpsdiffdvif, gpsdiffdvff
100 end interface
101
102 interface operator(**)
103 module procedure gpsdiffpwfd, gpsdiffpwdf, gpsdiffpwfi, gpsdiffpwif, gpsdiffpwff
104 end interface
105
106 interface sqrt
107 module procedure gpsdiffsqr
108 end interface
109
110 interface exp
111 module procedure gpsdiffexp
112 end interface
113
114 interface log
115 module procedure gpsdifflog
116 end interface
117
118 interface cos
119 module procedure gpsdiffcos
120 end interface
121
122 interface tan
123 module procedure gpsdifftan
124 end interface
125
126 interface acos
127 module procedure gpsdiffacos
128 end interface
129
130 interface atan
131 module procedure gpsdiffatan
132 end interface
133
134 interface erf
135 module procedure gpsdifferf
136 end interface
137
138!modgps04profile
139
140 type gps_profile
141 integer(i4) :: ngpslev
142 real(dp) :: rLat
143 real(dp) :: rLon
144 real(dp) :: rAzm
145 real(dp) :: rMT
146 real(dp) :: Rad
147 real(dp) :: geoid
148 real(dp) :: RadN
149 real(dp) :: RadM
150
151 type(gps_diff) :: P0
152
153 type(gps_diff), dimension(ngpssize) :: pst
154 type(gps_diff), dimension(ngpssize) :: tst
155 type(gps_diff), dimension(ngpssize) :: qst
156 type(gps_diff), dimension(ngpssize) :: rst
157 type(gps_diff), dimension(ngpssize) :: gst
158
159 logical :: bbst
160 type(gps_diff), dimension(ngpssize) :: dst
161 type(gps_diff), dimension(ngpssize+ngpsxlow) :: ast
162 type(gps_diff), dimension(ngpssize+ngpsxlow) :: bst
163 end type gps_profile
164
165!modgps04profilezd
166
167 type gps_profilezd
168 integer(i4) :: ngpslev
169 real(dp) :: rLat
170 real(dp) :: rLon
171 real(dp) :: rMT
172
173 type(gps_diff) :: P0
174
175 type(gps_diff), dimension(ngpssize) :: pst
176 type(gps_diff), dimension(ngpssize) :: tst
177 type(gps_diff), dimension(ngpssize) :: qst
178 type(gps_diff), dimension(ngpssize) :: rst
179 type(gps_diff), dimension(ngpssize) :: gst
180 type(gps_diff), dimension(ngpssize) :: ztd
181 logical :: bpst
182 end type gps_profilezd
183
184!modgpsro_mod
185
186 !
187 ! Values determined by input data:
188 !
189 integer :: gps_numROProfiles
190 integer , allocatable :: gps_vRO_IndexPrf(:,:) ! index for each profile
191
192 ! Public versions of namelist variables
193 INTEGER gps_Level_RO, gps_RO_MAXPRFSIZE
194 REAL*8 gps_SurfMin, gps_HsfMin, gps_HtpMax, gps_BgckBand, gps_HtpMaxEr
195 REAL*8 gps_roNsigma
196 REAL*4 gps_Wgps(0:1023,4)
197 character(len=20) :: gps_roError
198 LOGICAL :: gps_roBNorm, gps_gpsroEotvos
199
200
201!modgpsztd_mod
202
203 integer, parameter :: max_gps_sites = 1200
204 integer, parameter :: gps_gb_maxdata = max_gps_sites*24 ! (max_gps_sites) * (max_num_obs in 6h)
205
206 integer :: gps_gb_numZTD ! number of ZTD data to be assimilated
207 integer , allocatable :: gps_ZTD_Index (:) ! INDEX_HEADER in CMA (ObsSpace) for each ZTD observation
208
209 ! Public versions of namelist variables
210 REAL*8 gps_gb_DZMIN, gps_gb_YZTDERR, gps_gb_YSFERRWGT, gps_gb_YZDERRWGT
211 REAL(8) :: gps_gb_DZMAX = 1000.d0 ! need to give it a default value here in case setup not called
212 INTEGER gps_gb_IREFOPT, gps_gb_IZTDOP
213 LOGICAL gps_gb_LASSMET, gps_gb_LLBLMET, gps_gb_LBEVIS, gps_gb_L1OBS, gps_gb_LTESTOP
214
215contains
216
217!modgps02wgs84grav
218
219 pure function gps_gravitysrf(sLat)
220 !
221 !:Purpose: Normal gravity on ellipsoidal surface
222 !
223 implicit none
224
225 ! Arguments:
226 real(dp), intent(in) :: sLat ! sin(Latitude)
227 ! Result:
228 real(dp) :: gps_gravitysrf ! Normal gravity (m/s2)
229
230 ! Locals:
231 real(dp) :: ks2
232 real(dp) :: e2s
233
234 ks2 = ec_wgs_TNGk * sLat*sLat
235 e2s = 1._dp - ec_wgs_e2 * sLat*sLat
236 gps_gravitysrf = ec_wgs_GammaE * (1._dp + ks2) / sqrt(e2s)
237 end function gps_gravitysrf
238
239 pure function gps_gravityalt(sLat, Altitude)
240 !
241 !:Purpose: Normal gravity above the ellipsoidal surface
242 !
243 implicit none
244
245
246 ! Arguments:
247 real(dp), intent(in) :: sLat ! sin(Latitude)
248 real(dp), intent(in) :: Altitude ! Altitude (m)
249 ! Result:
250 real(dp) :: gps_gravityalt ! Normal gravity (m/s2)
251
252 ! Locals:
253 real(dp) :: C1
254 real(dp) :: C2
255
256 C1 =-2._dp/ec_wgs_a*(1._dp+ec_wgs_f+ec_wgs_m-2*ec_wgs_f*sLat*sLat)
257 C2 = 3._dp/ec_wgs_a**2
258 gps_gravityalt = gps_gravitysrf(sLat)* &
259 (1._dp + C1 * Altitude + C2 * Altitude**2)
260 end function gps_gravityalt
261
262 pure function gps_geopotential(Latitude, Altitude)
263 !
264 !:Purpose: Geopotential energy at a given point.
265 ! Result is based on the WGS84 approximate expression for the
266 ! gravity acceleration as a function of latitude and altitude,
267 ! integrated with the trapezoidal rule.
268 !
269 implicit none
270
271
272 ! Arguments:
273 real(dp), intent(in) :: Latitude ! (rad)
274 real(dp), intent(in) :: Altitude ! (m)
275 ! Result:
276 real(dp) :: gps_geopotential ! Geopotential (m2/s2)
277
278 ! Locals:
279 real(dp) :: dh, sLat
280 integer :: n, i
281 real(dp), allocatable :: hi(:)
282 real(dp), allocatable :: gi(:)
283
284 dh = 500._dp
285 n = 1 + int(Altitude/dh)
286
287 allocate(hi(0:n))
288 allocate(gi(0:n))
289
290 sLat=sin(Latitude)
291
292 do i = 0, n-1
293 hi(i) = i * dh
294 gi(i) = gps_gravityalt(sLat, hi(i))
295 end do
296 hi(n) = Altitude
297 gi(n) = gps_gravityalt(sLat, hi(n))
298
299 gps_geopotential = 0._dp
300 do i = 1, n
301 gps_geopotential = gps_geopotential + 0.5_dp * (gi(i)+gi(i-1)) * (hi(i)-hi(i-1))
302 end do
303
304 deallocate(hi)
305 deallocate(gi)
306 end function gps_geopotential
307
308 subroutine gpsRadii(Latitude, RadN, RadM)
309 implicit none
310
311 ! Arguments:
312 real(dp), intent(in) :: Latitude
313 real(dp), intent(out) :: RadN, RadM
314
315 ! Locals:
316 real(dp) :: sLat, e2s
317
318 sLat = sin(Latitude)
319 e2s = 1._dp - ec_wgs_e2 * sLat * sLat
320 RadN = ec_wgs_a / sqrt(e2s)
321 RadM = ec_wgs_a * (1._dp - ec_wgs_e2) / (e2s*sqrt(e2s))
322 end subroutine gpsRadii
323
324
325!modgps03diff
326 pure subroutine gpsdiffasfd(gd1, d2)
327 implicit none
328
329 ! Arguments:
330 type(gps_diff), intent(out) :: gd1
331 real(dp) , intent(in) :: d2
332
333 gd1%Var = d2
334 gd1%DVar = 0._dp
335 end subroutine gpsdiffasfd
336
337 pure subroutine gpsdiffasff(gd1, gd2)
338 implicit none
339
340 ! Arguments:
341 type(gps_diff), intent(out) :: gd1
342 type(gps_diff), intent(in) :: gd2
343
344 gd1%Var = gd2%Var
345 gd1%DVar = gd2%DVar
346 end subroutine gpsdiffasff
347
348 pure function gpsdiffsmfd(gd1, d2)
349 implicit none
350
351 ! Arguments:
352 type(gps_diff), intent(in) :: gd1
353 real(dp) , intent(in) :: d2
354 ! Result:
355 type(gps_diff) :: gpsdiffsmfd
356
357 gpsdiffsmfd%Var = gd1%Var + d2
358 gpsdiffsmfd%DVar = gd1%DVar
359 end function gpsdiffsmfd
360
361 pure function gpsdiffsmdf(d1, gd2)
362 implicit none
363
364 ! Arguments:
365 real(dp) , intent(in) :: d1
366 type(gps_diff), intent(in) :: gd2
367 ! Result:
368 type(gps_diff) :: gpsdiffsmdf
369
370 gpsdiffsmdf%Var = d1 + gd2%Var
371 gpsdiffsmdf%DVar = gd2%DVar
372 end function gpsdiffsmdf
373
374 pure function gpsdiffsmfi(gd1, i2)
375 implicit none
376
377 ! Arguments:
378 type(gps_diff), intent(in) :: gd1
379 integer(i4) , intent(in) :: i2
380 ! Result:
381 type(gps_diff) :: gpsdiffsmfi
382
383 gpsdiffsmfi%Var = gd1%Var + i2
384 gpsdiffsmfi%DVar = gd1%DVar
385 end function gpsdiffsmfi
386
387 pure function gpsdiffsmif(i1, gd2)
388 implicit none
389
390 ! Arguments:
391 integer(i4) , intent(in) :: i1
392 type(gps_diff), intent(in) :: gd2
393 ! Result:
394 type(gps_diff) :: gpsdiffsmif
395
396 gpsdiffsmif%Var = i1 + gd2%Var
397 gpsdiffsmif%DVar = gd2%DVar
398 end function gpsdiffsmif
399
400 pure function gpsdiffsmff(gd1, gd2)
401 implicit none
402
403 ! Arguments:
404 type(gps_diff), intent(in) :: gd1
405 type(gps_diff), intent(in) :: gd2
406 ! Result:
407 type(gps_diff) :: gpsdiffsmff
408
409 gpsdiffsmff%Var = gd1%Var + gd2%Var
410 gpsdiffsmff%DVar = gd1%DVar + gd2%DVar
411 end function gpsdiffsmff
412
413 pure function gpsdiffsbfd(gd1, d2)
414 implicit none
415
416 ! Arguments:
417 type(gps_diff), intent(in) :: gd1
418 real(dp) , intent(in) :: d2
419 ! Result:
420 type(gps_diff) :: gpsdiffsbfd
421
422 gpsdiffsbfd%Var = gd1%Var - d2
423 gpsdiffsbfd%DVar = gd1%DVar
424 end function gpsdiffsbfd
425
426 pure function gpsdiffsbdf(d1, gd2)
427 implicit none
428
429 ! Arguments:
430 real(dp) , intent(in) :: d1
431 type(gps_diff), intent(in) :: gd2
432 ! Result:
433 type(gps_diff) :: gpsdiffsbdf
434
435 gpsdiffsbdf%Var = d1 - gd2%Var
436 gpsdiffsbdf%DVar = - gd2%DVar
437 end function gpsdiffsbdf
438
439 pure function gpsdiffsbfi(gd1, i2)
440 implicit none
441
442 ! Arguments:
443 type(gps_diff), intent(in) :: gd1
444 integer(i4) , intent(in) :: i2
445 ! Result:
446 type(gps_diff) :: gpsdiffsbfi
447
448 gpsdiffsbfi%Var = gd1%Var - i2
449 gpsdiffsbfi%DVar = gd1%DVar
450 end function gpsdiffsbfi
451
452 pure function gpsdiffsbif(i1, gd2)
453 implicit none
454
455 ! Arguments:
456 integer(i4) , intent(in) :: i1
457 type(gps_diff), intent(in) :: gd2
458 ! Result:
459 type(gps_diff) :: gpsdiffsbif
460
461 gpsdiffsbif%Var = i1 - gd2%Var
462 gpsdiffsbif%DVar = - gd2%DVar
463 end function gpsdiffsbif
464
465 pure function gpsdiffsbff(gd1, gd2)
466 implicit none
467
468 ! Arguments:
469 type(gps_diff), intent(in) :: gd1
470 type(gps_diff), intent(in) :: gd2
471 ! Result:
472 type(gps_diff) :: gpsdiffsbff
473
474 gpsdiffsbff%Var = gd1%Var - gd2%Var
475 gpsdiffsbff%DVar = gd1%DVar - gd2%DVar
476 end function gpsdiffsbff
477
478 pure function gpsdiffmlfd(gd1, d2)
479 implicit none
480
481 ! Arguments:
482 type(gps_diff), intent(in) :: gd1
483 real(dp) , intent(in) :: d2
484 ! Result:
485 type(gps_diff) :: gpsdiffmlfd
486
487 gpsdiffmlfd%Var = d2 * gd1%Var
488 gpsdiffmlfd%DVar = d2 * gd1%DVar
489 end function gpsdiffmlfd
490
491 pure function gpsdiffmldf(d1, gd2)
492 implicit none
493
494 ! Arguments:
495 real(dp) , intent(in) :: d1
496 type(gps_diff), intent(in) :: gd2
497 ! Result:
498 type(gps_diff) :: gpsdiffmldf
499
500 gpsdiffmldf%Var = d1 * gd2%Var
501 gpsdiffmldf%DVar = d1 * gd2%DVar
502 end function gpsdiffmldf
503
504 pure function gpsdiffmlfi(gd1, i2)
505 implicit none
506
507 ! Arguments:
508 type(gps_diff), intent(in) :: gd1
509 integer(i4) , intent(in) :: i2
510 ! Result:
511 type(gps_diff) :: gpsdiffmlfi
512
513 gpsdiffmlfi%Var = i2 * gd1%Var
514 gpsdiffmlfi%DVar = i2 * gd1%DVar
515 end function gpsdiffmlfi
516
517 pure function gpsdiffmlif(i1, gd2)
518 implicit none
519
520 ! Arguments:
521 integer(i4) , intent(in) :: i1
522 type(gps_diff), intent(in) :: gd2
523 ! Result:
524 type(gps_diff) :: gpsdiffmlif
525
526 gpsdiffmlif%Var = i1 * gd2%Var
527 gpsdiffmlif%DVar = i1 * gd2%DVar
528 end function gpsdiffmlif
529
530 pure function gpsdiffmlff(gd1, gd2)
531 implicit none
532
533 ! Arguments:
534 type(gps_diff), intent(in) :: gd1
535 type(gps_diff), intent(in) :: gd2
536 ! Result:
537 type(gps_diff) :: gpsdiffmlff
538
539 gpsdiffmlff%Var = gd1%Var * gd2%Var
540 gpsdiffmlff%DVar = (gd2%Var * gd1%DVar) + (gd1%Var * gd2%DVar)
541 end function gpsdiffmlff
542
543 pure function gpsdiffdvfd(gd1, d2)
544 implicit none
545
546 ! Arguments:
547 type(gps_diff), intent(in) :: gd1
548 real(dp) , intent(in) :: d2
549 ! Result:
550 type(gps_diff) :: gpsdiffdvfd
551
552 gpsdiffdvfd%Var = gd1%Var / d2
553 gpsdiffdvfd%DVar = gd1%DVar / d2
554 end function gpsdiffdvfd
555
556 pure function gpsdiffdvdf(d1, gd2)
557 implicit none
558
559 ! Arguments:
560 real(dp) , intent(in) :: d1
561 type(gps_diff), intent(in) :: gd2
562 ! Result:
563 type(gps_diff) :: gpsdiffdvdf
564
565 gpsdiffdvdf%Var = d1 / gd2%Var
566 gpsdiffdvdf%DVar = (-d1 / gd2%Var**2) * gd2%DVar
567 end function gpsdiffdvdf
568
569 pure function gpsdiffdvfi(gd1, i2)
570 implicit none
571
572 ! Arguments:
573 type(gps_diff), intent(in) :: gd1
574 integer(i4) , intent(in) :: i2
575 ! Result:
576 type(gps_diff) :: gpsdiffdvfi
577
578 gpsdiffdvfi%Var = gd1%Var / i2
579 gpsdiffdvfi%DVar = gd1%DVar / i2
580 end function gpsdiffdvfi
581
582 pure function gpsdiffdvif(i1, gd2)
583 implicit none
584
585 ! Arguments:
586 integer(i4) , intent(in) :: i1
587 type(gps_diff), intent(in) :: gd2
588 ! Result:
589 type(gps_diff) :: gpsdiffdvif
590
591 gpsdiffdvif%Var = i1 / gd2%Var
592 gpsdiffdvif%DVar = (-i1 / gd2%Var**2) * gd2%DVar
593 end function gpsdiffdvif
594
595 pure function gpsdiffdvff(gd1, gd2)
596 implicit none
597
598 ! Arguments:
599 type(gps_diff), intent(in) :: gd1
600 type(gps_diff), intent(in) :: gd2
601 ! Result:
602 type(gps_diff) :: gpsdiffdvff
603
604 ! Locals:
605 real(dp) :: onegd2
606
607 onegd2 = 1._dp / gd2%Var
608 gpsdiffdvff%Var = gd1%Var * onegd2
609 gpsdiffdvff%DVar = onegd2 * gd1%DVar - (gd1%Var*onegd2*onegd2) * gd2%DVar
610 end function gpsdiffdvff
611
612 pure function gpsdiffpwfd(gd1, d2)
613 implicit none
614
615 ! Arguments:
616 type(gps_diff), intent(in) :: gd1
617 real(dp) , intent(in) :: d2
618 ! Result:
619 type(gps_diff) :: gpsdiffpwfd
620
621 gpsdiffpwfd%Var = gd1%Var ** d2
622 gpsdiffpwfd%DVar = (d2*(gd1%Var**(d2-1._dp))) * gd1%DVar
623 end function gpsdiffpwfd
624
625 pure function gpsdiffpwdf(d1, gd2)
626 implicit none
627
628 ! Arguments:
629 real(dp) , intent(in) :: d1
630 type(gps_diff), intent(in) :: gd2
631 ! Result:
632 type(gps_diff) :: gpsdiffpwdf
633
634 gpsdiffpwdf%Var = d1 ** gd2%Var
635 gpsdiffpwdf%DVar = (log(d1)*d1**gd2%Var) * gd2%DVar
636 end function gpsdiffpwdf
637
638 pure function gpsdiffpwfi(gd1, i2)
639 implicit none
640
641 ! Arguments:
642 type(gps_diff), intent(in) :: gd1
643 integer(i4) , intent(in) :: i2
644 ! Result:
645 type(gps_diff) :: gpsdiffpwfi
646
647 gpsdiffpwfi%Var = gd1%Var ** i2
648 gpsdiffpwfi%DVar = (i2*(gd1%Var**(i2-1))) * gd1%DVar
649 end function gpsdiffpwfi
650
651 pure function gpsdiffpwif(i1, gd2)
652 implicit none
653
654 ! Arguments:
655 integer(i4) , intent(in) :: i1
656 type(gps_diff), intent(in) :: gd2
657 ! Result:
658 type(gps_diff) :: gpsdiffpwif
659
660 gpsdiffpwif%Var = i1 ** gd2%Var
661 gpsdiffpwif%DVar = (log(1._dp*i1)*i1**gd2%Var) * gd2%DVar
662 end function gpsdiffpwif
663
664 pure function gpsdiffpwff(gd1, gd2)
665 implicit none
666
667 ! Arguments:
668 type(gps_diff), intent(in) :: gd1
669 type(gps_diff), intent(in) :: gd2
670 ! Result:
671 type(gps_diff) :: gpsdiffpwff
672
673 gpsdiffpwff%Var = gd1%Var ** gd2%Var
674 gpsdiffpwff%DVar = ( gd2%Var * ( gd1%Var**(gd2%Var-1) ) ) * gd1%DVar + &
675 (log(gd1%Var)*(gd1%Var**gd2%Var))*gd2%DVar
676 end function gpsdiffpwff
677
678 pure function gpsdiffsqr(gd1)
679 implicit none
680
681 ! Arguments:
682 type(gps_diff), intent(in) :: gd1
683 ! Result:
684 type(gps_diff) :: gpsdiffsqr
685
686 gpsdiffsqr%Var = sqrt( gd1%Var )
687 gpsdiffsqr%DVar = (0.5_dp / sqrt( gd1%Var )) * gd1%DVar
688 end function gpsdiffsqr
689
690 pure function gpsdiffexp(gd1)
691 implicit none
692
693 ! Arguments:
694 type(gps_diff), intent(in) :: gd1
695 ! Result:
696 type(gps_diff) :: gpsdiffexp
697
698 gpsdiffexp%Var = exp(gd1%Var)
699 gpsdiffexp%DVar = gd1%DVar * exp(gd1%Var)
700 end function gpsdiffexp
701
702 pure function gpsdifflog(gd1)
703 implicit none
704
705 ! Arguments:
706 type(gps_diff), intent(in) :: gd1
707 ! Result:
708 type(gps_diff) :: gpsdifflog
709
710 gpsdifflog%Var = log(gd1%Var)
711 gpsdifflog%DVar = gd1%DVar / gd1%Var
712 end function gpsdifflog
713
714 pure function gpsdiffcos(gd1)
715 implicit none
716
717 ! Arguments:
718 type(gps_diff), intent(in) :: gd1
719 ! Result:
720 type(gps_diff) :: gpsdiffcos
721
722 gpsdiffcos%Var = cos(gd1%Var)
723 gpsdiffcos%DVar = gd1%DVar * (-1._dp*sin(gd1%Var))
724 end function gpsdiffcos
725
726 pure function gpsdifftan(gd1)
727 implicit none
728
729 ! Arguments:
730 type(gps_diff), intent(in) :: gd1
731 ! Result:
732 type(gps_diff) :: gpsdifftan
733
734 gpsdifftan%Var = tan(gd1%Var)
735 gpsdifftan%DVar = (1._dp/cos(gd1%Var)**2) * gd1%DVar
736 end function gpsdifftan
737
738 pure function gpsdiffacos(gd1)
739 implicit none
740
741 ! Arguments:
742 type(gps_diff), intent(in) :: gd1
743 ! Result:
744 type(gps_diff) :: gpsdiffacos
745
746 gpsdiffacos%Var = acos(gd1%Var)
747 gpsdiffacos%DVar = gd1%DVar * (-1._dp/(1._dp-gd1%Var*gd1%Var))
748 end function gpsdiffacos
749
750 pure function gpsdiffatan(gd1)
751 implicit none
752
753 ! Arguments:
754 type(gps_diff), intent(in) :: gd1
755 ! Result:
756 type(gps_diff) :: gpsdiffatan
757
758 gpsdiffatan%Var = atan(gd1%Var)
759 gpsdiffatan%DVar = (1._dp/(1._dp+gd1%Var**2)) * gd1%DVar
760 end function gpsdiffatan
761
762 pure function gpsdifferf(gd1)
763 implicit none
764
765 ! Arguments:
766 type(gps_diff), intent(in) :: gd1
767 ! Result:
768 type(gps_diff) :: gpsdifferf
769
770 ! Locals:
771 real(dp) , parameter :: pi = MPC_PI_R8
772 ! real(dp) ::m_sqrtpi
773 gpsdifferf%Var = erf(gd1%Var)
774 gpsdifferf%DVar = ((2._dp/sqrt(pi)) * exp(-gd1%Var**2)) * gd1%DVar
775 end function gpsdifferf
776
777!modgps04profile
778
779 subroutine gps_struct1sw(ngpslev,rLat,rLon,rAzm,rMT,Rad,geoid, &
780 rP0,rPP,rDP,rTT,rHU,rUU,rVV,prf,printHeight_opt)
781 implicit none
782
783 ! Arguments:
784 integer(i4) , intent(in) :: ngpslev
785 real(dp) , intent(in) :: rLat
786 real(dp) , intent(in) :: rLon
787 real(dp) , intent(in) :: rAzm
788 real(dp) , intent(in) :: rMT
789 real(dp) , intent(in) :: Rad
790 real(dp) , intent(in) :: geoid
791 real(dp) , intent(in) :: rP0
792 real(dp) , intent(in) :: rPP (ngpssize)
793 real(dp) , intent(in) :: rDP (ngpssize)
794 real(dp) , intent(in) :: rTT (ngpssize)
795 real(dp) , intent(in) :: rHU (ngpssize)
796 real(dp) , intent(in) :: rUU (ngpssize)
797 type(gps_profile), intent(out) :: prf
798 real(dp) , intent(in) :: rVV (ngpssize)
799 logical, optional, intent(inout) :: printHeight_opt
800
801 ! Locals:
802 integer(i4) :: i
803 real(dp) , parameter :: delta = 0.6077686814144_dp
804 type(gps_diff) :: cmp(ngpssize)
805 real(dp) :: h0,dh,Rgh,Eot,Eot2, sLat, cLat
806 type(gps_diff) :: p, t, q, x
807 type(gps_diff) :: tr, z
808 type(gps_diff) :: mold, dd, dw, dx, n0, nd1, nw1, tvm
809 type(gps_diff) :: xi(ngpssize), tv(ngpssize)
810
811 prf%ngpslev = ngpslev
812 prf%rLat = rLat
813 prf%rLon = rLon
814 prf%rAzm = rAzm
815 prf%rMT = rMT
816 prf%Rad = Rad
817 prf%geoid = geoid
818 call gpsRadii(rLat, prf%RadN, prf%RadM)
819
820 !
821 ! Fill pressure placeholders:
822 !
823 prf%P0%Var = 0.01_dp*rP0
824 prf%P0%DVar = 0._dp
825 prf%P0%DVar(2*ngpslev+1) = 0.01_dp
826 do i=1,ngpslev
827 prf%pst(i)%Var = 0.01_dp*rPP(i)
828 prf%pst(i)%DVar = 0._dp
829 prf%pst(i)%DVar(2*ngpslev+1) = 0.01_dp*rDP(i)
830 end do
831
832 !
833 ! Fill temperature placeholders:
834 !
835 do i = 1, ngpslev
836 prf%tst(i)%Var = rTT(i)+MPC_K_C_DEGREE_OFFSET_R8
837 prf%tst(i)%DVar = 0._dp
838 prf%tst(i)%DVar(i) = 1._dp
839 end do
840
841 !
842 ! Fill moisture placeholders:
843 !
844 do i = 1, ngpslev
845 prf%qst(i)%Var = rHU(i)
846 prf%qst(i)%DVar = 0._dp
847 prf%qst(i)%DVar(ngpslev+i) = 1._dp
848 end do
849
850 ! Compressibility:
851 do i = 1, ngpslev
852 cmp(i)= gpscompressibility(prf%pst(i),prf%tst(i),prf%qst(i))
853 end do
854
855 ! Refractivity:
856 do i = 1, ngpslev
857 p = prf%pst(i)
858 t = prf%tst(i)
859 q = prf%qst(i)
860 x = gps_p_wa*q/(1._dp+gps_p_wb*q)
861
862 ! Densities (molar, total, dry, water vapor):
863 mold = p/t * (100._dp/(p_R*cmp(i))) ! note that p is in hPa
864 dd = mold * (1._dp-x) * (gps_p_md/1000._dp)
865 dw = mold * x * (gps_p_mw/1000._dp)
866 ! Aparicio (2011) expression
867 tr = MPC_K_C_DEGREE_OFFSET_R8/t-1._dp
868 nd1= ( 222.682_dp+ 0.069_dp*tr) * dd
869 nw1= (6701.605_dp+6385.886_dp*tr) * dw
870 n0 = (nd1+nw1)
871 prf%rst(i) = n0*(1._dp+(1.e-6_dp/6._dp)*n0)
872 end do
873
874 !
875 ! Hydrostatic equation
876 !
877 do i = 1, ngpslev
878 p = prf%pst(i)
879 t = prf%tst(i)
880 q = prf%qst(i)
881 !
882 ! Log(P)
883 !
884 xi(i) = log(p)
885 !
886 ! Virtual temperature (K) (corrected of compressibility)
887 !
888 tv(i) = (1._dp+delta*q) * t * cmp(i)
889 end do
890
891 sLat=sin(rLat)
892 cLat=cos(rLat)
893 dx = xi(ngpslev)-log(prf%P0)
894 Rgh = gps_gravitysrf(sLat)
895 z = (-p_Rd/Rgh) * tv(ngpslev) * dx
896 prf%gst(ngpslev) = rMT + z
897 do i=ngpslev-1,1,-1
898 dx = xi(i)-xi(i+1)
899 tvm = 0.5_dp*(tv(i)+tv(i+1))
900 !
901 ! Gravity acceleration (includes 2nd-order Eotvos effect)
902 !
903 h0 = prf%gst(i+1)%Var
904 Eot = 2*ec_wgs_OmegaPrime*cLat*rUU(i)
905 Eot2= (rUU(i)**2+rVV(i)**2)/ec_wgs_a
906 Rgh = gps_gravityalt(sLat, h0)-Eot-Eot2
907 dh = (-p_Rd/Rgh) * tvm%Var * dx%Var
908 Rgh = gps_gravityalt(sLat, h0+0.5_dp*dh)-Eot-Eot2
909 !
910 ! Height increment
911 !
912 z = (-p_Rd/Rgh) * tvm * dx
913 prf%gst(i) = prf%gst(i+1) + z
914 end do
915
916 if ( present(printHeight_opt) ) then
917 if ( printHeight_opt ) then
918 write(*,*) 'gps_struct1sw, height='
919 write(*,*) prf%gst(1:ngpslev)%Var
920
921 printHeight_opt = .false.
922 end if
923 end if
924
925 prf%bbst=.false.
926 end subroutine gps_struct1sw
927
928 subroutine gps_struct1sw_v2(ngpslev,rLat,rLon,rAzm,rMT,Rad,geoid, &
929 rP0,rPP,rTT,rHU,rUU,rVV,rALT,prf)
930 implicit none
931
932 ! Arguments:
933 integer(i4) , intent(in) :: ngpslev
934 real(dp) , intent(in) :: rLat
935 real(dp) , intent(in) :: rLon
936 real(dp) , intent(in) :: rAzm
937 real(dp) , intent(in) :: rMT
938 real(dp) , intent(in) :: Rad
939 real(dp) , intent(in) :: geoid
940 real(dp) , intent(in) :: rP0
941 real(dp) , intent(in) :: rPP (ngpssize)
942 real(dp) , intent(in) :: rTT (ngpssize)
943 real(dp) , intent(in) :: rHU (ngpssize)
944 real(dp) , intent(in) :: rUU (ngpssize)
945 real(dp) , intent(in) :: rVV (ngpssize)
946 real(dp) , intent(in) :: rALT (ngpssize)
947 type(gps_profile), intent(out) :: prf
948
949 ! Locals:
950 integer(i4) :: i
951 real(dp) :: rALT_E(ngpssize)
952 real(dp) , parameter :: delta = 0.6077686814144_dp
953 type(gps_diff) :: cmp(ngpssize)
954 type(gps_diff) :: p, t, q, x
955 type(gps_diff) :: tr
956 type(gps_diff) :: mold, dd, dw, n0, nd1, nw1
957
958 prf%ngpslev = ngpslev
959 prf%rLat = rLat
960 prf%rLon = rLon
961 prf%rAzm = rAzm
962 prf%rMT = rMT
963 prf%Rad = Rad
964 prf%geoid = geoid
965 call gpsRadii(rLat, prf%RadN, prf%RadM)
966
967 !
968 ! Fill pressure placeholders:
969 !
970 prf%P0%Var = 0.01_dp*rP0
971 prf%P0%DVar = 0._dp
972 prf%P0%DVar(4*ngpslev) = 0.01_dp
973 do i=1,ngpslev
974 prf%pst(i)%Var = 0.01_dp*rPP(i)
975 prf%pst(i)%DVar = 0._dp
976 prf%pst(i)%DVar(3*ngpslev+i) = 0.01_dp
977 end do
978
979 !
980 ! Fill temperature placeholders:
981 !
982 do i = 1, ngpslev
983 prf%tst(i)%Var = rTT(i)+MPC_K_C_DEGREE_OFFSET_R8
984 prf%tst(i)%DVar = 0._dp
985 prf%tst(i)%DVar(i) = 1._dp
986 end do
987
988 !
989 ! Fill moisture placeholders:
990 !
991 do i = 1, ngpslev
992 prf%qst(i)%Var = rHU(i)
993 prf%qst(i)%DVar = 0._dp
994 prf%qst(i)%DVar(ngpslev+i) = 1._dp
995 end do
996
997 !
998 ! Fill altitude placeholders:
999 !
1000 if (gps_gpsroEotvos) then
1001 call gpsro_Eotvos_dH(ngpslev, rLat, rALT, rUU, rVV, rALT_E)
1002 else
1003 rALT_E(1:ngpslev) = rALT(1:ngpslev)
1004 end if
1005 do i = 1, ngpslev
1006 prf%gst(i)%Var = rALT_E(i)
1007 prf%gst(i)%DVar = 0._dp
1008 prf%gst(i)%DVar(2*ngpslev+i) = 1._dp
1009 end do
1010
1011 ! Compressibility:
1012 do i = 1, ngpslev
1013 cmp(i)= gpscompressibility(prf%pst(i),prf%tst(i),prf%qst(i))
1014 end do
1015
1016 ! Refractivity:
1017 do i = 1, ngpslev
1018 p = prf%pst(i)
1019 t = prf%tst(i)
1020 q = prf%qst(i)
1021 x = gps_p_wa*q/(1._dp+gps_p_wb*q)
1022
1023 ! Densities (molar, total, dry, water vapor):
1024 mold = p/t * (100._dp/(p_R*cmp(i))) ! note that p is in hPa
1025 dd = mold * (1._dp-x) * (gps_p_md/1000._dp)
1026 dw = mold * x * (gps_p_mw/1000._dp)
1027 ! Aparicio (2011) expression
1028 tr = MPC_K_C_DEGREE_OFFSET_R8/t-1._dp
1029 nd1= ( 222.682_dp+ 0.069_dp*tr) * dd
1030 nw1= (6701.605_dp+6385.886_dp*tr) * dw
1031 n0 = (nd1+nw1)
1032 prf%rst(i) = n0*(1._dp+(1.e-6_dp/6._dp)*n0)
1033 end do
1034
1035 prf%bbst=.false.
1036 end subroutine gps_struct1sw_v2
1037
1038 function gpscompressibility(p,t,q)
1039 implicit none
1040
1041 ! Arguments:
1042 type(gps_diff), intent(in) :: p
1043 type(gps_diff), intent(in) :: t
1044 type(gps_diff), intent(in) :: q
1045 ! Result:
1046 type(gps_diff) :: gpscompressibility
1047
1048 ! Locals:
1049 real(dp) , parameter :: a0= 1.58123e-6_dp
1050 real(dp) , parameter :: a1=-2.9331e-8_dp
1051 real(dp) , parameter :: a2= 1.1043e-10_dp
1052 real(dp) , parameter :: b0= 5.707e-6_dp
1053 real(dp) , parameter :: b1=-2.051e-8_dp
1054 real(dp) , parameter :: c0= 1.9898e-4_dp
1055 real(dp) , parameter :: c1=-2.376e-6_dp
1056 real(dp) , parameter :: d = 1.83e-11_dp
1057 real(dp) , parameter :: e =-0.765e-8_dp
1058 type(gps_diff) :: x,tc,pt,tc2,x2
1059
1060 x = gps_p_wa*q/(1._dp+gps_p_wb*q)
1061 ! Estimate, from CIPM, Picard (2008)
1062 tc = t-MPC_K_C_DEGREE_OFFSET_R8
1063 pt = 1.e2_dp*p/t
1064 tc2= tc*tc
1065 x2 = x*x
1066 gpscompressibility = 1._dp-pt*(a0+a1*tc+a2*tc2+(b0+b1*tc)*x+(c0+c1*tc)*x2)+pt*pt*(d+e*x2)
1067 end function gpscompressibility
1068
1069 subroutine gpsro_Eotvos_dH(ngpslev, rLat, rALT, rUU, rVV, rALT_E)
1070 implicit none
1071
1072 ! Arguments:
1073 integer, intent(in) :: ngpslev
1074 real(dp), intent(in) :: rLat
1075 real(dp), intent(in) :: rALT(ngpslev)
1076 real(dp), intent(in) :: rUU (ngpslev)
1077 real(dp), intent(in) :: rVV (ngpslev)
1078 real(dp), intent(out) :: rALT_E(ngpslev)
1079
1080 ! Locals:
1081 integer :: i
1082 real(dp) :: cLat, dALT, Eot, Eot2, dALTE, ddAL, acc
1083
1084 cLat=cos(rLat)
1085 rALT_E(ngpslev) = rALT(ngpslev)
1086 acc = 0.d0
1087 do i = ngpslev-1, 1, -1
1088 dALT = rALT(i) - rALT(i+1)
1089 Eot = 2*ec_wgs_OmegaPrime*cLat*rUU(i)
1090 Eot2= (rUU(i)**2+rVV(i)**2)/ec_wgs_a
1091 dALTE = dALT*(1.d0+(Eot+Eot2)/ec_rg)
1092 ddAL = dALTE - dALT
1093 acc = acc + ddAL
1094 rALT_E(i) = rALT(i) + acc
1095 !write(*,'(A15,I4,8F15.8)')'EOTVOS shift', i, rALT(i), rALT_E(i), dALT, Eot, Eot2, ddAL, acc
1096 end do
1097 end subroutine gpsro_Eotvos_dH
1098
1099!modgps04profilezd
1100
1101 subroutine gps_structztd(ngpslev,rLat,rLon,rMT,rP0,rPP,rDP,rTT,rHU,lbevis,&
1102 refopt,prf)
1103 !
1104 !:Purpose: This subroutine fills GPS profiles of type gps_profilezd (for ZTD
1105 ! operator)
1106 !
1107 !:Arguments:
1108 ! :refopt:
1109 ! =1 --> use conventional expression for refractivity N
1110 !
1111 ! =2 --> use new Aparicio & Laroche refractivity N
1112 implicit none
1113
1114 ! Arguments:
1115 integer(i4) , intent(in) :: ngpslev ! number of profile levels
1116 real(dp) , intent(in) :: rLat ! radians
1117 real(dp) , intent(in) :: rLon ! radians
1118 real(dp) , intent(in) :: rMT ! height (ASL) of model surface (m)
1119 real(dp) , intent(in) :: rP0 ! surface pressure (Pa)
1120 real(dp) , intent(in) :: rPP (ngpssize) ! pressure P at each level (Pa)
1121 real(dp) , intent(in) :: rDP (ngpssize) ! dP/dP0 at each level (Pa/Pa)
1122 real(dp) , intent(in) :: rTT (ngpssize) ! temperature T at each level (C)
1123 real(dp) , intent(in) :: rHU (ngpssize) ! q at each level
1124 logical , intent(in) :: lbevis ! determines which set of refractivity constants to use (Bevis or Rueger)
1125 integer , intent(in) :: refopt
1126 type(gps_profilezd), intent(out) :: prf
1127
1128 ! Locals:
1129 ! ******** PARAMETERS *************
1130 real(dp), parameter :: delta = 0.6077686814144_dp
1131 real(dp), parameter :: eps = 0.6219800221014_dp
1132 ! Reuger (2002) refractivity constants (MKS units)
1133 real(dp), parameter :: k1r = 0.776890_dp
1134 real(dp), parameter :: k2r = 0.712952_dp
1135 real(dp), parameter :: k3r = 3754.63_dp
1136 ! Bevis (1994) refractivity constants (MKS units)
1137 real(dp), parameter :: k1b = 0.776000_dp
1138 real(dp), parameter :: k2b = 0.704000_dp
1139 real(dp), parameter :: k3b = 3739.000_dp
1140 ! ******** VARIABLES *************
1141 real(dp) :: a0,a1,a2,b0,b1,c0,c1,d,e
1142 type(gps_diff) :: tc, pt, tc2, x2, tr
1143 type(gps_diff) :: mold, dd, dw, dx, n0, nd1, nw1
1144 integer(i4) :: i
1145 real(dp) :: k1, k2, k3, k2p
1146 real(dp) :: h0, dh, Rgh, sLat, ptop
1147 type(gps_diff) :: p, t, q, x, na, tvm, z
1148 type(gps_diff) :: xi(ngpssize), tv(ngpssize), cmp(ngpssize), N(ngpssize)
1149
1150 prf%ngpslev = ngpslev
1151 prf%rLat = rLat
1152 prf%rLon = rLon
1153 prf%rMT = rMT
1154 prf%bpst = .false.
1155 !
1156 ! Fill pressure (P) placeholders (Pa):
1157 !
1158 prf%P0%Var = rP0
1159 prf%P0%DVar = 0._dp
1160 prf%P0%DVar(2*ngpslev+1) = 1._dp
1161 do i = 1, ngpslev
1162 prf%pst(i)%Var = rPP(i)
1163 prf%pst(i)%DVar = 0._dp
1164 prf%pst(i)%DVar(2*ngpslev+1) = rDP(i)
1165 end do
1166 ! Pressure at model top (Pa)
1167 ptop = rPP(1)
1168 prf%bpst = .true.
1169 !
1170 ! Fill temperature (T) placeholders (C--> K):
1171 !
1172 do i = 1, ngpslev
1173 prf%tst(i)%Var = rTT(i)+MPC_K_C_DEGREE_OFFSET_R8
1174 prf%tst(i)%DVar = 0._dp
1175 prf%tst(i)%DVar(i) = 1._dp
1176 end do
1177
1178 !
1179 ! Fill moisture (Q) placeholders (kg/kg):
1180 !
1181 do i = 1, ngpslev
1182 prf%qst(i)%Var = rHU(i)
1183 prf%qst(i)%DVar = 0._dp
1184 prf%qst(i)%DVar(ngpslev+i) = 1._dp
1185 end do
1186
1187 if ( refopt == 2 ) then ! use Aparicio & Laroche refractivity
1188 ! This code is copied from modgps04profile.cdk90
1189 !
1190 ! Compressibility:
1191 !
1192 a0 = 1.58123e-6_dp
1193 a1 = -2.9331e-8_dp
1194 a2 = 1.1043e-10_dp
1195 b0 = 5.707e-6_dp
1196 b1 = -2.051e-8_dp
1197 c0 = 1.9898e-4_dp
1198 c1 = -2.376e-6_dp
1199 d = 1.83e-11_dp
1200 e = -0.765e-8_dp
1201 do i = 1, ngpslev
1202 p = prf%pst(i)
1203 t = prf%tst(i)
1204 q = prf%qst(i)
1205 x = gps_p_wa*q/(1._dp+gps_p_wb*q)
1206 ! Estimate, from CIPM, Piccard (2008)
1207 tc = t-MPC_K_C_DEGREE_OFFSET_R8
1208 pt = p/t
1209 tc2 = tc*tc
1210 x2 = x*x
1211 cmp(i) = 1._dp-pt*(a0+a1*tc+a2*tc2+(b0+b1*tc)*x+(c0+c1*tc)*x2)+pt*pt*(d+e*x2)
1212 end do
1213
1214 ! Refractivity:
1215 do i = 1, ngpslev
1216 p = prf%pst(i)
1217 t = prf%tst(i)
1218 q = prf%qst(i)
1219 x = gps_p_wa*q/(1._dp+gps_p_wb*q)
1220
1221 ! Densities (molar, total, dry, water vapor):
1222 mold = p/(p_R*t*cmp(i))
1223 dd = mold * (1._dp-x) * (gps_p_md/1000._dp)
1224 dw = mold * x * (gps_p_mw/1000._dp)
1225 ! Aparicio (2011) expression
1226 tr = MPC_K_C_DEGREE_OFFSET_R8/t-1._dp
1227 nd1= ( 222.682_dp+ 0.069_dp*tr) * dd
1228 nw1= (6701.605_dp+6385.886_dp*tr) * dw
1229 n0 = (nd1+nw1)
1230 na = n0*(1._dp+1.e-6_dp*n0/6._dp)
1231 N(i) = na
1232 end do
1233
1234 end if
1235
1236 ! Refractivity constants
1237 if ( lbevis ) then
1238 k1 = k1b
1239 k2 = k2b
1240 k3 = k3b
1241 else
1242 k1 = k1r
1243 k2 = k2r
1244 k3 = k3r
1245 end if
1246 k2p = k2-(eps*k1)
1247
1248 ! Virtual temperature Tv and log(P) profiles
1249 !
1250 do i = 1, ngpslev
1251 p = prf%pst(i)
1252 t = prf%tst(i)
1253 q = prf%qst(i)
1254 xi(i) = log(p)
1255 tv(i) = (1._dp+delta*q) * t
1256 end do
1257
1258 ! Geometric height (m) profile from lowest model level to top --> prf%gst
1259 sLat = sin(rLat)
1260 dx = xi(ngpslev)-log(prf%P0)
1261 Rgh = gps_gravitysrf(sLat)
1262 z = (-p_Rd/Rgh) * tv(ngpslev) * dx
1263 prf%gst(ngpslev) = rMT + z
1264 do i = ngpslev-1, 1, -1
1265 dx = xi(i)-xi(i+1)
1266 tvm = 0.5_dp*(tv(i)+tv(i+1))
1267 !
1268 ! Gravity acceleration
1269 !
1270 h0 = prf%gst(i+1)%Var
1271 Rgh = gps_gravityalt(sLat, h0)
1272 dh = (-p_Rd/Rgh) * tvm%Var * dx%Var
1273 Rgh = gps_gravityalt(sLat, h0+0.5_dp*dh)
1274 !
1275 ! Height increment (m)
1276 !
1277 z = (-p_Rd/Rgh) * tvm * dx
1278 prf%gst(i) = prf%gst(i+1) + z
1279 end do
1280
1281 ! Profile of dZTD/dp --> prf%rst
1282 do i = 1, ngpslev
1283 p = prf%pst(i)
1284 t = prf%tst(i)
1285 q = prf%qst(i)
1286 if ( refopt == 1 ) then
1287 na = (k1/tv(i)) + (k2p*(q/(eps*t))) + (k3*(q/(eps*t**2)))
1288 else
1289 na = N(i) / p
1290 end if
1291 prf%rst(i) = 1.e-6_dp * na * (p_Rd*tv(i))/gps_gravityalt(sLat, prf%gst(i)%Var)
1292 end do
1293
1294 ! ZTD (m) profile from model top down to lowest model level --> prf%ztd
1295 prf%ztd(1) = 1.e-6_dp * ((k1*p_Rd*ptop)/(gps_gravityalt(sLat, prf%gst(1)%Var)))
1296 do i = 2, ngpslev
1297 !
1298 ! ZTD increment = Avg(dZTD/dP) * delta_P
1299 !
1300 z = ((prf%rst(i-1) + prf%rst(i))/2._dp) * (prf%pst(i)-prf%pst(i-1))
1301 prf%ztd(i) = prf%ztd(i-1) + z
1302 end do
1303
1304 end subroutine gps_structztd
1305
1306 subroutine gps_structztd_v2(ngpslev,rLat,rLon,rMT,rP0,rPP,rTT,rHU,rALT,&
1307 lbevis,refopt,prf)
1308 !
1309 !:Purpose: This subroutine fills GPS profiles of type gps_profilezd (for ZTD
1310 ! operator)
1311 !
1312 !:Arguments:
1313 ! :refopt: =1 --> use conventional expression for refractivity N
1314 !
1315 ! =2 --> use new Aparicio & Laroche refractivity N
1316 implicit none
1317
1318 ! Arguments:
1319 integer(i4) , intent(in) :: ngpslev ! number of profile levels
1320 real(dp) , intent(in) :: rLat ! radians
1321 real(dp) , intent(in) :: rLon ! radians
1322 real(dp) , intent(in) :: rMT ! height (ASL) of model surface (m)
1323 real(dp) , intent(in) :: rP0 ! surface pressure (Pa)
1324 real(dp) , intent(in) :: rPP (ngpssize) ! pressure P at each level (Pa)
1325 real(dp) , intent(in) :: rTT (ngpssize) ! temperature T at each level (C)
1326 real(dp) , intent(in) :: rHU (ngpssize) ! q at each level
1327 real(dp) , intent(in) :: rALT (ngpssize) ! altitude at each level
1328 logical , intent(in) :: lbevis ! determines which set of refractivity constants to use (Bevis or Rueger)
1329 integer , intent(in) :: refopt
1330 type(gps_profilezd), intent(out) :: prf
1331
1332 ! Locals:
1333 ! ******** PARAMETERS *************
1334 real(dp), parameter :: delta = 0.6077686814144_dp
1335 real(dp), parameter :: eps = 0.6219800221014_dp
1336 ! Reuger (2002) refractivity constants (MKS units)
1337 real(dp), parameter :: k1r = 0.776890_dp
1338 real(dp), parameter :: k2r = 0.712952_dp
1339 real(dp), parameter :: k3r = 3754.63_dp
1340 ! Bevis (1994) refractivity constants (MKS units)
1341 real(dp), parameter :: k1b = 0.776000_dp
1342 real(dp), parameter :: k2b = 0.704000_dp
1343 real(dp), parameter :: k3b = 3739.000_dp
1344 ! ******** VARIABLES *************
1345 real(dp) :: a0,a1,a2,b0,b1,c0,c1,d,e
1346 type(gps_diff) :: tc, pt, tc2, x2, tr
1347 type(gps_diff) :: mold, dd, dw, n0, nd1, nw1
1348 integer(i4) :: i
1349 real(dp) :: k1, k2, k3, k2p
1350 real(dp) :: sLat, ptop
1351 type(gps_diff) :: p, t, q, x, na, z
1352 type(gps_diff) :: tv(ngpssize), cmp(ngpssize), N(ngpssize)
1353
1354 prf%ngpslev = ngpslev
1355 prf%rLat = rLat
1356 prf%rLon = rLon
1357 prf%rMT = rMT
1358 prf%bpst = .false.
1359 !
1360 ! Fill pressure (P) placeholders (Pa):
1361 !
1362 prf%P0%Var = rP0
1363 prf%P0%DVar = 0._dp
1364 prf%P0%DVar(4*ngpslev) = 1._dp
1365 do i = 1, ngpslev
1366 prf%pst(i)%Var = rPP(i)
1367 prf%pst(i)%DVar = 0._dp
1368 prf%pst(i)%DVar(3*ngpslev+i) = 1._dp
1369 end do
1370 ! Pressure at model top (Pa)
1371 ptop = rPP(1)
1372 prf%bpst = .true.
1373 !
1374 ! Fill temperature (T) placeholders (C--> K):
1375 !
1376 do i = 1, ngpslev
1377 prf%tst(i)%Var = rTT(i)+MPC_K_C_DEGREE_OFFSET_R8
1378 prf%tst(i)%DVar = 0._dp
1379 prf%tst(i)%DVar(i) = 1._dp
1380 end do
1381
1382 !
1383 ! Fill moisture (Q) placeholders (kg/kg):
1384 !
1385 do i = 1, ngpslev
1386 prf%qst(i)%Var = rHU(i)
1387 prf%qst(i)%DVar = 0._dp
1388 prf%qst(i)%DVar(ngpslev+i) = 1._dp
1389 end do
1390
1391 !
1392 ! Fill altitude (AL) placeholders (m):
1393 !
1394 do i = 1, ngpslev
1395 prf%gst(i)%Var = rALT(i)
1396 prf%gst(i)%DVar = 0._dp
1397 prf%gst(i)%DVar(2*ngpslev+i) = 1._dp
1398 end do
1399
1400 if ( refopt == 2 ) then ! use Aparicio & Laroche refractivity
1401 ! This code is copied from modgps04profile.cdk90
1402 !
1403 ! Compressibility:
1404 !
1405 a0 = 1.58123e-6_dp
1406 a1 = -2.9331e-8_dp
1407 a2 = 1.1043e-10_dp
1408 b0 = 5.707e-6_dp
1409 b1 = -2.051e-8_dp
1410 c0 = 1.9898e-4_dp
1411 c1 = -2.376e-6_dp
1412 d = 1.83e-11_dp
1413 e = -0.765e-8_dp
1414 do i = 1, ngpslev
1415 p = prf%pst(i)
1416 t = prf%tst(i)
1417 q = prf%qst(i)
1418 x = gps_p_wa*q/(1._dp+gps_p_wb*q)
1419 ! Estimate, from CIPM, Piccard (2008)
1420 tc = t-MPC_K_C_DEGREE_OFFSET_R8
1421 pt = p/t
1422 tc2 = tc*tc
1423 x2 = x*x
1424 cmp(i) = 1._dp-pt*(a0+a1*tc+a2*tc2+(b0+b1*tc)*x+(c0+c1*tc)*x2)+pt*pt*(d+e*x2)
1425 end do
1426
1427 ! Refractivity:
1428 do i = 1, ngpslev
1429 p = prf%pst(i)
1430 t = prf%tst(i)
1431 q = prf%qst(i)
1432 x = gps_p_wa*q/(1._dp+gps_p_wb*q)
1433
1434 ! Densities (molar, total, dry, water vapor):
1435 mold = p/(p_R*t*cmp(i))
1436 dd = mold * (1._dp-x) * (gps_p_md/1000._dp)
1437 dw = mold * x * (gps_p_mw/1000._dp)
1438 ! Aparicio (2011) expression
1439 tr = MPC_K_C_DEGREE_OFFSET_R8/t-1._dp
1440 nd1= ( 222.682_dp+ 0.069_dp*tr) * dd
1441 nw1= (6701.605_dp+6385.886_dp*tr) * dw
1442 n0 = (nd1+nw1)
1443 na = n0*(1._dp+1.e-6_dp*n0/6._dp)
1444 N(i) = na
1445 end do
1446
1447 end if
1448
1449 ! Refractivity constants
1450 if ( lbevis ) then
1451 k1 = k1b
1452 k2 = k2b
1453 k3 = k3b
1454 else
1455 k1 = k1r
1456 k2 = k2r
1457 k3 = k3r
1458 end if
1459 k2p = k2-(eps*k1)
1460
1461 ! Virtual temperature Tv and log(P) profiles
1462 !
1463 do i = 1, ngpslev
1464 p = prf%pst(i)
1465 t = prf%tst(i)
1466 q = prf%qst(i)
1467 tv(i) = (1._dp+delta*q) * t
1468 end do
1469
1470 sLat = sin(rLat)
1471
1472 ! Profile of dZTD/dp --> prf%rst
1473 do i = 1, ngpslev
1474 p = prf%pst(i)
1475 t = prf%tst(i)
1476 q = prf%qst(i)
1477 if ( refopt == 1 ) then
1478 na = (k1/tv(i)) + (k2p*(q/(eps*t))) + (k3*(q/(eps*t**2)))
1479 else
1480 na = N(i) / p
1481 end if
1482 prf%rst(i) = 1.e-6_dp * na * (p_Rd*tv(i))/gps_gravityalt(sLat, prf%gst(i)%Var)
1483 end do
1484
1485 ! ZTD (m) profile from model top down to lowest model level --> prf%ztd
1486 prf%ztd(1) = 1.e-6_dp * ((k1*p_Rd*ptop)/(gps_gravityalt(sLat, prf%gst(1)%Var)))
1487 do i = 2, ngpslev
1488 !
1489 ! ZTD increment = Avg(dZTD/dP) * delta_P
1490 !
1491 z = ((prf%rst(i-1) + prf%rst(i))/2._dp) * (prf%pst(i)-prf%pst(i-1))
1492 prf%ztd(i) = prf%ztd(i-1) + z
1493 end do
1494
1495 end subroutine gps_structztd_v2
1496
1497!modgps05refstruct
1498
1499 subroutine gpscmp(prf, cmp)
1500 implicit none
1501
1502 ! Arguments:
1503 type(gps_profile), intent(in) :: prf
1504 type(gps_diff) , intent(out) :: cmp(:)
1505
1506 ! Locals:
1507 integer(i4) :: i, ngpslev
1508 type(gps_diff) :: p, t, q
1509 type(gps_diff) :: x,tc,pt,tc2,x2,ZtC
1510 real(dp) :: a0,a1,a2,b0,b1,c0,c1,d,e
1511 real(dp) , parameter :: md=28.965516_dp
1512 real(dp) , parameter :: mw=18.015254_dp
1513 real(dp) , parameter :: wa=md/mw
1514 real(dp) , parameter :: wb=(md-mw)/mw
1515
1516 a0=1.58123e-6_dp
1517 a1=-2.9331e-8_dp
1518 a2=1.1043e-10_dp
1519 b0=5.707e-6_dp
1520 b1=-2.051e-8_dp
1521 c0=1.9898e-4_dp
1522 c1=-2.376e-6_dp
1523 d =1.83e-11_dp
1524 e =-0.765e-8_dp
1525 !
1526 ngpslev = prf%ngpslev
1527 do i = 1, ngpslev
1528 p = prf%pst(i)
1529 t = prf%tst(i)
1530 q = prf%qst(i)
1531 x = wa*q/(1._dp+wb*q)
1532 ! First implementation (2007)
1533 !Zn=1._dp+(0.03913_dp-1.408_dp/(0.08314472_dp*t))*p/(83.14472_dp*t)
1534 !Zo=1._dp+(0.03183_dp-1.378_dp/(0.08314472_dp*t))*p/(83.14472_dp*t)
1535 !Za=1._dp+(0.03219_dp-1.363_dp/(0.08314472_dp*t))*p/(83.14472_dp*t)
1536 !Zw=1._dp+(0.03049_dp-5.536_dp/(0.08314472_dp*t))*p/(83.14472_dp*t)
1537 !Zd=0.78_dp*Zn+0.21_dp*Zo+0.01_dp*Za
1538 !Zt=(1._dp-q)*Zd+q*Zw
1539 ! Better estimate, from CIPM, Piccard (2008)
1540 tc = t-MPC_K_C_DEGREE_OFFSET_R8
1541 pt = 1.e2_dp*p/t
1542 tc2= tc*tc
1543 x2 = x*x
1544 ZtC= 1._dp-pt*(a0+a1*tc+a2*tc2+(b0+b1*tc)*x+(c0+c1*tc)*x2) !+pt*pt*(d+e*x2)
1545 ! Either choose Zt (First implementation) or ZtC (CIPM, better)
1546 cmp(i)=ZtC
1547 end do
1548 end subroutine gpscmp
1549
1550 subroutine gpsden(prf, den)
1551 implicit none
1552
1553 ! Arguments:
1554 type(gps_profile), intent(in) :: prf
1555 type(gps_diff) , intent(out) :: den(:)
1556
1557 ! Locals:
1558 type(gps_diff) :: mold, dd, dw, cmp(ngpssize)
1559 integer(i4) :: i, ngpslev
1560 real(dp) , parameter :: R=8.314472_dp
1561 real(dp) , parameter :: md=28.965516_dp
1562 real(dp) , parameter :: mw=18.015254_dp
1563 real(dp) , parameter :: wa=md/mw
1564 real(dp) , parameter :: wb=(md-mw)/mw
1565 type(gps_diff) :: p, t, q, x
1566
1567 call gpscmp(prf, cmp)
1568 ngpslev = prf%ngpslev
1569 do i = 1, ngpslev
1570 p = prf%pst(i)
1571 t = prf%tst(i)
1572 q = prf%qst(i)
1573 x = wa*q/(1._dp+wb*q)
1574
1575 ! Densities (molar, total, dry, water vapor):
1576 mold = 100._dp*p/(R*t*cmp(i)) ! note that p is in hPa
1577 dd = mold * (1._dp-x) * (md/1000._dp)
1578 dw = mold * x * (mw/1000._dp)
1579 den(i)=dd+dw
1580 end do
1581 end subroutine gpsden
1582
1583
1584!modgps07geostruct
1585
1586 subroutine gpsbvf(prf, bvf)
1587 implicit none
1588
1589 ! Arguments:
1590 type(gps_profile), intent(in) :: prf
1591 type(gps_diff) , intent(out) :: bvf(ngpssize)
1592
1593 ! Locals:
1594 type(gps_diff) :: den(ngpssize), dddz(ngpssize)
1595 integer(i4) :: i, ngpslev, im, ip
1596 real(dp) :: g, sLat
1597
1598 call gpsden(prf, den)
1599
1600 ngpslev = prf%ngpslev
1601 sLat=sin(prf%rLat)
1602 do i = 1, ngpslev
1603 ip=i+1
1604 im=i-1
1605 if (i==1) im=1
1606 if (i==ngpslev) ip=ngpslev
1607 dddz(i)=den(i)*(log(den(ip))-log(den(im)))/(prf%gst(ip)-prf%gst(im))
1608 g=gps_gravityalt(sLat, prf%gst(i)%Var)
1609 bvf(i)=sqrt((-g)/den(i)*dddz(i))
1610 end do
1611 end subroutine gpsbvf
1612
1613
1614!modgps08refop
1615
1616 pure subroutine gps_refopv(hv, nval, prf, refopv)
1617 !
1618 !:Purpose: GPSRO Refractivity operator
1619 !
1620 implicit none
1621
1622 ! Arguments:
1623 real(dp) , intent(in) :: hv(:) ! an array of height values
1624 integer(i4) , intent(in) :: nval
1625 type(gps_profile) , intent(in) :: prf ! local profile
1626 type(gps_diff) , intent(out):: refopv(:) ! an array of refractivity values (with derivatives)
1627
1628 ! Locals:
1629 integer(i4) :: iSize, i, ngpslev
1630 integer(i4) :: j, jloc
1631 real(dp) :: h
1632 type(gps_diff) :: dz
1633 type(gps_diff) :: dzm
1634 type(gps_diff) :: dzp
1635
1636 ngpslev=prf%ngpslev
1637 iSize = size(hv)
1638 if (nval < iSize) iSize=nval
1639 !
1640 ! Given a height
1641 !
1642 jloc = 1
1643 do i = 1, iSize
1644 h = hv(i)
1645 !
1646 ! Search where it is located
1647 !
1648 if (h > prf%gst(1)%Var) then
1649 jloc = 1
1650 end if
1651
1652 do j=1, ngpslev-1
1653 if ((h <= prf%gst(j)%Var) .and. (h > prf%gst(j+1)%Var)) then
1654 jloc = j
1655 exit
1656 end if
1657 end do
1658
1659 if (h <= prf%gst(ngpslev)%Var) then
1660 jloc = ngpslev-1
1661 end if
1662 !
1663 ! Interpolation/extrapolation
1664 !
1665 if (h >= prf%gst(ngpslev)%Var) then
1666 !
1667 ! Either linear-log interpolation
1668 !
1669 dz = prf%gst(jloc) - prf%gst(jloc+1)
1670
1671 dzm = h - prf%gst(jloc+1)
1672 dzp = prf%gst(jloc) - h
1673
1674 refopv(i) = exp( (dzm * log(prf%rst(jloc)) + dzp * log(prf%rst(jloc+1))) / dz )
1675 else
1676 !
1677 ! Or exp extrapolation at the lower edge
1678 ! (better standard exp profile than linear-log, which may be unstable)
1679 !
1680 dzm = h - prf%gst(jloc+1)
1681 refopv(i) = prf%rst(jloc+1) * exp((-1._dp/6500._dp)*dzm)
1682 end if
1683 end do
1684 end subroutine gps_refopv
1685
1686 subroutine gpshgtopv(pr, prf, hgtopv)
1687 implicit none
1688
1689 ! Arguments:
1690 real(dp) , intent(in) :: pr
1691 type(gps_profile), intent(in) :: prf
1692 type(gps_diff) , intent(out):: hgtopv
1693
1694 ! Locals:
1695 integer(i4) :: j, jloc, ngpslev
1696 real(dp) :: p
1697 type(gps_diff) :: vpm
1698 type(gps_diff) :: vpp
1699 type(gps_diff) :: dpr
1700 type(gps_diff) :: dxm
1701 type(gps_diff) :: dxp
1702 type(gps_diff) :: Hm
1703 type(gps_diff) :: Hp
1704 type(gps_diff) :: H
1705
1706 ngpslev=prf%ngpslev
1707 !
1708 ! Given a pressure
1709 !
1710 p = pr
1711 !
1712 ! Search where it is located
1713 !
1714 if (p < prf%pst(1)%Var) then
1715 jloc = 1
1716 end if
1717
1718 do j=1, ngpslev-1
1719 if ((p >= prf%pst(j)%Var) .and. (p < prf%pst(j+1)%Var)) then
1720 jloc = j
1721 exit
1722 end if
1723 end do
1724
1725 if (p >= prf%pst(ngpslev)%Var) then
1726 jloc = ngpslev-1
1727 end if
1728 !
1729 ! Find properties in that band
1730 !
1731 vpm = log(prf%pst(jloc))
1732 vpp = log(prf%pst(jloc+1))
1733
1734 dpr = vpp-vpm
1735
1736 dxm = (vpp-log(p)) / dpr
1737 dxp = (log(p)-vpm) / dpr
1738
1739 Hm = prf%gst(jloc)
1740 Hp = prf%gst(jloc+1)
1741
1742 H = dxm * Hm + dxp * Hp
1743
1744 hgtopv = H
1745 end subroutine gpshgtopv
1746
1747 subroutine gpstemopv(pr, nval, prf, temopv)
1748 implicit none
1749
1750 ! Arguments:
1751 real(dp) , intent(in) :: pr(:)
1752 integer(i4) , intent(in) :: nval
1753 type(gps_profile) , intent(in) :: prf
1754 type(gps_diff) , intent(out):: temopv(:)
1755
1756 ! Locals:
1757 integer :: iSize, ngpslev
1758 integer(i4) :: i, j, jloc
1759 real(dp) :: p
1760 type(gps_diff) :: vpm
1761 type(gps_diff) :: vpp
1762 type(gps_diff) :: dpr
1763 type(gps_diff) :: dxm
1764 type(gps_diff) :: dxp
1765 type(gps_diff) :: Tm
1766 type(gps_diff) :: Tp
1767 type(gps_diff) :: T
1768
1769 ngpslev=prf%ngpslev
1770 iSize = size(pr)
1771 if (nval < iSize) iSize=nval
1772 do i = 1, iSize
1773 !
1774 ! Given a pressure
1775 !
1776 p = pr(i)
1777 !
1778 ! Search where it is located
1779 !
1780 if (p < prf%pst(1)%Var) then
1781 jloc = 1
1782 end if
1783
1784 do j=1, ngpslev-1
1785 if ((p >= prf%pst(j)%Var) .and. (p < prf%pst(j+1)%Var)) then
1786 jloc = j
1787 exit
1788 end if
1789 end do
1790
1791 if (p >= prf%pst(ngpslev)%Var) then
1792 jloc = ngpslev-1
1793 end if
1794 !
1795 ! Find properties in that band
1796 !
1797 vpm = log(prf%pst(jloc))
1798 vpp = log(prf%pst(jloc+1))
1799
1800 dpr = vpp-vpm
1801
1802 dxm = (vpp-log(p)) / dpr
1803 dxp = (log(p)-vpm) / dpr
1804
1805 Tm = prf%tst(jloc)
1806 Tp = prf%tst(jloc+1)
1807
1808 T = dxm * Tm + dxp * Tp
1809
1810 temopv(i) = T
1811 end do
1812 end subroutine gpstemopv
1813
1814 subroutine gpswmropv(pr, prf, wmropv)
1815 implicit none
1816
1817 ! Arguments:
1818 real(dp) , intent(in) :: pr(:)
1819 type(gps_profile) , intent(in) :: prf
1820 type(gps_diff) , intent(out):: wmropv(:)
1821
1822 ! Locals:
1823 integer :: iSize, ngpslev
1824 integer(i4) :: i, j, jloc
1825 real(dp) :: p
1826 type(gps_diff) :: vpm
1827 type(gps_diff) :: vpp
1828 type(gps_diff) :: dpr
1829 type(gps_diff) :: dxm
1830 type(gps_diff) :: dxp
1831 type(gps_diff) :: Rm
1832 type(gps_diff) :: Rp
1833 type(gps_diff) :: R
1834
1835 ngpslev=prf%ngpslev
1836 iSize = size(pr)
1837 do i = 1, iSize
1838 !
1839 ! Given a pressure
1840 !
1841 p = pr(i)
1842 !
1843 ! Search where it is located
1844 !
1845 if (p < prf%pst(1)%Var) then
1846 jloc = 1
1847 end if
1848
1849 do j=1, ngpslev-1
1850 if ((p >= prf%pst(j)%Var) .and. (p < prf%pst(j+1)%Var)) then
1851 jloc = j
1852 exit
1853 end if
1854 end do
1855
1856 if (p >= prf%pst(ngpslev)%Var) then
1857 jloc = ngpslev-1
1858 end if
1859 !
1860 ! Find properties in that band
1861 !
1862 vpm = log(prf%pst(jloc))
1863 vpp = log(prf%pst(jloc+1))
1864
1865 dpr = vpp-vpm
1866
1867 dxm = (vpp-log(p)) / dpr
1868 dxp = (log(p)-vpm) / dpr
1869
1870 Rm = prf%qst(jloc)
1871 Rp = prf%qst(jloc+1)
1872
1873 R = dxm * Rm + dxp * Rp
1874
1875 wmropv(i) = R * 28.97_dp / 18.01528_dp
1876 end do
1877 end subroutine gpswmropv
1878
1879 subroutine gpsbvfopv(hv, nval, prf, bvfopv)
1880 implicit none
1881
1882 ! Arguments:
1883 real(dp) , intent(in) :: hv(:)
1884 integer(i4) , intent(in) :: nval
1885 type(gps_profile) , intent(in) :: prf
1886 type(gps_diff) , intent(out):: bvfopv(:)
1887
1888 ! Locals:
1889 integer(i4) :: iSize, i, ngpslev
1890 integer(i4) :: j, jloc
1891 real(dp) :: h
1892 type(gps_diff) :: bvf(ngpssize)
1893 type(gps_diff) :: gpm
1894 type(gps_diff) :: gpp
1895 type(gps_diff) :: dz
1896 type(gps_diff) :: dxm
1897 type(gps_diff) :: dxp
1898 type(gps_diff) :: BVm
1899 type(gps_diff) :: BVp
1900
1901 call gpsbvf(prf,bvf)
1902
1903 ngpslev=prf%ngpslev
1904 iSize = size(hv)
1905 if (nval < iSize) iSize=nval
1906 !
1907 ! Given a height
1908 !
1909 do i = 1, iSize
1910 h = hv(i)
1911 !
1912 ! Search where it is located
1913 !
1914 if (h > prf%gst(1)%Var) then
1915 jloc = 1
1916 end if
1917
1918 do j=1, ngpslev-1
1919 if ((h <= prf%gst(j)%Var) .and. (h > prf%gst(j+1)%Var)) then
1920 jloc = j
1921 exit
1922 end if
1923 end do
1924
1925 if (h <= prf%gst(ngpslev)%Var) then
1926 jloc = ngpslev-1
1927 end if
1928 !
1929 ! Find properties in that band
1930 !
1931 gpm = prf%gst(jloc)
1932 gpp = prf%gst(jloc+1)
1933
1934 dz = gpm - gpp
1935
1936 dxm = (h-gpp) / dz
1937 dxp = (gpm-h) / dz
1938
1939 BVm = bvf(jloc)
1940 BVp = bvf(jloc+1)
1941
1942 bvfopv (i) = dxm * BVm + dxp * BVp
1943 end do
1944 end subroutine gpsbvfopv
1945
1946
1947!modgps08ztdop
1948
1949 pure subroutine gps_ztdopv(hv, prf, lbevis, dzmin, ZTDopv, rPobs, mode)
1950 !
1951 !:Purpose: GB-GPS ZTD operator
1952 !
1953 !:Arguments:
1954 ! :dzmin: Minimum DZ = Zobs-Zmod (m) for which DZ adjustment to ZTD will
1955 ! be made when Zobs < Zmod.
1956 ! :mode: 1 = normal mode: use stored ZTD profiles
1957 !
1958 ! 2 = Vedel & Huang ZTD formulation: ZTD = ZHD(Pobs) + ZWD
1959 ! Pobs computed from P0 using CMC hydrostatic extrapolation.
1960 !
1961 implicit none
1962
1963 ! Arguments:
1964 real(dp) , intent(in) :: hv ! height of ZTD observation Zobs (m)
1965 type(gps_profilezd), intent(in) :: prf ! local model profile (type gps_profilezd)
1966 logical , intent(in) :: lbevis! true/false --> use Bevis instead of Rueger k values
1967 real(dp) , intent(in) :: dzmin
1968 type(gps_diff) , intent(out) :: ZTDopv! ZTD (m) at height of observation (with derivatives)
1969 real(dp) , intent(out) :: rPobs ! Pressure (Pa) at height of observation
1970 integer , intent(in) :: mode
1971
1972 ! Locals:
1973 integer(i4) :: ngpslev
1974 integer(i4) :: j, jloc
1975 real(dp) :: h, x, lat, sLat, dh
1976 real(dp) :: k1, k2, k3, k2p
1977 real(dp) :: zcon, zcon1, zconh, zfph, zconw
1978 type(gps_diff) :: dz, tvsfc, tobs, qobs, tvobs, naobs, Pobs
1979 type(gps_diff) :: dztddp, dztddpm
1980 type(gps_diff) :: zhd, tbar, qbar, qtterm, zsum, ztmobs, zqmobs
1981 type(gps_diff) :: zpbar, ztbar, zqbar, zrmean, zwd
1982 type(gps_diff) :: dzm, dzp
1983 real(dp), parameter :: delta = 0.6077686814144_dp
1984 real(dp), parameter :: eps = 0.6219800221014_dp
1985 real(dp), parameter :: kappa = (1.0_dp/eps)-1.0_dp
1986 real(dp), parameter :: gamma = 0.0065_dp ! -dT/dz (K/m)
1987 real(dp), parameter :: Rgm = 9.784_dp
1988 real(dp), parameter :: dzmax = 100.0
1989 ! Reuger (2002) refractivity constants (MKS units)
1990 real(dp), parameter :: k1r = 0.776890_dp
1991 real(dp), parameter :: k2r = 0.712952_dp
1992 real(dp), parameter :: k3r = 3754.63_dp
1993 ! Bevis (1994) refractivity constants (MKS units)
1994 real(dp), parameter :: k1b = 0.776000_dp
1995 real(dp), parameter :: k2b = 0.704000_dp
1996 real(dp), parameter :: k3b = 3739.000_dp
1997
1998 ! Refractivity constants to use
1999 if ( lbevis ) then
2000 k1 = k1b
2001 k2 = k2b
2002 k3 = k3b
2003 else
2004 k1 = k1r
2005 k2 = k2r
2006 k3 = k3r
2007 end if
2008 k2p = k2-(eps*k1)
2009
2010 ngpslev = prf%ngpslev
2011 lat = prf%rLat
2012 sLat = sin(lat)
2013 !
2014 ! Given obs height hv
2015 !
2016 h = hv
2017 dh = h - prf%gst(ngpslev)%Var ! dh = Zgps-Zmod
2018 !
2019 ! Search where it is located
2020 !
2021 do j = 1, ngpslev-1
2022 if ((h <= prf%gst(j)%Var) .and. (h > prf%gst(j+1)%Var)) then
2023 jloc = j ! the model level above the observation
2024 exit
2025 end if
2026 end do
2027
2028 if (h <= prf%gst(ngpslev)%Var) then ! obs is at or below model lowest level
2029 jloc = ngpslev
2030 end if
2031
2032 if ( mode == 2 ) then
2033
2034 ! Compute ZTD the Vedel and Huang (2004) way: (as in old s/r gpsztdop.ftn)
2035
2036 zcon = 1.0e-06_dp*p_Rd
2037 zcon1 = zcon*k1
2038 zconw = zcon/eps
2039 zconh = zcon1/Rgm
2040 zfph = (1.0_dp - 2.66e-03_dp*cos(2.0*lat) - 2.8e-07_dp*h)
2041
2042 ! Pressure at obs height (CMC hydrostatic extrapolation from Psfc)
2043 x = ec_rg/(p_Rd*gamma)
2044 tvsfc = prf%tst(ngpslev)*(1._dp+delta*prf%qst(ngpslev))
2045 Pobs = prf%pst(ngpslev)*(((tvsfc-gamma*dh)/tvsfc)**x)
2046 ! Dry delay ZHD (m) at obs height
2047 zhd = (zconh/zfph) * Pobs
2048
2049 ! Integrate column q/T on pressure levels to get model ZWD
2050 do j = 1, ngpslev-1
2051 tbar = (prf%tst(j) + prf%tst(j+1))*0.5_dp
2052 qbar = (prf%qst(j) + prf%qst(j+1))*0.5_dp
2053 qtterm = ((qbar + kappa*qbar**2 )/gps_gravityalt(sLat,prf%gst(j)%Var))*(k2p + k3/tbar)
2054 if ( j == 1 ) then
2055 zsum = qtterm*(prf%pst(j+1)-prf%pst(j))
2056 else
2057 zsum = zsum + qtterm*(prf%pst(j+1)-prf%pst(j))
2058 end if
2059 end do
2060
2061 ! Compute ZWD at obs height using Higgins method (HU constant over dh layer)
2062 ztmobs = prf%tst(ngpslev) - (gamma * dh)
2063 zqmobs = prf%qst(ngpslev)
2064 zpbar = (Pobs + prf%pst(ngpslev)) * 0.5_dp
2065 ztbar = (ztmobs + prf%tst(ngpslev)) * 0.5_dp
2066 zqbar = (zqmobs + prf%qst(ngpslev)) * 0.5_dp
2067 ! Mean (wet) refractivity of dz layer
2068 zrmean = 1.0e-06_dp*(k2p*((zpbar*zqbar)/(eps*ztbar)) + k3*((zpbar*zqbar)/(eps*ztbar**2)))
2069
2070 ! Make sure adjusted ZWD >= 0
2071 if ( (zsum%Var*zconw)-(zrmean%Var*dh) > 0._dp ) then
2072 zwd = (zsum*zconw) - (zrmean*dh)
2073 else
2074 zwd = (zsum*zconw)
2075 end if
2076
2077 ! Compute ZTD as sum of ZHD and ZWD
2078 ZTDopv = zhd + zwd
2079
2080
2081 else ! mode = 1: Compute ZTD using stored ZTD profile
2082
2083
2084 if ( jloc /= ngpslev ) then
2085 !
2086 ! Linear-log interpolation in height between levels when obs above lowest level
2087 !
2088 dz = prf%gst(jloc) - prf%gst(jloc+1)
2089
2090 dzm = h - prf%gst(jloc+1)
2091 dzp = prf%gst(jloc) - h
2092
2093 ZTDopv = exp( (dzm*log(prf%ztd(jloc)) + dzp*log(prf%ztd(jloc+1))) / dz )
2094 Pobs = exp( (dzm*log(prf%pst(jloc)) + dzp*log(prf%pst(jloc+1))) / dz )
2095
2096 else ! jloc = ngpslev ; obs is at or below model lowest level
2097 !
2098 if ( abs(dh) <= dzmin ) then ! take lowest level values when obs is close to sfc
2099 ZTDopv = prf%ztd(jloc)
2100 Pobs = prf%pst(jloc)
2101 else ! otherwise do extrapolation from lowest level values
2102 x = ec_rg/(p_Rd*gamma)
2103 tvsfc = prf%tst(jloc)*(1._dp+delta*prf%qst(jloc))
2104 Pobs = prf%pst(jloc)*(((tvsfc-gamma*dh)/tvsfc)**x)
2105 if ( abs(dh) <= dzmax ) then
2106 dztddpm = prf%rst(jloc) ! lowest level value of dZTD/dp
2107 else
2108 tobs = prf%tst(jloc)-gamma*dh
2109 qobs = prf%qst(jloc)
2110 tvobs = tvsfc-gamma*dh
2111 naobs = (k1/tvobs) + (k2p*(qobs/(eps*tobs))) + (k3*(qobs/(eps*tobs**2)))
2112 dztddp = 1.e-6_dp * naobs * (p_Rd*tvobs)/gps_gravityalt(sLat, h)
2113 dztddpm = (dztddp + prf%rst(jloc))/2._dp ! mean value of dZTD/dp over dh layer
2114 end if
2115 ZTDopv = prf%ztd(jloc) + dztddpm*(Pobs-prf%pst(jloc))
2116 end if
2117
2118 end if
2119
2120 end if
2121
2122 rPobs = Pobs%Var
2123
2124 end subroutine gps_ztdopv
2125
2126 subroutine gps_pw(prf, PW)
2127 !
2128 !:Purpose: To compute lowest level PW (kg/m2) using layer mean Q and layer
2129 ! delta_p (Pa)
2130 !
2131 implicit none
2132
2133 ! Arguments:
2134 type(gps_profilezd) , intent(in) :: prf
2135 real(dp) , intent(out) :: PW
2136
2137 ! Locals:
2138 integer(i4) :: i, ngpslev
2139 real(dp) :: qbar, gt, gb, g, lat, sLat
2140 real(dp) :: pt, pb
2141
2142 ngpslev = prf%ngpslev
2143 lat = prf%rLat
2144 sLat = sin(lat)
2145
2146 PW = 0.0_dp
2147
2148 do i = 1, ngpslev-1
2149 qbar = 0.5_dp * (prf%qst(i+1)%Var + prf%qst(i)%Var)
2150 gt = gps_gravityalt(sLat, prf%gst(i)%Var)
2151 gb = gps_gravityalt(sLat, prf%gst(i+1)%Var)
2152 pt = prf%pst(i)%Var
2153 pb = prf%pst(i+1)%Var
2154 g = 0.5_dp * (gt + gb)
2155 PW = PW + (qbar/g)*(pb-pt)
2156 end do
2157
2158 end subroutine gps_pw
2159
2160
2161!modgps09bend
2162
2163 subroutine gpsbend(prf)
2164 implicit none
2165
2166 ! Arguments:
2167 type(gps_profile), intent(inout) :: prf
2168
2169 ! Locals:
2170 type(gps_diff) :: sum,ta,tb,tm,trap,simp,boole,num,fa,fb,fm,nm,alpha_B
2171 type(gps_diff) :: sa,sb,sm,ra,rm,rb,dlnndra,dlnndrb,dlnndrm
2172 type(gps_diff) :: s1,s2,s3,s4,s5,r1,r2,r3,r4,r5
2173 type(gps_diff) :: nu1,nu2,nu3,nu4,nu5,n1,n2,n3,n4,n5
2174 type(gps_diff) :: t1,t2,t3,t4,t5,dlnndr1,dlnndr2,dlnndr3,dlnndr4,dlnndr5
2175 type(gps_diff) :: f1,f2,f3,f4,f5
2176 type(gps_diff) :: r (ngpssize)
2177 type(gps_diff) :: ref(ngpssize)
2178 type(gps_diff) :: nu (ngpssize)
2179 type(gps_diff) :: lnu(ngpssize)
2180 type(gps_diff) :: n (ngpssize)
2181 type(gps_diff) :: dlgnudr(ngpssize-1)
2182 type(gps_diff) :: rsq(ngpssize)
2183 type(gps_diff) :: nsq(ngpssize)
2184 type(gps_diff) :: x (-ngpsxlow+1:ngpssize)
2185 type(gps_diff) :: xsq(-ngpsxlow+1:ngpssize)
2186 type(gps_diff) :: s(ngpssize),t(ngpssize)
2187 integer :: i,j,ngpslev
2188 logical :: lok
2189
2190 if (.not. prf%bbst) then
2191 ngpslev=prf%ngpslev
2192
2193 ! Radial distances and impact parameters:
2194 do i=1,ngpslev
2195 prf%dst(i)= (prf%Rad+prf%geoid+prf%gst(i))
2196 prf%ast(i)= prf%dst(i) * (1._dp+1.e-6_dp*prf%rst(i))
2197 end do
2198 ! Extended lower levels:
2199 do i=ngpslev+1,ngpslev+ngpsxlow
2200 prf%ast(i)= prf%ast(i-1)-50._dp
2201 end do
2202
2203 ! Standard levels:
2204 do i=1,ngpslev
2205 r (i)=prf%dst(ngpslev-i+1)
2206 ref(i)=prf%rst(ngpslev-i+1)
2207 !ref(i)=300._dp*exp((-1._dp/7000._dp)*(r(i)%Var-prf%Rad))
2208 end do
2209 ! Extended upper levels:
2210 do i=ngpslev+1,ngpssize
2211 r (i)=r (i-1)+1000._dp
2212 ref(i)=ref(i-1)*exp(-1000._dp/7000_dp)
2213 end do
2214
2215 ! log n and x:
2216 do i=1,ngpssize
2217 nu(i)=1.e-6_dp*ref(i)
2218 lnu(i)=log(nu(i))
2219 n (i)=1._dp+nu(i)
2220 x (i)=n(i)*r(i)
2221 rsq(i)=r(i)**2
2222 nsq(i)=n(i)**2
2223 xsq(i)=x(i)**2
2224 end do
2225 do i=0,-ngpsxlow+1,-1
2226 x (i)=x(i+1)-50._dp
2227 xsq(i)=x(i)**2
2228 end do
2229
2230 ! Radial derivatives of log refractivity.
2231 ! Refractivity will be assumed exponential within each shell.
2232 ! We store the derivative of log(nu).
2233 ! dn/dr = nu * dlgnudr
2234 do i=1,ngpssize-1
2235 dlgnudr(i)=(lnu(i+1)-lnu(i))/(r(i+1)-r(i))
2236 end do
2237
2238 ! Evaluation of complete bending for ray tangent at r(i):
2239 do i=1,ngpslev
2240 ! Check that ray is not trapped
2241 lok=.true.
2242 do j = i+1,ngpssize
2243 lok= lok .and. (x(j)%Var .gt. x(i)%Var)
2244 end do
2245 if (lok) then
2246 s(i)=0._dp
2247 t(i)=1._dp
2248 do j=i+1,ngpssize
2249 s(j)=sqrt(nsq(i)*rsq(j)-xsq(i))
2250 t(j)=s(j)/sqrt(xsq(j)-xsq(i))
2251 end do
2252
2253 ! Trapezoid integration:
2254 sum=0._dp
2255 do j=i, ngpssize-1
2256 sa=s(j)
2257 sb=s(j+1)
2258 ta=t(j)
2259 tb=t(j+1)
2260 dlnndra=dlgnudr(j)*nu(j )/n(j )
2261 dlnndrb=dlgnudr(j)*nu(j+1)/n(j+1)
2262 fa=dlnndra*ta/sqrt(xsq(i)+sa*sa)
2263 fb=dlnndrb*tb/sqrt(xsq(i)+sb*sb)
2264 sum=sum+(1._dp/2._dp)*(fa+fb)*(sb-sa)
2265 end do
2266 trap=(-2)*r(i)*sum
2267
2268 ! Simpson 1/3 integration:
2269 sum=0._dp
2270 do j=i, ngpssize-1
2271 sa=s(j)
2272 sb=s(j+1)
2273 sm=0.5_dp*(sa+sb)
2274 !
2275 ra=r(j)
2276 rb=r(j+1)
2277 rm=sqrt(xsq(i)+sm*sm)/n(i)
2278 !
2279 num=nu(j)*exp(dlgnudr(j)*(rm-ra))
2280 nm=(1._dp+num)
2281 !
2282 ta=t(j)
2283 tb=t(j+1)
2284 tm=sm/sqrt(nm*nm*rm*rm-xsq(i))
2285 !
2286 dlnndra=dlgnudr(j)*nu(j )/n(j )
2287 dlnndrb=dlgnudr(j)*nu(j+1)/n(j+1)
2288 dlnndrm=dlgnudr(j)*num /nm
2289 !
2290 fa=dlnndra*ta/sqrt(xsq(i)+sa*sa)
2291 fb=dlnndrb*tb/sqrt(xsq(i)+sb*sb)
2292 fm=dlnndrm*tm/sqrt(xsq(i)+sm*sm)
2293 !
2294 sum=sum+(1._dp/6._dp)*(fa+4*fm+fb)*(sb-sa)
2295 end do
2296 simp=(-2)*r(i)*sum
2297
2298 ! Boole 2/45 integration:
2299 sum=0._dp
2300 do j=i, ngpssize-1
2301 s1=s(j)
2302 s5=s(j+1)
2303 s2=0.75_dp*s1+0.25_dp*s5
2304 s3=0.50_dp*s1+0.50_dp*s5
2305 s4=0.25_dp*s1+0.75_dp*s5
2306 !
2307 r1=r(j)
2308 r5=r(j+1)
2309 r2=sqrt(xsq(i)+s2*s2)/n(i)
2310 r3=sqrt(xsq(i)+s3*s3)/n(i)
2311 r4=sqrt(xsq(i)+s4*s4)/n(i)
2312 !
2313 nu1=nu(j)
2314 nu2=nu(j)*exp(dlgnudr(j)*(r2-r1))
2315 nu3=nu(j)*exp(dlgnudr(j)*(r3-r1))
2316 nu4=nu(j)*exp(dlgnudr(j)*(r4-r1))
2317 nu5=nu(j+1)
2318 n1=n(j)
2319 n2=(1._dp+nu2)
2320 n3=(1._dp+nu3)
2321 n4=(1._dp+nu4)
2322 n5=n(j+1)
2323 !
2324 t1=t(j)
2325 t2=s2/sqrt(n2*n2*r2*r2-xsq(i))
2326 t3=s3/sqrt(n3*n3*r3*r3-xsq(i))
2327 t4=s4/sqrt(n4*n4*r4*r4-xsq(i))
2328 t5=t(j+1)
2329 !
2330 dlnndr1=dlgnudr(j)*nu(j )/n(j )
2331 dlnndr5=dlgnudr(j)*nu(j+1)/n(j+1)
2332 dlnndr2=dlgnudr(j)*nu2 /n2
2333 dlnndr3=dlgnudr(j)*nu3 /n3
2334 dlnndr4=dlgnudr(j)*nu4 /n4
2335 !
2336 f1=dlnndr1*t1/sqrt(xsq(i)+s1*s1)
2337 f2=dlnndr2*t2/sqrt(xsq(i)+s2*s2)
2338 f3=dlnndr3*t3/sqrt(xsq(i)+s3*s3)
2339 f4=dlnndr4*t4/sqrt(xsq(i)+s4*s4)
2340 f5=dlnndr5*t5/sqrt(xsq(i)+s5*s5)
2341 !
2342 sum=sum+(1._dp/90._dp)*(7*f1+32*f2+12*f3+32*f4+7*f5)*(s5-s1)
2343 end do
2344 boole=(-2)*r(i)*sum
2345
2346 prf%bst(ngpslev-i+1)=boole
2347 else
2348 prf%bst(ngpslev-i+1)=-10._dp
2349 end if
2350 end do
2351
2352 ! Extended low levels:
2353 do i=0,-ngpsxlow+1,-1
2354 lok=.true.
2355 do j = 1,ngpssize
2356 lok= lok .and. (x(j)%Var .gt. x(i)%Var)
2357 end do
2358 if (lok) then
2359 do j=1,ngpssize
2360 s(j)=sqrt(nsq(1)*rsq(j)-xsq(i))
2361 t(j)=s(j)/sqrt(xsq(j)-xsq(i))
2362 end do
2363
2364 ! Simpson integration:
2365 sum=0._dp
2366 do j=1, ngpssize-1
2367 sa=s(j)
2368 sb=s(j+1)
2369 sm=0.5_dp*(sa+sb)
2370 !
2371 ra=r(j)
2372 rb=r(j+1)
2373 rm=sqrt(xsq(i)+sm*sm)/n(1)
2374 !
2375 num=nu(j)*exp(dlgnudr(j)*(rm-ra))
2376 nm=(1._dp+num)
2377 !
2378 ta=t(j)
2379 tb=t(j+1)
2380 tm=sm/sqrt(nm*nm*rm*rm-xsq(i))
2381 !
2382 dlnndra=dlgnudr(j)*nu(j )/n(j )
2383 dlnndrb=dlgnudr(j)*nu(j+1)/n(j+1)
2384 dlnndrm=dlgnudr(j)*num/nm
2385 !
2386 fa=dlnndra*ta/sqrt(xsq(i)+sa*sa)
2387 fb=dlnndrb*tb/sqrt(xsq(i)+sb*sb)
2388 fm=dlnndrm*tm/sqrt(xsq(i)+sm*sm)
2389 !
2390 sum=sum+(1._dp/6._dp)*(fa+4*fm+fb)*(sb-sa)
2391 end do
2392 simp=(-2)*(x(i)/n(1))*sum
2393 alpha_B=acos(x(i)/x(1))
2394 prf%bst(ngpslev-i+1)=simp-2*alpha_B
2395 else
2396 prf%bst(ngpslev-i+1)=-10._dp
2397 end if
2398 end do
2399
2400 prf%bbst=.true.
2401 end if
2402 end subroutine gpsbend
2403
2404 subroutine gpsbend1(prf)
2405 implicit none
2406
2407 ! Arguments:
2408 type(gps_profile), intent(inout) :: prf
2409
2410 ! Locals:
2411 type(gps_diff) :: r (ngpssize)
2412 type(gps_diff) :: ref(ngpssize)
2413 type(gps_diff) :: nu (ngpssize)
2414 type(gps_diff) :: lnu(ngpssize)
2415 type(gps_diff) :: n (ngpssize)
2416 type(gps_diff) :: dlgnudr(ngpssize-1)
2417 type(gps_diff) :: x (-ngpsxlow+1:ngpssize)
2418 type(gps_diff) :: angle0,angle,angleB,bend,nu0,th,sum,nexp
2419 real(dp) :: dxn
2420 integer :: ngpslev,i,j,jmin
2421 logical :: lok, lok2
2422
2423 if (.not. prf%bbst) then
2424 ngpslev=prf%ngpslev
2425
2426 ! Radial distances and impact parameters:
2427 do i=1,ngpslev
2428 prf%dst(i)= (prf%Rad+prf%geoid+prf%gst(i))
2429 prf%ast(i)= prf%dst(i) * (1._dp+1.e-6_dp*prf%rst(i))
2430 end do
2431 ! Extended lower levels:
2432 do i=ngpslev+1,ngpslev+ngpsxlow
2433 prf%ast(i)= prf%ast(i-1)-50._dp
2434 end do
2435
2436 ! Standard levels:
2437 do i=1,ngpslev
2438 r (i)=prf%dst(ngpslev-i+1)
2439 ref(i)=prf%rst(ngpslev-i+1)
2440 end do
2441 ! Extended upper levels:
2442 do i=ngpslev+1,ngpssize
2443 r (i)=r (i-1)+1000._dp
2444 ref(i)=ref(i-1)*exp(-1000._dp/7000_dp)
2445 end do
2446
2447 ! log n and x:
2448 do i=1,ngpssize
2449 nu(i) = 1.e-6_dp*ref(i)
2450 lnu(i)= log(nu(i))
2451 n (i) = 1._dp+nu(i)
2452 x (i) = n(i)*r(i)
2453 end do
2454 dxn=20._dp
2455 do i=0,-ngpsxlow+1,-1
2456 x (i) = x(i+1)-dxn
2457 end do
2458
2459 ! Radial derivatives of log refractivity.
2460 ! Refractivity will be assumed exponential within each shell.
2461 ! We store the derivative of log(nu).
2462 ! dn/dr = nu * dlgnudr
2463 do i=1,ngpssize-1
2464 dlgnudr(i)=(lnu(i+1)-lnu(i))/(r(i+1)-r(i))
2465 end do
2466
2467 ! Evaluation of complete bending for ray tangent at r(i):
2468 do i=-ngpsxlow+1,ngpslev
2469 lok=.true.
2470 lok2=.false.
2471 ! Check that the ray is not trapped
2472 ! For low impact (reflected, jmin<1) rays, begin at the surface
2473 jmin = i
2474 if (jmin < 1) jmin=1
2475 do j = jmin+1,ngpssize
2476 lok= lok .and. (x(j)%Var .gt. x(i)%Var)
2477 end do
2478 if (lok) then
2479 ! Integration:
2480 sum=0._dp
2481 if (i.ge.1) then
2482 ! Direct rays
2483 angleB=0._dp
2484 else
2485 ! Reflected
2486 angleB=sqrt(2*(-i+1)*dxn/x(1))
2487 end if
2488 angle0=angleB
2489 do j=jmin, ngpssize-1
2490 th=r(j+1)-r(j)
2491 nu0=nu(j)
2492 nexp=dlgnudr(j)
2493 call gpsbendlayer(r(j), th, nu0, nexp, angle0, angle, bend, lok2)
2494 sum=sum+bend
2495 angle0=angle
2496 end do
2497 end if
2498 if (lok2) then
2499 prf%bst(ngpslev-i+1)=(-2)*(sum+angleB)
2500 else
2501 prf%bst(ngpslev-i+1)=-10._dp
2502 end if
2503 end do
2504 end if
2505 end subroutine gpsbend1
2506
2507 subroutine gpsbendlayer(ra, th, nu0, nexp, angle0, angle, bend, lok)
2508 !
2509 !:Arguments:
2510 ! :nu0, nexp: Refraction index coefs: n=1+nu0*exp(nexp*(r-ra));
2511 ! nexp in in 1/m
2512 implicit none
2513
2514 ! Arguments:
2515 type(gps_diff), intent(in) :: ra ! Radius of inner shell (m)
2516 type(gps_diff), intent(in) :: th ! Shell thickness (m)
2517 type(gps_diff), intent(in) :: nu0
2518 type(gps_diff), intent(in) :: nexp
2519 type(gps_diff), intent(in) :: angle0 ! Ray angle above horizon at ra
2520 type(gps_diff), intent(out) :: angle ! Ray angle above horizon at rb
2521 type(gps_diff), intent(out) :: bend ! Accumulated bending over the layer
2522 logical , intent(out) :: lok
2523
2524 ! Locals:
2525 type(gps_diff) :: rb,angle0i,dh,hi,rai,nu0i,anglei
2526 integer :: i,numunits
2527
2528 lok=.false.
2529 if (th%Var.lt.0._dp) return
2530
2531 ! Radius of the outer shell:
2532 rb = ra + th
2533
2534 ! Divide layer in smaller layers:
2535 numunits=10
2536 dh =th/(1._dp*numunits)
2537 angle0i=angle0
2538 bend =0._dp
2539 do i = 1, numunits
2540 hi =(i-1)*dh
2541 rai=ra+(i-1)*dh
2542 nu0i=nu0*exp(nexp*hi)
2543 call gpsbendunit(rai, dh, nu0i, nexp, angle0i, anglei, bend, lok)
2544 angle0i=anglei
2545 if (.not.lok) return
2546 end do
2547 angle=anglei
2548 end subroutine gpsbendlayer
2549
2550 subroutine gpsbendunit(ra, th, nu0, nexp, angle0, angle, bend, lok)
2551 !
2552 !:Arguments:
2553 ! :nu0, nexp: Refraction index coefs: n=1+nu0*exp(nexp*(r-ra));
2554 ! nexp in 1/m
2555 implicit none
2556
2557 ! Arguments:
2558 type(gps_diff), intent(in) :: ra ! Radius of inner shell (m)
2559 type(gps_diff), intent(in) :: th ! Shell thickness (m)
2560 type(gps_diff), intent(in) :: nu0, nexp
2561 type(gps_diff), intent(in) :: angle0 ! Ray angle above horizon at ra
2562 type(gps_diff), intent(out) :: angle ! Ray angle above horizon at rb
2563 type(gps_diff), intent(inout) :: bend ! Accumulated bending over the layer
2564 logical , intent(out) :: lok
2565
2566 ! Locals:
2567 type(gps_diff) :: rb, nu, dlnndh, g0,g1,g2,f0,f1,f2,x,a,b,c,disc,ds,bendi,g1av
2568
2569 lok=.false.
2570 if (th%Var.lt.0._dp) return
2571
2572 ! Radius of the outer shell:
2573 rb = ra + th
2574
2575 ! Excess refraction index:
2576 ! at ra: nu0
2577 ! at rb: nu0*exp(nexp*h)
2578 nu = nu0*exp(0.5_dp*nexp*th)
2579 dlnndh = nexp*nu/(1._dp+nu)
2580
2581 ! Geometric trajectory:
2582 ! g(x) = g0+g1*x+g2*x^2
2583 !
2584 g0=0._dp
2585 g1=tan(angle0)
2586 g2=0.5_dp*dlnndh*cos(angle0)
2587
2588 ! Outer circle:
2589 ! f(x) = f0+f1*x+f2*x^2
2590 !
2591 f0=th
2592 f1=0._dp
2593 f2=(-0.5_dp)/rb
2594
2595 ! Difference:
2596 a=f2-g2
2597 b=f1-g1
2598 c=f0-g0
2599
2600 ! Discriminant:
2601 disc=b*b-4*a*c
2602 if (disc%Var.lt.0._dp) then
2603 lok=.false.
2604 return
2605 else
2606 x =((-1)*b-sqrt(disc))/(2*a)
2607 g1av=g1+g2*x
2608 ds=x*(1._dp+(g2*x)**2)
2609 bendi = 2 * g2 * ds
2610 angle = angle0+atan(x/rb)+bendi
2611 bend = bend + bendi
2612 if (angle%Var .gt. 0) lok=.true.
2613 end if
2614 end subroutine gpsbendunit
2615
2616 subroutine gpsbndopv(impv, azmv, nval, prf, bstv)
2617 implicit none
2618
2619 ! Arguments:
2620 real(dp) , intent(in) :: impv(:)
2621 real(dp) , intent(in) :: azmv(:)
2622 integer(i4) , intent(in) :: nval
2623 type(gps_profile) , intent(inout) :: prf
2624 type(gps_diff) , intent(out) :: bstv(:)
2625
2626 ! Locals:
2627 integer :: iSize, i, j, ngpslev, jlocm, jlocp
2628 real(dp) :: imp1,azm1,rad, rad0
2629 real(dp) :: imp(ngpssize+ngpsxlow)
2630 type(gps_diff) :: am, ap, da, dam, dap
2631
2632 call gpsbend(prf)
2633 ngpslev=prf%ngpslev
2634 iSize = size(impv)
2635 if (nval < iSize) iSize=nval
2636 rad0=prf%rad
2637 !
2638 ! Given an impact
2639 !
2640 do i = 1, iSize
2641 imp1 = impv(i)
2642 azm1 = azmv(i)
2643 rad=1._dp/(cos(azm1)**2/prf%radM+sin(azm1)**2/prf%radN)
2644 do j=1, ngpslev+ngpsxlow
2645 imp(j)=prf%ast(j)%Var
2646 end do
2647 !
2648 ! Search where it is located
2649 !
2650 jlocm = -1000
2651 jlocp = -1000
2652 if (imp1 > imp(1)) then
2653 jlocm = 1
2654 jlocp = 2
2655 end if
2656
2657 do j=1, ngpslev+ngpsxlow-1
2658 if ((imp1 <= imp(j)) .and. (abs(prf%bst(j)%Var) < 1._dp)) then
2659 jlocm = j
2660 end if
2661 end do
2662
2663 do j=jlocm+1, ngpslev+ngpsxlow
2664 if ((imp1 > imp(j)) .and. (abs(prf%bst(j)%Var) < 1._dp)) then
2665 jlocp = j
2666 exit
2667 end if
2668 end do
2669
2670 if (jlocm == -1000) jlocm = ngpslev+ngpsxlow-1
2671 if (jlocp == -1000) jlocp = ngpslev+ngpsxlow
2672
2673 !
2674 ! Find properties in that band
2675 !
2676 am = prf%ast(jlocm)
2677 ap = prf%ast(jlocp)
2678
2679 da = am - ap
2680 dam = (imp1-ap) / da
2681 dap = (am-imp1) / da
2682
2683 ! Use loglinear interpolation for most data (notably direct rays)
2684 if (prf%bst(jlocm)%Var > 1.e-6_dp .and. prf%bst(jlocp)%Var > 1.e-6_dp) then
2685 bstv(i)=exp(dam*log(prf%bst(jlocm))+dap*log(prf%bst(jlocp)))*(rad/rad0)
2686 else
2687 ! Use linear interpolation for near-zero or negative bending (most reflected rays)
2688 bstv(i)=(dam*prf%bst(jlocm)+dap*prf%bst(jlocp))*(rad/rad0)
2689 end if
2690 end do
2691 end subroutine gpsbndopv
2692
2693 subroutine gps_bndopv1(impv, azmv, nval, prf, bstv)
2694 !:Purpose: Computation of the observation operator for Bending
2695 !
2696 !:Note: The Operator is based from Assimilation experiments withCHAMP GPS radio occultation measurements
2697 ! (S. B. HEALY and J.-N. THEPAUT, 2005)
2698 implicit none
2699
2700 ! Arguments:
2701 real(dp) , intent(in) :: impv(:)
2702 real(dp) , intent(in) :: azmv(:)
2703 integer(i4) , intent(in) :: nval
2704 type(gps_profile) , intent(in) :: prf
2705 type(gps_diff) , intent(out) :: bstv(:)
2706
2707 ! Locals:
2708 integer :: levIndexObs, ngpslev,last_levIndexObs,numLevels,levelHigh,levelLow,levIndexAnl
2709 type(gps_diff) :: h(ngpssize), nu(ngpssize), lnu(ngpssize), n(ngpssize), z(ngpssize)
2710 type(gps_diff) :: N0a, N1a, ka, NAa,Aa, Ba, Ba2, Ba3, delta_alpha, delta_alpha_top, z_0, h_0
2711 real(dp) :: a2, a, gz, cazm, sazm, last_a
2712
2713 ! model levels
2714 ngpslev=prf%ngpslev
2715 do levIndexAnl = 1,ngpslev
2716 h(levIndexAnl) = prf%geoid+prf%gst(levIndexAnl)
2717 nu(levIndexAnl) = prf%rst(levIndexAnl)
2718 lnu(levIndexAnl)=log(nu(levIndexAnl))
2719 n(levIndexAnl) = 1._dp+nu(levIndexAnl)*1e-6_dp
2720 z(levIndexAnl) = n(levIndexAnl)*(prf%Rad+prf%geoid+prf%gst(levIndexAnl))
2721 end do
2722 ! number of observed levels in the profile
2723 numLevels = size(impv)
2724 if (nval < numLevels) numLevels=nval
2725
2726 do levIndexObs = numLevels,1,-1
2727 a2 = impv(levIndexObs)*impv(levIndexObs)
2728 a = impv(levIndexObs)
2729 cazm = cos(azmv(levIndexObs))
2730 sazm = sin(azmv(levIndexObs))
2731 !find model levels that bracket the observation
2732 ! note to self: like in GEM, level=1 is the highest level
2733 do levIndexAnl = 1, ngpslev-1
2734 levelHigh = levIndexAnl - 1
2735 levelLow = levIndexAnl
2736 if (z(levIndexAnl)%VaR< a) exit
2737 levelLow = 0
2738 end do
2739
2740 if (levelLow/=0) then
2741 h_0 = h(levelLow)+(((a-z(levelLow))/(z(levelHigh)-z(levelLow)))*(h(levelHigh)-h(levelLow)))
2742 N0a = nu(levelLow)
2743 gz = (lnu(levelLow+1)%Var-lnu(levelLow)%Var)/(h(levelLow+1)%Var-h(levelLow)%Var)
2744 NAa = nu(levelLow)*exp(gz*(h_0-h(levelLow)))
2745 delta_alpha = 0.d0
2746 delta_alpha_top = 0.d0
2747 z_0 = a
2748 do while ((levelHigh)>=1)
2749 N1a = nu(levelHigh)
2750 ka = log(N0a/N1a)/(z(levelHigh) - z(levelLow))
2751 ! Test of Reflected
2752 do while (ka%Var<0.or.ka%Var>0.1)
2753 levelHigh = levelHigh - 1
2754 N1a = nu(levelHigh)
2755 ka = log(N0a/N1a)/(z(levelHigh) - z(levelLow))
2756 end do
2757 Aa = 1e-6_dp* sqrt((MPC_PI_R8/2.d0*a)/ka )*NAa* exp(ka*(z_0-a))
2758 if (z_0%Var==a) then
2759 Ba = erf(sqrt(ka*(z(levelHigh)-a)))
2760 else
2761 Ba2 = erf(sqrt(ka*(z(levelHigh)-a)))
2762 Ba3 = erf(sqrt((ka*(z_0-a))))
2763 Ba = Ba2 - Ba3
2764 end if
2765 delta_alpha = delta_alpha+2*ka*Ba*Aa
2766 N0a = N1a
2767 NAa = N1a
2768 z_0 = z(levelHigh)
2769
2770 levelLow = levelHigh
2771 levelHigh = levelLow-1
2772 end do
2773 Ba = erf(1-erf(sqrt((ka*(z_0-a)))))
2774 delta_alpha_top = 2*Aa*ka*Ba
2775 last_a = a
2776 last_levIndexObs = levIndexObs
2777 bstv(levIndexObs)= delta_alpha +delta_alpha_top
2778 else ! (levelLow==0)
2779 ! Use loglinear extrapolation for most data (notably direct rays)
2780 if (a>(1._dp+prf%rst(ngpslev)%Var*1e-6_dp)*prf%Rad) then
2781 bstv(levIndexObs)=bstv(last_levIndexObs)*exp((-1._dp/6500._dp)*(a-last_a))
2782 else
2783 ! Use linear extrapolation (most reflected rays) from Information content in reflected
2784 ! signals during GPS Radio Occultation observations (Josep Aparicio et al.,2017)
2785 bstv(levIndexObs)=bstv(last_levIndexObs)*exp((-1._dp/6500._dp)*(a-last_a))-2*acos(a/((1._dp+prf%rst(ngpslev)*1e-6_dp)*prf%Rad))
2786 end if
2787
2788 end if
2789 end do
2790 end subroutine gps_bndopv1
2791
2792
2793!modgpsro_mod
2794
2795 subroutine gps_setupro
2796 implicit none
2797
2798 ! Locals:
2799 integer :: nulnam,ierr,fnom,fclos,SatID
2800
2801 ! Namelist variables for GPS-RO
2802 INTEGER :: LEVELGPSRO ! Data level to use (1 for bending angle, 2 for refractivity)
2803 INTEGER :: GPSRO_MAXPRFSIZE ! Maximal number of data that is expected from a profile (default 300)
2804 REAL(8) :: SURFMIN ! Minimum allowed distance to the model surface (default 0 m)
2805 REAL(8) :: HSFMIN ! Minimum allowed MSL height of an obs (default 0 m)
2806 REAL(8) :: HTPMAX ! Maximum allowed MSL height of an obs (default 70000 m)
2807 REAL(8) :: BGCKBAND ! Maximum allowed deviation abs(O-P)/P (default 0.05)
2808 REAL(8) :: HTPMAXER ! Maximum MSL height to evaluate the obs error (default to HTPMAX)
2809 REAL(4) :: WGPS(0:1023,4) ! WGPS values for each satellite sensor
2810 character(len=20) :: gpsroError ! key for using dynamic/static refractivity error estimation (default 'DYNAMIC')
2811 LOGICAL :: gpsroBNorm ! Choose to normalize based on B=H(x) (default=.True.), or approximate exponential reference
2812 LOGICAL :: gpsroEotvos ! Add an operator-only Eotvos correction to local gravity (shift of altitudes, default False)
2813 REAL(8) :: gpsroNsigma ! Factor applied to observation error for background departure check when gpsroBNorm is .true. (default 1.d6)
2814
2815 NAMELIST /NAMGPSRO/ LEVELGPSRO, GPSRO_MAXPRFSIZE, SURFMIN, HSFMIN, HTPMAX, HTPMAXER, &
2816 BGCKBAND, WGPS, gpsroError, gpsroBNorm, gpsroEotvos, gpsroNsigma
2817
2818 !
2819 ! Define default values:
2820 !
2821 LEVELGPSRO = gps_Level_RO_Ref
2822 GPSRO_MAXPRFSIZE = 300
2823 SURFMIN = 0.d0
2824 HSFMIN = 0.d0
2825 HTPMAX = 70000.d0
2826 HTPMAXER = -1.d0
2827 BGCKBAND = 0.05d0
2828 gpsroError = 'DYNAMIC'
2829 gpsroBNorm = .True.
2830 gpsroEotvos= .False.
2831 gpsroNsigma= 1000000.d0
2832 !
2833 ! Force a pre-NML default for the effective data weight of all
2834 ! GPSRO satellites. This array has rows 0-1023 (following BUFR element
2835 ! SATID), and 4 cols. The 4 parameters for each SATID are used to
2836 ! represent data correlation, a combined property of the satellite
2837 ! hardware and provider postprocessing.
2838 ! The default assumes no correlation.
2839 !
2840 WGPS = 0.
2841 WGPS(:,1) = 1.
2842 !
2843 ! Override with NML values:
2844 !
2845 nulnam=0
2846 ierr=fnom(nulnam,'./flnml','FTN+SEQ+R/O',0)
2847 read(nulnam,nml=NAMGPSRO,iostat=ierr)
2848 if(ierr.ne.0) call utl_abort('gps_setupro: Error reading namelist')
2849 !if(mmpi_myid.eq.0) write(*,nml=NAMGPSRO)
2850 ierr=fclos(nulnam)
2851 if (HTPMAXER < 0.0D0) HTPMAXER = HTPMAX
2852 gps_Level_RO = LEVELGPSRO
2853 gps_RO_MAXPRFSIZE = GPSRO_MAXPRFSIZE
2854 gps_SurfMin = SURFMIN
2855 gps_HsfMin = HSFMIN
2856 gps_HtpMax = HTPMAX
2857 gps_HtpMaxEr = HTPMAXER
2858 gps_BgckBand = BGCKBAND
2859 gps_roError = gpsroError
2860 gps_roBNorm = gpsroBNorm
2861 gps_WGPS = WGPS
2862 gps_gpsroEotvos = gpsroEotvos
2863 gps_roNsigma = gpsroNsigma
2864
2865 if(mmpi_myid.eq.0) then
2866 write(*,*)'NAMGPSRO',gps_Level_RO, gps_RO_MAXPRFSIZE, gps_SurfMin, gps_HsfMin, &
2867 gps_HtpMax, gps_HtpMaxEr, gps_BgckBand, trim(gps_roError), gps_roBNorm, gpsroEotvos
2868 do SatID = 0, 1023
2869 if (WGPS(SatID,2) /= 0.) then
2870 write(*,*)'WGPS', SatID, gps_WGPS(SatID, 1:4)
2871 end if
2872 end do
2873 end if
2874 end subroutine gps_setupro
2875
2876 integer function gps_iprofile_from_index(index)
2877 implicit none
2878
2879 ! Arguments:
2880 integer, intent(in) :: index
2881
2882 ! Locals:
2883 integer :: i
2884
2885 gps_iprofile_from_index=-1
2886 do i=1,gps_numROProfiles
2887 if (index.eq.gps_vRO_IndexPrf(i, 1)) then
2888 gps_iprofile_from_index=i
2889 return
2890 end if
2891 end do
2892 return
2893 end function gps_iprofile_from_index
2894
2895
2896!modgpsztd_mod
2897
2898 subroutine gps_setupgb
2899 !
2900 !:Purpose: Initialisation of ground-based GPS - to read and to initialize
2901 ! GB-GPS namelist parameters and print information on options
2902 ! selected.
2903 !
2904 implicit none
2905
2906 ! Locals:
2907 integer :: nulnam,ierr,fnom,fclos
2908
2909 ! Namelist variables for Ground-based GPS (ZTD)
2910 REAL(8) :: DZMIN ! Minimum DZ = Zobs-Zmod (m) for which DZ adjustment to ZTD will be made
2911 REAL(8) :: DZMAX = 1000.0D0 ! Maximum DZ (m) over which ZTD rejected due to topography (when LTOPOFILT = .TRUE.)
2912 REAL(8) :: YZTDERR ! If < 0 use errors in input files; if > 0 use value as constant error (m); if 0 compute error as f(ZWD)
2913 REAL(8) :: YSFERRWGT ! Scale factor for GPS surface met errors (account for time series obs with error correlations)
2914 REAL(8) :: YZDERRWGT ! Scale factor for GPS ZTD errors (account for time series obs with error correlations)
2915 LOGICAL :: LASSMET ! Choose to assimilate GPS Met surface P, T, T-Td
2916 LOGICAL :: LLBLMET ! Indicate that surface met data blacklisted for GPS sites close to surface weather stations.
2917 LOGICAL :: LBEVIS ! If .true. use Bevis(1994); if .false. use Rueger(2002) refractivity (k1,k2,k3) constants
2918 LOGICAL :: L1OBS ! Choose to select a single ZTD observation
2919 LOGICAL :: LTESTOP ! Choose to test ZTD observation operator (Omp and Bgck modes only)
2920 INTEGER :: IREFOPT ! 1 = conventional expression for N using k1,k2,k3; 2 = Aparicio & Laroche N (incl. compressibility)
2921 INTEGER :: IZTDOP ! 1 = use stored ZTD profiles to get ZTDmod; 2 = Vedel & Huang ZTD formulation: ZTDmod = ZHD(Pobs) + ZWD
2922
2923 NAMELIST /NAMGPSGB/ DZMIN, DZMAX, YZTDERR, LASSMET, YSFERRWGT, &
2924 LLBLMET, YZDERRWGT, LBEVIS, L1OBS, LTESTOP, IREFOPT, IZTDOP
2925
2926 !* . 1.1 Default values
2927 !! . --------------
2928
2929 DZMIN = 2.0D0
2930 DZMAX = 1000.0D0
2931 YZTDERR = 0.012D0
2932 LASSMET = .TRUE.
2933 YSFERRWGT = 1.0D0
2934 LLBLMET = .FALSE.
2935 YZDERRWGT = 1.0D0
2936 LBEVIS = .TRUE.
2937 IREFOPT = 1
2938 L1OBS = .FALSE.
2939 LTESTOP = .FALSE.
2940 IZTDOP = 1
2941
2942 nulnam=0
2943 ierr=fnom(nulnam,'./flnml','FTN+SEQ+R/O',0)
2944 read(nulnam,nml=NAMGPSGB,iostat=ierr)
2945 if(ierr.ne.0) call utl_abort('gps_setupgb: Error reading namelist')
2946 gps_gb_DZMIN = DZMIN
2947 gps_gb_DZMAX = DZMAX
2948 gps_gb_YZTDERR = YZTDERR
2949 gps_gb_LASSMET = LASSMET
2950 gps_gb_YSFERRWGT = YSFERRWGT
2951 gps_gb_LLBLMET = LLBLMET
2952 gps_gb_YZDERRWGT = YZDERRWGT
2953 gps_gb_LBEVIS = LBEVIS
2954 gps_gb_IREFOPT = IREFOPT
2955 gps_gb_L1OBS = L1OBS
2956 gps_gb_LTESTOP = LTESTOP
2957 gps_gb_IZTDOP = IZTDOP
2958 if(mmpi_myid.eq.0) write(*,nml=NAMGPSGB)
2959 ierr=fclos(nulnam)
2960
2961 IF (L1OBS.and.mmpi_myid.eq.0) THEN
2962 write(*,*)' '
2963 write(*,*)' ******************************************'
2964 write(*,*)' * GB-GPS OBSERVATIONS *'
2965 write(*,*)' * *'
2966 write(*,*)' * ONE OBSERVATION MODE *'
2967 write(*,*)' * *'
2968 write(*,*)' ******************************************'
2969 write(*,*)' '
2970 END IF
2971
2972 ! Options to fix/adjust model ZTD to observation height and
2973 ! assimilate GPS met data
2974
2975 if(mmpi_myid.eq.0) then
2976 write(*,*)' '
2977 write(*,*)' ******************************************'
2978 write(*,*)' * GB-GPS OBSERVATIONS *'
2979 write(*,*)' * DZ ADJUSTMENT IN gps_ztdopv IF DZ>DZMIN *'
2980 write(*,*)' * ZTD NOT ASSIM. IF DZ > DZMAX *'
2981 write(*,*)' * *'
2982 write(*,*)' ******************************************'
2983 write(*,*) ' '
2984 write(*,*) 'DZMIN, DZMAX = ', DZMIN, DZMAX
2985 write(*,*) ' '
2986
2987 IF (LASSMET) THEN
2988 IF ( LLBLMET ) THEN
2989 write(*,*)' '
2990 write(*,*)' *****************************************'
2991 write(*,*)' * GB-GPS OBSERVATIONS *'
2992 write(*,*)' * GPS MET DATA ARE ASSIMILATED *'
2993 write(*,*)' * BUT BLACKLISTED NEAR SYNO STNS *'
2994 write(*,*)' * *'
2995 write(*,*)' *****************************************'
2996 write(*,*) 'YSFERRWGT = ', YSFERRWGT
2997 write(*,*) 'YZDERRWGT = ', YZDERRWGT
2998 write(*,*) ' '
2999 ELSE
3000 write(*,*)' '
3001 write(*,*)' *****************************************'
3002 write(*,*)' * GB-GPS OBSERVATIONS *'
3003 write(*,*)' * GPS MET DATA ARE ASSIMILATED *'
3004 write(*,*)' * *'
3005 write(*,*)' *****************************************'
3006 write(*,*) 'YSFERRWGT = ', YSFERRWGT
3007 write(*,*) 'YZDERRWGT = ', YZDERRWGT
3008 write(*,*) ' '
3009 END IF
3010 ELSE
3011 write(*,*)' '
3012 write(*,*)' *****************************************'
3013 write(*,*)' * GB-GPS OBSERVATIONS *'
3014 write(*,*)' * GPS MET DATA ARE NOT ASSIMILATED *'
3015 write(*,*)' * *'
3016 write(*,*)' *****************************************'
3017 write(*,*) 'YZDERRWGT = ', YZDERRWGT
3018 write(*,*) ' '
3019 END IF
3020
3021 IF (YZTDERR .LT. 0.0D0) THEN
3022 write(*,*)' '
3023 write(*,*)' *****************************************'
3024 write(*,*)' * GB-GPS OBSERVATIONS *'
3025 write(*,*)' * ZTD OBSERVATION ERROR FROM FERR *'
3026 write(*,*)' * *'
3027 write(*,*)' *****************************************'
3028 ELSE IF (YZTDERR .GT. 0.0D0) THEN
3029 write(*,*)' '
3030 write(*,*)' *****************************************'
3031 write(*,*)' * GB-GPS OBSERVATIONS *'
3032 write(*,*)' * ZTD OBSERVATION ERROR IS FIXED *'
3033 write(*,*)' * *'
3034 write(*,*)' *****************************************'
3035 write(*,*)' '
3036 write(*,*)'YZTDERR (mm) = ', YZTDERR*1000.D0
3037 ELSE
3038 write(*,*)' '
3039 write(*,*)' *****************************************'
3040 write(*,*)' * GB-GPS OBSERVATIONS *'
3041 write(*,*)' * ZTD OBSERVATION ERROR IS FROM ZWD *'
3042 write(*,*)' * USING SD(O-P) STATS (REGRESSION) *'
3043 write(*,*)' * *'
3044 write(*,*)' *****************************************'
3045 write(*,*)' '
3046 END IF
3047
3048 IF (IREFOPT .EQ. 1) THEN
3049 IF (LBEVIS) THEN
3050 write(*,*)' '
3051 write(*,*)' *****************************************'
3052 write(*,*)' * GB-GPS OBSERVATIONS *'
3053 write(*,*)' * *'
3054 write(*,*)' * CONVENTIONAL REFACTIVITY N USING *'
3055 write(*,*)' * BEVIS 92 K1, K2, K3 TO COMPUTE ZTD *'
3056 write(*,*)' *****************************************'
3057 write(*,*)' '
3058 ELSE
3059 write(*,*)' '
3060 write(*,*)' *****************************************'
3061 write(*,*)' * GB-GPS OBSERVATIONS *'
3062 write(*,*)' * *'
3063 write(*,*)' * CONVENTIONAL REFACTIVITY N USING *'
3064 write(*,*)' * RUEGER 02 K1, K2, K3 TO COMPUTE ZTD *'
3065 write(*,*)' *****************************************'
3066 write(*,*)' '
3067 END IF
3068 IF (IZTDOP .EQ. 1) THEN
3069 write(*,*)' '
3070 write(*,*)' *****************************************'
3071 write(*,*)' * GB-GPS OBSERVATIONS *'
3072 write(*,*)' * *'
3073 write(*,*)' * NORMAL ZTD OPERATOR -- ZTD COMPUTED *'
3074 write(*,*)' * FROM ZTD(K) PROFILE *'
3075 write(*,*)' *****************************************'
3076 write(*,*)' '
3077 ELSE
3078 write(*,*)' '
3079 write(*,*)' *****************************************'
3080 write(*,*)' * GB-GPS OBSERVATIONS *'
3081 write(*,*)' * *'
3082 write(*,*)' * ORIGINAL OPERATOR -- ZTD = ZHD+ZWD *'
3083 write(*,*)' * VEDEL AND HUANG (2004) *'
3084 write(*,*)' *****************************************'
3085 write(*,*)' '
3086 END IF
3087 ELSE
3088 write(*,*)' '
3089 write(*,*)' *****************************************'
3090 write(*,*)' * GB-GPS OBSERVATIONS *'
3091 write(*,*)' * *'
3092 write(*,*)' * APARICIO & LAROCHE REFRACTIVITY N *'
3093 write(*,*)' * USED TO COMPUTE ZTD *'
3094 write(*,*)' *****************************************'
3095 write(*,*)' '
3096 END IF
3097
3098 end if
3099
3100 end subroutine gps_setupgb
3101
3102 integer function gps_iztd_from_index(index)
3103 implicit none
3104
3105 ! Arguments:
3106 integer, intent(in) :: index
3107
3108 ! Locals:
3109 integer :: i
3110
3111 gps_iztd_from_index = -1
3112 do i = 1, size(gps_ZTD_Index)
3113 if (index .eq. gps_ZTD_Index(i)) then
3114 gps_iztd_from_index = i
3115 return
3116 end if
3117 end do
3118 return
3119 end function gps_iztd_from_index
3120
3121end module gps_mod