*IF DEF,C93_1A,OR,DEF,C93_2A                                               APB0F402.55     
C ******************************COPYRIGHT******************************    GTS2F400.2827   
C (c) CROWN COPYRIGHT 1995, METEOROLOGICAL OFFICE, All Rights Reserved.    GTS2F400.2828   
C                                                                          GTS2F400.2829   
C Use, duplication or disclosure of this code is subject to the            GTS2F400.2830   
C restrictions as set forth in the contract.                               GTS2F400.2831   
C                                                                          GTS2F400.2832   
C                Meteorological Office                                     GTS2F400.2833   
C                London Road                                               GTS2F400.2834   
C                BRACKNELL                                                 GTS2F400.2835   
C                Berkshire UK                                              GTS2F400.2836   
C                RG12 2SZ                                                  GTS2F400.2837   
C                                                                          GTS2F400.2838   
C If no contract has been raised with this copy of the code, the use,      GTS2F400.2839   
C duplication or disclosure of it is strictly prohibited.  Permission      GTS2F400.2840   
C to do so must first be obtained in writing from the Head of Numerical    GTS2F400.2841   
C Modelling at the above address.                                          GTS2F400.2842   
C ******************************COPYRIGHT******************************    GTS2F400.2843   
C                                                                          GTS2F400.2844   
CLL  SUBROUTINE FILTER     -----------------------------------------       FILTER1A.3      
CLL                                                                        FILTER1A.4      
CLL  PURPOSE: FOURIER DAMPS ALL WAVES AFTER THE WAVE-NUMBER HELD IN        FILTER1A.5      
CLL           FILTER_WAVE_NUMBER FOR ALL ROWS WHERE FILTERING IS           FILTER1A.6      
CLL           NECESSARY. USES THE ECMWF FFT ROUTINES TO CALCULATE THE      FILTER1A.7      
CLL           FOURIER PARTS OF THE CODE.                                   FILTER1A.8      
CLL  NOT SUITABLE FOR I.B.M USE.                                           FILTER1A.9      
CLL                                                                        FILTER1A.10     
CLL  WRITTEN BY M.H MAWSON.                                                FILTER1A.11     
CLL                                                                        FILTER1A.12     
CLL  MODEL            MODIFICATION HISTORY FROM MODEL VERSION 3.0:         FILTER1A.13     
CLL VERSION  DATE                                                          FILTER1A.14     
!   4.1      09/05/96 Added MPP code.   P.Burton                           APB7F401.1      
!    4.2    18/10/96  New name for group of processors in all_to_all       GPB0F402.181    
!                     P.Burton                                             GPB0F402.182    
!LL 4.2      16/08/96 Added TYPLDPT variables.                             APB0F402.56     
!LL                   Made FILTER_WAVE_NUMBER globally sized.              APB0F402.57     
!LL                   Removal of identical deck FILTER2A, requires         APB0F402.58     
!LL                   *DEFs to be changed.                P.Burton         APB0F402.59     
!LL 4.2      17/10/96 Changed arguments to ALLTOALL for GCC v1.1           GPB2F402.1      
!LL                   P.Burton                                             GPB2F402.2      
C     vn4.3    Mar. 97   T3E migration : optimisation changes              GSS1F403.1039   
C                                       D.Salmond                          GSS1F403.1040   
!LL 4.4      08/08/97 Remove filter data common block, adding new          GPB2F404.1      
!LL                   subroutine MPP_FILTER.                               GPB2F404.2      
!LL                   Add chunking optimisation.                           GPB2F404.3      
!LL                   Add T3E optimised communications.                    GPB2F404.4      
!LL                                                       P.Burton         GPB2F404.5      
!LL 4.5      22/06/98 Remove redundant divides.                            GBCNF405.1      
!LL                     Author: Bob Carruthers, Cray Research              GBCNF405.2      
CLL                                                                        FILTER1A.15     
CLL                                                                        FILTER1A.16     
CLL  PROGRAMMING STANDARD: UNIFIED MODEL DOCUMENTATION PAPER NO. 4,        FILTER1A.17     
CLL                        STANDARD B. VERSION 2, DATED 18/01/90           FILTER1A.18     
CLL  SYSTEM COMPONENTS COVERED: 142                                        FILTER1A.19     
CLL  SYSTEM TASK: P1                                                       FILTER1A.20     
CLL  DOCUMENTATION:        EQUATIONS (53) AND (54) IN SECTION 3.5          FILTER1A.21     
CLL                        OF UNIFIED MODEL DOCUMENTATION PAPER            FILTER1A.22     
CLL                        NO. 10 M.J.P. CULLEN,T.DAVIES AND M.H.MAWSON    FILTER1A.23     
CLL                        VERSION 11, DATED 10/10/90.                     FILTER1A.24     
CLLEND-------------------------------------------------------------        FILTER1A.25     
                                                                           FILTER1A.26     
C                                                                          FILTER1A.27     
C*L  ARGUMENTS:---------------------------------------------------         FILTER1A.28     

      SUBROUTINE FILTER                                                     16,3FILTER1A.29     
     1                 (FIELD,FIELD_LENGTH,LEVELS,FILTER_SPACE,            FILTER1A.30     
     2                  ROW_LENGTH,                                        APB0F402.60     
*CALL ARGFLDPT                                                             APB0F402.61     
     &                  FILTER_WAVE_NUMBER,TRIGS,IFAX,                     APB0F402.62     
     3                  NORTHERN_FILTERED_ROW,                             FILTER1A.32     
     4                  SOUTHERN_FILTERED_ROW)                             FILTER1A.33     
                                                                           FILTER1A.34     
      IMPLICIT NONE                                                        FILTER1A.35     
                                                                           APB0F402.63     
