New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
obs_oper.F90 in branches/UKMO/dev_r5518_obs_oper_update_sit/NEMOGCM/NEMO/OPA_SRC/OBS – NEMO

source: branches/UKMO/dev_r5518_obs_oper_update_sit/NEMOGCM/NEMO/OPA_SRC/OBS/obs_oper.F90

Last change on this file was 12609, checked in by dcarneir, 4 years ago

Making SIT changes in global configs to be compatible with build in shelf configs

File size: 38.9 KB
RevLine 
[2128]1MODULE obs_oper
2   !!======================================================================
3   !!                       ***  MODULE obs_oper  ***
4   !! Observation diagnostics: Observation operators for various observation
5   !!                          types
6   !!======================================================================
7
8   !!----------------------------------------------------------------------
[7992]9   !!   obs_prof_opt :    Compute the model counterpart of profile data
10   !!   obs_surf_opt :    Compute the model counterpart of surface data
[2128]11   !!----------------------------------------------------------------------
12
[7992]13   !! * Modules used
[2128]14   USE par_kind, ONLY : &         ! Precision variables
15      & wp
16   USE in_out_manager             ! I/O manager
17   USE obs_inter_sup              ! Interpolation support
[7992]18   USE obs_inter_h2d, ONLY : &    ! Horizontal interpolation to the obs pt
[2128]19      & obs_int_h2d, &
20      & obs_int_h2d_init
[7992]21   USE obs_averg_h2d, ONLY : &    ! Horizontal averaging to the obs footprint
22      & obs_avg_h2d, &
23      & obs_avg_h2d_init, &
24      & obs_max_fpsize
25   USE obs_inter_z1d, ONLY : &    ! Vertical interpolation to the obs pt
[2128]26      & obs_int_z1d,    &
27      & obs_int_z1d_spl
[7992]28   USE obs_const,  ONLY :    &    ! Obs fill value
29      & obfillflt
[2128]30   USE dom_oce,       ONLY : &
[7992]31      & glamt, glamf, &
32      & gphit, gphif
33   USE lib_mpp,       ONLY : &    ! Warning and stopping routines
[2715]34      & ctl_warn, ctl_stop
[7992]35   USE sbcdcy,        ONLY : &    ! For calculation of where it is night-time
36      & sbc_dcy, nday_qsr
37   USE obs_grid,      ONLY : & 
38      & obs_level_search     
[11932]39#if defined key_cice
40   USE ice_constants, ONLY : &    ! For conversion from sea ice freeboard to thickness
41      & rhos, rhoi, rhow
42#endif
[2128]43
44   IMPLICIT NONE
45
46   !! * Routine accessibility
47   PRIVATE
48
[7992]49   PUBLIC obs_prof_opt, &  ! Compute the model counterpart of profile obs
50      &   obs_surf_opt     ! Compute the model counterpart of surface obs
[2128]51
[7992]52   INTEGER, PARAMETER, PUBLIC :: &
53      & imaxavtypes = 20   ! Max number of daily avgd obs types
[2128]54
[2287]55   !!----------------------------------------------------------------------
56   !! NEMO/OPA 3.3 , NEMO Consortium (2010)
57   !! $Id$
58   !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
59   !!----------------------------------------------------------------------
60
[7992]61   !! * Substitutions
62#  include "domzgr_substitute.h90" 
[2128]63CONTAINS
64
[7992]65
[9306]66   SUBROUTINE obs_prof_opt( prodatqc, kt, kpi, kpj, kpk, &
67      &                     kit000, kdaystp, kvar,       &
[11468]68      &                     pvar, pclim,                 &
69      &                     pgdept, pgdepw, pmask,       & 
[9306]70      &                     plam, pphi,                  &
[7992]71      &                     k1dint, k2dint, kdailyavtypes )
72
[2128]73      !!-----------------------------------------------------------------------
74      !!
75      !!                     ***  ROUTINE obs_pro_opt  ***
76      !!
77      !! ** Purpose : Compute the model counterpart of profiles
78      !!              data by interpolating from the model grid to the
79      !!              observation point.
80      !!
81      !! ** Method  : Linearly interpolate to each observation point using
82      !!              the model values at the corners of the surrounding grid box.
83      !!
84      !!    First, a vertical profile of horizontally interpolated model
[7992]85      !!    now values is computed at the obs (lon, lat) point.
[2128]86      !!    Several horizontal interpolation schemes are available:
87      !!        - distance-weighted (great circle) (k2dint = 0)
88      !!        - distance-weighted (small angle)  (k2dint = 1)
89      !!        - bilinear (geographical grid)     (k2dint = 2)
90      !!        - bilinear (quadrilateral grid)    (k2dint = 3)
91      !!        - polynomial (quadrilateral grid)  (k2dint = 4)
92      !!
[7992]93      !!    Next, the vertical profile is interpolated to the
[2128]94      !!    data depth points. Two vertical interpolation schemes are
95      !!    available:
96      !!        - linear       (k1dint = 0)
97      !!        - Cubic spline (k1dint = 1)
98      !!
99      !!    For the cubic spline the 2nd derivative of the interpolating
100      !!    polynomial is computed before entering the vertical interpolation
101      !!    routine.
102      !!
[7992]103      !!    If the logical is switched on, the model equivalent is
[2128]104      !!    a daily mean model temperature field. So, we first compute
105      !!    the mean, then interpolate only at the end of the day.
106      !!
[7992]107      !!    Note: in situ temperature observations must be converted
[2128]108      !!    to potential temperature (the model variable) prior to
109      !!    assimilation.
110      !!
111      !! ** Action  :
112      !!
113      !! History :
114      !!      ! 97-11 (A. Weaver, S. Ricci, N. Daget)
115      !!      ! 06-03 (G. Smith) NEMOVAR migration
116      !!      ! 06-10 (A. Weaver) Cleanup
117      !!      ! 07-01 (K. Mogensen) Merge of temperature and salinity
118      !!      ! 07-03 (K. Mogensen) General handling of profiles
[7992]119      !!      ! 15-02 (M. Martin) Combined routine for all profile types
120      !!      ! 17-02 (M. Martin) Include generalised vertical coordinate changes
[2128]121      !!-----------------------------------------------------------------------
[7992]122
[2128]123      !! * Modules used
124      USE obs_profiles_def ! Definition of storage space for profile obs.
125
126      IMPLICIT NONE
127
128      !! * Arguments
[7992]129      TYPE(obs_prof), INTENT(INOUT) :: &
130         & prodatqc                  ! Subset of profile data passing QC
131      INTEGER, INTENT(IN) :: kt      ! Time step
132      INTEGER, INTENT(IN) :: kpi     ! Model grid parameters
[2128]133      INTEGER, INTENT(IN) :: kpj
134      INTEGER, INTENT(IN) :: kpk
[7992]135      INTEGER, INTENT(IN) :: kit000  ! Number of the first time step
136                                     !   (kit000-1 = restart time)
137      INTEGER, INTENT(IN) :: k1dint  ! Vertical interpolation type (see header)
138      INTEGER, INTENT(IN) :: k2dint  ! Horizontal interpolation type (see header)
139      INTEGER, INTENT(IN) :: kdaystp ! Number of time steps per day
[9306]140      INTEGER, INTENT(IN) :: kvar    ! Number of variable in prodatqc
[2128]141      REAL(KIND=wp), INTENT(IN), DIMENSION(kpi,kpj,kpk) :: &
[9306]142         & pvar,   &                 ! Model field for variable
[11468]143         & pclim,  &                 ! Climatology field for variable         
[9306]144         & pmask                     ! Land-sea mask for variable
[7992]145      REAL(KIND=wp), INTENT(IN), DIMENSION(kpi,kpj) :: &
[9306]146         & plam,   &                 ! Model longitudes for variable
147         & pphi                      ! Model latitudes for variable
[7992]148      REAL(KIND=wp), INTENT(IN), DIMENSION(kpi,kpj,kpk) :: & 
149         & pgdept, &                 ! Model array of depth T levels
150         & pgdepw                    ! Model array of depth W levels
[2128]151      INTEGER, DIMENSION(imaxavtypes), OPTIONAL :: &
[7992]152         & kdailyavtypes             ! Types for daily averages
153
[2128]154      !! * Local declarations
155      INTEGER ::   ji
156      INTEGER ::   jj
157      INTEGER ::   jk
158      INTEGER ::   jobs
159      INTEGER ::   inrc
160      INTEGER ::   ipro
161      INTEGER ::   idayend
162      INTEGER ::   ista
163      INTEGER ::   iend
164      INTEGER ::   iobs
[7992]165      INTEGER ::   iin, ijn, ikn, ik   ! looping indices over interpolation nodes
166      INTEGER ::   inum_obs
[2128]167      INTEGER, DIMENSION(imaxavtypes) :: &
168         & idailyavtypes
[7992]169      INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
[9306]170         & igrdi, &
171         & igrdj
[7992]172      INTEGER, ALLOCATABLE, DIMENSION(:) :: iv_indic
173
[2128]174      REAL(KIND=wp) :: zlam
175      REAL(KIND=wp) :: zphi
176      REAL(KIND=wp) :: zdaystp
177      REAL(KIND=wp), DIMENSION(kpk) :: &
178         & zobsk,    &
[11468]179         & zobs2k,   &
180         & zclm2k         
[7992]181      REAL(KIND=wp), DIMENSION(2,2,1) :: &
182         & zweig1, &
[2128]183         & zweig
184      REAL(wp), DIMENSION(:,:,:,:), ALLOCATABLE :: &
[9306]185         & zmask,  &
[11468]186         & zclim,  &         
[9306]187         & zint,   &
188         & zinm,   &
[7992]189         & zgdept, & 
190         & zgdepw
[2128]191      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
[9306]192         & zglam,  &
193         & zgphi
194      REAL(KIND=wp), DIMENSION(1) :: zmsk
[7992]195      REAL(KIND=wp), DIMENSION(:,:,:), ALLOCATABLE :: interp_corner
[11468]196      REAL(KIND=wp), DIMENSION(:,:,:), ALLOCATABLE :: interp_corner_clim
197     
[7992]198      LOGICAL :: ld_dailyav
199
[2128]200      !------------------------------------------------------------------------
201      ! Local initialization
202      !------------------------------------------------------------------------
[7992]203      ! Record and data counters
[2128]204      inrc = kt - kit000 + 2
205      ipro = prodatqc%npstp(inrc)
[7992]206
[2128]207      ! Daily average types
[7992]208      ld_dailyav = .FALSE.
[2128]209      IF ( PRESENT(kdailyavtypes) ) THEN
210         idailyavtypes(:) = kdailyavtypes(:)
[7992]211         IF ( ANY (idailyavtypes(:) /= -1) ) ld_dailyav = .TRUE.
[2128]212      ELSE
213         idailyavtypes(:) = -1
214      ENDIF
215
[7992]216      ! Daily means are calculated for values over timesteps:
217      !  [1 <= kt <= kdaystp], [kdaystp+1 <= kt <= 2*kdaystp], ...
[2128]218      idayend = MOD( kt - kit000 + 1, kdaystp )
219
[7992]220      IF ( ld_dailyav ) THEN
221
222         ! Initialize daily mean for first timestep of the day
223         IF ( idayend == 1 .OR. kt == 0 ) THEN
224            DO jk = 1, jpk
225               DO jj = 1, jpj
226                  DO ji = 1, jpi
[9306]227                     prodatqc%vdmean(ji,jj,jk,kvar) = 0.0
[7992]228                  END DO
[2128]229               END DO
230            END DO
[7992]231         ENDIF
[2128]232
233         DO jk = 1, jpk
234            DO jj = 1, jpj
235               DO ji = 1, jpi
[9306]236                  ! Increment field for computing daily mean
237                  prodatqc%vdmean(ji,jj,jk,kvar) = prodatqc%vdmean(ji,jj,jk,kvar) &
238                     &                           + pvar(ji,jj,jk)
[2128]239               END DO
240            END DO
241         END DO
[7992]242
243         ! Compute the daily mean at the end of day
244         zdaystp = 1.0 / REAL( kdaystp )
245         IF ( idayend == 0 ) THEN
246            IF (lwp) WRITE(numout,*) 'Calculating prodatqc%vdmean on time-step: ',kt
247            CALL FLUSH(numout)
248            DO jk = 1, jpk
249               DO jj = 1, jpj
250                  DO ji = 1, jpi
[9306]251                     prodatqc%vdmean(ji,jj,jk,kvar) = prodatqc%vdmean(ji,jj,jk,kvar) &
252                        &                           * zdaystp
[7992]253                  END DO
254               END DO
255            END DO
256         ENDIF
257
[2128]258      ENDIF
259
260      ! Get the data for interpolation
261      ALLOCATE( &
[9306]262         & igrdi(2,2,ipro),       &
263         & igrdj(2,2,ipro),       &
264         & zglam(2,2,ipro),       &
265         & zgphi(2,2,ipro),       &
266         & zmask(2,2,kpk,ipro),   &
267         & zint(2,2,kpk,ipro),    &
[7992]268         & zgdept(2,2,kpk,ipro),  & 
269         & zgdepw(2,2,kpk,ipro)   & 
[2128]270         & )
271
[11468]272      IF ( prodatqc%lclim ) ALLOCATE( zclim(2,2,kpk,ipro) )
273
[2128]274      DO jobs = prodatqc%nprofup + 1, prodatqc%nprofup + ipro
275         iobs = jobs - prodatqc%nprofup
[9306]276         igrdi(1,1,iobs) = prodatqc%mi(jobs,kvar)-1
277         igrdj(1,1,iobs) = prodatqc%mj(jobs,kvar)-1
278         igrdi(1,2,iobs) = prodatqc%mi(jobs,kvar)-1
279         igrdj(1,2,iobs) = prodatqc%mj(jobs,kvar)
280         igrdi(2,1,iobs) = prodatqc%mi(jobs,kvar)
281         igrdj(2,1,iobs) = prodatqc%mj(jobs,kvar)-1
282         igrdi(2,2,iobs) = prodatqc%mi(jobs,kvar)
283         igrdj(2,2,iobs) = prodatqc%mj(jobs,kvar)
[2128]284      END DO
285
[7992]286      ! Initialise depth arrays
287      zgdept(:,:,:,:) = 0.0
288      zgdepw(:,:,:,:) = 0.0
[2128]289
[9306]290      CALL obs_int_comm_2d( 2, 2, ipro, kpi, kpj, igrdi, igrdj, plam, zglam )
291      CALL obs_int_comm_2d( 2, 2, ipro, kpi, kpj, igrdi, igrdj, pphi, zgphi )
292      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pmask, zmask )
293      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pvar,   zint )
[7992]294
[9306]295      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pgdept, zgdept ) 
296      CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pgdepw, zgdepw ) 
[7992]297
[11468]298      IF ( prodatqc%lclim ) THEN
299         CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, pclim, zclim )           
300      ENDIF 
301     
[2128]302      ! At the end of the day also get interpolated means
[7992]303      IF ( ld_dailyav .AND. idayend == 0 ) THEN
[2128]304
[9306]305         ALLOCATE( zinm(2,2,kpk,ipro) )
[2128]306
[9306]307         CALL obs_int_comm_3d( 2, 2, ipro, kpi, kpj, kpk, igrdi, igrdj, &
308            &                  prodatqc%vdmean(:,:,:,kvar), zinm )
[2128]309
310      ENDIF
311
[7992]312      ! Return if no observations to process
313      ! Has to be done after comm commands to ensure processors
314      ! stay in sync
315      IF ( ipro == 0 ) RETURN
316
[2128]317      DO jobs = prodatqc%nprofup + 1, prodatqc%nprofup + ipro
318
319         iobs = jobs - prodatqc%nprofup
320
321         IF ( kt /= prodatqc%mstp(jobs) ) THEN
[7992]322
[2128]323            IF(lwp) THEN
324               WRITE(numout,*)
325               WRITE(numout,*) ' E R R O R : Observation',              &
326                  &            ' time step is not consistent with the', &
327                  &            ' model time step'
328               WRITE(numout,*) ' ========='
329               WRITE(numout,*)
330               WRITE(numout,*) ' Record  = ', jobs,                    &
331                  &            ' kt      = ', kt,                      &
332                  &            ' mstp    = ', prodatqc%mstp(jobs), &
333                  &            ' ntyp    = ', prodatqc%ntyp(jobs)
334            ENDIF
335            CALL ctl_stop( 'obs_pro_opt', 'Inconsistent time' )
336         ENDIF
[7992]337
[2128]338         zlam = prodatqc%rlam(jobs)
339         zphi = prodatqc%rphi(jobs)
340
[7992]341         ! Horizontal weights
342         ! Masked values are calculated later. 
[9306]343         IF ( prodatqc%npvend(jobs,kvar) > 0 ) THEN
[2128]344
[7992]345            CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi,     &
[9306]346               &                   zglam(:,:,iobs), zgphi(:,:,iobs), &
347               &                   zmask(:,:,1,iobs), zweig1, zmsk )
[2128]348
349         ENDIF
350
[9306]351         IF ( prodatqc%npvend(jobs,kvar) > 0 ) THEN
[7992]352
[2128]353            zobsk(:) = obfillflt
354
[7992]355            IF ( ANY (idailyavtypes(:) == prodatqc%ntyp(jobs)) ) THEN
[2128]356
357               IF ( idayend == 0 )  THEN
[7992]358                  ! Daily averaged data
[2128]359
[7992]360                  ! vertically interpolate all 4 corners
[9306]361                  ista = prodatqc%npvsta(jobs,kvar) 
362                  iend = prodatqc%npvend(jobs,kvar) 
[7992]363                  inum_obs = iend - ista + 1 
364                  ALLOCATE(interp_corner(2,2,inum_obs),iv_indic(inum_obs)) 
[11468]365                  IF ( prodatqc%lclim ) ALLOCATE( interp_corner_clim(2,2,inum_obs) )
366                 
[7992]367                  DO iin=1,2 
368                     DO ijn=1,2 
[2128]369
[7992]370                        IF ( k1dint == 1 ) THEN
371                           CALL obs_int_z1d_spl( kpk, & 
[9306]372                              &     zinm(iin,ijn,:,iobs), & 
[7992]373                              &     zobs2k, zgdept(iin,ijn,:,iobs), & 
[9306]374                              &     zmask(iin,ijn,:,iobs)) 
[11468]375
376                           IF ( prodatqc%lclim ) THEN
377                              CALL obs_int_z1d_spl( kpk, & 
378                                 &     zclim(iin,ijn,:,iobs), & 
379                                 &     zclm2k, zgdept(iin,ijn,:,iobs), & 
380                                 &     zmask(iin,ijn,:,iobs)) 
381                           ENDIF
382
[7992]383                        ENDIF
384       
385                        CALL obs_level_search(kpk, & 
386                           &    zgdept(iin,ijn,:,iobs), & 
[9306]387                           &    inum_obs, prodatqc%var(kvar)%vdep(ista:iend), & 
[7992]388                           &    iv_indic) 
[2128]389
[7992]390                        CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs, & 
[9306]391                           &    prodatqc%var(kvar)%vdep(ista:iend), & 
392                           &    zinm(iin,ijn,:,iobs), & 
[7992]393                           &    zobs2k, interp_corner(iin,ijn,:), & 
394                           &    zgdept(iin,ijn,:,iobs), & 
[9306]395                           &    zmask(iin,ijn,:,iobs)) 
[11468]396
397                        IF ( prodatqc%lclim ) THEN
398                           CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs, & 
399                              &    prodatqc%var(kvar)%vdep(ista:iend), & 
400                              &    zclim(iin,ijn,:,iobs), & 
401                              &    zclm2k, interp_corner_clim(iin,ijn,:), & 
402                              &    zgdept(iin,ijn,:,iobs), & 
403                              &    zmask(iin,ijn,:,iobs)) 
404                        ENDIF
405                       
[7992]406                     ENDDO 
407                  ENDDO 
[2128]408
[7992]409               ENDIF !idayend
[2128]410
[7992]411            ELSE   
[2128]412
[7992]413               ! Point data
414     
415               ! vertically interpolate all 4 corners
[9306]416               ista = prodatqc%npvsta(jobs,kvar) 
417               iend = prodatqc%npvend(jobs,kvar) 
[7992]418               inum_obs = iend - ista + 1 
419               ALLOCATE(interp_corner(2,2,inum_obs), iv_indic(inum_obs)) 
[11468]420               IF ( prodatqc%lclim ) ALLOCATE( interp_corner_clim(2,2,inum_obs) )                 
[7992]421               DO iin=1,2 
422                  DO ijn=1,2 
423                   
424                     IF ( k1dint == 1 ) THEN
425                        CALL obs_int_z1d_spl( kpk, & 
[9306]426                           &    zint(iin,ijn,:,iobs),& 
[7992]427                           &    zobs2k, zgdept(iin,ijn,:,iobs), & 
[9306]428                           &    zmask(iin,ijn,:,iobs)) 
[11468]429
430                        IF ( prodatqc%lclim ) THEN
431                           CALL obs_int_z1d_spl( kpk, & 
432                              &    zclim(iin,ijn,:,iobs),& 
433                              &    zclm2k, zgdept(iin,ijn,:,iobs), & 
434                              &    zmask(iin,ijn,:,iobs)) 
435                        ENDIF
[7992]436 
437                     ENDIF
438       
439                     CALL obs_level_search(kpk, & 
440                         &        zgdept(iin,ijn,:,iobs),& 
[9306]441                         &        inum_obs, prodatqc%var(kvar)%vdep(ista:iend), & 
[7992]442                         &        iv_indic) 
[2128]443
[7992]444                     CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs,     & 
[9306]445                         &          prodatqc%var(kvar)%vdep(ista:iend),     & 
446                         &          zint(iin,ijn,:,iobs),            & 
[7992]447                         &          zobs2k,interp_corner(iin,ijn,:), & 
448                         &          zgdept(iin,ijn,:,iobs),         & 
[9306]449                         &          zmask(iin,ijn,:,iobs) )     
[11468]450
451                     IF ( prodatqc%lclim ) THEN
452                        CALL obs_int_z1d(kpk, iv_indic, k1dint, inum_obs,     & 
453                            &          prodatqc%var(kvar)%vdep(ista:iend),     & 
454                            &          zclim(iin,ijn,:,iobs),            & 
455                            &          zclm2k,interp_corner_clim(iin,ijn,:), & 
456                            &          zgdept(iin,ijn,:,iobs),         & 
457                            &          zmask(iin,ijn,:,iobs) )   
458                     ENDIF   
[7992]459         
460                  ENDDO 
461               ENDDO 
462             
463            ENDIF 
[2128]464
[7992]465            !-------------------------------------------------------------
466            ! Compute the horizontal interpolation for every profile level
467            !-------------------------------------------------------------
468             
469            DO ikn=1,inum_obs 
470               iend=ista+ikn-1
[2128]471                 
[7992]472               zweig(:,:,1) = 0._wp 
473   
474               ! This code forces the horizontal weights to be 
475               ! zero IF the observation is below the bottom of the 
476               ! corners of the interpolation nodes, Or if it is in 
477               ! the mask. This is important for observations near 
478               ! steep bathymetry
479               DO iin=1,2 
480                  DO ijn=1,2 
481     
[9306]482                     depth_loop: DO ik=kpk,2,-1 
483                        IF(zmask(iin,ijn,ik-1,iobs ) > 0.9 )THEN   
[7992]484                           
485                           zweig(iin,ijn,1) = & 
486                              & zweig1(iin,ijn,1) * & 
487                              & MAX( SIGN(1._wp,(zgdepw(iin,ijn,ik,iobs) ) & 
[9306]488                              &  - prodatqc%var(kvar)%vdep(iend)),0._wp) 
[7992]489                           
[9306]490                           EXIT depth_loop
[2128]491
[7992]492                        ENDIF
[2128]493
[9306]494                     ENDDO depth_loop
[7992]495     
496                  ENDDO 
497               ENDDO 
498   
499               CALL obs_int_h2d( 1, 1, zweig, interp_corner(:,:,ikn), & 
[9306]500                  &              prodatqc%var(kvar)%vmod(iend:iend) ) 
[2128]501
[11468]502               IF ( prodatqc%lclim ) THEN
503                  CALL obs_int_h2d( 1, 1, zweig, interp_corner_clim(:,:,ikn), & 
504                     &              prodatqc%var(kvar)%vclm(iend:iend) )
505               ENDIF
506
[7992]507                  ! Set QC flag for any observations found below the bottom
508                  ! needed as the check here is more strict than that in obs_prep
[9306]509               IF (sum(zweig) == 0.0_wp) prodatqc%var(kvar)%nvqc(iend:iend)=4
[7992]510 
511            ENDDO 
512 
513            DEALLOCATE(interp_corner,iv_indic) 
[11468]514            IF ( prodatqc%lclim ) DEALLOCATE( interp_corner_clim )         
515             
[9306]516         ENDIF
[2128]517
[7992]518      ENDDO
[2128]519
520      ! Deallocate the data for interpolation
[9306]521      DEALLOCATE(  &
522         & igrdi,  &
523         & igrdj,  &
524         & zglam,  &
525         & zgphi,  &
526         & zmask,  &
527         & zint,   &
[7992]528         & zgdept, &
529         & zgdepw  &
[2128]530         & )
531
[11468]532      IF ( prodatqc%lclim ) DEALLOCATE( zclim )
533     
[7992]534      ! At the end of the day also get interpolated means
535      IF ( ld_dailyav .AND. idayend == 0 ) THEN
[9306]536         DEALLOCATE( zinm )
[7992]537      ENDIF
[2128]538
[9306]539      IF ( kvar == prodatqc%nvar ) THEN
540         prodatqc%nprofup = prodatqc%nprofup + ipro 
541      ENDIF
[2128]542
[7992]543   END SUBROUTINE obs_prof_opt
544
545   SUBROUTINE obs_surf_opt( surfdataqc, kt, kpi, kpj,            &
[11468]546      &                     kit000, kdaystp, psurf, pclim, psurfmask,   &
[7992]547      &                     k2dint, ldnightav, plamscl, pphiscl, &
[12380]548      &                     lindegrees, kmeanstp )
[7992]549
[2128]550      !!-----------------------------------------------------------------------
551      !!
[7992]552      !!                     ***  ROUTINE obs_surf_opt  ***
[2128]553      !!
[7992]554      !! ** Purpose : Compute the model counterpart of surface
[2128]555      !!              data by interpolating from the model grid to the
556      !!              observation point.
557      !!
558      !! ** Method  : Linearly interpolate to each observation point using
559      !!              the model values at the corners of the surrounding grid box.
560      !!
[7992]561      !!    The new model value is first computed at the obs (lon, lat) point.
[2128]562      !!
563      !!    Several horizontal interpolation schemes are available:
564      !!        - distance-weighted (great circle) (k2dint = 0)
565      !!        - distance-weighted (small angle)  (k2dint = 1)
566      !!        - bilinear (geographical grid)     (k2dint = 2)
567      !!        - bilinear (quadrilateral grid)    (k2dint = 3)
568      !!        - polynomial (quadrilateral grid)  (k2dint = 4)
569      !!
[7992]570      !!    Two horizontal averaging schemes are also available:
571      !!        - weighted radial footprint        (k2dint = 5)
572      !!        - weighted rectangular footprint   (k2dint = 6)
[2128]573      !!
[7992]574      !!
[2128]575      !! ** Action  :
576      !!
577      !! History :
[7992]578      !!      ! 07-03 (A. Weaver)
579      !!      ! 15-02 (M. Martin) Combined routine for surface types
580      !!      ! 17-03 (M. Martin) Added horizontal averaging options
[2128]581      !!-----------------------------------------------------------------------
582
583      !! * Modules used
584      USE obs_surf_def  ! Definition of storage space for surface observations
585
586      IMPLICIT NONE
587
588      !! * Arguments
589      TYPE(obs_surf), INTENT(INOUT) :: &
[7992]590         & surfdataqc                  ! Subset of surface data passing QC
[2128]591      INTEGER, INTENT(IN) :: kt        ! Time step
592      INTEGER, INTENT(IN) :: kpi       ! Model grid parameters
593      INTEGER, INTENT(IN) :: kpj
594      INTEGER, INTENT(IN) :: kit000    ! Number of the first time step
595                                       !   (kit000-1 = restart time)
[7992]596      INTEGER, INTENT(IN) :: kdaystp   ! Number of time steps per day
[2128]597      INTEGER, INTENT(IN) :: k2dint    ! Horizontal interpolation type (see header)
[12380]598      INTEGER, INTENT(IN), OPTIONAL :: &
599                             kmeanstp  ! Number of time steps for the time meaning
600                                       ! Averaging is triggered if present and greater than one                   
[7992]601      REAL(wp), INTENT(IN), DIMENSION(kpi,kpj) :: &
602         & psurf,  &                   ! Model surface field
[11468]603         & pclim,  &                   ! Climatological surface field         
[7992]604         & psurfmask                   ! Land-sea mask
605      LOGICAL, INTENT(IN) :: ldnightav ! Logical for averaging night-time data
606      REAL(KIND=wp), INTENT(IN) :: &
607         & plamscl, &                  ! Diameter in metres of obs footprint in E/W, N/S directions
608         & pphiscl                     ! This is the full width (rather than half-width)
609      LOGICAL, INTENT(IN) :: &
610         & lindegrees                  ! T=> plamscl and pphiscl are specified in degrees, F=> in metres
[3651]611
[2128]612      !! * Local declarations
613      INTEGER :: ji
614      INTEGER :: jj
615      INTEGER :: jobs
616      INTEGER :: inrc
[7992]617      INTEGER :: isurf
[2128]618      INTEGER :: iobs
[7992]619      INTEGER :: imaxifp, imaxjfp
620      INTEGER :: imodi, imodj
[3651]621      INTEGER :: idayend
[12380]622      INTEGER :: imeanend
[7992]623      INTEGER, DIMENSION(:,:,:), ALLOCATABLE :: &
624         & igrdi,   &
625         & igrdj,   &
626         & igrdip1, &
627         & igrdjp1
[3651]628      INTEGER, DIMENSION(:,:), SAVE, ALLOCATABLE :: &
[7992]629         & icount_night,      &
[3651]630         & imask_night
[7992]631      REAL(wp) :: zlam
632      REAL(wp) :: zphi
[11468]633      REAL(wp), DIMENSION(1) :: zext, zobsmask, zclm
[7992]634      REAL(wp) :: zdaystp
[12380]635      REAL(wp) :: zmeanstp
[2128]636      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: &
[7992]637         & zweig,  &
638         & zmask,  &
639         & zsurf,  &
640         & zsurfm, &
641         & zsurftmp, &
[11468]642         & zclim,  &
[7992]643         & zglam,  &
644         & zgphi,  &
645         & zglamf, &
646         & zgphif
[2128]647
[7992]648      REAL(wp), DIMENSION(:,:), SAVE, ALLOCATABLE :: &
649         & zintmp,  &
650         & zouttmp, &
651         & zmeanday    ! to compute model sst in region of 24h daylight (pole)
[12380]652
653      LOGICAL :: l_timemean
[11468]654         
[7992]655      !------------------------------------------------------------------------
[2128]656      ! Local initialization
[7992]657      !------------------------------------------------------------------------
658      ! Record and data counters
[2128]659      inrc = kt - kit000 + 2
[7992]660      isurf = surfdataqc%nsstp(inrc)
[2128]661
[12380]662      l_timemean = .FALSE.
663      IF ( PRESENT( kmeanstp ) ) THEN
664         IF ( kmeanstp > 1 ) l_timemean = .TRUE.
665      ENDIF
666
[7992]667      ! Work out the maximum footprint size for the
668      ! interpolation/averaging in model grid-points - has to be even.
[3651]669
[7992]670      CALL obs_max_fpsize( k2dint, plamscl, pphiscl, lindegrees, psurfmask, imaxifp, imaxjfp )
[3651]671
672
[12380]673      IF ( l_timemean ) THEN
674         ! Initialize time mean for first timestep
675         imeanend = MOD( kt - kit000 + 1, kmeanstp )
676         IF (lwp) WRITE(numout,*) 'Obs time mean ', kt, kit000, kmeanstp, imeanend
677
678         ! Added kt == 0 test to catch restart case
679         IF ( ( imeanend == 1 ) .OR. ( kt == 0 ) ) THEN
680            IF (lwp) WRITE(numout,*) 'Reset surfdataqc%vdmean on time-step: ',kt
681            DO jj = 1, jpj
682               DO ji = 1, jpi
683                  surfdataqc%vdmean(ji,jj) = 0.0
684               END DO
685            END DO
686         ENDIF
687
688         ! On each time-step, increment the field for computing time mean
689         IF (lwp) WRITE(numout,*)'Accumulating surfdataqc%vdmean on time-step: ',kt
690         DO jj = 1, jpj
691            DO ji = 1, jpi
692               surfdataqc%vdmean(ji,jj) = surfdataqc%vdmean(ji,jj) &
693                  &                        + psurf(ji,jj)
694            END DO
695         END DO
696
697         ! Compute the time mean at the end of time period
698         IF ( imeanend == 0 ) THEN
699            zmeanstp = 1.0 / REAL( kmeanstp )
700            IF (lwp) WRITE(numout,*)'Calculating surfdataqc%vdmean time mean on time-step: ',kt,' with weight: ',zmeanstp
701            DO jj = 1, jpj
702               DO ji = 1, jpi
703                  surfdataqc%vdmean(ji,jj) = surfdataqc%vdmean(ji,jj) &
704                     &                       * zmeanstp
705               END DO
706            END DO
707         ENDIF
708      ENDIF !l_timemean
709
710
[7992]711      IF ( ldnightav ) THEN
[3651]712
[7992]713      ! Initialize array for night mean
714         IF ( kt == 0 ) THEN
715            ALLOCATE ( icount_night(kpi,kpj) )
716            ALLOCATE ( imask_night(kpi,kpj) )
717            ALLOCATE ( zintmp(kpi,kpj) )
718            ALLOCATE ( zouttmp(kpi,kpj) )
719            ALLOCATE ( zmeanday(kpi,kpj) )
720            nday_qsr = -1   ! initialisation flag for nbc_dcy
721         ENDIF
[3651]722
[7992]723         ! Night-time means are calculated for night-time values over timesteps:
724         !  [1 <= kt <= kdaystp], [kdaystp+1 <= kt <= 2*kdaystp], .....
725         idayend = MOD( kt - kit000 + 1, kdaystp )
[3651]726
[7992]727         ! Initialize night-time mean for first timestep of the day
728         IF ( idayend == 1 .OR. kt == 0 ) THEN
729            DO jj = 1, jpj
730               DO ji = 1, jpi
731                  surfdataqc%vdmean(ji,jj) = 0.0
732                  zmeanday(ji,jj) = 0.0
733                  icount_night(ji,jj) = 0
734               END DO
735            END DO
736         ENDIF
[3651]737
[7992]738         zintmp(:,:) = 0.0
739         zouttmp(:,:) = sbc_dcy( zintmp(:,:), .TRUE. )
740         imask_night(:,:) = INT( zouttmp(:,:) )
[3651]741
742         DO jj = 1, jpj
743            DO ji = 1, jpi
[7992]744               ! Increment the temperature field for computing night mean and counter
745               surfdataqc%vdmean(ji,jj) = surfdataqc%vdmean(ji,jj)  &
746                      &                    + psurf(ji,jj) * REAL( imask_night(ji,jj) )
747               zmeanday(ji,jj)          = zmeanday(ji,jj) + psurf(ji,jj)
748               icount_night(ji,jj)      = icount_night(ji,jj) + imask_night(ji,jj)
[3651]749            END DO
750         END DO
751
[7992]752         ! Compute the night-time mean at the end of the day
753         zdaystp = 1.0 / REAL( kdaystp )
754         IF ( idayend == 0 ) THEN
755            IF (lwp) WRITE(numout,*) 'Calculating surfdataqc%vdmean on time-step: ',kt
756            DO jj = 1, jpj
757               DO ji = 1, jpi
758                  ! Test if "no night" point
759                  IF ( icount_night(ji,jj) > 0 ) THEN
760                     surfdataqc%vdmean(ji,jj) = surfdataqc%vdmean(ji,jj) &
761                       &                        / REAL( icount_night(ji,jj) )
762                  ELSE
763                     !At locations where there is no night (e.g. poles),
764                     ! calculate daily mean instead of night-time mean.
765                     surfdataqc%vdmean(ji,jj) = zmeanday(ji,jj) * zdaystp
766                  ENDIF
767               END DO
768            END DO
769         ENDIF
770
[3651]771      ENDIF
772
[2128]773      ! Get the data for interpolation
[7992]774
[2128]775      ALLOCATE( &
[7992]776         & zweig(imaxifp,imaxjfp,1),      &
777         & igrdi(imaxifp,imaxjfp,isurf), &
778         & igrdj(imaxifp,imaxjfp,isurf), &
779         & zglam(imaxifp,imaxjfp,isurf), &
780         & zgphi(imaxifp,imaxjfp,isurf), &
781         & zmask(imaxifp,imaxjfp,isurf), &
782         & zsurf(imaxifp,imaxjfp,isurf), &
783         & zsurftmp(imaxifp,imaxjfp,isurf),  &
784         & zglamf(imaxifp+1,imaxjfp+1,isurf), &
785         & zgphif(imaxifp+1,imaxjfp+1,isurf), &
786         & igrdip1(imaxifp+1,imaxjfp+1,isurf), &
787         & igrdjp1(imaxifp+1,imaxjfp+1,isurf) &
[2128]788         & )
[3651]789
[11468]790      IF ( surfdataqc%lclim ) ALLOCATE( zclim(imaxifp,imaxjfp,isurf) )
791
[7992]792      DO jobs = surfdataqc%nsurfup + 1, surfdataqc%nsurfup + isurf
793         iobs = jobs - surfdataqc%nsurfup
794         DO ji = 0, imaxifp
795            imodi = surfdataqc%mi(jobs) - int(imaxifp/2) + ji - 1
[2128]796           
[7992]797            !Deal with wrap around in longitude
798            IF ( imodi < 1      ) imodi = imodi + jpiglo
799            IF ( imodi > jpiglo ) imodi = imodi - jpiglo
[2128]800           
[7992]801            DO jj = 0, imaxjfp
802               imodj = surfdataqc%mj(jobs) - int(imaxjfp/2) + jj - 1
803               !If model values are out of the domain to the north/south then
804               !set them to be the edge of the domain
805               IF ( imodj < 1      ) imodj = 1
806               IF ( imodj > jpjglo ) imodj = jpjglo
[3651]807
[7992]808               igrdip1(ji+1,jj+1,iobs) = imodi
809               igrdjp1(ji+1,jj+1,iobs) = imodj
810               
811               IF ( ji >= 1 .AND. jj >= 1 ) THEN
812                  igrdi(ji,jj,iobs) = imodi
813                  igrdj(ji,jj,iobs) = imodj
814               ENDIF
815               
816            END DO
817         END DO
[2128]818      END DO
[3651]819
[7992]820      CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
[2128]821         &                  igrdi, igrdj, glamt, zglam )
[7992]822      CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
[2128]823         &                  igrdi, igrdj, gphit, zgphi )
[7992]824      CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
825         &                  igrdi, igrdj, psurfmask, zmask )
[2128]826
[12380]827      ! At the end of the averaging period get interpolated means
828      IF ( l_timemean ) THEN
829         IF ( imeanend == 0 ) THEN
830            ALLOCATE( zsurfm(imaxifp,imaxjfp,isurf) )
831            IF (lwp) WRITE(numout,*)' Interpolating the time mean values on time step: ',kt
832            CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
833               &                  igrdi, igrdj, surfdataqc%vdmean(:,:), zsurfm )
834         ENDIF
835      ELSE
836         CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
837            &                  igrdi, igrdj, psurf, zsurf )
838      ENDIF
839
[11468]840      IF ( k2dint > 4 ) THEN         
841         CALL obs_int_comm_2d( imaxifp+1, imaxjfp+1, isurf, kpi, kpj, &
842            &                  igrdip1, igrdjp1, glamf, zglamf )
843         CALL obs_int_comm_2d( imaxifp+1, imaxjfp+1, isurf, kpi, kpj, &
844            &                  igrdip1, igrdjp1, gphif, zgphif )
845      ENDIF
846     
847      IF ( surfdataqc%lclim ) THEN
848         CALL obs_int_comm_2d( imaxifp, imaxjfp, isurf, kpi, kpj, &
849            &                  igrdi, igrdj, pclim, zclim )
850      ENDIF
851
[7992]852      ! At the end of the day get interpolated means
853      IF ( idayend == 0 .AND. ldnightav ) THEN
[2128]854
855         ALLOCATE( &
[7992]856            & zsurfm(imaxifp,imaxjfp,isurf)  &
[2128]857            & )
858
[7992]859         CALL obs_int_comm_2d( imaxifp,imaxjfp, isurf, kpi, kpj, igrdi, igrdj, &
860            &               surfdataqc%vdmean(:,:), zsurfm )
[2128]861
862      ENDIF
863
[7992]864      ! Loop over observations
865      DO jobs = surfdataqc%nsurfup + 1, surfdataqc%nsurfup + isurf
[2128]866
[7992]867         iobs = jobs - surfdataqc%nsurfup
[2128]868
[7992]869         IF ( kt /= surfdataqc%mstp(jobs) ) THEN
[2128]870
871            IF(lwp) THEN
872               WRITE(numout,*)
873               WRITE(numout,*) ' E R R O R : Observation',              &
874                  &            ' time step is not consistent with the', &
875                  &            ' model time step'
876               WRITE(numout,*) ' ========='
877               WRITE(numout,*)
[7992]878               WRITE(numout,*) ' Record  = ', jobs,                &
879                  &            ' kt      = ', kt,                  &
880                  &            ' mstp    = ', surfdataqc%mstp(jobs), &
881                  &            ' ntyp    = ', surfdataqc%ntyp(jobs)
[2128]882            ENDIF
[7992]883            CALL ctl_stop( 'obs_surf_opt', 'Inconsistent time' )
[2128]884
885         ENDIF
886
[7992]887         zlam = surfdataqc%rlam(jobs)
888         zphi = surfdataqc%rphi(jobs)
[2128]889
[12380]890         IF (( ldnightav .AND. idayend == 0 ) .OR. (l_timemean .AND. imeanend == 0)) THEN
891            ! Night-time or N=kmeanstp timestep averaged data
[7992]892            zsurftmp(:,:,iobs) = zsurfm(:,:,iobs)
893         ELSE
894            zsurftmp(:,:,iobs) = zsurf(:,:,iobs)
[2128]895         ENDIF
896
[12380]897         IF (   ( .NOT. l_timemean ) .OR. & 
898             &  ( l_timemean .AND. imeanend == 0) ) THEN
899            IF ( k2dint <= 4 ) THEN
[2128]900
[12380]901               ! Get weights to interpolate the model value to the observation point
902               CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi,         &
903                  &                   zglam(:,:,iobs), zgphi(:,:,iobs), &
904                  &                   zmask(:,:,iobs), zweig, zobsmask )
[2576]905
[12380]906               ! Interpolate the model value to the observation point
907               CALL obs_int_h2d( 1, 1, zweig, zsurftmp(:,:,iobs), zext )
[2128]908
[12380]909               IF ( surfdataqc%lclim ) THEN 
910                  CALL obs_int_h2d( 1, 1, zweig, zclim(:,:,iobs), zclm )
911               ENDIF
[11468]912
913
[12380]914            ELSE
[2128]915
[12380]916               ! Get weights to average the model SLA to the observation footprint
917               CALL obs_avg_h2d_init( 1, 1, imaxifp, imaxjfp, k2dint, zlam,  zphi, &
918                  &                   zglam(:,:,iobs), zgphi(:,:,iobs), &
919                  &                   zglamf(:,:,iobs), zgphif(:,:,iobs), &
920                  &                   zmask(:,:,iobs), plamscl, pphiscl, &
921                  &                   lindegrees, zweig, zobsmask )
[2128]922
[12380]923               ! Average the model SST to the observation footprint
924               CALL obs_avg_h2d( 1, 1, imaxifp, imaxjfp, &
925                  &              zweig, zsurftmp(:,:,iobs),  zext )
[2128]926
[12380]927               IF ( surfdataqc%lclim ) THEN 
928                  CALL obs_avg_h2d( 1, 1, imaxifp, imaxjfp, &
929                     &              zweig, zclim(:,:,iobs),  zclm )
930               ENDIF
931
[11468]932            ENDIF
933
[12380]934            IF ( TRIM(surfdataqc%cvars(1)) == 'SLA' .AND. surfdataqc%nextra == 2 ) THEN
935               ! ... Remove the MDT from the SSH at the observation point to get the SLA
936               surfdataqc%rext(jobs,1) = zext(1)
937               surfdataqc%rmod(jobs,1) = surfdataqc%rext(jobs,1) - surfdataqc%rext(jobs,2)
938            ELSE
939               surfdataqc%rmod(jobs,1) = zext(1)
940            ENDIF
[2128]941
[12380]942            IF ( surfdataqc%lclim ) surfdataqc%rclm(jobs,1) = zclm(1)
943
944            IF ( zext(1) == obfillflt ) THEN
945               ! If the observation value is a fill value, set QC flag to bad
946               surfdataqc%nqc(jobs) = 4
947            ENDIF         
[2128]948         ENDIF
[8653]949         
[11468]950         IF ( surfdataqc%lclim ) surfdataqc%rclm(jobs,1) = zclm(1)
[11932]951
[12609]952#if defined key_cice
[11932]953         IF ( TRIM(surfdataqc%cvars(1)) == 'FBD' ) THEN
954            ! Convert radar freeboard to true freeboard (add 1/4 snow depth; 1/4 based on ratio of speed of light in vacuum compared to snow (3.0e8 vs 2.4e8 m/s))
955            surfdataqc%rext(jobs,1) = surfdataqc%robs(jobs,1) 
956            surfdataqc%robs(jobs,1) = surfdataqc%rext(jobs,1) + 0.25*surfdataqc%rext(jobs,2)
957            ! If the corrected freeboard observation is outside -0.3 to 3.0 m (CPOM) then set the QC flag to bad
958            IF ((surfdataqc%robs(jobs,1) < -0.3) .OR. (surfdataqc%robs(jobs,1) > 3.0)) THEN
959               surfdataqc%nqc(jobs) = 4
960            ENDIF           
961            ! Convert corrected freeboard to ice thickness following Tilling et al. (2016)
962            surfdataqc%robs(jobs,1) = (surfdataqc%robs(jobs,1)*rhow + surfdataqc%rext(jobs,2)*rhos)/ &
963                                      (rhow - rhoi)
964            ! Flag any negative ice thickness values as bad
965            IF (surfdataqc%robs(jobs,1) < 0.0) THEN
966               surfdataqc%nqc(jobs) = 4
967            ENDIF                                     
968         ENDIF
[11468]969         
[8653]970         IF ( zext(1) == obfillflt ) THEN
971            ! If the observation value is a fill value, set QC flag to bad
972            surfdataqc%nqc(jobs) = 4
973         ENDIF
[12609]974#endif defined key_cice
[12380]975         
[2128]976      END DO
[7992]977
[2128]978      ! Deallocate the data for interpolation
979      DEALLOCATE( &
[7992]980         & zweig, &
981         & igrdi, &
982         & igrdj, &
983         & zglam, &
984         & zgphi, &
985         & zmask, &
986         & zsurf, &
987         & zsurftmp, &
988         & zglamf, &
989         & zgphif, &
990         & igrdip1,&
991         & igrdjp1 &
[2128]992         & )
[7992]993
[11468]994      IF ( surfdataqc%lclim ) DEALLOCATE( zclim )
995
[7992]996      ! At the end of the day also deallocate night-time mean array
[12380]997      IF (( idayend == 0 .AND. ldnightav ) .OR. ( imeanend == 0 .AND. l_timemean )) THEN
[2128]998         DEALLOCATE( &
[7992]999            & zsurfm  &
[2128]1000            & )
1001      ENDIF
1002
[7992]1003      surfdataqc%nsurfup = surfdataqc%nsurfup + isurf
[2128]1004
[7992]1005   END SUBROUTINE obs_surf_opt
1006
[2128]1007END MODULE obs_oper
Note: See TracBrowser for help on using the repository browser.