20 use missing_values_mod
21 use fckit_log_module,
only : fckit_log
41 logical :: vert_interp_ops
44 real(kind_real) :: min_temp_grad
49 real(kind_real),
allocatable :: k(:,:)
77 logical(c_bool),
intent(in) :: vert_interp_ops
78 logical(c_bool),
intent(in) :: pseudo_ops
79 real(c_float),
intent(in) :: min_temp_grad
81 self % vert_interp_ops = vert_interp_ops
82 self % pseudo_ops = pseudo_ops
83 self % min_temp_grad = min_temp_grad
108 type(c_ptr),
value,
intent(in) :: obss
111 character(len=*),
parameter :: myname_=
"ufo_gnssro_refmetoffice_tlad_settraj"
114 character(max_string) :: err_msg
122 real(kind_real),
allocatable :: obs_height(:)
126 write(err_msg,*)
"TRACE: ufo_gnssro_refmetoffice_tlad_settraj: begin"
127 call fckit_log%info(err_msg)
135 if( p_temp%vals(1,1) < p_temp%vals(p_temp%nval,1) )
then
136 self%flip_it = .true.
138 self%flip_it = .false.
149 self % nlevp = prs % nval
150 self % nlevq = q % nval
151 self % nlocs = obsspace_get_nlocs(obss)
154 allocate(obs_height(self%nlocs))
155 call obsspace_get_db(obss,
"MetaData",
"obs_height", obs_height)
156 allocate(self % K(1:self%nlocs, 1:prs%nval + q%nval))
159 obs_loop:
do iobs = 1, self % nlocs
162 rho_heights % vals(:,iobs), &
163 theta_heights % vals(:,iobs), &
164 prs % vals(:,iobs), &
167 self % vert_interp_ops, &
168 self % min_temp_grad, &
170 obs_height(iobs:iobs), &
171 self % K(iobs:iobs,1:prs%nval+q%nval))
177 deallocate(obs_height)
204 real(kind_real),
intent(inout) :: hofx(:)
205 type(c_ptr),
value,
intent(in) :: obss
208 character(len=*),
parameter :: myname_=
"ufo_gnssro_refmetoffice_simobs_tl"
213 character(max_string) :: err_msg
216 real(kind_real),
allocatable :: x_d(:)
218 write(err_msg,*)
"TRACE: ufo_gnssro_refmetoffice_simobs_tl: begin"
219 call fckit_log%info(err_msg)
222 if (.not. self%ltraj)
then
223 write(err_msg,*) myname_,
' trajectory wasnt set!'
224 call abor1_ftn(err_msg)
228 if (geovals%nlocs /=
size(hofx))
then
229 write(err_msg,*) myname_,
' error: nlocs inconsistent!'
230 call abor1_ftn(err_msg)
239 allocate(x_d(1:prs_d%nval+q_d%nval))
241 obs_loop:
do iobs = 1, nlocs
243 x_d(1:prs_d%nval) = prs_d % vals(:,iobs)
244 x_d(prs_d%nval+1:prs_d%nval+q_d%nval) = q_d % vals(:,iobs)
245 hofx(iobs) = sum(self % K(iobs,:) * x_d)
251 write(err_msg,*)
"TRACE: ufo_gnssro_refmetoffice_simobs_tl: complete"
252 call fckit_log%info(err_msg)
276 use typesizes,
only: wp => eightbytereal
283 real(kind_real),
intent(in) :: hofx(:)
284 type(c_ptr),
value,
intent(in) :: obss
287 character(len=*),
parameter :: myname_=
"ufo_gnssro_refmetoffice_simobs_ad"
290 real(c_double) :: missing
294 real(kind_real),
allocatable :: x_d(:)
295 character(max_string) :: err_msg
297 write(err_msg,*)
"TRACE: ufo_gnssro_refmetoffice_simobs_ad: begin"
298 call fckit_log%info(err_msg)
301 if (.not. self%ltraj)
then
302 write(err_msg,*) myname_,
' trajectory wasnt set!'
303 call abor1_ftn(err_msg)
307 if (geovals%nlocs /=
size(hofx))
then
308 write(err_msg,*) myname_,
' error: nlocs inconsistent!'
309 call abor1_ftn(err_msg)
316 missing = missing_value(missing)
317 allocate(x_d(1:prs_d%nval + q_d%nval))
320 obs_loop:
do iobs = 1, self % nlocs
322 if (hofx(iobs) /= missing)
then
323 x_d = self % K(iobs,:) * hofx(iobs)
324 if (self%flip_it)
then
325 prs_d % vals(:,iobs) = prs_d % vals(:,iobs) + x_d(prs_d%nval:1:-1)
326 q_d % vals(:,iobs) = q_d % vals(:,iobs) + x_d(prs_d%nval+q_d%nval:prs_d%nval+1:-1)
328 prs_d % vals(:,iobs) = prs_d % vals(:,iobs) + x_d(1:prs_d%nval)
329 q_d % vals(:,iobs) = q_d % vals(:,iobs) + x_d(prs_d%nval+1:prs_d%nval+q_d%nval)
337 write(err_msg,*)
"TRACE: ufo_gnssro_refmetoffice_simobs_ad: complete"
338 call fckit_log%info(err_msg)
360 character(len=*),
parameter :: myname_=
"ufo_gnssro_refmetoffice_tlad_delete"
365 if (
allocated(self%K))
deallocate(self%K)
408 integer,
intent(in) :: nlevp
409 integer,
intent(in) :: nlevq
410 real(kind_real),
intent(in) :: za(:)
411 real(kind_real),
intent(in) :: zb(:)
412 real(kind_real),
intent(in) :: p(:)
413 real(kind_real),
intent(in) :: q(:)
414 logical,
intent(in) :: vert_interp_ops
415 logical,
intent(in) :: pseudo_ops
416 real(kind_real),
intent(in) :: min_temp_grad
417 integer,
intent(in) :: nobs
418 real(kind_real),
intent(in) :: zobs(:)
419 real(kind_real),
intent(out) :: Kmat(:,:)
424 real(kind_real) :: Exner(nlevp)
425 real(kind_real) :: Pb(nlevq)
426 real(kind_real) :: Tv(nlevq)
427 real(kind_real) :: T(nlevq)
428 real(kind_real) :: dExtheta_dPb(nlevq,nlevq)
429 real(kind_real),
ALLOCATABLE :: drefob_dPob(:,:)
430 real(kind_real),
ALLOCATABLE :: drefob_dTob(:,:)
431 real(kind_real),
ALLOCATABLE :: drefob_dqob(:,:)
432 real(kind_real),
ALLOCATABLE :: dqob_dqb(:,:)
433 real(kind_real),
ALLOCATABLE :: dTob_dTb(:,:)
434 real(kind_real),
ALLOCATABLE :: dPob_dT(:,:)
435 real(kind_real),
ALLOCATABLE :: dPob_dPb(:,:)
436 real(kind_real),
ALLOCATABLE :: dPob_dP(:,:)
437 real(kind_real),
ALLOCATABLE :: dTob_dP(:,:)
438 real(kind_real),
ALLOCATABLE :: dTb_dp(:,:)
440 real(kind_real) :: P_ob
441 real(kind_real) :: q_ob
442 real(kind_real) :: T_ob
443 real(kind_real) :: gamma
444 real(kind_real) :: beta
445 real(kind_real) :: Ndry
446 real(kind_real) :: Nwet
447 real(kind_real) :: refrac(nlevq)
448 real(kind_real) :: dEx_dP(nlevp,nlevp)
449 real(kind_real) :: dPb_dp(nlevq,nlevp)
450 real(kind_real) :: dTv_dExtheta(nlevq,nlevq)
451 real(kind_real) :: dTv_dEx(nlevq,nlevp)
452 real(kind_real) :: dT_dTv(nlevq,nlevq)
453 real(kind_real) :: dT_dq(nlevq,nlevq)
454 real(kind_real) :: dref_dPb(nlevq,nlevq)
455 real(kind_real) :: dref_dT(nlevq,nlevq)
456 real(kind_real) :: dref_dq(nlevq,nlevq)
457 real(kind_real) :: dNref_dref(nobs,nlevq)
458 real(kind_real) :: kmatP(nobs,nlevp)
459 real(kind_real) :: kmatq(nobs,nlevq)
460 real(kind_real) :: Nref(nobs)
461 real(kind_real) :: m1(nobs,nlevq)
462 real(kind_real) :: m2(nobs,nlevp)
463 real(kind_real) :: m3(nobs,nlevq)
464 real(kind_real) :: m4(nobs,nlevq)
465 real(kind_real) :: g_RB
466 real(kind_real) :: c_ZZ
467 real(kind_real) :: dPo_dT1
468 real(kind_real) :: dPo_dTo
469 real(kind_real) :: dTo_dT1
470 real(kind_real) :: dPo_dbeta
471 real(kind_real) :: dbeta_dT1
472 real(kind_real) :: dTo_dbeta
473 real(kind_real) :: dbeta_dT2
474 real(kind_real) :: dPo_dc
475 real(kind_real) :: dc_dT1
476 real(kind_real) :: dc_dbeta
477 real(kind_real) :: dc_dt2
478 real(kind_real) :: dPo_dP1
479 real(kind_real) :: dc_dP1
480 real(kind_real) :: dc_dP2
481 real(kind_real) :: model_height_diff
482 real(kind_real) :: obs_height_diff
483 real(kind_real) :: height_diff_ratio
490 ALLOCATE (drefob_dpob(nobs,nobs))
491 ALLOCATE (drefob_dtob(nobs,nobs))
492 ALLOCATE (drefob_dqob(nobs,nobs))
493 ALLOCATE (dqob_dqb(nobs,nlevq))
494 ALLOCATE (dtob_dtb(nobs,nlevq))
495 ALLOCATE (dpob_dt(nobs,nlevq))
496 ALLOCATE (dpob_dpb(nobs,nlevq))
497 ALLOCATE (dpob_dp(nobs,nlevp))
498 ALLOCATE (dtob_dp(nobs,nlevp))
499 ALLOCATE (dtb_dp(nlevq,nlevp))
501 drefob_dpob(:,:) = 0.0
502 drefob_dtob(:,:) = 0.0
503 drefob_dqob(:,:) = 0.0
535 dnref_dref(:,:) = 0.0
547 if (zobs(n) >= zb(nlevq) .or. zobs(n) == missing_value(zobs(n))) cycle
550 IF (zobs(n) < zb(i + 1))
EXIT
558 model_height_diff = zb(i + 1) - zb(i)
559 obs_height_diff = zobs(n) - zb(i)
560 height_diff_ratio = obs_height_diff / model_height_diff
563 IF (min(q(i), q(i + 1)) > 0.0)
THEN
565 gamma = log(q(i) / q(i + 1)) / model_height_diff
566 q_ob = q(i) * exp(-gamma * obs_height_diff)
568 dqob_dqb(n,i) = (q_ob / q(i)) * (1.0 - height_diff_ratio)
569 dqob_dqb(n,i + 1) = (q_ob / q(i + 1)) * height_diff_ratio
573 q_ob = q(i) + (q(i + 1) - q(i)) * height_diff_ratio
575 dqob_dqb(n,i) = (zb(i + 1) - zobs(n)) / model_height_diff
576 dqob_dqb(n,i + 1) = height_diff_ratio
580 beta = (t(i + 1) - t(i)) / model_height_diff
581 t_ob = t(i) + beta * obs_height_diff
583 dtob_dtb(n,i) = (zb(i + 1) - zobs(n)) / model_height_diff
584 dtob_dtb(n,i + 1) = height_diff_ratio
587 IF (abs(t(i + 1) - t(i)) > min_temp_grad)
THEN
588 c = ((pb(i + 1) / pb(i)) * (t(i + 1)/t(i)) ** (grav / (
rd * beta)) - 1.0) / model_height_diff
589 p_ob = (pb(i) * (t_ob / t(i)) ** &
590 (-grav / (
rd * beta))) * (1.0 + c * obs_height_diff)
594 p_ob = pb(i) * exp(log(pb(i + 1) / pb(i)) * height_diff_ratio)
598 g_rb = grav / (
rd * beta)
599 c_zz = c + 1.0 / model_height_diff
601 dpo_dt1 = (g_rb / t(i)) * p_ob
602 dpo_dto = -(g_rb / t_ob) * p_ob
603 dto_dt1 = dtob_dtb(n,i)
604 dpo_dbeta = (g_rb / beta) * log(t_ob / t(i)) * p_ob
605 dbeta_dt1 = -1.0 / model_height_diff
606 dto_dbeta = obs_height_diff
607 dbeta_dt2 = 1.0 / model_height_diff
610 IF (abs(t(i + 1) - t(i)) > min_temp_grad)
THEN
611 dpo_dc = obs_height_diff * pb(i) * (t_ob / t(i)) ** (-g_rb)
612 dc_dt1 = -(g_rb / (t(i))) * (c_zz)
613 dc_dbeta = -(g_rb / beta) * log(t(i + 1) / t(i)) * c_zz
614 dc_dt2 = (g_rb / t(i + 1)) * c_zz
615 dpo_dp1 = p_ob / pb(i)
616 dpob_dt(n,i) = dpo_dt1 + dpo_dto * dto_dt1 + dpo_dbeta * dbeta_dt1 + dpo_dc * &
617 (dc_dt1 + dc_dbeta * dbeta_dt1)
618 dpob_dt(n,i+1) = (dpo_dbeta + dpo_dto * dto_dbeta + dpo_dc * dc_dbeta) * &
619 dbeta_dt2 + dpo_dc * dc_dt2
621 dc_dp1 = -(1.0 / pb(i)) * c_zz
622 dc_dp2 = (1.0 / pb(i + 1)) * c_zz
624 dpob_dpb(n,i) = dpo_dp1 + dpo_dc * dc_dp1
625 dpob_dpb(n,i + 1) = dpo_dc * dc_dp2
627 dpob_dpb(n,i) = exp(log(pb(i + 1) / pb(i)) * height_diff_ratio) * &
628 (1.0 - height_diff_ratio)
629 dpob_dpb(n,i + 1) = (pb(i) / pb(i + 1)) * height_diff_ratio * &
630 exp(log(pb(i + 1) / pb(i)) * height_diff_ratio)
634 ndry = n_alpha * p_ob / t_ob
635 nwet = n_beta * p_ob * q_ob / (t_ob ** 2 * (mw_ratio + (1.0 - mw_ratio) * q_ob))
636 nref(n) = ndry + nwet
638 drefob_dpob(n,n) = nref(n) / p_ob
639 drefob_dtob(n,n) = -(ndry + 2.0 * nwet) / t_ob
640 drefob_dqob(n,n) = n_beta * p_ob * mw_ratio / (t_ob * (mw_ratio + (1.0 - mw_ratio) * q_ob)) ** 2
646 gamma = (zb(i + 1) - zobs(n)) / (zb(i + 1) - zb(i))
650 nref(n) = exp(gamma * log(refrac(i)) + beta * log(refrac(i + 1)))
652 dnref_dref(n,i) = nref(n) * gamma / refrac(i)
654 dnref_dref(n,i + 1) = nref(n) * beta / refrac(i + 1)
667 dpob_dp = matmul(dpob_dpb, dpb_dp) + matmul(dpob_dt, matmul(dt_dtv, matmul(dtv_dex, dex_dp)))
669 dtob_dp = matmul(dtob_dtb, matmul(dt_dtv, matmul(dtv_dex, dex_dp)))
673 kmatp(:,:) = matmul(drefob_dpob, dpob_dp) + matmul(drefob_dtob, dtob_dp)
677 kmatq(:,:) = matmul(drefob_dqob, dqob_dqb) + matmul(matmul(drefob_dtob, dtob_dtb), dt_dq) + &
678 matmul(matmul(drefob_dpob, dpob_dt), dt_dq)
684 kmatp(:,:) = matmul(dnref_dref, matmul(dref_dpb, dpb_dp))
687 m1(:,:) = matmul(dnref_dref, matmul(dref_dt, dt_dtv))
688 m2(:,:) = matmul(m1, dtv_dex)
689 kmatp(:,:) = kmatp(:,:) + matmul(m2, dex_dp)
692 m3(:,:) = matmul(m1, dtv_dextheta)
693 m4(:,:) = matmul(m3, dextheta_dpb)
694 kmatp(:,:) = kmatp(:,:) + matmul(m4,dpb_dp)
698 kmatq(:,:) = kmatq(:,:) + matmul(dnref_dref, matmul(dref_dt, dt_dq))
704 kmat(1:nobs, 1:nlevp) = 1.0e2 * kmatp(1:nobs, 1:nlevp)
706 kmat(1:nobs, nlevp+1:nlevp+nlevq) = 1.0e-3 * kmatq(1:nobs, 1:nlevq)
712 IF (
ALLOCATED (drefob_dpob))
DEALLOCATE (drefob_dpob)
713 IF (
ALLOCATED (drefob_dtob))
DEALLOCATE (drefob_dtob)
714 IF (
ALLOCATED (drefob_dqob))
DEALLOCATE (drefob_dqob)
715 IF (
ALLOCATED (dqob_dqb))
DEALLOCATE (dqob_dqb)
716 IF (
ALLOCATED (dtob_dtb))
DEALLOCATE (dtob_dtb)
717 IF (
ALLOCATED (dpob_dt))
DEALLOCATE (dpob_dt)
718 IF (
ALLOCATED (dpob_dpb))
DEALLOCATE (dpob_dpb)
719 IF (
ALLOCATED (dpob_dp))
DEALLOCATE (dpob_dp)
720 IF (
ALLOCATED (dtob_dp))
DEALLOCATE (dtob_dp)
721 IF (
ALLOCATED (dtb_dp))
DEALLOCATE (dtb_dp)
real(kind_real), parameter, public rd
type(registry_t), public ufo_geovals_registry
Linked list interface - defines registry_t type.
subroutine, public ufo_geovals_reorderzdir(self, varname, zdir)
subroutine, public ufo_geovals_copy(self, other)
Copy one GeoVaLs object into another.
subroutine, public ufo_geovals_get_var(self, varname, geoval)
Fortran module for gnssro refractivity Met Office's tangent linear and adjoint.
subroutine ufo_gnssro_refmetoffice_tlad_delete(self)
Tidy up the variables that are used for passing information.
subroutine ufo_gnssro_refmetoffice_tlad_setup(self, vert_interp_ops, pseudo_ops, min_temp_grad)
Set up the Met Office GNSS-RO refractivity TL/AD.
subroutine ufo_gnssro_refmetoffice_simobs_tl(self, geovals, hofx, obss)
Given an increment to the model state, calculate an increment to the observation.
subroutine ufo_gnssro_refmetoffice_simobs_ad(self, geovals, hofx, obss)
Given an increment to the observation, find the equivalent increment to the model state.
integer, parameter max_string
subroutine ufo_gnssro_refmetoffice_tlad_settraj(self, geovals, obss)
Set up the K-matrix for (Jacobian) for the Met Office's GNSS-RO refractivity operator.
subroutine jacobian_interface(nlevp, nlevq, za, zb, p, q, pseudo_ops, vert_interp_ops, min_temp_grad, nobs, zobs, Kmat)
Calculate the K-matrix used in the TL/AD.
Module for containing a general refractivity forward operator and its K-matrix.
subroutine ufo_refractivity_partial_derivatives(nlevP, nlevq, za, zb, P, q, vert_interp_ops, dT_dTv, dT_dq, dref_dPb, dref_dT, dref_dq, refractivity, T, Pb, dEx_dP, dExtheta_dPb, dTv_dExtheta, dPb_dP_local, dTv_dEx)
Calculate some partial derivatives of refractivity on model levels.
subroutine, public ufo_calculate_refractivity(nlevP, nlevq, za, zb, P, q, vert_interp_ops, pseudo_ops, min_temp_grad, refracerr, nRefLevels, refractivity, model_heights, temperature, interp_pressure)
Calculation of the refractivity from the pressure and specific humidity.
character(len=maxvarlen), parameter, public var_prsi
character(len=maxvarlen), parameter, public var_q
character(len=maxvarlen), parameter, public var_zi
character(len=maxvarlen), parameter, public var_z
Fortran module to perform linear interpolation.
type to hold interpolated field for one variable, one observation
type to hold interpolated fields required by the obs operators
Fortran derived type for gnssro trajectory.