! All TYPFLDPT arguments are intent IN                                     APB0F402.64     
*CALL TYPFLDPT                                                             APB0F402.65     
                                                                           FILTER1A.36     
      INTEGER                                                              FILTER1A.37     
     *  FIELD_LENGTH       !IN HORIZONTAL DIMENSION OF FIELD TO BE         FILTER1A.38     
     *                     !   FILTERED.                                   FILTER1A.39     
     *, LEVELS             !IN NUMBER OF MODEL LEVELS IN FIELD.            FILTER1A.40     
     *, ROW_LENGTH         !IN NUMBER OF POINTS ON A ROW.                  FILTER1A.41     
     *, NORTHERN_FILTERED_ROW !IN LAST ROW, MOVING EQUATORWARDS,           FILTER1A.42     
     *                          ! IN NORTHERN HEMISPHERE                   FILTER1A.43     
     *                          ! ON WHICH FILTERING IS PERFORMED.         FILTER1A.44     
     *, SOUTHERN_FILTERED_ROW !IN LAST ROW, MOVING EQUATORWARDS,           FILTER1A.45     
     *                          ! IN SOUTHERN HEMISPHERE                   FILTER1A.46     
     *                          ! ON WHICH FILTERING IS PERFORMED.         FILTER1A.47     
     *, FILTER_SPACE       !IN HORIZONTAL DIMENSION OF ARRAY NEEDED TO     FILTER1A.48     
     *                     ! HOLD DATA TO BE FILTERED TO PASS TO FFT'S.    FILTER1A.49     
     *, IFAX(10)           !IN HOLDS FACTORS OF ROW_LENGTH USED IN FFT'S   FILTER1A.50     
     *, FILTER_WAVE_NUMBER(GLOBAL_P_FIELD/GLOBAL_ROW_LENGTH)               APB0F402.66     
     &     ! LAST WAVE NUMBER ON EACH ROW WHICH IS NOT FILTERED            APB0F402.67     
                                                                           FILTER1A.54     
      REAL                                                                 FILTER1A.55     
     * FIELD(FIELD_LENGTH,LEVELS) !INOUT HOLDS FIELD TO BE FILTERED.       FILTER1A.56     
                                                                           FILTER1A.57     
      REAL                                                                 FILTER1A.58     
     * TRIGS(ROW_LENGTH)    !IN HOLDS TRIGONOMETRIC TERMS USED IN FFT'S    FILTER1A.59     
C*---------------------------------------------------------------------    FILTER1A.60     
*IF DEF,MPP                                                                APB7F401.2      
! Common blocks and parameters for MPP code                                APB7F401.3      
*CALL PARVARS                                                              APB7F401.4      
*CALL PARFFTS                                                              APB7F401.5      
*CALL GCCOM                                                                APB7F401.6      
*ENDIF                                                                     APB7F401.7      
                                                                           FILTER1A.61     
C*L  DEFINE ARRAYS AND VARIABLES USED IN THIS ROUTINE-----------------     FILTER1A.62     
C   DEFINE LOCAL ARRAYS: 1 IS REQUIRED                                     FILTER1A.63     
                                                                           FILTER1A.64     
*IF -DEF,MPP                                                               APB7F401.8      
      REAL                                                                 FILTER1A.65     
     *  FILTER_DATA(FILTER_SPACE,LEVELS)  ! HOLDS DATA PASSED TO FFT'S     FILTER1A.66     
     *                                    ! AND COEFFICIENTS RETURNED.     FILTER1A.67     
*ENDIF                                                                     APB7F401.12     
C*---------------------------------------------------------------------    FILTER1A.68     
C   DEFINE LOCAL VARIABLES                                                 FILTER1A.69     
                                                                           FILTER1A.70     
C   COUNT VARIABLES FOR DO LOOPS ETC.                                      FILTER1A.71     
      INTEGER                                                              APB7F401.13     
     &  I,J ,IJ                                                            APB7F401.14     
     &, LOT                 ! NUMBER OF DATA VECTORS PASSED TO FFT'S.      APB7F401.15     
     &, JUMP                ! NUMBER OF STORAGE LOCATIONS BETWEEN THE      APB7F401.16     
     &                      ! START OF CONSECUTIVE DATA VECTOR.            APB7F401.17     
     &, INCREMENT           ! NUMBER OF STORAGE LOCATIONS BETWEEN EACH     APB7F401.18     
     &                      ! ELEMENT OF THE SAME DATA VECTOR, 1, IF       APB7F401.19     
     &                      ! CONSECUTIVE.                                 APB7F401.20     
     &, FFTSIGN             ! PARAMETER DETERMINING WHETHER SPECTRAL       APB7F401.21     
     &                      ! TO GRID-POINT (FFTSIGN = 1) OR GRID-POINT    APB7F401.22     
     &                      ! TO SPECTRAL (FFTSIGN = -1) FFT'S ARE         APB7F401.23     
     &                      ! REQUIRED.                                    APB7F401.24     
*IF -DEF,MPP                                                               APB7F401.25     
     &, K,IK,IL                                                            APB7F401.26     
     &, ROWS                ! NUMBER OF ROWS IN FIELD                      APB7F401.27     
*ELSE                                                                      APB7F401.28     
     &, fld_type,fft_row_len                                               GPB2F404.6      
     &, info,max_field_length                                              ACN2F405.125    
*ENDIF                                                                     APB7F401.30     
                                                                           FILTER1A.85     
C*L  EXTERNAL SUBROUTINE CALLS:------------------------------------        FILTER1A.86     
      EXTERNAL FOURIER                                                     FILTER1A.87     
C*---------------------------------------------------------------------    FILTER1A.88     
                                                                           FILTER1A.89     
*IF -DEF,MPP                                                               APB7F401.31     
CL  MAXIMUM VECTOR LENGTH ASSUMED IS ROW_LENGTH                            FILTER1A.90     
CL---------------------------------------------------------------------    FILTER1A.91     
CL    INTERNAL STRUCTURE.                                                  FILTER1A.92     
CL---------------------------------------------------------------------    FILTER1A.93     
CL                                                                         FILTER1A.94     
                                                                           FILTER1A.95     
