UFO
ufo_satcolumn_mod.F90
Go to the documentation of this file.
2 contains
3 
4 subroutine simulate_column_ob(nlayers_obs, nlayers_model, avgkernel_obs, &
5  prsi_obs, prsi_model, &
6  prsl_obs, prsl_model, temp_model, zi_model, &
7  profile_model, hofx, &
8  troplev_obs, airmass_tot, airmass_trop)
9  use kinds
12  implicit none
13  integer, intent(in ) :: nlayers_obs, nlayers_model
14  real(kind_real), intent(in ), dimension(nlayers_obs) :: avgkernel_obs
15  real(kind_real), intent(in ), dimension(nlayers_obs+1) :: prsi_obs
16  real(kind_real), intent(in ), dimension(nlayers_model+1) :: prsi_model
17  real(kind_real), intent(in ), dimension(nlayers_obs) :: prsl_obs
18  real(kind_real), intent(in ), dimension(nlayers_model) :: prsl_model
19  real(kind_real), intent(in ), dimension(nlayers_model) :: profile_model
20  real(kind_real), intent(in ), dimension(nlayers_model) :: temp_model
21  real(kind_real), intent(in ), dimension(nlayers_model+1) :: zi_model
22  real(kind_real), intent( out) :: hofx
23  real(kind_real), intent(in ), optional :: airmass_tot, airmass_trop
24  integer, intent(in ), optional :: troplev_obs
25  real(kind_real) :: airmass_ratio, lnp_ob, lnpi_ob, wf, dz, ptmp
26  real(kind_real), dimension(nlayers_obs) :: avgkernel_use
27  real(kind_real), dimension(nlayers_model) :: lnp_model, profile_model_use
28  real(kind_real), dimension(nlayers_model+1) :: lnpi_model
29  real(kind_real), dimension(nlayers_obs) :: profile_obslayers
30  real(kind_real), dimension(nlayers_obs+1) :: zi_obs
31  integer :: k, wi
32  logical :: troposphere
33 
34  troposphere = .false.
35  ! determine if we are computing a total column or just tropospheric column
36  if (present(airmass_tot) .and. present(airmass_trop) .and. present(troplev_obs)) then
37  troposphere = .true.
38  end if
39 
40  if (troposphere) then
41  ! compute air mass ratio and apply it to the averaging kernel
42  airmass_ratio = airmass_tot / airmass_trop
43  avgkernel_use = avgkernel_obs * airmass_ratio
44 
45  ! set all layers to zero above tropopause layer
46  avgkernel_use(troplev_obs+1:nlayers_obs) = zero
47  else
48  avgkernel_use = avgkernel_obs
49  end if
50 
51  ! need to convert from kg/kg to molec/m3 for each layer's T and P
52  profile_model_use = profile_model * ((avogadro*prsl_model)/(temp_model*gas_constant))
53 
54  ! need to interpolate model profile layers to observation layers
55  lnp_model = log(prsl_model)
56  do k=1,nlayers_obs
57  ptmp = max(prsl_obs(k), 1.0_kind_real)
58  lnp_ob = log(ptmp)
59  call vert_interp_weights(nlayers_model, lnp_ob, lnp_model, wi, wf)
60  call vert_interp_apply(nlayers_model, profile_model_use, &
61  profile_obslayers(k), wi, wf)
62  end do
63 
64  ! next, interpolate model z to observation interface levels
65  lnpi_model = log(prsi_model)
66  do k=1,nlayers_obs+1
67  ptmp = max(prsi_obs(k), 1.0_kind_real)
68  lnpi_ob = log(ptmp)
69  call vert_interp_weights(nlayers_model+1, lnpi_ob, lnpi_model, wi, wf)
70  call vert_interp_apply(nlayers_model+1, zi_model, &
71  zi_obs(k), wi, wf)
72  end do
73 
74  ! now, convert from molec/m3 to molec/cm2 using dz and 1e4
75  do k=1,nlayers_obs
76  dz = (zi_obs(k+1) - zi_obs(k))
77  profile_obslayers(k) = profile_obslayers(k) * dz ! convert to molec/m2
78  profile_obslayers(k) = profile_obslayers(k) / 1.0e4_kind_real ! to molec/cm2
79  end do
80 
81  ! compute hofx as column integral
82  hofx = zero
83  do k=1,nlayers_obs
84  hofx = hofx + (avgkernel_use(k) * profile_obslayers(k))
85  end do
86 
87 end subroutine simulate_column_ob
88 
89 subroutine simulate_column_ob_tl(nlayers_obs, nlayers_model, avgkernel_obs, &
90  prsi_obs, prsi_model, &
91  prsl_obs, prsl_model, temp_model, zi_model, &
92  profile_model, hofx, &
93  troplev_obs, airmass_tot, airmass_trop)
94  use kinds
97  implicit none
98  integer, intent(in ) :: nlayers_obs, nlayers_model
99  real(kind_real), intent(in ), dimension(nlayers_obs) :: avgkernel_obs
100  real(kind_real), intent(in ), dimension(nlayers_obs+1) :: prsi_obs
101  real(kind_real), intent(in ), dimension(nlayers_model+1) :: prsi_model
102  real(kind_real), intent(in ), dimension(nlayers_obs) :: prsl_obs
103  real(kind_real), intent(in ), dimension(nlayers_model) :: prsl_model
104  real(kind_real), intent(in ), dimension(nlayers_model) :: profile_model
105  real(kind_real), intent(in ), dimension(nlayers_model) :: temp_model
106  real(kind_real), intent(in ), dimension(nlayers_model+1) :: zi_model
107  real(kind_real), intent( out) :: hofx
108  real(kind_real), intent(in ), optional :: airmass_tot, airmass_trop
109  integer, intent(in ), optional :: troplev_obs
110  real(kind_real) :: airmass_ratio, lnp_ob, lnpi_ob, wf, dz, ptmp
111  real(kind_real), dimension(nlayers_obs) :: avgkernel_use
112  real(kind_real), dimension(nlayers_model) :: lnp_model, profile_model_use
113  real(kind_real), dimension(nlayers_model+1) :: lnpi_model
114  real(kind_real), dimension(nlayers_obs) :: profile_obslayers
115  real(kind_real), dimension(nlayers_obs+1) :: zi_obs
116  integer :: k, wi
117  logical :: troposphere
118 
119  troposphere = .false.
120  ! determine if we are computing a total column or just tropospheric column
121  if (present(airmass_tot) .and. present(airmass_trop) .and. present(troplev_obs)) then
122  troposphere = .true.
123  end if
124 
125  if (troposphere) then
126  ! compute air mass ratio and apply it to the averaging kernel
127  airmass_ratio = airmass_tot / airmass_trop
128  avgkernel_use = avgkernel_obs * airmass_ratio
129 
130  ! set all layers to zero above tropopause layer
131  avgkernel_use(troplev_obs+1:nlayers_obs) = zero
132  else
133  avgkernel_use = avgkernel_obs
134  end if
135 
136  ! need to convert from kg/kg to molec/m3 for each layer's T and P
137  profile_model_use = profile_model * ((avogadro*prsl_model)/(temp_model*gas_constant))
138 
139  ! need to interpolate model profile layers to observation layers
140  lnp_model = log(prsl_model)
141  do k=1,nlayers_obs
142  ptmp = max(prsl_obs(k), 1.0_kind_real)
143  lnp_ob = log(ptmp)
144  call vert_interp_weights(nlayers_model, lnp_ob, lnp_model, wi, wf)
145  call vert_interp_apply_tl(nlayers_model, profile_model_use, &
146  profile_obslayers(k), wi, wf)
147  end do
148 
149  ! next, interpolate model z to observation interface levels
150  lnpi_model = log(prsi_model)
151  do k=1,nlayers_obs+1
152  ptmp = max(prsi_obs(k), 1.0_kind_real)
153  lnpi_ob = log(ptmp)
154  call vert_interp_weights(nlayers_model+1, lnpi_ob, lnpi_model, wi, wf)
155  call vert_interp_apply_tl(nlayers_model+1, zi_model, &
156  zi_obs(k), wi, wf)
157  end do
158 
159  ! now, convert from molec/m3 to molec/cm2 using dz and 1e4
160  do k=1,nlayers_obs
161  dz = (zi_obs(k+1) - zi_obs(k))
162  profile_obslayers(k) = profile_obslayers(k) * dz ! convert to molec/m2
163  profile_obslayers(k) = profile_obslayers(k) / 1.0e4_kind_real ! to molec/cm2
164  end do
165 
166  ! compute hofx as column integral
167  hofx = zero
168  do k=1,nlayers_obs
169  hofx = hofx + (avgkernel_use(k) * profile_obslayers(k))
170  end do
171 
172  end subroutine simulate_column_ob_tl
173 
174 subroutine simulate_column_ob_ad(nlayers_obs, nlayers_model, avgkernel_obs, &
175  prsi_obs, prsi_model, &
176  prsl_obs, prsl_model, temp_model, zi_model, &
177  profile_model_ad, hofx_ad, &
178  troplev_obs, airmass_tot, airmass_trop)
179  use kinds
182  implicit none
183  integer, intent(in ) :: nlayers_obs, nlayers_model
184  real(kind_real), intent(in ), dimension(nlayers_obs) :: avgkernel_obs
185  real(kind_real), intent(in ), dimension(nlayers_obs+1) :: prsi_obs
186  real(kind_real), intent(in ), dimension(nlayers_model+1) :: prsi_model
187  real(kind_real), intent(in ), dimension(nlayers_obs) :: prsl_obs
188  real(kind_real), intent(in ), dimension(nlayers_model) :: prsl_model
189  real(kind_real), intent(inout), dimension(nlayers_model) :: profile_model_ad
190  real(kind_real), intent(in ), dimension(nlayers_model) :: temp_model
191  real(kind_real), intent(in ), dimension(nlayers_model+1) :: zi_model
192  real(kind_real), intent(in ) :: hofx_ad
193  real(kind_real), intent(in ), optional :: airmass_tot, airmass_trop
194  integer, intent(in ), optional :: troplev_obs
195  real(kind_real) :: airmass_ratio, lnp_ob, lnpi_ob, wf, dz, ptmp
196  real(kind_real), dimension(nlayers_obs) :: avgkernel_use
197  real(kind_real), dimension(nlayers_model) :: lnp_model, profile_model_use_ad
198  real(kind_real), dimension(nlayers_model+1) :: lnpi_model
199  real(kind_real), dimension(nlayers_obs) :: profile_obslayers_ad
200  real(kind_real), dimension(nlayers_obs+1) :: zi_obs
201  integer :: k, wi
202  logical :: troposphere
203  integer :: nlevs
204 
205  troposphere = .false.
206  ! determine if we are computing a total column or just tropospheric column
207  if (present(airmass_tot) .and. present(airmass_trop) .and. present(troplev_obs)) then
208  troposphere = .true.
209  end if
210 
211  if (troposphere) then
212  ! compute air mass ratio and apply it to the averaging kernel
213  airmass_ratio = airmass_tot / airmass_trop
214  avgkernel_use = avgkernel_obs * airmass_ratio
215 
216  ! set all layers to zero above tropopause layer
217  avgkernel_use(troplev_obs+1:nlayers_obs) = zero
218  else
219  avgkernel_use = avgkernel_obs
220  end if
221 
222  profile_obslayers_ad = zero
223  do k=nlayers_obs,1,-1
224  profile_obslayers_ad(k) = profile_obslayers_ad(k) + avgkernel_use(k) * hofx_ad
225  end do
226 
227  ! interpolate model z to observation interface levels
228  lnpi_model = log(prsi_model)
229  do k=nlayers_obs+1,1,-1
230  ptmp = max(prsi_obs(k), 1.0_kind_real)
231  lnpi_ob = log(ptmp)
232  call vert_interp_weights(nlayers_model+1, lnpi_ob, lnpi_model, wi, wf)
233  call vert_interp_apply_tl(nlayers_model+1, zi_model, &
234  zi_obs(k), wi, wf)
235  end do
236 
237  ! now, convert from molec/m3 to molec/m2 using dz and 1e4
238  do k=nlayers_obs,1,-1
239  dz = (zi_obs(k+1) - zi_obs(k))
240  profile_obslayers_ad(k) = profile_obslayers_ad(k) * dz ! to molec/m2
241  profile_obslayers_ad(k) = profile_obslayers_ad(k) / 1.0e4_kind_real ! to molec/cm2
242  end do
243 
244  profile_model_use_ad = zero
245  ! need to interpolate model profile layers to observation layers
246  lnp_model = log(prsl_model)
247  do k=nlayers_obs,1,-1
248  lnp_ob = log(prsl_obs(k))
249  call vert_interp_weights(nlayers_model, lnp_ob, lnp_model, wi, wf)
250  call vert_interp_apply_ad(nlayers_model, profile_model_use_ad, &
251  profile_obslayers_ad(k), wi, wf)
252  end do
253 
254  profile_model_ad = profile_model_use_ad * ((avogadro*prsl_model)/(temp_model*gas_constant))
255 
256  end subroutine simulate_column_ob_ad
257 
258 end module satcolumn_mod
subroutine simulate_column_ob_ad(nlayers_obs, nlayers_model, avgkernel_obs, prsi_obs, prsi_model, prsl_obs, prsl_model, temp_model, zi_model, profile_model_ad, hofx_ad, troplev_obs, airmass_tot, airmass_trop)
subroutine simulate_column_ob(nlayers_obs, nlayers_model, avgkernel_obs, prsi_obs, prsi_model, prsl_obs, prsl_model, temp_model, zi_model, profile_model, hofx, troplev_obs, airmass_tot, airmass_trop)
subroutine simulate_column_ob_tl(nlayers_obs, nlayers_model, avgkernel_obs, prsi_obs, prsi_model, prsl_obs, prsl_model, temp_model, zi_model, profile_model, hofx, troplev_obs, airmass_tot, airmass_trop)
real(kind_real), parameter, public avogadro
real(kind_real), parameter, public zero
real(kind_real), parameter, public gas_constant
Fortran module to perform linear interpolation.
Definition: vert_interp.F90:8
subroutine vert_interp_apply_ad(nlev, fvec_ad, f_ad, wi, wf)
subroutine vert_interp_weights(nlev, obl, vec, wi, wf)
Definition: vert_interp.F90:22
subroutine vert_interp_apply(nlev, fvec, f, wi, wf)
Definition: vert_interp.F90:73
subroutine vert_interp_apply_tl(nlev, fvec_tl, f_tl, wi, wf)
Definition: vert_interp.F90:92