C *****************************COPYRIGHT****************************** DOSUMS1.2
C (c) CROWN COPYRIGHT 1996, METEOROLOGICAL OFFICE, All Rights Reserved. DOSUMS1.3
C DOSUMS1.4
C Use, duplication or disclosure of this code is subject to the DOSUMS1.5
C restrictions as set forth in the contract. DOSUMS1.6
C DOSUMS1.7
C Meteorological Office DOSUMS1.8
C London Road DOSUMS1.9
C BRACKNELL DOSUMS1.10
C Berkshire UK DOSUMS1.11
C RG12 2SZ DOSUMS1.12
C DOSUMS1.13
C If no contract has been raised with this copy of the code, the use, DOSUMS1.14
C duplication or disclosure of it is strictly prohibited. Permission DOSUMS1.15
C to do so must first be obtained in writing from the Head of Numerical DOSUMS1.16
C Modelling at the above address. DOSUMS1.17
C ******************************COPYRIGHT****************************** DOSUMS1.18
!+ General purpose global sum routine for calculating the DOSUMS1.19
! sum of a horizontal field DOSUMS1.20
! DOSUMS1.21
! Subroutine Interface DOSUMS1.22
SUBROUTINE DO_SUMS(SUM_ARRAY,FIELD_SIZE,START_POINT,END_POINT, 4,1DOSUMS1.23
& N_SUMS,SUM_RESULTS) DOSUMS1.24
IMPLICIT NONE DOSUMS1.25
! DOSUMS1.26
! Description: DOSUMS1.27
! Primarily written for the energy correction suite of routines: DOSUMS1.28
! Calculate N_SUMS global sums of the SUM_ARRAY field between DOSUMS1.29
! the points START_POINT and END_POINT, adding results DOSUMS1.30
! onto SUM_RESULTS DOSUMS1.31
! DOSUMS1.32
! Method: DOSUMS1.33
*IF -DEF,MPP DOSUMS1.34
! Loop over N_SUMS and do sum of SUM_ARRAY for points between DOSUMS1.35
! START_POINT and END_POINT, putting results in SUM_RESULTS DOSUMS1.36
*ELSE DOSUMS1.37
*IF DEF,REPROD DOSUMS1.38
! Farm out N_SUMS global sums : 1 global sum/processor - do the DOSUMS1.39
! sums and then return the results to all processors DOSUMS1.40
*ELSE DOSUMS1.41
! Every processor does its local part of the sum - then all these DOSUMS1.42
! sub-sums are summed together. DOSUMS1.43
*ENDIF DOSUMS1.44
*ENDIF DOSUMS1.45
! DOSUMS1.46
! Current code owner : Paul Burton DOSUMS1.47
! DOSUMS1.48
! History DOSUMS1.49
! Model Date Modification history from model version 4.1 DOSUMS1.50
! version DOSUMS1.51
! 4.1 9/11/95 New DECK created to make EMDIAG suitable for DOSUMS1.52
! MPP use. P.Burton DOSUMS1.53
! 4.2 18/11/96 *CALL to AMAXSIZE for MaxFieldSize P.Burton GPB3F402.22
! 4.2 18/10/96 New name for group of processors in gather_field GPB0F402.178
! P.Burton GPB0F402.179
! 4.3 29/04/97 Correct call to GATHER_FIELD. D Robinson. GDR1F403.1
! DOSUMS1.54
! Subroutine Arguments: DOSUMS1.55
DOSUMS1.56
INTEGER FIELD_SIZE, ! IN size of SUM_ARRAY DOSUMS1.57
& START_POINT, ! IN local point to start sum at DOSUMS1.58
& END_POINT, ! IN local point to end sum at DOSUMS1.59
& N_SUMS ! IN number of sums to do DOSUMS1.60
DOSUMS1.61
REAL SUM_ARRAY(FIELD_SIZE,N_SUMS), DOSUMS1.62
! ! IN array containing fields DOSUMS1.63
! ! to be summed DOSUMS1.64
& SUM_RESULTS(N_SUMS) ! INOUT sum of SUM_ARRAY added onto DOSUMS1.65
! ! initial value of SUM_RESULTS DOSUMS1.66
DOSUMS1.67
! Parameters and COMMON DOSUMS1.68
*IF DEF,MPP DOSUMS1.69
*CALL PARVARS
DOSUMS1.70
*CALL AMAXSIZE
GPB3F402.23
*CALL GCCOM
DOSUMS1.71
*ENDIF DOSUMS1.72
DOSUMS1.73
! Local variabels DOSUMS1.74
*IF DEF,MPP DOSUMS1.75
REAL SUM_RESULTS_TMP(N_SUMS) ! actual sum which will eventually DOSUMS1.76
! ! be added to SUM_RESULTS DOSUMS1.77
DOSUMS1.78
INTEGER FIRST_COL, ! local column of START_POINT DOSUMS1.79
& LAST_COL, ! local column of END_POINT DOSUMS1.80
& FIRST_ROW, ! local row of START_POINT DOSUMS1.81
& LAST_ROW ! local row of END_POINT DOSUMS1.82
DOSUMS1.83
INTEGER info ! return code from GC stuff DOSUMS1.84
DOSUMS1.85
*IF DEF,REPROD DOSUMS1.86
INTEGER MAP(N_SUMS), ! processor number for sum DOSUMS1.87
& N_SUMS_ON_PROC(0:MAXPROC), ! number of sums to do on pe DOSUMS1.88
& RESULT_NUMBER, ! result index in SUM_RESULTS DOSUMS1.89
& GLOBAL_START, ! global point to start sum at DOSUMS1.90
& GLOBAL_END ! global point to end sum at DOSUMS1.91
DOSUMS1.92
INTEGER iproc ! loop index in COMMS DOSUMS1.93
DOSUMS1.94
REAL global_sum_data(MaxFieldSize,N_SUMS) DOSUMS1.95
! area for doing global sums in DOSUMS1.96
*ELSE DOSUMS1.97
INTEGER LOCAL_START, ! modified version of START_POINT DOSUMS1.98
& LOCAL_END, ! modified version of END_POINT DOSUMS1.99
& J ! loop variable for rows DOSUMS1.100
*ENDIF DOSUMS1.101
*ENDIF DOSUMS1.102
INTEGER I,K ! loop variables DOSUMS1.103
DOSUMS1.104
*IF -DEF,MPP DOSUMS1.105
DOSUMS1.106
DO K=1,N_SUMS DOSUMS1.107
DOSUMS1.108
DO I=START_POINT,END_POINT DOSUMS1.109
SUM_RESULTS(K)=SUM_RESULTS(K)+SUM_ARRAY(I,K) DOSUMS1.110
ENDDO ! loop over points DOSUMS1.111
DOSUMS1.112
ENDDO ! loop over sums DOSUMS1.113
DOSUMS1.114
*ELSE DOSUMS1.115
DOSUMS1.116
! 1. Calculate local column and row of start and end, and if DOSUMS1.117
! necessary move them out of the halos. DOSUMS1.118
DOSUMS1.119
! 1.1 FIRST_COL and LAST_COL DOSUMS1.120
DOSUMS1.121
FIRST_COL=MOD(START_POINT-1,lasize(1))+1 DOSUMS1.122
LAST_COL=MOD(END_POINT-1,lasize(1))+1 DOSUMS1.123
DOSUMS1.124
*IF -DEF,REPROD DOSUMS1.125
LOCAL_START=START_POINT DOSUMS1.126
LOCAL_END=END_POINT DOSUMS1.127
*ENDIF DOSUMS1.128
DOSUMS1.129
IF (FIRST_COL .LE. Offx) THEN ! START_POINT lies in halo DOSUMS1.130
*IF -DEF,REPROD DOSUMS1.131
LOCAL_START=START_POINT+(Offx+1-FIRST_COL) DOSUMS1.132
*ENDIF DOSUMS1.133
FIRST_COL=FIRST_COL+(Offx+1-FIRST_COL) DOSUMS1.134
ENDIF DOSUMS1.135
DOSUMS1.136
IF (LAST_COL .GT. lasize(1)-Offx) THEN ! END_POINT in halo DOSUMS1.137
*IF -DEF,REPROD DOSUMS1.138
LOCAL_END=END_POINT-(LAST_COL-(lasize(1)-Offx)) DOSUMS1.139
*ENDIF DOSUMS1.140
LAST_COL=LAST_COL-(LAST_COL-(lasize(1)-Offx)) DOSUMS1.141
ENDIF DOSUMS1.142
DOSUMS1.143
! 1.2 FIRST_ROW and LAST_ROW DOSUMS1.144
DOSUMS1.145
FIRST_ROW=(START_POINT/lasize(1))+1 DOSUMS1.146
LAST_ROW=((END_POINT-1)/lasize(1))+1 DOSUMS1.147
DOSUMS1.148
IF (FIRST_ROW .LE. Offy) THEN ! First row in halo DOSUMS1.149
FIRST_ROW=Offy+1 DOSUMS1.150
*IF -DEF,REPROD DOSUMS1.151
LOCAL_START=(Offy*lasize(1))+Offx+1 DOSUMS1.152
*ENDIF DOSUMS1.153
ENDIF DOSUMS1.154
DOSUMS1.155
IF (LAST_ROW .GT. lasize(2)-Offy) THEN ! Last row in halo DOSUMS1.156
LAST_ROW=lasize(2)-Offy DOSUMS1.157
*IF -DEF,REPROD DOSUMS1.158
LOCAL_END=lasize(1)*(lasize(2)-Offy) - Offx DOSUMS1.159
*ENDIF DOSUMS1.160
ENDIF DOSUMS1.161
DOSUMS1.162
*IF DEF,REPROD DOSUMS1.163
! Reproducible parallel global sums DOSUMS1.164
! We assume all the fields are standard P_FIELDS mapping DOSUMS1.165
! onto the full global grid DOSUMS1.166
DOSUMS1.167
! 2. Convert local start and end points to global values DOSUMS1.168
DOSUMS1.169
FIRST_COL=(FIRST_COL-Offx)+datastart(1)-1 DOSUMS1.170
LAST_COL=(LAST_COL-Offx)+datastart(1)-1 DOSUMS1.171
FIRST_ROW=(FIRST_ROW-Offy)+datastart(2)-1 DOSUMS1.172
LAST_ROW=(LAST_ROW-Offy)+datastart(2)-1 DOSUMS1.173
DOSUMS1.174
GLOBAL_START=FIRST_COL+(FIRST_ROW-1)*glsize(1) DOSUMS1.175
GLOBAL_END=LAST_COL+(LAST_ROW-1)*glsize(1) DOSUMS1.176
DOSUMS1.177
! 2.1 This is only the local version - we must now find out DOSUMS1.178
! the absolute global values of START and END DOSUMS1.179
DOSUMS1.180
CALL GC_IMIN(
1,nproc,info,GLOBAL_START) DOSUMS1.181
CALL GC_IMAX(
1,nproc,info,GLOBAL_END) DOSUMS1.182
DOSUMS1.183
! 3. Calculate mapping - which sum is done on which processor DOSUMS1.184
DOSUMS1.185
DO K=1,N_SUMS DOSUMS1.186
SUM_RESULTS_TMP(K)=0.0 DOSUMS1.187
MAP(K)=first_comp_pe+MOD((K-1),nproc) DOSUMS1.188
IF (mype .EQ. MAP(K)) SUM_RESULTS_TMP(K)=SUM_RESULTS(K) DOSUMS1.189
ENDDO DOSUMS1.190
DOSUMS1.191
! 4. Distribute the sums DOSUMS1.192
DOSUMS1.193
DO K=0,nproc-1 DOSUMS1.194
N_SUMS_ON_PROC(K)=0 DOSUMS1.195
ENDDO DOSUMS1.196
DOSUMS1.197
DO K=1,N_SUMS DOSUMS1.198
N_SUMS_ON_PROC(MAP(K))=N_SUMS_ON_PROC(MAP(K))+1 DOSUMS1.199
DOSUMS1.200
CALL GATHER_FIELD
(SUM_ARRAY(1,K), GDR1F403.2
& global_sum_data(1,N_SUMS_ON_PROC(MAP(K))), DOSUMS1.202
& lasize(1),lasize(2), DOSUMS1.203
& glsize(1),glsize(2), DOSUMS1.204
& MAP(K),GC_ALL_PROC_GROUP, GPB0F402.180
& info) DOSUMS1.206
DOSUMS1.207
ENDDO ! K : loop over N_SUMS DOSUMS1.208
DOSUMS1.209
! 5. And do the sums DOSUMS1.210
DOSUMS1.211
DO K=1,N_SUMS_ON_PROC(mype) DOSUMS1.212
RESULT_NUMBER=(K-1)*nproc+mype+1 DOSUMS1.213
DOSUMS1.214
DO I=GLOBAL_START,GLOBAL_END DOSUMS1.215
SUM_RESULTS_TMP(RESULT_NUMBER)= DOSUMS1.216
& SUM_RESULTS_TMP(RESULT_NUMBER)+ global_sum_data(I,K) DOSUMS1.217
ENDDO ! I : loop over points DOSUMS1.218
DOSUMS1.219
ENDDO ! K : loop over number of sums I must do DOSUMS1.220
DOSUMS1.221
! 6. Broadcast the results to everyone DOSUMS1.222
! Rather than do a bcast for each sum, we'll do a DOSUMS1.223
! parallel sum. Only the processor doing a particular DOSUMS1.224
! sum will contribute, ie.: DOSUMS1.225
! SUM PE0 PE1 PE2 PE3 PE0 PE1 PE2 PE3 DOSUMS1.226
! 1 3.2 0.0 0.0 0.0 --SUM--> 3.2 3.2 3.2 3.2 DOSUMS1.227
! 2 0.0 9.2 0.0 0.0 --SUM--> 9.2 9.2 9.2 9.2 DOSUMS1.228
! 3 0.0 0.0 5.7 0.0 --SUM--> 5.7 5.7 5.7 5.7 DOSUMS1.229
DOSUMS1.230
CALL GC_RSUM(
N_SUMS,nproc,info,SUM_RESULTS_TMP) DOSUMS1.231
DOSUMS1.232
DO K=1,N_SUMS DOSUMS1.233
SUM_RESULTS(K)= SUM_RESULTS_TMP(K) DOSUMS1.234
ENDDO DOSUMS1.235
*ELSE DOSUMS1.236
! This is the faster version of the global sum. DOSUMS1.237
! Each processor works out its local sum across its part of the field DOSUMS1.238
! and then these are summed up. DOSUMS1.239
! This can give non-reproducible answers of two kinds: DOSUMS1.240
! 1) If sums across processors are always done in the same order then DOSUMS1.241
! the same answer will always be obtained for the same processor DOSUMS1.242
! arrangement. However, the answer will be different on different DOSUMS1.243
! processor arrangements DOSUMS1.244
! 2) If the sums across processor are not done in any particular order DOSUMS1.245
! then different results will be obtained even when the same DOSUMS1.246
! processor arrangement is used. DOSUMS1.247
! Which case is true depends on how GC_RSUM has been implemented on DOSUMS1.248
! this particular platform. It is probably safest to assume that (2) DOSUMS1.249
! is the case, and this is the method that generally gives the DOSUMS1.250
! fastest sum. DOSUMS1.251
DOSUMS1.252
! 2 Do the local sum of my part of SUM_ARRAY DOSUMS1.253
DOSUMS1.254
DO K=1,N_SUMS DOSUMS1.255
DOSUMS1.256
SUM_RESULTS_TMP(K)=0.0 DOSUMS1.257
DOSUMS1.258
! 2.1 The first row (or part of row) DOSUMS1.259
DO I=LOCAL_START,FIRST_ROW*lasize(1)-Offx DOSUMS1.260
SUM_RESULTS_TMP(K)=SUM_RESULTS_TMP(K)+SUM_ARRAY(I,K) DOSUMS1.261
ENDDO DOSUMS1.262
DOSUMS1.263
! 2.2 All the rows between first and last rows DOSUMS1.264
DO J=FIRST_ROW+1,LAST_ROW-1 DOSUMS1.265
DO I=(J-1)*lasize(1)+Offx+1,J*lasize(1)-Offx DOSUMS1.266
SUM_RESULTS_TMP(K)=SUM_RESULTS_TMP(K)+SUM_ARRAY(I,K) DOSUMS1.267
ENDDO ! I : all points along row between halos DOSUMS1.268
ENDDO ! J : all rows between start and end DOSUMS1.269
DOSUMS1.270
! 2.3 The last row (or part of row) DOSUMS1.271
DO I=(LAST_ROW-1)*lasize(1)+Offx+1,LOCAL_END DOSUMS1.272
SUM_RESULTS_TMP(K)=SUM_RESULTS_TMP(K)+SUM_ARRAY(I,K) DOSUMS1.273
ENDDO DOSUMS1.274
DOSUMS1.275
ENDDO ! K : loop over N_SUMS DOSUMS1.276
DOSUMS1.277
! 3. and now sum up all the local sums, and give everyone DOSUMS1.278
! the total sum DOSUMS1.279
DOSUMS1.280
CALL GC_RSUM(
N_SUMS,nproc,info,SUM_RESULTS_TMP) DOSUMS1.281
DOSUMS1.282
DO K=1,N_SUMS DOSUMS1.283
SUM_RESULTS(K)=SUM_RESULTS(K)+SUM_RESULTS_TMP(K) DOSUMS1.284
ENDDO DOSUMS1.285
DOSUMS1.286
*ENDIF DOSUMS1.287
*ENDIF DOSUMS1.288
DOSUMS1.289
RETURN DOSUMS1.290
END DOSUMS1.291