CL---------------------------------------------------------------------    FILTER1A.96     
CL    SECTION 1.     COLLECT ALL DATA TO BE FILTERED INTO CONTIGUOUS       FILTER1A.97     
CL                   STORAGE IN FILTER_DATA. LAST 2 ELEMENTS ON EACH ROW   FILTER1A.98     
CL                   ARE LEFT EMPTY AS FFT ROUTINE RETURNS                 FILTER1A.99     
CL                   ROW_LENGTH/2+1 PAIRS OF COEFFICIENTS. DATA IS STILL   FILTER1A.100    
CL                   ARRANGED ON ROWS AS FFT ROUTINES USE CONSTANT         FILTER1A.101    
CL                   STRIDE VECTORISATION CAPABILITY OF CRAY MACHINE.      FILTER1A.102    
CL---------------------------------------------------------------------    FILTER1A.103    
                                                                           FILTER1A.104    
      ROWS = FIELD_LENGTH/ROW_LENGTH                                       FILTER1A.105    
                                                                           FILTER1A.106    
CL COLLECT DATA FROM NORTHERN HEMISPHERE.                                  FILTER1A.107    
                                                                           FILTER1A.108    
CFPP$ NODEPCHK                                                             FILTER1A.109    
! Fujitsu vectorization directive                                          GRB0F405.599    
!OCL NOVREC                                                                GRB0F405.600    
      DO 100 I=2,NORTHERN_FILTERED_ROW                                     FILTER1A.110    
        IJ = (I-2)*(ROW_LENGTH+2)                                          FILTER1A.111    
        IK = (I-1)*ROW_LENGTH                                              FILTER1A.112    
        DO 110 K=1,LEVELS                                                  FILTER1A.113    
          DO 120 J=1,ROW_LENGTH                                            FILTER1A.114    
            FILTER_DATA(IJ+J,K)=FIELD(IK+J,K)                              FILTER1A.115    
 120      CONTINUE                                                         FILTER1A.116    
 110    CONTINUE                                                           FILTER1A.117    
 100  CONTINUE                                                             FILTER1A.118    
                                                                           FILTER1A.119    
CL COLLECT DATA FROM SOUTHERN HEMISPHERE.                                  FILTER1A.120    
                                                                           FILTER1A.121    
      IL = (NORTHERN_FILTERED_ROW-1)*(ROW_LENGTH+2)                        FILTER1A.122    
CFPP$ NODEPCHK                                                             FILTER1A.123    
! Fujitsu vectorization directive                                          GRB0F405.601    
!OCL NOVREC                                                                GRB0F405.602    
      DO 130 I=SOUTHERN_FILTERED_ROW,ROWS-1                                FILTER1A.124    
        IJ = IL+(I-SOUTHERN_FILTERED_ROW)*(ROW_LENGTH+2)                   FILTER1A.125    
        IK = (I-1)*ROW_LENGTH                                              FILTER1A.126    
        DO 140 K=1,LEVELS                                                  FILTER1A.127    
          DO 150 J=1,ROW_LENGTH                                            FILTER1A.128    
            FILTER_DATA(IJ+J,K)=FIELD(IK+J,K)                              FILTER1A.129    
 150      CONTINUE                                                         FILTER1A.130    
 140    CONTINUE                                                           FILTER1A.131    
 130  CONTINUE                                                             FILTER1A.132    
                                                                           FILTER1A.133    
CL---------------------------------------------------------------------    FILTER1A.134    
CL    SECTION 2.     CALL FOURIER TO GET FOURIER DECOMPOSITION OF DATA.    FILTER1A.135    
CL---------------------------------------------------------------------    FILTER1A.136    
                                                                           FILTER1A.137    
      INCREMENT = 1                                                        FILTER1A.138    
      JUMP = ROW_LENGTH+2                                                  FILTER1A.139    
      FFTSIGN=-1                                                           APB7F401.32     
      LOT = ((NORTHERN_FILTERED_ROW-1)+(ROWS-SOUTHERN_FILTERED_ROW))       FILTER1A.141    
     *      *LEVELS                                                        FILTER1A.142    
      CALL FOURIER(FILTER_DATA,TRIGS,IFAX,INCREMENT,JUMP,ROW_LENGTH,       FILTER1A.143    
     *            LOT,FFTSIGN)                                             APB7F401.33     
                                                                           FILTER1A.145    
CL---------------------------------------------------------------------    FILTER1A.146    
CL    SECTION 3.     ZERO COEFFICIENTS OF WAVE-NUMBERS TO BE CHOPPED.      FILTER1A.147    
CL                   COEFFICIENTS ARE HELD AS A(0),B(0),A(1),B(1), ETC     FILTER1A.148    
CL                   ON EACH ROW.                                          FILTER1A.149    
CL---------------------------------------------------------------------    FILTER1A.150    
                                                                           FILTER1A.151    
CL NORTHERN HEMISPHERE DATA                                                FILTER1A.152    
      DO 300 K=1,LEVELS                                                    FILTER1A.153    
        DO 310 I=2,NORTHERN_FILTERED_ROW                                   FILTER1A.154    
          IJ = (I-2)*(ROW_LENGTH+2)                                        FILTER1A.155    
C 3 IS USED IN LOOP 320 COUNTER AS WAVE-NUMBER 0 HAS TO BE RETAINED.       FILTER1A.156    
          DO 320 J=3+(FILTER_WAVE_NUMBER(I))*2,ROW_LENGTH+2                FILTER1A.157    
            FILTER_DATA(IJ+J,K)=FILTER_DATA(IJ+J,K)*                       FILTER1A.158    
     *                     (FILTER_WAVE_NUMBER(I)/REAL(((J-1)/2)*2))**2    FILTER1A.159    
 320      CONTINUE                                                         FILTER1A.160    
 310    CONTINUE                                                           FILTER1A.161    
 300  CONTINUE                                                             FILTER1A.162    
                                                                           FILTER1A.163    
