2 SUBROUTINE ATMS_Spatial_Average(Num_Obs, NChanl, FOV, Time, BT_InOut, &
3 Scanline, Error_Status)
8 ! Declare passed variables
9 integer(i_kind) ,intent(in ) :: Num_Obs, NChanl
10 integer(i_kind) ,intent(in ) :: Fov(num_obs)
11 real(r_kind) ,intent(in ) :: Time(Num_Obs)
12 real(r_kind) ,intent(inout) :: BT_InOut(NChanl,Num_Obs)
13 integer(i_kind) ,intent( out) :: Scanline(Num_Obs)
14 integer(i_kind) ,intent( out) :: Error_Status
15 ! Declare local parameters
16 integer(i_kind), parameter :: atms1c_h_wmosatid=224
17 integer(i_kind), parameter :: lninfile=15
18 integer(i_kind), parameter :: max_fov=96
19 integer(i_kind), parameter :: max_obs=1000000
20 real(r_kind), parameter :: scan_interval = 8.0_r_kind/3.0_r_kind
21 ! Maximum number of channels
22 integer(i_kind), parameter :: MaxChans = 22
23 ! Minimum allowed BT as a function of channel number
24 real(r_kind), parameter :: MinBT(MaxChans) = &
25 (/ 120.0_r_kind, 120.0_r_kind, 190.0_r_kind, 190.0_r_kind, &
26 200.0_r_kind, 200.0_r_kind, 200.0_r_kind, 190.0_r_kind, &
27 190.0_r_kind, 180.0_r_kind, 180.0_r_kind, 180.0_r_kind, &
28 190.0_r_kind, 200.0_r_kind, 200.0_r_kind, 120.0_r_kind, &
29 120.0_r_kind, 120.0_r_kind, 150.0_r_kind, 170.0_r_kind, &
30 180.0_r_kind, 190.0_r_kind /)
31 ! Maximum allowed BT as a function of channel number
32 real(r_kind), parameter :: MaxBT(MaxChans) = &
33 (/ 320.0_r_kind, 320.0_r_kind, 300.0_r_kind, 300.0_r_kind, &
34 300.0_r_kind, 270.0_r_kind, 250.0_r_kind, 240.0_r_kind, &
35 240.0_r_kind, 250.0_r_kind, 250.0_r_kind, 270.0_r_kind, &
36 280.0_r_kind, 290.0_r_kind, 300.0_r_kind, 320.0_r_kind, &
37 320.0_r_kind, 300.0_r_kind, 300.0_r_kind, 300.0_r_kind, &
38 300.0_r_kind, 300.0_r_kind /)
40 ! Declare local variables
41 character(30) :: Cline
42 integer(i_kind) :: i, iscan, ifov, ichan, nchannels, wmosatid, version
43 integer(i_kind) :: ios, max_scan, mintime
44 integer(i_kind) :: nxaverage(nchanl), nyaverage(nchanl)
45 integer(i_Kind) :: channelnumber(nchanl),qc_dist(nchanl)
46 integer(i_kind), ALLOCATABLE :: scanline_back(:,:)
47 real(r_kind) :: sampling_dist, beamwidth(nchanl)
48 real(r_kind) :: newwidth(nchanl), cutoff(nchanl)
49 real(r_kind), allocatable, target :: bt_image(:,:,:)
50 real(r_kind), pointer :: bt_image1(:,:)
52 IF (NChanl > MaxChans) THEN
53 WRITE(0,*) 'Unexpected number of ATMS channels: ',nchanl
57 ! Read the beamwidth requirements
58 OPEN(lninfile,file='radiance_info/atms_beamwidth.txt',form='formatted',status='old', &
61 WRITE(*,*) 'Unable to open atms_beamwidth.txt'
66 read(lninfile,'(a30)',iostat=ios) Cline
67 DO WHILE (wmosatid /= atms1c_h_wmosatid .AND. ios == 0)
68 DO WHILE (Cline(1:1) == '#')
69 read(lninfile,'(a30)') Cline
71 READ(Cline,*) wmosatid
73 read(lninfile,'(a30)') Cline
74 DO WHILE (Cline(1:1) == '#')
75 read(lninfile,'(a30)') Cline
79 read(lninfile,'(a30)') Cline
80 DO WHILE (Cline(1:1) == '#')
81 read(lninfile,'(a30)') Cline
83 READ(Cline,*) sampling_dist
85 read(lninfile,'(a30)') Cline
86 DO WHILE (Cline(1:1) == '#')
87 read(lninfile,'(a30)') Cline
89 READ(Cline,*) nchannels
91 read(lninfile,'(a30)') Cline
92 if (nchannels > 0) then
94 read(lninfile,'(a30)') Cline
95 DO WHILE (Cline(1:1) == '#')
96 read(lninfile,'(a30)') Cline
98 READ(Cline,*) channelnumber(ichan),beamwidth(ichan), &
99 newwidth(ichan),cutoff(ichan),nxaverage(ichan), &
100 nyaverage(ichan), qc_dist(ichan)
103 read(lninfile,'(a30)',iostat=ios) Cline
105 IF (wmosatid /= atms1c_h_wmosatid) THEN
106 WRITE(*,*) 'ATMS_Spatial_Averaging: sat id not matched in atms_beamwidth.dat'
112 ! Determine scanline from time
113 MinTime = MINVAL(Time)
114 Scanline(:) = NINT((Time(1:Num_Obs)-MinTime)/Scan_Interval)+1
115 Max_Scan=MAXVAL(Scanline)
116 write(*,*) 'Max_Scan:',Max_Scan
118 ALLOCATE(BT_Image(Max_FOV,Max_Scan,nchanl))
119 ALLOCATE(Scanline_Back(Max_FOV,Max_Scan))
120 BT_Image(:,:,:) = 1000.0_r_kind
122 ScanLine_Back(:,:) = -1
124 bt_image(FOV(I),Scanline(I),:)=bt_inout(:,I)
125 Scanline_Back(FOV(I),Scanline(I))=I
130 bt_image1 => bt_image(:,:,ichan)
131 ! Set all scan positions to missing in a scanline if one is missing
133 if (ANY(bt_image1(:,iscan) > 500.0_r_kind)) &
134 bt_image1(:,iscan)=1000.0_r_kind
136 ! If the channel number is present in the channelnumber array we should process it
137 ! (otherwise bt_inout just keeps the same value):
138 IF (ANY(channelnumber(1:nchannels) == ichan)) THEN
139 CALL MODIFY_BEAMWIDTH ( max_fov, max_scan, bt_image1, &
140 sampling_dist, beamwidth(ichan), newwidth(ichan), &
141 cutoff(ichan), nxaverage(ichan), nyaverage(ichan), &
142 qc_dist(ichan), MinBT(Ichan), MaxBT(IChan), IOS)
147 IF (Scanline_Back(IFov, IScan) > 0) &
148 bt_inout(channelnumber(ichan),Scanline_Back(IFov, IScan)) = &
149 BT_Image1(ifov,iscan)
158 DEALLOCATE(BT_Image, Scanline_Back)
161 END Subroutine ATMS_Spatial_Average
163 SUBROUTINE MODIFY_BEAMWIDTH ( nx, ny, image, sampling_dist,&
164 beamwidth, newwidth, mtfcutoff, nxaverage, nyaverage, qc_dist, &
165 Minval, MaxVal, Error)
167 !-----------------------------------------
168 ! Name: $Id: modify_beamwidth.F 222 2010-08-11 14:39:09Z frna $
171 ! Manipulate the effective beam width of an image. For example, convert ATMS
172 ! to AMSU-A-like resolution while reducing the noise.
175 ! 1) Pad the image to a power of 2 in each dimension.
176 ! If FFT technique is to be used then:
177 ! 2) Assuming Gaussian beam shapes, calcluate the input and output Modulation
178 ! Transfer Functions (MTF).
179 ! 3) FFT image to frequency domain (2-D).
180 ! 4) Multiply by output MTF divided by input MTF. If a cut-off is specified
181 ! (when attempting to make the beam width narrower), attenuate further
182 ! by an exponential function - factor of 2 at the cutoff.
183 ! 5) FFT back to image domain
185 ! 6) Over-write the input image, with averaging if requested.
188 ! This software was developed within the context of the EUMETSAT Satellite
189 ! Application Facility on Numerical Weather Prediction (NWP SAF), under the
190 ! Cooperation Agreement dated 1 December 2006, between EUMETSAT and the
191 ! Met Office, UK, by one or more partners within the NWP SAF. The partners
192 ! in the NWP SAF are the Met Office, ECMWF, KNMI and MeteoFrance.
194 ! Copyright 2010, EUMETSAT, All Rights Reserved.
197 ! Version Date Comment
199 ! 1.0 22/07/2010 N.C.Atkinson
200 ! 1.1 21/11/2011 Convert to f90. A. Collard
203 ! FORTRAN 77, following AAPP standards
208 real(r_kind), parameter :: Missing_Value=-888888.0
209 INTEGER(I_KIND), PARAMETER :: nxmax=128 !Max number of spots per scan line
210 INTEGER(I_KIND), PARAMETER :: nymax=8192 !Max number of lines. Allows 6hrs of ATMS.
212 INTEGER(I_KIND), INTENT(IN) :: nx, ny !Size of image
213 REAL(R_KIND), INTENT(INOUT) :: image(nx,ny) !BT or radiance image
214 REAL(R_KIND), INTENT(IN) :: sampling_dist !typically degrees
215 REAL(R_KIND), INTENT(IN) :: beamwidth !ditto
216 REAL(R_KIND), INTENT(IN) :: newwidth !ditto
217 REAL(R_KIND), INTENT(IN) :: mtfcutoff !0.0 to 1.0
218 INTEGER(I_KIND), INTENT(IN) :: nxaverage !Number of samples to average (or zero)
219 INTEGER(I_KIND), INTENT(IN) :: nyaverage !Number of samples to average (or zero)
220 INTEGER(I_KIND), INTENT(IN) :: qc_dist !Number of samples around missing data to set to
221 REAL(R_KIND), INTENT(IN) :: maxval !BTs above this are considered missing
222 REAL(R_KIND), INTENT(IN) :: minval !BTs below this are considered missing
223 INTEGER(I_KIND), INTENT(OUT) :: Error !Error Status
226 INTEGER(I_KIND) :: nxpad, nypad, dx, dy
227 INTEGER(I_KIND) :: i,j,k,ix,iy, ii, jj
228 INTEGER(I_KIND) :: ifirst
229 INTEGER(I_KIND) :: xpow2, ypow2
230 INTEGER(I_KIND) :: nxav2, nyav2, naverage
231 INTEGER(I_KIND) :: deltax, minii, maxii, minjj, maxjj
232 REAL(R_KIND), ALLOCATABLE :: mtfxin(:),mtfxout(:)
233 REAL(R_KIND), ALLOCATABLE :: mtfyin(:),mtfyout(:)
234 REAL(R_KIND) :: mtfin,mtfout,mtf_constant
235 REAL(R_KIND), ALLOCATABLE :: mtfpad(:,:)
236 REAL(R_KIND), ALLOCATABLE :: imagepad(:,:)
237 REAL(R_KIND), ALLOCATABLE :: work(:)
238 REAL(R_KIND) :: f,df,factor
239 REAL(R_KIND) :: PI, LN2, LNcsquared
241 LOGICAL, ALLOCATABLE :: gooddata_map(:,:)
242 ! End of declarations
243 !-----------------------------------------
245 PI = 4.0_r_kind*atan(1.0)
246 LN2 = LOG(2.0_r_kind)
247 MTF_Constant=-(PI/(2*sampling_dist))**2/LN2
248 IF (mtfcutoff > 0.0_r_kind) LNcsquared = LOG(mtfcutoff)**2
251 naverage = nxaverage*nyaverage
253 !1) Pad the image up to the nearest power of 2 in each dimension, by reversing
254 !the points near the edge.
255 xpow2 = INT(LOG(nx*1.0_r_kind)/LN2 + 1.0_r_kind)
256 ypow2 = INT(LOG(ny*1.0_r_kind)/LN2 + 1.0_r_kind)
261 IF (nxpad > nxmax) THEN
262 write(*,*) 'ATMS_Spatial_Average: nx too large, maximum allowed value is ',nxmax-1
267 IF (nypad > nymax) THEN
268 write(*,*) 'ATMS_Spatial_Average: ny too large, maximum allowed value is ',nymax-1
272 ALLOCATE(mtfxin(nxpad),mtfxout(nxpad))
273 ALLOCATE(mtfyin(nypad),mtfyout(nypad))
274 ALLOCATE(mtfpad(nxpad,nypad))
275 ALLOCATE(imagepad(nxpad,nypad))
276 ALLOCATE(work(nypad))
277 ALLOCATE(gooddata_map(nxmax,nymax))
278 !Loop over scan positions
281 if (image(i-dx,j-dy) < minval) &
282 image(i-dx,j-dy) = minval - 1.0_r_kind
283 if (image(i-dx,j-dy) > maxval ) &
284 image(i-dx,j-dy) = maxval + 1.0_r_kind
285 imagepad(i,j) = image(i-dx,j-dy) !Take a copy of the input data
286 gooddata_map(i,j) = .TRUE. ! Initialised for step 6)
288 !Interpolate missing points in the along-track direction
293 IF (.not.missing) THEN
294 IF (imagepad(i,j) >= minval .AND. imagepad(i,j) <= maxval) THEN
300 IF (imagepad(i,j) >= minval .AND. imagepad(i,j) <= maxval) THEN !First good point
303 IF (ifirst == -1) THEN
305 imagepad(k,j) = imagepad(i,j) !Constant
309 factor = (i-k)*1.0_r_kind/(i-ifirst) !Interpolate
310 imagepad(k,j) = imagepad(ifirst,j)*factor + &
311 imagepad(i,j)*(1.0_r_kind-factor)
317 IF (missing) THEN !Last scan is missing
318 IF (ifirst >= 1) then
320 imagepad(k,j) = imagepad(ifirst,j) !Constant
324 !Continue padding the edges
326 imagepad(i,j) = imagepad(dx+dx+2-i,j)
329 imagepad(i,j) = imagepad(nx+dx+nx+dx-i,j)
334 imagepad(i,j) = imagepad(i,dy+dy+2-j)
339 imagepad(i,j) = imagepad(i,ny+dy+ny+dy-j)
342 !2) Compute the MTF modifications. Assume beams are Gaussian.
343 IF (newwidth > 0) THEN
344 df = 1.0_r_kind/nxpad
346 f = df*(i-1) !DC to Nyquist
347 mtfxin(i) = exp(MTF_Constant*(f*beamwidth)**2)
348 mtfxout(i) = exp(MTF_Constant*(f*newwidth)**2)
349 IF (i > 1 .AND. i < nxpad/2+1) THEN
350 mtfxin(nxpad-i+2) = mtfxin(i)
351 mtfxout(nxpad-i+2) = mtfxout(i)
354 df = 1.0_r_kind/nypad
356 f = df*(i-1) !DC to Nyquist
357 mtfyin(i) = exp(MTF_Constant*(f*beamwidth)**2)
358 mtfyout(i) = exp(MTF_Constant*(f*newwidth)**2)
359 IF (i > 1 .AND. i < nypad/2+1) THEN
360 mtfyin(nypad-i+2) = mtfyin(i)
361 mtfyout(nypad-i+2) = mtfyout(i)
366 mtfin = mtfxin(i)*mtfyin(j)
367 mtfout = mtfxout(i)*mtfyout(j)
368 if (mtfcutoff > 0.0_r_kind) THEN
369 mtfpad(i,j) = (mtfout * &
370 exp(-LN2/LNcsquared*(LOG(mtfout))**2))/mtfin
372 mtfpad(i,j) = mtfout/mtfin
376 !3) Fourier transform, line by line then column by column.
377 !After each FFT, points 1 to nxpad/2+1 contain the real part of the spectrum,
378 !the rest contain the imaginary part in reverse order.
380 CALL SFFTCF(imagepad(:,j),nxpad,xpow2)
384 work(j) = imagepad(i,j)
386 CALL SFFTCF(work,nypad,ypow2)
388 imagepad(i,j) = work(j)
391 !4) Multiply the spectrum by the MTF factor
394 imagepad(i,j) = imagepad(i,j)*mtfpad(i,j)
397 !5) Inverse Fourier transform, column by column then line by line
400 work(j) = imagepad(i,j)
402 CALL SFFTCB(work,nypad,ypow2)
404 imagepad(i,j) = work(j)
408 CALL SFFTCB(imagepad(:,j),nxpad,xpow2)
410 ENDIF !New width is specified
411 !6) Reset missing values in gooddata_map, based on qc_dist and the values
412 ! in the input image array
413 ! Set the ends of the image to missing in the along track direction
414 ! (doing the same across track will remove too much data)
415 gooddata_map(:,1:qc_dist)=.FALSE.
416 gooddata_map(:,ny-qc_dist+1:ny)=.FALSE.
420 IF (image(i,j) <= minval .OR. image(i,j) >= maxval ) THEN
421 minjj=max(j+dy-qc_dist,1)
422 maxjj=min(j+dy+qc_dist,nymax)
424 deltax=INT(SQRT(REAL(qc_dist**2 - (jj-j-dy)**2 )))
425 minii=max(i+dx-deltax,1)
426 maxii=min(i+dx+deltax,nxmax)
428 gooddata_map(ii,jj)=.FALSE.
434 !7) Over-write the input image (points that are not missing)
437 IF (gooddata_map(i+dx,j+dy)) THEN
438 IF (nxav2 == 0.0_r_kind .AND. nyav2 == 0) THEN
439 image(i,j) = imagepad(i+dx,j+dy)
441 image(i,j) = 0.0_r_kind !Do averaging
444 image(i,j) = image(i,j) + imagepad(i+dx+ix,j+dy+iy)
447 image(i,j) = image(i,j)/naverage
450 image(i,j) = missing_value
454 !8) Deallocate arrays
455 DEALLOCATE(mtfxin,mtfxout)
456 DEALLOCATE(mtfyin,mtfyout)
460 DEALLOCATE(gooddata_map)
462 END SUBROUTINE MODIFY_BEAMWIDTH
463 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
465 ! A real-valued, in place, split-radix FFT program
466 ! Real input and output in data array X
467 ! Length is N = 2 ** M
468 ! Decimation-in-time, cos/sin in second loop
470 ! [ Re(0), Re(1), ..., Re(N/2), Im(N/2-1), ..., Im(1) ]
473 ! X(k) = sum_{j=0}^{N-1} x(j)*exp(-2ijk*pi/N)
476 ! H.V. Sorensen, Rice University, Oct. 1985
478 ! Reference: H.V. Sorensen, D.L. Jones, M.T. Heideman, & C.S. Burrus;
479 ! Real-Valued Fast Fourier Transform Algorithms; IEEE
480 ! Trans. Acoust., Speech, Signal Process.; Vol ASSP-35,
481 ! June 1987, pp. 849-863.
483 ! This code was originally named RVFFT.
486 ! 21/11/2011 Converted to something resembling f90. A.Collard
489 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
491 SUBROUTINE SFFTCF( X, N, M )
494 REAL(R_KIND), PARAMETER :: SQRT2 = 1.4142135623730950488
495 REAL(R_KIND), PARAMETER :: TWOPI = 6.2831853071795864769
496 ! ... Scalar arguments ...
497 INTEGER(I_KIND), INTENT(IN) :: N, M
498 ! ... Array arguments ...
499 REAL(R_KIND), INTENT(INOUT) :: X(N)
500 ! ... Local scalars ...
501 INTEGER(I_KIND) J, I, K, IS, ID, I0, I1, I2, I3, I4, I5, I6, I7, I8
502 INTEGER(I_KIND) N1, N2, N4, N8
503 REAL(R_KIND) XT, R1, T1, T2, T3, T4, T5, T6
504 REAL(R_KIND) A, A3, E, CC1, SS1, CC3, SS3
506 ! ... Exe. statements ...
513 IF ( I >= J ) GOTO 101
518 102 IF ( K >= J ) GOTO 103
527 70 DO 60, I0 = IS, N, ID
535 IF ( IS < N ) GOTO 70
545 40 DO 38, I = IS, N-1, ID
551 X(I4) = X(I4) - X(I3)
554 IF ( N4 == 1 ) GOTO 38
559 T1 = ( X(I3) + X(I4) ) / SQRT2
560 T2 = ( X(I3) - X(I4) ) / SQRT2
568 IF ( IS < N ) GOTO 40
579 36 DO 30, I = IS, N-1, ID
588 T1 = X(I3) * CC1 + X(I7) * SS1
589 T2 = X(I7) * CC1 - X(I3) * SS1
590 T3 = X(I4) * CC3 + X(I8) * SS3
591 T4 = X(I8) * CC3 - X(I4) * SS3
611 IF ( IS < N ) GOTO 36
616 ! ... End of subroutine SFFTCF ...
618 END SUBROUTINE SFFTCF
619 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
621 ! A real-valued, in place, split-radix IFFT program
622 ! Hermitian symmetric input and real output in array X
623 ! Length is N = 2 ** M
624 ! Decimation-in-frequency, cos/sin in second loop
626 ! [ Re(0), Re(1), ..., Re(N/2), Im(N/2-1), ..., Im(1) ]
629 ! x(j) = (1/N) * sum_{k=0}^{N-1} X(k)*exp(2ijk*pi/N)
632 ! H.V. Sorensen, Rice University, Nov. 1985
634 ! Reference: H.V. Sorensen, D.L. Jones, M.T. Heideman, & C.S. Burrus;
635 ! Real-Valued Fast Fourier Transform Algorithms; IEEE
636 ! Trans. Acoust., Speech, Signal Process.; Vol ASSP-35,
637 ! June 1987, pp. 849-863.
639 ! This code was originally named IRVFFT.
642 ! 21/11/2011 Converted to something resembling f90. A.Collard
645 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
647 SUBROUTINE SFFTCB( X, N, M )
650 REAL(R_KIND), PARAMETER :: SQRT2 = 1.4142135623730950488
651 REAL(R_KIND), PARAMETER :: TWOPI = 6.2831853071795864769
652 ! ... Scalar arguments ...
653 INTEGER(I_KIND), INTENT(IN) :: N, M
654 ! ... Array arguments ...
655 REAL(R_KIND), INTENT(INOUT) :: X(N)
656 ! ... Local scalars ...
657 INTEGER(I_KIND) J, I, K, IS, ID, I0, I1, I2, I3, I4, I5, I6, I7, I8
658 INTEGER(I_KIND) N1, N2, N4, N8
659 REAL(R_KIND) XT, R1, T1, T2, T3, T4, T5
660 REAL(R_KIND) A, A3, E, CC1, SS1, CC3, SS3
662 ! ... Exe. statements ...
674 17 DO 15, I = IS, N-1, ID
680 X(I1) = X(I1) + X(I3)
682 X(I3) = T1 - 2 * X(I4)
683 X(I4) = T1 + 2 * X(I4)
684 IF ( N4 == 1 ) GOTO 15
689 T1 = ( X(I2) - X(I1) ) / SQRT2
690 T2 = ( X(I4) + X(I3) ) / SQRT2
691 X(I1) = X(I1) + X(I2)
692 X(I2) = X(I4) - X(I3)
693 X(I3) = 2 * ( - T2 - T1 )
694 X(I4) = 2 * ( -T2 + T1 )
698 IF ( IS < N-1 ) GOTO 17
709 40 DO 30, I = IS, N-1, ID
719 X(I1) = X(I1) + X(I6)
721 X(I5) = X(I2) + X(I5)
723 X(I6) = X(I8) - X(I3)
725 X(I2) = X(I4) - X(I7)
730 X(I3) = T5 * CC1 + T4 * SS1
731 X(I7) = - T4 * CC1 + T5 * SS1
732 X(I4) = T1 * CC3 - T2 * SS3
733 X(I8) = T2 * CC3 + T1 * SS3
737 IF ( IS < N-1 ) GOTO 40
743 70 DO 60, I0 = IS, N, ID
751 IF ( IS < N ) GOTO 70
756 IF ( I >= J ) GOTO 101
761 102 IF ( K >= J ) GOTO 103
767 XT = 1.0_r_kind / FLOAT( N )
773 ! ... End of subroutine SFFTCB ...
775 END SUBROUTINE SFFTCB