CL SOUTHERN HEMISPHERE DATA                                                FILTER1A.164    
      IL = (NORTHERN_FILTERED_ROW-1)*(ROW_LENGTH+2)                        FILTER1A.165    
      DO 330 K=1,LEVELS                                                    FILTER1A.166    
        DO 340 I=SOUTHERN_FILTERED_ROW,ROWS-1                              FILTER1A.167    
          IJ = IL+(I-SOUTHERN_FILTERED_ROW)*(ROW_LENGTH+2)                 FILTER1A.168    
C 3 IS USED IN LOOP 320 COUNTER AS WAVE-NUMBER 0 HAS TO BE RETAINED.       FILTER1A.169    
          DO 350 J=3+(FILTER_WAVE_NUMBER(I))*2,ROW_LENGTH+2                FILTER1A.170    
            FILTER_DATA(IJ+J,K)=FILTER_DATA(IJ+J,K)*                       FILTER1A.171    
     *                     (FILTER_WAVE_NUMBER(I)/REAL(((J-1)/2)*2))**2    FILTER1A.172    
 350      CONTINUE                                                         FILTER1A.173    
 340    CONTINUE                                                           FILTER1A.174    
 330  CONTINUE                                                             FILTER1A.175    
                                                                           FILTER1A.176    
CL---------------------------------------------------------------------    FILTER1A.177    
CL    SECTION 4.     CALL FOURIER TO RE-CREATE GRID-POINT FIELDS FROM      FILTER1A.178    
CL                   FILTERED FOURIER MODES.                               FILTER1A.179    
CL---------------------------------------------------------------------    FILTER1A.180    
                                                                           FILTER1A.181    
      INCREMENT = 1                                                        FILTER1A.182    
      JUMP = ROW_LENGTH+2                                                  FILTER1A.183    
      FFTSIGN=1                                                            APB7F401.34     
      LOT = ((NORTHERN_FILTERED_ROW-1)+(ROWS-SOUTHERN_FILTERED_ROW))       FILTER1A.185    
     *      *LEVELS                                                        FILTER1A.186    
      CALL FOURIER(FILTER_DATA,TRIGS,IFAX,INCREMENT,JUMP,ROW_LENGTH,       FILTER1A.187    
     *            LOT,FFTSIGN)                                             APB7F401.35     
                                                                           FILTER1A.189    
CL---------------------------------------------------------------------    FILTER1A.190    
CL    SECTION 5.     COPY FILTERED FIELD BACK OVER ORIGINAL ONE.           FILTER1A.191    
CL---------------------------------------------------------------------    FILTER1A.192    
                                                                           FILTER1A.193    
CL RESTORE DATA IN NORTHERN HEMISPHERE.                                    FILTER1A.194    
                                                                           FILTER1A.195    
      DO 500 I=2,NORTHERN_FILTERED_ROW                                     FILTER1A.196    
        IJ = (I-2)*(ROW_LENGTH+2)                                          FILTER1A.197    
        IK = (I-1)*ROW_LENGTH                                              FILTER1A.198    
        DO 510 K=1,LEVELS                                                  FILTER1A.199    
          DO 520 J=1,ROW_LENGTH                                            FILTER1A.200    
            FIELD(IK+J,K) = FILTER_DATA(IJ+J,K)                            FILTER1A.201    
 520      CONTINUE                                                         FILTER1A.202    
 510    CONTINUE                                                           FILTER1A.203    
 500  CONTINUE                                                             FILTER1A.204    
                                                                           FILTER1A.205    
CL RESTORE DATA IN SOUTHERN HEMISPHERE.                                    FILTER1A.206    
                                                                           FILTER1A.207    
      IL = (NORTHERN_FILTERED_ROW-1)*(ROW_LENGTH+2)                        FILTER1A.208    
      DO 530 I=SOUTHERN_FILTERED_ROW,ROWS-1                                FILTER1A.209    
        IJ = IL+(I-SOUTHERN_FILTERED_ROW)*(ROW_LENGTH+2)                   FILTER1A.210    
        IK = (I-1)*ROW_LENGTH                                              FILTER1A.211    
        DO 540 K=1,LEVELS                                                  FILTER1A.212    
          DO 550 J=1,ROW_LENGTH                                            FILTER1A.213    
            FIELD(IK+J,K) = FILTER_DATA(IJ+J,K)                            FILTER1A.214    
 550      CONTINUE                                                         FILTER1A.215    
 540    CONTINUE                                                           FILTER1A.216    
 530  CONTINUE                                                             FILTER1A.217    
                                                                           APB7F401.36     
*ELSE                                                                      APB7F401.37     
                                                                           APB7F401.38     
      IF (filter_off) THEN  ! if filter has been switched off for          APB7F401.43     
!                             some reason                                  APB7F401.44     
        WRITE(6,*) 'FILTERING SWITCHED OFF.'                               APB7F401.45     
        WRITE(6,*) 'See earlier in output for error message'               APB7F401.46     
        GOTO 9999                                                          APB7F401.47     
      ENDIF                                                                APB7F401.48     
                                                                           APB7F401.49     
                                                                           APB7F401.55     
! Determine what field type this is, and set variables accordingly         APB7F401.56     
      fld_type=south_filt_p_row-SOUTHERN_FILTERED_ROW+1                    APB7F401.57     
!             =1 for p_field and =2 for u_field                            APB7F401.58     
                                                                           APB7F401.59     
! Find the number of levels involved in the data transpose                 APB7F401.60     
                                                                           APB7F401.61     
      DO I = 1, n_items_to_send(fld_type)                                  APB7F401.62     
        filt_send_map(S_NUMBER_OF_ELEMENTS_IN_ITEM,i,fld_type) =           GPB2F402.4      
     &    MAX( MIN(filt_send_max(i,fld_type),                              GPB2F402.5      
     &             LEVELS - filt_send_start(i,fld_type) + 1),              GPB2F402.6      
     &         0)                                                          GPB2F402.7      
      ENDDO                                                                APB7F401.65     
      DO I = 1, n_items_to_recv(fld_type)                                  APB7F401.66     
        filt_recv_map(R_NUMBER_OF_ELEMENTS_IN_ITEM,i,fld_type) =           GPB2F402.8      
     &    MAX( MIN(filt_recv_max(i,fld_type),                              GPB2F402.9      
     &             LEVELS - filt_recv_start(i,fld_type) + 1),              GPB2F402.10     
     &         0)                                                          GPB2F402.11     
      ENDDO                                                                APB7F401.69     
                                                                           APB7F401.70     
                                                                           GPB2F404.7      
      fft_row_len=glsize(1)+2                                              GPB2F404.8      
! Call routine to perform redistribution of data and filtering             GPB2F404.9      
                                                                           GPB2F404.10     
! Find the maximum field size across processors                            ACN2F405.126    
                                                                           ACN2F405.127    
      max_field_length=FIELD_LENGTH*LEVELS                                 ACN2F405.128    
      CALL GC_IMAX(1,nproc,info,max_field_length)                          ACN2F405.129    
                                                                           ACN2F405.130    
      CALL MPP_FILTER(FIELD,FIELD_LENGTH,LEVELS,max_field_length,          ACN2F405.131    
     &                fft_rows(fld_type),fft_row_len,fld_type,             GPB2F404.12     
     &                GLOBAL_P_FIELD/GLOBAL_ROW_LENGTH,                    GPB2F404.13     
     &                FILTER_WAVE_NUMBER,IFAX)                             GPB2F404.14     
 9999 CONTINUE                                                             APB7F401.119    
*ENDIF                                                                     APB7F401.120    
                                                                           FILTER1A.218    
CL END OF ROUTINE FILTER                                                   FILTER1A.219    
                                                                           FILTER1A.220    
      RETURN                                                               FILTER1A.221    
      END                                                                  FILTER1A.222    
*IF DEF,MPP                                                                GPB2F404.15     
                                                                           GPB2F404.16     
                                                                           GPB2F404.17     

      SUBROUTINE MPP_FILTER                                                 1,2GPB2F404.18     
     &                     (FIELD,FIELD_LENGTH,LEVELS,dummy_len,           ACN2F405.132    
     &                      rows_to_fft,fft_row_len,fld_type,              GPB2F404.20     
     &                      global_rows,                                   GPB2F404.21     
     &                      filter_wave_number,ifax)                       GPB2F404.22     
                                                                           GPB2F404.23     
      IMPLICIT NONE                                                        GPB2F404.24     
                                                                           GPB2F404.25     
      INTEGER                                                              GPB2F404.26     
     &  FIELD_LENGTH  ! IN : horizontal size of FIELD array                GPB2F404.27     
     &, LEVELS        ! IN : number of levels in FIELD                     GPB2F404.28     
     &, dummy_len     ! IN : size for dummy_FIELD                          ACN2F405.133    
     &, rows_to_fft   ! IN : number of rows I will fft                     GPB2F404.29     
     &, fft_row_len   ! IN : size of rows that I will fft                  GPB2F404.30     
     &, fld_type      ! IN : field type (P or U) of FIELD                  GPB2F404.31     
     &, global_rows   ! IN : number of rows in global field                GPB2F404.32     
     &, filter_wave_number(global_rows)                                    GPB2F404.33     
!                       IN : last wave number on each global row           GPB2F404.34     
!                            which is not filtered                         GPB2F404.35     
     &, ifax(10)      ! IN : factors of row length used in ffts            GPB2F404.36     
                                                                           GPB2F404.37     
      REAL                                                                 GPB2F404.38     
     &  FIELD(FIELD_LENGTH,LEVELS)  ! IN/OUT : data to be filtered         GPB2F404.39     
                                                                           GPB2F404.40     
                                                                           GPB2F404.41     
! Dynamic array for putting data to be filtered                            GPB2F404.42     
                                                                           GPB2F404.43     
      REAL                                                                 GPB2F404.44     
     &  FILTER_DATA(fft_row_len*rows_to_fft)                               GPB2F404.45     
cdir$ cache_align filter_data                                              GBCNF405.3      
                                                                           GPB2F404.46     
! Comdecks/ commonblocks/parameters                                        GPB2F404.47     
*CALL PARVARS                                                              GPB2F404.48     
*CALL PARFFTS                                                              GPB2F404.49     
*CALL GCCOM                                                                GPB2F404.50     
                                                                           GPB2F404.51     
                                                                           GPB2F404.52     
! The following variables are used to make the MPP filter more             GPB2F404.53     
! efficient. The FILTER_DATA array may contain rows of data for            GPB2F404.54     
! levels LEVELS+1 -> P_LEVELS containing null data, but which              GPB2F404.55     
! was filtered. Now, the chunk_start(i) array points to chunks of          GPB2F404.56     
! rows (being chunk_row(i) rows in length) which require filtering         GPB2F404.57     
! n_chunks says how many chunks there are for filtering                    GPB2F404.58     
                                                                           GPB2F404.59     
      INTEGER                                                              GPB2F404.60     
     &  chunk_start(rows_to_fft)                                           GPB2F404.61     
     &, chunk_rows(rows_to_fft)                                            GPB2F404.62     
     &, n_chunks,chunk                                                     GPB2F404.63     
                                                                           GPB2F404.64     
! Local scalars                                                            GPB2F404.65     
                                                                           GPB2F404.66     
      INTEGER                                                              GPB2F404.67     
     &  increment,jump,fftsign,lot,row_number,filt_wave_no                 GPB2F404.68     
     &, i,j                                                                GPB2F404.69     
                                                                           GPB2F404.70     
*IF -DEF,T3E                                                               GPB2F404.71     
      INTEGER                                                              GPB2F404.72     
     &  info,flag                                                          GPB2F404.73     
*ELSE                                                                      GPB2F404.74     
      INTEGER address_FIELD(0:MAXPROC)  ! address of FIELD array on        GPB2F404.75     
!                                       ! each PE                          GPB2F404.76     
      COMMON /shmem_align_address_FIELD/ address_FIELD                     GPB2F404.77     
cdir$ cache_align /shmem_align_address_FIELD/                              GBCNF405.4      
                                                                           GPB2F404.78     
      REAL dummy_FIELD(dummy_len)                                          ACN2F405.134    
                                                                           ACN2F405.135    
      POINTER (PTR_dummy_FIELD,dummy_FIELD)                                GPB2F404.80     
! dummy_FIELD will point to the address of FIELD on the remote PE          GPB2F404.81     
                                                                           GPB2F404.82     
      INTEGER lbase,lstride,rbase,rstride                                  GPB2F404.83     
      INTEGER this_pe,last_pe                                              GPB2F404.84     
*CALL AMAXSIZE                                                             GBCNF405.5      
c                                                                          GBCNF405.6      
      integer                                                              GBCNF405.7      
     & old_fft_row_len,     ! Preserve the row length for which            GBCNF405.8      
                            ! factors have been prepared                   GBCNF405.9      
     & old_filt_wave_no     ! Preserve the last filt_wave_no for           GBCNF405.10     
                            ! which factors have been prepared             GBCNF405.11     
      data old_fft_row_len/0/, old_filt_wave_no/0/                         GBCNF405.12     
      save old_fft_row_len, old_filt_wave_no                               GBCNF405.13     
c                                                                          GBCNF405.14     
      real                                                                 GBCNF405.15     
     & fft_row_factors(row_length_max+2)                                   GBCNF405.16     
                            ! Factors for the Filtering in Fourier         GBCNF405.17     
                            ! Space                                        GBCNF405.18     
      data fft_row_factors/row_length_max*0./                              GBCNF405.19     
      save fft_row_factors                                                 GBCNF405.20     
c                                                                          GBCNF405.21     
c--variables to determine the loop direction, based on PE parity           GBCNF405.22     
      integer loop_start, loop_end, loop_inc                               GBCNF405.23     
c                                                                          GBCNF405.24     
                                                                           GPB2F404.85     
*ENDIF                                                                     GPB2F404.86     
                                                                           GPB2F404.87     
! 1.0 Set up chunk arrays describing where the filterable data             GPB2F404.88     
!     in filter_data will be.                                              GPB2F404.89     
                                                                           GPB2F404.90     
      n_chunks=1                                                           GPB2F404.91     
      chunk_start(1)=-1                                                    GPB2F404.92     
      chunk_rows(1)=0                                                      GPB2F404.93     
                                                                           GPB2F404.94     
      DO i=1,rows_to_fft                                                   GPB2F404.95     
                                                                           GPB2F404.96     
        IF ((filt_level(i,fld_type) .GT. LEVELS) .AND.                     GPB2F404.97     
     &      (chunk_rows(n_chunks) .NE. 0)) THEN                            GPB2F404.98     
          n_chunks=n_chunks+1                                              GPB2F404.99     
          chunk_start(n_chunks)=-1                                         GPB2F404.100    
          chunk_rows(n_chunks)=0                                           GPB2F404.101    
        ENDIF                                                              GPB2F404.102    
                                                                           GPB2F404.103    
        IF (filt_level(i,fld_type) .LE. LEVELS) THEN                       GPB2F404.104    
          IF (chunk_start(n_chunks) .EQ. -1)                               GPB2F404.105    
     &      chunk_start(n_chunks)=i                                        GPB2F404.106    
          chunk_rows(n_chunks)=chunk_rows(n_chunks)+1                      GPB2F404.107    
        ENDIF                                                              GPB2F404.108    
                                                                           GPB2F404.109    
      ENDDO                                                                GPB2F404.110    
                                                                           GPB2F404.111    
      IF (chunk_start(n_chunks) .EQ. -1) THEN                              GPB2F404.112    
        n_chunks=n_chunks-1                                                GPB2F404.113    
      ENDIF                                                                GPB2F404.114    
                                                                           GPB2F404.115    
! 2.0 Move the data to the filter_data array                               GPB2F404.116    
                                                                           GPB2F404.117    
*IF -DEF,T3E                                                               GPB2F404.118    
                                                                           GPB2F404.119    
      flag=GC_NONE                                                         GPB2F404.120    
                                                                           GPB2F404.121    
      CALL GC_SETOPT(GC_SHM_DIR,GC_SHM_PUT,info)                           GPB2F404.122    
      info=GC_NONE                                                         GPB2F404.123    
                                                                           GPB2F404.124    
      CALL gcg_ralltoalle(field, filt_send_map(1,1,fld_type),              GPB2F404.125    
     &                    n_items_to_send(fld_type),                       GPB2F404.126    
     &                    FIELD_LENGTH*LEVELS,                             GPB2F404.127    
     &                    filter_data, filt_recv_map(1,1,fld_type),        GPB2F404.128    
     &                    n_items_to_recv(fld_type),                       GPB2F404.129    
     &                    fft_row_len*rows_to_fft,                         GPB2F404.130    
     &                    gc_all_proc_group, flag, info)                   GPB2F404.131    
                                                                           GPB2F404.132    
*ELSE                                                                      GPB2F404.133    
                                                                           GPB2F404.134    
! Send the address of my FIELD array to other PEs                          GPB2F404.135    
      CALL barrier()                                                       GPB2F404.136    
                                                                           GPB2F404.137    
      last_pe=-1                                                           GPB2F404.138    
      DO i=1,n_items_to_send(fld_type)                                     GPB2F404.139    
        this_pe=filt_send_map(1,i,fld_type)                                GPB2F404.140    
        IF (this_pe .ne. last_pe) THEN                                     GPB2F404.141    
          last_pe=this_pe                                                  GPB2F404.142    
          CALL shmem_put(address_FIELD(mype),LOC(FIELD),1,                 GPB2F404.143    
     &                   this_pe)                                          GPB2F404.144    
        ENDIF                                                              GPB2F404.145    
      ENDDO                                                                GPB2F404.146    
                                                                           GPB2F404.147    
      CALL barrier()                                                       GPB2F404.148    
                                                                           GPB2F404.149    
! And now each PE must get the data it's going to filter                   GPB2F404.150    
                                                                           GPB2F404.151    
c--select the loop direction for the gather based on PE parity             GBCNF405.25     
      if(gridpos(2).eq.(gridpos(2)/2)*2) then                              GBCNF405.26     
        loop_start=1                                                       GBCNF405.27     
        loop_end=n_items_to_recv(fld_type)                                 GBCNF405.28     
        loop_inc=1                                                         GBCNF405.29     
      else                                                                 GBCNF405.30     
        loop_start=n_items_to_recv(fld_type)                               GBCNF405.31     
        loop_end=1                                                         GBCNF405.32     
        loop_inc=-1                                                        GBCNF405.33     
      endif                                                                GBCNF405.34     
c                                                                          GBCNF405.35     
      do j=loop_start, loop_end, loop_inc                                  GBCNF405.36     
                                                                           GPB2F404.153    
        lbase=filt_recv_map(R_BASE_ADDRESS_IN_RECV_ARRAY,j,fld_type)       GPB2F404.154    
        lstride=filt_recv_map(R_STRIDE_IN_RECV_ARRAY,j,fld_type)           GPB2F404.155    
        rbase=filt_recv_map(R_BASE_ADDRESS_IN_SEND_ARRAY,j,fld_type)       GPB2F404.156    
        rstride=filt_recv_map(R_STRIDE_IN_SEND_ARRAY,j,fld_type)           GPB2F404.157    
                                                                           GPB2F404.158    
        PTR_dummy_FIELD=                                                   GPB2F404.159    
     &    address_FIELD(filt_recv_map(R_SOURCE_PE,j,fld_type))             GPB2F404.160    
! This causes dummy_FIELD to have the address of FIELD on the PE           GPB2F404.161    
! we are about to shmem_get from                                           GPB2F404.162    
                                                                           GPB2F404.163    
        DO i=1,filt_recv_map(R_NUMBER_OF_ELEMENTS_IN_ITEM,J,fld_type)      GPB2F404.164    
                                                                           GPB2F404.165    
          CALL shmem_get(FILTER_DATA(lbase+(i-1)*lstride),                 GPB2F404.166    
     &                   dummy_FIELD(rbase+(i-1)*rstride),                 GPB2F404.167    
     &                   filt_recv_map(R_ELEMENT_LENGTH,j,fld_type),       GPB2F404.168    
     &                   filt_recv_map(R_SOURCE_PE,j,fld_type))            GPB2F404.169    
                                                                           GPB2F404.170    
        ENDDO                                                              GPB2F404.171    
                                                                           GPB2F404.172    
      ENDDO                                                                GPB2F404.173    
*ENDIF                                                                     GPB2F404.174    
                                                                           GPB2F404.175    
! 3.0 Move to wave space                                                   GPB2F404.176    
                                                                           GPB2F404.177    
      INCREMENT=1                                                          GPB2F404.178    
      JUMP=fft_row_len                                                     GPB2F404.179    
      FFTSIGN=-1                                                           GPB2F404.180    
                                                                           GPB2F404.181    
      DO chunk=1,n_chunks                                                  GPB2F404.182    
                                                                           GPB2F404.183    
        LOT=chunk_rows(chunk)                                              GPB2F404.184    
                                                                           GPB2F404.185    
        CALL FOURIER(FILTER_DATA(1+(chunk_start(chunk)-1)*fft_row_len),    GPB2F404.186    
     &               global_trigs,                                         GPB2F404.187    
     &               IFAX,INCREMENT,JUMP,glsize(1),LOT,FFTSIGN)            GPB2F404.188    
      ENDDO                                                                GPB2F404.189    
                                                                           GPB2F404.190    
! 4.0 Perform the truncation                                               GPB2F404.191    
                                                                           GPB2F404.192    
      DO chunk=1,n_chunks                                                  GPB2F404.193    
        DO I=chunk_start(chunk),chunk_start(chunk)+chunk_rows(chunk)-1     GPB2F404.194    
                                                                           GPB2F404.195    
          row_number=filt_info(I,fld_type)                                 GPB2F404.196    
          filt_wave_no=FILTER_WAVE_NUMBER(row_number)                      GPB2F404.197    
*IF DEF,T3E                                                                GBCNF405.37     
c                                                                          GBCNF405.38     
c--precompute the filtering term if necessary                              GBCNF405.39     
          if(old_fft_row_len.ne.fft_row_len .or.                           GBCNF405.40     
     2       old_filt_wave_no.ne.filt_wave_no) then                        GBCNF405.41     
c--prepare the new factors                                                 GBCNF405.42     
            do j=3+(filt_wave_no)*2, fft_row_len                           GBCNF405.43     
              fft_row_factors(j)=(filt_wave_no/REAL(((J-1)/2)*2))**2       GBCNF405.44     
            end do                                                         GBCNF405.45     
c--preserve the indicative constants                                       GBCNF405.46     
            old_fft_row_len=fft_row_len                                    GBCNF405.47     
            old_filt_wave_no=filt_wave_no                                  GBCNF405.48     
          endif                                                            GBCNF405.49     
c                                                                          GBCNF405.50     
*ENDIF                                                                     GBCNF405.51     
                                                                           GPB2F404.198    
          DO J=3+(filt_wave_no)*2,fft_row_len                              GPB2F404.199    
                                                                           GPB2F404.200    
            FILTER_DATA((I-1)*fft_row_len+J)=                              GPB2F404.201    
     &                       FILTER_DATA((I-1)*fft_row_len+J)*             GPB2F404.202    
*IF DEF,T3E                                                                GBCNF405.52     
     &                       fft_row_factors(j)                            GBCNF405.53     
*ELSE                                                                      GBCNF405.54     
     &                       (filt_wave_no/REAL(((J-1)/2)*2))**2           GPB2F404.203    
*ENDIF                                                                     GBCNF405.55     
                                                                           GPB2F404.204    
          ENDDO ! J : loop along fft row                                   GPB2F404.205    
        ENDDO ! I : loop over fft rows in chunk                            GPB2F404.206    
      ENDDO ! chunk : loop over chunks of rows                             GPB2F404.207    
                                                                           GPB2F404.208    
! 5.0 Move back to grid-point space                                        GPB2F404.209    
                                                                           GPB2F404.210    
      FFTSIGN=1                                                            GPB2F404.211    
                                                                           GPB2F404.212    
      DO chunk=1,n_chunks                                                  GPB2F404.213    
                                                                           GPB2F404.214    
        LOT=chunk_rows(chunk)                                              GPB2F404.215    
                                                                           GPB2F404.216    
        CALL FOURIER(FILTER_DATA(1+(chunk_start(chunk)-1)*fft_row_len),    GPB2F404.217    
     &               global_trigs,                                         GPB2F404.218    
     &               IFAX,INCREMENT,JUMP,glsize(1),LOT,FFTSIGN)            GPB2F404.219    
      ENDDO                                                                GPB2F404.220    
                                                                           GPB2F404.221    
! 6.0 And finally, move the data back to the FIELD array                   GPB2F404.222    
                                                                           GPB2F404.223    
*IF -DEF,T3E                                                               GPB2F404.224    
                                                                           GPB2F404.225    
      flag=GC_NONE                                                         GPB2F404.226    
                                                                           GPB2F404.227    
      CALL GC_SETOPT(GC_SHM_DIR,GC_SHM_GET,info)                           GPB2F404.228    
      info=GC_NONE                                                         GPB2F404.229    
      CALL gcg_ralltoalle(filter_data, filt_recv_map(1,1,fld_type),        GPB2F404.230    
     &                   n_items_to_recv(fld_type),                        GJC0F405.16     
     &                    fft_row_len*rows_to_fft,                         GPB2F404.232    
     &                    field, filt_send_map(1,1,fld_type),              GPB2F404.233    
     &                    n_items_to_send(fld_type),                       GPB2F404.234    
     &                    FIELD_LENGTH*LEVELS,                             GPB2F404.235    
     &                    gc_all_proc_group, flag, info)                   GPB2F404.236    
                                                                           GPB2F404.237    
*ELSE                                                                      GPB2F404.238    
                                                                           GPB2F404.239    
c--select the loop direction for the gather based on PE parity             GBCNF405.56     
      if(gridpos(2).eq.(gridpos(2)/2)*2) then                              GBCNF405.57     
        loop_start=1                                                       GBCNF405.58     
        loop_end=n_items_to_recv(fld_type)                                 GBCNF405.59     
        loop_inc=1                                                         GBCNF405.60     
      else                                                                 GBCNF405.61     
        loop_start=n_items_to_recv(fld_type)                               GBCNF405.62     
        loop_end=1                                                         GBCNF405.63     
        loop_inc=-1                                                        GBCNF405.64     
      endif                                                                GBCNF405.65     
c                                                                          GBCNF405.66     
      do j=loop_start, loop_end, loop_inc                                  GBCNF405.67     
                                                                           GPB2F404.241    
        lbase=filt_recv_map(R_BASE_ADDRESS_IN_RECV_ARRAY,j,fld_type)       GPB2F404.242    
        lstride=filt_recv_map(R_STRIDE_IN_RECV_ARRAY,j,fld_type)           GPB2F404.243    
        rbase=filt_recv_map(R_BASE_ADDRESS_IN_SEND_ARRAY,j,fld_type)       GPB2F404.244    
        rstride=filt_recv_map(R_STRIDE_IN_SEND_ARRAY,j,fld_type)           GPB2F404.245    
                                                                           GPB2F404.246    
        PTR_dummy_FIELD=                                                   GPB2F404.247    
     &    address_FIELD(filt_recv_map(R_SOURCE_PE,j,fld_type))             GPB2F404.248    
! This causes dummy_FIELD to have the address of FIELD on the PE           GPB2F404.249    
! we are about to shmem_get from                                           GPB2F404.250    
                                                                           GPB2F404.251    
        DO I=1,filt_recv_map(R_NUMBER_OF_ELEMENTS_IN_ITEM,j,fld_type)      GPB2F404.252    
                                                                           GPB2F404.253    
          call shmem_put(dummy_FIELD(rbase+(i-1)*rstride),                 GPB2F404.254    
     &                   FILTER_DATA(lbase+(i-1)*lstride),                 GPB2F404.255    
     &                   filt_recv_map(R_ELEMENT_LENGTH,j,fld_type),       GPB2F404.256    
     &                   filt_recv_map(R_SOURCE_PE,j,fld_type))            GPB2F404.257    
        ENDDO                                                              GPB2F404.258    
      ENDDO                                                                GPB2F404.259    
                                                                           GPB2F404.260    
      CALL barrier()                                                       GPB2F404.261    
*ENDIF                                                                     GPB2F404.262    
                                                                           GPB2F404.263    
      RETURN                                                               GPB2F404.264    
      END                                                                  GPB2F404.265    
*ENDIF                                                                     GPB2F404.266    
*ENDIF                                                                     FILTER1A.223