1module globalSpectralTransform_mod
2 ! MODULE globalSpectralTransform_mod (prefix='gst' category='4. Data Object transformations')
3 !
4 !:Purpose: To perform global spectral transform (spherical harmonic transform
5 ! with grid-point field on a standard global Gaussian grid).
6 !
7 use codePrecision_mod
8 use mpi
9 use midasMpi_mod
10 use MathPhysConstants_mod
11 use earthConstants_mod
12 use utilities_mod
13 implicit none
14 save
15 private
16
17 ! public subroutines
18 public :: gst_setup
19 public :: gst_speree, gst_speree_ad, gst_speree_kij, gst_speree_kij_ad, gst_reespe, gst_reespe_kij
20 public :: gst_spgd, gst_spgda, gst_gdsp, gst_zleginv, gst_zlegdir
21 public :: gst_setID, gst_setDefaultID, gst_setToDefaultID
22 public :: gst_ilaList_mpilocal, gst_ilaList_mpiglobal
23 ! public functions
24 public :: gst_getRmu, gst_getRwt, gst_getnind, gst_getrlati, gst_getr1qm2, gst_getrsqm2
25 public :: gst_getrnnp1, gst_getr1snp1, gst_getzleg, gst_getNla
26
27
28 type :: T_gst
29 real(8),allocatable :: rmu(:)
30 real(8),allocatable :: rwt(:)
31 real(8),allocatable :: rsqm2(:)
32 real(8),allocatable :: r1qm2(:)
33 real(8),allocatable :: rlati(:)
34 integer,allocatable :: nind(:)
35 integer,allocatable :: nindrh(:)
36 real(8),allocatable :: dalp(:,:)
37 real(8),allocatable :: dealp(:,:)
38 real(8),allocatable :: rwocs(:)
39 real(8),allocatable :: r1mu2(:)
40 real(8),allocatable :: rcolat(:)
41 real(8),allocatable :: r1mui(:)
42 real(8),allocatable :: r1mua(:)
43 integer,allocatable :: nclm(:)
44 real(8),allocatable :: r1snp1(:)
45 real(8),allocatable :: rnnp1(:)
46 real(8),allocatable :: zleg(:,:)
47 integer :: ntrunc
48 integer :: nla
49 integer :: nlarh
50 integer :: njlath
51 integer :: ni
52 integer :: nj
53 integer :: nk
54 integer :: myLatBeg, myLatEnd, latPerPE, latPerPEmax
55 integer,allocatable :: allLatBeg(:), allLatEnd(:), allLatPerPE(:)
56 integer :: myLonBeg, myLonEnd, lonPerPE, lonPerPEmax
57 integer,allocatable :: allLonBeg(:), allLonEnd(:), allLonPerPE(:)
58 integer :: myLatHalfBeg, myLatHalfEnd
59 integer :: mymBeg, mymEnd, mymSkip, mymCount, maxmCount
60 integer :: mynBeg, mynEnd, mynSkip, mynCount
61 integer :: myNla, maxMyNla
62 integer,allocatable :: allNla(:)
63 integer,allocatable :: mymIndex(:)
64 integer,pointer :: ilaList(:), allIlaList(:,:)
65 integer,allocatable :: allmBeg(:), allmEnd(:), allmSkip(:)
66 integer,allocatable :: allnBeg(:), allnEnd(:), allnSkip(:)
67 integer :: myLevBeg, myLevEnd, myLevCount, maxMyLevCount
68 integer,allocatable :: allLevBeg(:), allLevEnd(:)
69 integer :: sendType_LevToLon, recvType_LevToLon
70 integer :: sendType_LonToLev, recvType_LonToLev
71 logical :: lonLatDivisible
72 end type T_gst
73
74 integer,parameter :: nMaxGst = 20
75 integer :: gstIdDefault = -1
76 integer :: nGstAlreadyAllocated = 0
77 integer :: gstID = 0
78 type(T_gst) :: gst(nmaxgst)
79
80 integer :: nlatbd = 8
81
82contains
83
84 subroutine GST_setID(gstID_in)
85 implicit none
86
87 ! Arguments:
88 integer, intent(in) :: gstID_in
89
90 gstID = gstID_in
91
92 end subroutine GST_setID
93
94
95 subroutine GST_setDefaultID(gstID_in)
96 implicit none
97
98 ! Arguments:
99 integer, intent(in) :: gstID_in
100
101 gstIDDefault = gstID_in
102
103 end subroutine GST_setDefaultID
104
105
106 subroutine GST_setToDefaultID
107 implicit none
108
109 gstID = gstIdDefault
110
111 end subroutine GST_setToDefaultID
112
113
114 integer function GST_getNla(gstID_opt)
115 implicit none
116
117 ! Arguments:
118 integer, optional, intent(in) :: gstID_opt
119
120 ! Locals:
121 integer :: gstID_l
122
123 if(present(gstID_opt)) then
124 gstID_l = gstID_opt
125 else
126 gstID_l = gstIdDefault
127 endif
128
129 gst_getNla = gst(gstID_l)%myNla
130
131 end function GST_getNla
132
133
134 real(8) function GST_getRmu(latIndex,gstID_opt)
135 implicit none
136
137 ! Arguments:
138 integer, intent(in) :: latIndex
139 integer, optional, intent(in) :: gstID_opt
140
141 ! Locals:
142 integer :: gstID_l
143 integer :: latIndex2
144
145 if(present(gstID_opt)) then
146 gstID_l = gstID_opt
147 else
148 gstID_l = gstIdDefault
149 endif
150
151 ! use a flipped latitude (south to north)
152 latIndex2 = gst(gstID_l)%nj - latIndex + 1
153 gst_getRmu = gst(gstID_l)%rmu(latIndex2)
154
155 end function GST_getRmu
156
157
158 real(8) function GST_getRnnp1(ilaIndex,gstID_opt)
159 implicit none
160
161 ! Arguments:
162 integer, intent(in) :: ilaIndex
163 integer, optional, intent(in) :: gstID_opt
164
165 ! Locals:
166 integer :: gstID_l
167
168 if(present(gstID_opt)) then
169 gstID_l = gstID_opt
170 else
171 gstID_l = gstIdDefault
172 endif
173
174 gst_getRnnp1 = gst(gstID_l)%rnnp1(ilaIndex)
175
176 end function GST_getRnnp1
177
178
179 real(8) function GST_getR1snp1(ilaIndex,gstID_opt)
180 implicit none
181
182 ! Arguments:
183 integer, intent(in) :: ilaIndex
184 integer, optional, intent(in) :: gstID_opt
185
186 ! Locals:
187 integer :: gstID_l
188
189 if(present(gstID_opt)) then
190 gstID_l = gstID_opt
191 else
192 gstID_l = gstIdDefault
193 endif
194
195 gst_getR1snp1 = gst(gstID_l)%r1snp1(ilaIndex)
196
197 end function GST_getR1snp1
198
199
200 real(8) function GST_getRwt(latIndex,gstID_opt)
201 implicit none
202
203 ! Arguments:
204 integer, intent(in) :: latIndex
205 integer, optional, intent(in) :: gstID_opt
206
207 ! Locals:
208 integer :: gstID_l
209 integer :: latIndex2
210
211 if(present(gstID_opt)) then
212 gstID_l = gstID_opt
213 else
214 gstID_l = gstIdDefault
215 endif
216
217 ! use a flipped latitude (south to north)
218 latIndex2 = gst(gstID_l)%nj - latIndex + 1
219 gst_getRwt = gst(gstID_l)%rwt(latIndex2)
220
221 end function GST_getRwt
222
223
224 integer function GST_getNind(mIndex,gstID_opt)
225 implicit none
226
227 ! Arguments:
228 integer, intent(in) :: mIndex
229 integer, optional, intent(in) :: gstID_opt
230
231 ! Locals:
232 integer :: gstID_l
233
234 if(present(gstID_opt)) then
235 gstID_l = gstID_opt
236 else
237 gstID_l = gstIdDefault
238 endif
239
240 gst_getNind = gst(gstID_l)%nind(mIndex)
241
242 end function GST_getNind
243
244
245 real(8) function GST_getRlati(latIndex,gstID_opt)
246 implicit none
247
248 ! Arguments:
249 integer, intent(in) :: latIndex
250 integer, optional, intent(in) :: gstID_opt
251
252 ! Locals:
253 integer :: gstID_l
254 integer :: latIndex2
255
256 if(present(gstID_opt)) then
257 gstID_l = gstID_opt
258 else
259 gstID_l = gstIdDefault
260 endif
261
262 ! use a flipped latitude (south to north)
263 latIndex2 = gst(gstID_l)%nj - latIndex + 1
264 gst_getRlati = gst(gstID_l)%rlati(latIndex2)
265
266 end function GST_getRlati
267
268
269 real(8) function GST_getR1qm2(latIndex,gstID_opt)
270 implicit none
271
272 ! Arguments:
273 integer, intent(in) :: latIndex
274 integer, optional, intent(in) :: gstID_opt
275
276 ! Locals:
277 integer :: gstID_l
278 integer :: latIndex2
279
280 if(present(gstID_opt)) then
281 gstID_l = gstID_opt
282 else
283 gstID_l = gstIdDefault
284 endif
285
286 ! use a flipped latitude (south to north)
287 latIndex2 = gst(gstID_l)%nj - latIndex + 1
288 gst_getR1qm2 = gst(gstID_l)%r1qm2(latIndex2)
289
290 end function GST_getR1qm2
291
292
293 real(8) function GST_getRsqm2(latIndex,gstID_opt)
294 implicit none
295
296 ! Arguments:
297 integer, intent(in) :: latIndex
298 integer, optional, intent(in) :: gstID_opt
299
300 ! Locals:
301 integer :: gstID_l
302 integer :: latIndex2
303
304 if(present(gstID_opt)) then
305 gstID_l = gstID_opt
306 else
307 gstID_l = gstIdDefault
308 endif
309
310 ! use a flipped latitude (south to north)
311 latIndex2 = gst(gstID_l)%nj - latIndex + 1
312 gst_getRsqm2 = gst(gstID_l)%rsqm2(latIndex2)
313
314 end function GST_getRsqm2
315
316
317 real(8) function GST_getzleg(legendreIndex,latIndex,gstID_in)
318 !
319 !:Purpose: To pass on Legendre polynomial element
320 !
321 implicit none
322
323 ! Arguments:
324 integer :: legendreIndex
325 integer :: latIndex
326 integer :: gstID_in
327
328 gst_getzleg=gst(gstID_in)%zleg(legendreIndex,latIndex)
329
330 end function GST_getzleg
331
332
333 subroutine GST_ilaList_mpiglobal(ilaList,myNla,maxMyNla,gstID_in,mymBeg,&
334 mymEnd,mymSkip,mynBeg,mynEnd,mynSkip)
335 !
336 !:Purpose: To produce an array to convert an mpilocal "ila" into an
337 ! mpiglobal "ila"
338 implicit none
339
340 ! Arguments:
341 integer, pointer, intent(out) :: ilaList(:)
342 integer, intent(out) :: myNla
343 integer, intent(in) :: maxMyNla
344 integer, intent(in) :: gstID_in
345 integer, intent(in) :: mymBeg
346 integer, intent(in) :: mymEnd
347 integer, intent(in) :: mymSkip
348 integer, intent(in) :: mynBeg
349 integer, intent(in) :: mynEnd
350 integer, intent(in) :: mynSkip
351
352 ! Locals:
353 integer :: jm, jn, ierr
354
355 ! compute mpilocal value of nla
356 myNla = 0
357 do jm = mymBeg, mymEnd, mymSkip
358 do jn = mynBeg, mynEnd, mynSkip
359 if(jm.le.jn) then
360 myNla = myNla + 1
361 endif
362 enddo
363 enddo
364
365 ! determine maximum value of myNla over all processors (used for dimensioning)
366 call rpn_comm_allreduce(myNla,maxMyNla,1,'MPI_INTEGER','MPI_MAX','GRID',ierr)
367
368 allocate(ilaList(maxMyNla))
369 ilaList(:) = 0
370
371 myNla = 0
372 do jm = mymBeg, mymEnd, mymSkip
373 do jn = mynBeg, mynEnd, mynSkip
374 if(jm.le.jn) then
375 myNla = myNla + 1
376 ilaList(myNla) = gst_getNind(jm,gstID_in) + jn - jm
377 endif
378 enddo
379 enddo
380
381 end subroutine GST_ilaList_mpiglobal
382
383
384 subroutine GST_ilaList_mpilocal(ilaList,gstID_in,mymBeg,mymEnd,mymSkip,&
385 mynBeg,mynEnd,mynSkip)
386 !
387 !:Purpose: To produce an array to convert an mpiglobal "ila" into an
388 ! mpilocal "ila"
389 !
390 implicit none
391
392 ! Arguments:
393 integer, pointer, intent(out) :: ilaList(:)
394 integer, intent(in) :: gstID_in
395 integer, intent(in) :: mymBeg
396 integer, intent(in) :: mymEnd
397 integer, intent(in) :: mymSkip
398 integer, intent(in) :: mynBeg
399 integer, intent(in) :: mynEnd
400 integer, intent(in) :: mynSkip
401
402 ! Locals:
403 integer :: jm, jn, myNla
404
405 ! assume mpiglobal value of nla already set in gst structure
406 allocate(ilaList(gst(gstID_in)%nla))
407 ilaList(:) = 0
408
409 myNla = 0
410 do jm = mymBeg, mymEnd, mymSkip
411 do jn = mynBeg, mynEnd, mynSkip
412 if(jm.le.jn) then
413 myNla = myNla + 1
414 ilaList(gst_getNind(jm,gstID_in) + jn - jm) = myNla
415 endif
416 enddo
417 enddo
418
419 end subroutine GST_ilaList_mpilocal
420
421
422 integer function gst_setup(ni_in,nj_in,ntrunc_in,maxlevels_in)
423 implicit none
424
425 ! Arguments:
426 integer, intent(in) :: ni_in
427 integer, intent(in) :: nj_in
428 integer, intent(in) :: ntrunc_in
429 integer, intent(in) :: maxlevels_in
430
431 ! Locals:
432 integer :: jn, jm, ila, ierr
433 integer :: latPerPE, latPerPEmax, myLatBeg, myLatEnd, myLatHalfBeg, myLatHalfEnd
434 integer :: lonPerPE, lonPerPEmax, myLonBeg, myLonEnd
435 integer :: myLevBeg, myLevEnd, myLevCount
436 integer :: mymBeg, mymEnd, mymSkip, mymCount
437 integer :: mynBeg, mynEnd, mynSkip, mynCount
438 real(8) :: znnp1, z1snp1
439 integer(kind=MPI_ADDRESS_KIND) :: lowerBound, extent
440 integer :: realSize, sendType, recvType
441 logical :: divisibleLon, divisibleLat
442
443 if(nGstAlreadyAllocated.eq.nMaxGst) then
444 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: The maxmimum number of spectral transform have already been allocated! ', nMaxGst
445 call utl_abort('gst_setup')
446 endif
447
448 nGstAlreadyAllocated = nGstAlreadyAllocated+1
449 gstID = nGstAlreadyAllocated
450 call gst_setDefaultID(gstID)
451 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: Now setting up spectral transform #', gstID
452 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: following *kind* used for internal reals : ', pre_specTransReal
453
454 gst(gstID)%ni = ni_in
455 gst(gstID)%nj = nj_in
456 gst(gstID)%njlath = (gst(gstID)%nj + 1)/2
457
458 if (ntrunc_in == -1) then ! no truncation case
459 gst(gstID)%ntrunc = gst(gstID)%ni / 2
460 else
461 gst(gstID)%ntrunc = ntrunc_in
462 end if
463 gst(gstID)%nla = (gst(gstID)%ntrunc + 1) * (gst(gstID)%ntrunc +2)/2
464 gst(gstID)%nlarh = (gst(gstID)%ntrunc+1) * (gst(gstID)%ntrunc+1)
465 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: ntrunc=', gst(gstID)%ntrunc
466
467 call mmpi_setup_latbands(gst(gstID)%nj, &
468 latPerPE, latPerPEmax, myLatBeg, myLatEnd, myLatHalfBeg, myLatHalfEnd, divisible_opt=divisibleLat)
469 call mmpi_setup_lonbands(gst(gstID)%ni, &
470 lonPerPE, lonPerPEmax, myLonBeg, myLonEnd, divisible_opt= divisibleLon)
471
472 gst(gstID)%lonLatDivisible = (divisibleLon .and. divisibleLat)
473 if( mmpi_myid == 0 ) write(*,*) 'gst_setup: lonLatDivisible = ', gst(gstID)%lonLatDivisible
474
475 gst(gstID)%nk = maxlevels_in
476 ! 2D MPI decomposition: split levels across npex
477 call mmpi_setup_levels(maxlevels_in, myLevBeg, myLevEnd, myLevCount)
478 write(*,*) 'gst_setup: myLevBeg,End,Count=', myLevBeg, myLevEnd, myLevCount
479
480 !!! Distribution of lon/lat tiles (gridpoint space) and n/m (spectral space)
481 ! range of lons handled by this processor
482 gst(gstID)%myLonBeg = myLonBeg
483 gst(gstID)%myLonEnd = myLonEnd
484 gst(gstID)%lonPerPE = lonPerPE
485 gst(gstID)%lonPerPEmax = lonPerPEmax
486 ! range of lats handled by this processor
487 gst(gstID)%myLatBeg = myLatBeg
488 gst(gstID)%myLatEnd = myLatEnd
489 gst(gstID)%myLatHalfBeg = myLatHalfBeg
490 gst(gstID)%myLatHalfEnd = myLatHalfEnd
491 gst(gstID)%latPerPE = latPerPE
492 gst(gstID)%latPerPEmax = latPerPEmax
493 ! range of n handled by this processor
494 call mmpi_setup_n(gst(gstID)%ntrunc,mynBeg,mynEnd,mynSkip,mynCount)
495 gst(gstID)%mynBeg = mynBeg
496 gst(gstID)%mynEnd = mynEnd
497 gst(gstID)%mynSkip = mynSkip
498 gst(gstID)%mynCount = mynCount
499 ! range of m handled by this processor
500 call mmpi_setup_m(gst(gstID)%ntrunc,mymBeg,mymEnd,mymSkip,mymCount)
501 gst(gstID)%mymBeg = mymBeg
502 gst(gstID)%mymEnd = mymEnd
503 gst(gstID)%mymSkip = mymSkip
504 gst(gstID)%mymCount = mymCount
505 call rpn_comm_allreduce(gst(gstID)%mymCount,gst(gstID)%maxmCount, &
506 1,'MPI_INTEGER','MPI_MAX','GRID',ierr)
507 ! range of levels handled by this processor when in spectral space
508 gst(gstID)%myLevBeg = myLevBeg
509 gst(gstID)%myLevEnd = myLevEnd
510 gst(gstID)%myLevCount = myLevCount
511 call rpn_comm_allreduce(gst(gstID)%myLevCount,gst(gstID)%maxMyLevCount, &
512 1,'MPI_INTEGER','MPI_MAX','GRID',ierr)
513
514 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allocating comleg...'
515 call allocate_comleg
516 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: calling suleg...'
517 call suleg(.false.)
518 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: calling sualp...'
519 call sualp
520
521 ! compute the list of spectral coefficient indices when distributed by n and m
522 call gst_ilaList_mpiglobal(gst(gstID)%ilaList,gst(gstID)%myNla,gst(gstID)%maxMyNla,gstID, &
523 gst(gstID)%mymBeg,gst(gstID)%mymEnd,gst(gstID)%mymSkip, &
524 gst(gstID)%mynBeg,gst(gstID)%mynEnd,gst(gstID)%mynSkip)
525 allocate(gst(gstID)%allNla(mmpi_npex))
526 call rpn_comm_allgather(gst(gstID)%myNla,1,'mpi_integer', &
527 gst(gstID)%allNla,1,'mpi_integer','EW',ierr)
528 allocate(gst(gstID)%allIlaList(gst(gstID)%maxMyNla,mmpi_npex))
529 call rpn_comm_allgather(gst(gstID)%ilaList,gst(gstID)%maxMyNla,'mpi_integer', &
530 gst(gstID)%allIlaList,gst(gstID)%maxMyNla,'mpi_integer','EW',ierr)
531
532 allocate(gst(gstID)%allLonBeg(mmpi_npex))
533 CALL rpn_comm_allgather(gst(gstID)%myLonBeg,1,'mpi_integer', &
534 gst(gstID)%allLonBeg,1,'mpi_integer','EW',ierr)
535 allocate(gst(gstID)%allLonEnd(mmpi_npex))
536 CALL rpn_comm_allgather(gst(gstID)%myLonEnd,1,'mpi_integer', &
537 gst(gstID)%allLonEnd,1,'mpi_integer','EW',ierr)
538 allocate(gst(gstID)%allLonPerPE(mmpi_npex))
539 CALL rpn_comm_allgather(gst(gstID)%lonPerPE,1,'mpi_integer', &
540 gst(gstID)%allLonPerPE,1,'mpi_integer','EW',ierr)
541
542 allocate(gst(gstID)%allLatBeg(mmpi_npey))
543 CALL rpn_comm_allgather(gst(gstID)%myLatBeg,1,'mpi_integer', &
544 gst(gstID)%allLatBeg,1,'mpi_integer','NS',ierr)
545 allocate(gst(gstID)%allLatEnd(mmpi_npey))
546 CALL rpn_comm_allgather(gst(gstID)%myLatEnd,1,'mpi_integer', &
547 gst(gstID)%allLatEnd,1,'mpi_integer','NS',ierr)
548 allocate(gst(gstID)%allLatPerPE(mmpi_npey))
549 CALL rpn_comm_allgather(gst(gstID)%latPerPE,1,'mpi_integer', &
550 gst(gstID)%allLatPerPE,1,'mpi_integer','NS',ierr)
551
552 allocate(gst(gstID)%mymIndex(gst(gstID)%mymBeg:gst(gstID)%mymEnd))
553 gst(gstID)%mymIndex(:) = 0
554 do jm = gst(gstID)%mymBeg,gst(gstID)%mymEnd,gst(gstID)%mymSkip
555 if(jm.eq.gst(gstID)%mymBeg) then
556 gst(gstID)%mymIndex(jm) = 1
557 else
558 gst(gstID)%mymIndex(jm) = gst(gstID)%mymIndex(jm-gst(gstID)%mymSkip) + 1
559 endif
560 write(*,*) 'gst_setup: mymIndex(',jm,')=',gst(gstID)%mymIndex(jm)
561 enddo
562
563 allocate(gst(gstID)%allnBeg(mmpi_npex))
564 CALL rpn_comm_allgather(gst(gstID)%mynBeg,1,'mpi_integer', &
565 gst(gstID)%allnBeg,1,'mpi_integer','EW',ierr)
566 allocate(gst(gstID)%allnEnd(mmpi_npex))
567 CALL rpn_comm_allgather(gst(gstID)%mynEnd,1,'mpi_integer', &
568 gst(gstID)%allnEnd,1,'mpi_integer','EW',ierr)
569 allocate(gst(gstID)%allnSkip(mmpi_npex))
570 CALL rpn_comm_allgather(gst(gstID)%mynSkip,1,'mpi_integer', &
571 gst(gstID)%allnSkip,1,'mpi_integer','EW',ierr)
572
573 allocate(gst(gstID)%allmBeg(mmpi_npey))
574 CALL rpn_comm_allgather(gst(gstID)%mymBeg,1,'mpi_integer', &
575 gst(gstID)%allmBeg,1,'mpi_integer','NS',ierr)
576 allocate(gst(gstID)%allmEnd(mmpi_npey))
577 CALL rpn_comm_allgather(gst(gstID)%mymEnd,1,'mpi_integer', &
578 gst(gstID)%allmEnd,1,'mpi_integer','NS',ierr)
579 allocate(gst(gstID)%allmSkip(mmpi_npey))
580 CALL rpn_comm_allgather(gst(gstID)%mymSkip,1,'mpi_integer', &
581 gst(gstID)%allmSkip,1,'mpi_integer','NS',ierr)
582
583 allocate(gst(gstID)%allLevBeg(mmpi_npex))
584 CALL rpn_comm_allgather(gst(gstID)%myLevBeg,1,'mpi_integer', &
585 gst(gstID)%allLevBeg,1,'mpi_integer','EW',ierr)
586 allocate(gst(gstID)%allLevEnd(mmpi_npex))
587 CALL rpn_comm_allgather(gst(gstID)%myLevEnd,1,'mpi_integer', &
588 gst(gstID)%allLevEnd,1,'mpi_integer','EW',ierr)
589
590 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allLonBeg=',gst(gstID)%allLonBeg
591 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allLonEnd=',gst(gstID)%allLonEnd
592 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allLatBeg=',gst(gstID)%allLatBeg
593 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allLatEnd=',gst(gstID)%allLatEnd
594 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allnBeg=',gst(gstID)%allnBeg
595 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allnEnd=',gst(gstID)%allnEnd
596 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allnSkip=',gst(gstID)%allnSkip
597 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allmBeg=',gst(gstID)%allmBeg
598 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allmEnd=',gst(gstID)%allmEnd
599 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allmSkip=',gst(gstID)%allmSkip
600 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allLevBeg=',gst(gstID)%allLevBeg
601 if(mmpi_myid.eq.0) write(*,*) 'gst_setup: allLevEnd=',gst(gstID)%allLevEnd
602 write(*,*) 'gst_setup: mymCount=',gst(gstID)%mymCount
603 write(*,*) 'gst_setup: maxmCount=',gst(gstID)%maxmCount
604 write(*,*) 'gst_setup: myNla=',gst(gstID)%myNla
605 write(*,*) 'gst_setup: maxMyNla=',gst(gstID)%maxMyNla
606
607 allocate(gst(gstID)%r1snp1(gst(gstID)%nla))
608 allocate(gst(gstID)%rnnp1(gst(gstID)%nla))
609 gst(gstID)%r1snp1(1) = 0.d0
610 gst(gstID)%rnnp1(1) = 0.d0
611 do jn = 1, gst(gstID)%ntrunc
612 znnp1 = -real(jn,8)*real(jn+1,8)
613 z1snp1 = 1.d0/znnp1
614 do jm = 0, jn
615 ila = gst(gstID)%nind(jm) + jn - jm
616 gst(gstID)%r1snp1(ila) = z1snp1
617 gst(gstID)%rnnp1(ila) = znnp1
618 enddo
619 enddo
620
621 call gst_zlegpol(gstID)
622
623 ! setup mpi derived types used in transposes (only used when grid is divisible)
624 ! ... mpi_type_vector(count, blocklength, stride, ...)
625 ! ... mpi_type_create_resized(oldtype, lowerbound, extent(in bytes), newtype, ierr)
626
627 call mpi_type_size(pre_specTransMpiType, realSize, ierr)
628 lowerBound = 0
629
630 ! create the send type for LevToLon
631 extent = gst(gstID)%maxMyLevCount * gst(gstID)%lonPerPE * realSize
632 call mpi_type_vector(gst(gstID)%latPerPE, gst(gstID)%maxMyLevCount * gst(gstID)%lonPerPE, &
633 gst(gstID)%maxMyLevCount * gst(gstID)%ni, pre_specTransMpiType, sendtype, ierr)
634 call mpi_type_create_resized(sendtype, lowerBound , extent, gst(gstID)%sendType_LevToLon, ierr);
635 call mpi_type_commit(gst(gstID)%sendType_LevToLon,ierr)
636
637 ! create the receive type for LevToLon
638 extent = gst(gstID)%maxMyLevCount * realSize
639 call mpi_type_vector(gst(gstID)%lonPerPE * gst(gstID)%latPerPE , gst(gstID)%maxMyLevCount, &
640 gst(gstID)%nk, pre_specTransMpiType, recvtype, ierr);
641 call mpi_type_create_resized(recvtype, lowerBound, extent, gst(gstID)%recvType_LevToLon, ierr);
642 call mpi_type_commit(gst(gstID)%recvType_LevToLon, ierr);
643
644 ! create the send type for LonToLev
645 extent = gst(gstID)%maxMyLevCount * realSize
646 call mpi_type_vector(gst(gstID)%lonPerPE * gst(gstID)%latPerPE , gst(gstID)%maxMyLevCount, &
647 gst(gstID)%nk, pre_specTransMpiType, sendtype, ierr);
648 call mpi_type_create_resized(sendtype, lowerBound, extent, gst(gstID)%sendType_LonToLev, ierr);
649 call mpi_type_commit(gst(gstID)%sendType_LonToLev, ierr);
650
651 ! create the recv type for LonToLev
652 extent = gst(gstID)%maxMyLevCount * gst(gstID)%lonPerPE * realSize
653 call mpi_type_vector(gst(gstID)%latPerPE, gst(gstID)%maxMyLevCount * gst(gstID)%lonPerPE, &
654 gst(gstID)%maxMyLevCount * gst(gstID)%ni, pre_specTransMpiType, recvtype, ierr)
655 call mpi_type_create_resized(recvtype, lowerBound , extent, gst(gstID)%recvType_LonToLev, ierr);
656 call mpi_type_commit(gst(gstID)%recvType_LonToLev,ierr)
657
658 gst_setup = gstID
659
660 end function GST_SETUP
661
662!-------------------------------------------------------------------------------
663! Data transposes with respect to 1 of 2 dimensions (i.e. NS or EW)
664!-------------------------------------------------------------------------------
665
666 subroutine transpose2d_NtoLev(psp_in,psp_out)
667 implicit none
668
669 ! Arguments:
670 real(8), intent(in) :: psp_in (gst(gstID)%myNla, 2, gst(gstID)%nk)
671 real(8), intent(out) :: psp_out(gst(gstID)%nla, 2, &
672 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
673
674 ! Locals:
675 real(pre_specTransReal) :: sp_send(gst(gstID)%maxMyNla, 2, &
676 gst(gstID)%maxMyLevCount, mmpi_npex)
677 real(pre_specTransReal) :: sp_recv(gst(gstID)%maxMyNla, 2, &
678 gst(gstID)%maxMyLevCount, mmpi_npex)
679 integer :: yourid,ila,icount,nsize,ierr,jlev,jlev2
680
681 call utl_tmg_start(152,'low-level--gst_barr')
682 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
683 call utl_tmg_stop(152)
684
685 call utl_tmg_start(153,'low-level--gst_transpose_NtoLEV')
686
687 !$OMP PARALLEL DO PRIVATE(yourid,jlev,jlev2,icount)
688 do yourid = 0, (mmpi_npex-1)
689 do jlev = gst(gstID)%allLevBeg(yourid+1), gst(gstID)%allLevEnd(yourid+1)
690 jlev2 = jlev - gst(gstID)%allLevBeg(yourid+1) + 1
691 do icount = 1, gst(gstID)%myNla
692 sp_send(icount,1,jlev2,yourid+1) = psp_in(icount,1,jlev)
693 sp_send(icount,2,jlev2,yourid+1) = psp_in(icount,2,jlev)
694 enddo
695 enddo
696 enddo
697 !$OMP END PARALLEL DO
698
699 nsize = gst(gstID)%maxMyNla * 2 * gst(gstID)%maxMyLevCount
700 if(mmpi_npex.gt.1) then
701 call rpn_comm_alltoall(sp_send, nsize, pre_specTransMpiReal, &
702 sp_recv, nsize, pre_specTransMpiReal, 'EW', ierr)
703 else
704 sp_recv(:,:,:,1) = sp_send(:,:,:,1)
705 endif
706
707 !$OMP PARALLEL DO PRIVATE(yourid,jlev,jlev2,icount,ila)
708 do yourid = 0, (mmpi_npex-1)
709 do jlev = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
710 jlev2 = jlev - gst(gstID)%myLevBeg + 1
711 do icount = 1, gst(gstID)%allNla(yourid+1)
712 ila = gst(gstID)%allIlaList(icount,yourid+1)
713 psp_out(ila,1,jlev) = sp_recv(icount,1,jlev2,yourid+1)
714 psp_out(ila,2,jlev) = sp_recv(icount,2,jlev2,yourid+1)
715 enddo
716 enddo
717 enddo
718 !$OMP END PARALLEL DO
719
720 call utl_tmg_stop(153)
721
722 end subroutine transpose2d_NtoLev
723
724
725 subroutine transpose2d_LevtoN(psp_in,psp_out)
726 implicit none
727
728 ! Arguments:
729 real(8), intent(in) :: psp_in (gst(gstID)%nla, 2, &
730 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
731 real(8), intent(out) :: psp_out(gst(gstID)%myNla, 2, gst(gstID)%nk)
732
733 ! Locals:
734 real(pre_specTransReal) :: sp_send(gst(gstID)%maxMyNla, 2, &
735 gst(gstID)%maxMyLevCount, mmpi_npex)
736 real(pre_specTransReal) :: sp_recv(gst(gstID)%maxMyNla, 2, &
737 gst(gstID)%maxMyLevCount, mmpi_npex)
738 integer :: yourid,ila,icount,nsize,ierr,jlev,jlev2
739
740 call utl_tmg_start(152,'low-level--gst_barr')
741 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
742 call utl_tmg_stop(152)
743
744 call utl_tmg_start(153,'low-level--gst_transpose_NtoLEV')
745
746 !$OMP PARALLEL DO PRIVATE(yourid,jlev,jlev2,icount,ila)
747 do yourid = 0, (mmpi_npex-1)
748 do jlev = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
749 jlev2 = jlev - gst(gstID)%myLevBeg + 1
750 sp_send(:,:,jlev2,yourid+1) = 0.0d0
751 do icount = 1, gst(gstID)%allNla(yourid+1)
752 ila = gst(gstID)%allIlaList(icount,yourid+1)
753 sp_send(icount,1,jlev2,yourid+1) = psp_in(ila,1,jlev)
754 sp_send(icount,2,jlev2,yourid+1) = psp_in(ila,2,jlev)
755 enddo
756 enddo
757 enddo
758 !$OMP END PARALLEL DO
759
760 nsize = gst(gstID)%maxMyNla * 2 * gst(gstID)%maxMyLevCount
761 if(mmpi_npex.gt.1) then
762 call rpn_comm_alltoall(sp_send, nsize, pre_specTransMpiReal, &
763 sp_recv, nsize, pre_specTransMpiReal, 'EW', ierr)
764 else
765 sp_recv(:,:,:,1) = sp_send(:,:,:,1)
766 endif
767
768 !$OMP PARALLEL DO PRIVATE(yourid,jlev,jlev2,icount)
769 do yourid = 0, (mmpi_npex-1)
770 do jlev = gst(gstID)%allLevBeg(yourid+1), gst(gstID)%allLevEnd(yourid+1)
771 jlev2 = jlev - gst(gstID)%allLevBeg(yourid+1) + 1
772 do icount = 1, gst(gstID)%myNla
773 psp_out(icount,1,jlev) = sp_recv(icount,1,jlev2,yourid+1)
774 psp_out(icount,2,jlev) = sp_recv(icount,2,jlev2,yourid+1)
775 enddo
776 enddo
777 enddo
778 !$OMP END PARALLEL DO
779
780 call utl_tmg_stop(153)
781
782 end subroutine transpose2d_LevtoN
783
784
785 subroutine transpose2d_MtoLat(pgd_in,pgd_out)
786 implicit none
787
788 ! Arguments:
789 real(8), intent(in) :: pgd_in(2*gst(gstID)%maxmCount, gst(gstID)%nj, &
790 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
791 real(8), intent(out) :: pgd_out(gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, &
792 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
793
794 ! Locals:
795 real(pre_specTransReal) :: gd_send(gst(gstID)%maxmCount, 2, gst(gstID)%latPerPEmax, &
796 gst(gstID)%maxMyLevCount, mmpi_npey)
797 real(pre_specTransReal) :: gd_recv(gst(gstID)%maxmCount, 2, gst(gstID)%latPerPEmax, &
798 gst(gstID)%maxMyLevCount, mmpi_npey)
799 integer :: yourid,jm,jm2,icount,nsize,ierr,jlev,jlev2,jlat,jlat2
800
801 call utl_tmg_start(152,'low-level--gst_barr')
802 if(mmpi_doBarrier) call rpn_comm_barrier('NS',ierr)
803 call utl_tmg_stop(152)
804
805 call utl_tmg_start(154,'low-level--gst_transpose_MtoLAT')
806
807 !$OMP PARALLEL DO PRIVATE(yourid,jlat,jlat2,jlev,jlev2,icount,jm,jm2)
808 do yourid = 0, (mmpi_npey-1)
809 do jlev = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
810 jlev2 = jlev - gst(gstID)%myLevBeg + 1
811 gd_send(:, :, :, jlev2, yourid+1) = 0.0d0
812 do jlat = gst(gstID)%allLatBeg(yourid+1), gst(gstID)%allLatEnd(yourid+1)
813 jlat2 = jlat - gst(gstID)%allLatBeg(yourid+1) + 1
814 icount = 0
815 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
816 jm2 = 2*gst(gstID)%mymIndex(jm)
817 icount = icount + 1
818 gd_send(icount, 1, jlat2, jlev2, yourid+1) = pgd_in(jm2-1, jlat, jlev)
819 gd_send(icount, 2, jlat2, jlev2, yourid+1) = pgd_in(jm2 , jlat, jlev)
820 enddo
821 enddo
822 enddo
823 enddo
824 !$OMP END PARALLEL DO
825
826 nsize = gst(gstID)%maxmCount * 2 * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPEmax
827 if(mmpi_npey.gt.1) then
828 call rpn_comm_alltoall(gd_send, nsize, pre_specTransMpiReal, &
829 gd_recv, nsize, pre_specTransMpiReal, 'NS', ierr)
830 else
831 gd_recv(:,:,:,:,1) = gd_send(:,:,:,:,1)
832 endif
833
834 !$OMP PARALLEL DO PRIVATE(yourid,jlat,jlat2,jlev,jlev2,icount,jm,jm2)
835 do yourid = 0, (mmpi_npey-1)
836 do jlev = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
837 jlev2 = jlev - gst(gstID)%myLevBeg + 1
838 do jlat = gst(gstID)%myLatBeg, gst(gstID)%myLatEnd
839 jlat2 = jlat - gst(gstID)%myLatBeg + 1
840 icount = 0
841 do jm = gst(gstID)%allmBeg(yourid+1), gst(gstID)%allmEnd(yourid+1), gst(gstID)%allmSkip(yourid+1)
842 jm2 = 2*jm+1
843 icount = icount + 1
844 pgd_out(jm2 , jlat, jlev) = gd_recv(icount, 1, jlat2, jlev2, yourid+1)
845 pgd_out(jm2+1, jlat, jlev) = gd_recv(icount, 2, jlat2, jlev2, yourid+1)
846 enddo
847 enddo
848 enddo
849 enddo
850 !$OMP END PARALLEL DO
851
852 call utl_tmg_stop(154)
853
854 end subroutine transpose2d_MtoLat
855
856
857 subroutine transpose2d_MtoLat_kij(pgd_in,pgd_out)
858 implicit none
859
860 ! Arguments:
861 real(8), intent(in) :: pgd_in(gst(gstID)%maxMyLevCount, 2*gst(gstID)%maxmCount, &
862 gst(gstID)%nj)
863 real(8), intent(out) :: pgd_out(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
864 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
865
866 ! Locals:
867 real(pre_specTransReal), allocatable, save :: gd_send(:,:,:,:,:)
868 real(pre_specTransReal), allocatable, save :: gd_recv(:,:,:,:,:)
869 integer :: yourid,jm,jm2,icount,nsize,ierr,jlev,jlat,jlat2
870
871 call utl_reAllocate(gd_send, gst(gstID)%maxMyLevCount, gst(gstID)%maxmCount, 2, gst(gstID)%latPerPEmax, mmpi_npey)
872 call utl_reAllocate(gd_recv, gst(gstID)%maxMyLevCount, gst(gstID)%maxmCount, 2, gst(gstID)%latPerPEmax, mmpi_npey)
873
874 call utl_tmg_start(152,'low-level--gst_barr')
875 if(mmpi_doBarrier) call rpn_comm_barrier('NS',ierr)
876 call utl_tmg_stop(152)
877
878 call utl_tmg_start(154,'low-level--gst_transpose_MtoLAT')
879
880 !$OMP PARALLEL DO PRIVATE(yourid,jlat,jlat2,jlev,icount,jm,jm2)
881 do yourid = 0, (mmpi_npey-1)
882 gd_send(:, :, :, :, yourid+1) = 0.0d0
883 do jlat = gst(gstID)%allLatBeg(yourid+1), gst(gstID)%allLatEnd(yourid+1)
884 jlat2 = jlat - gst(gstID)%allLatBeg(yourid+1) + 1
885 icount = 0
886 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
887 jm2 = 2*gst(gstID)%mymIndex(jm)
888 icount = icount + 1
889 do jlev = 1, gst(gstID)%maxMyLevCount
890 gd_send(jlev, icount, 1, jlat2, yourid+1) = pgd_in(jlev, jm2-1, jlat)
891 gd_send(jlev, icount, 2, jlat2, yourid+1) = pgd_in(jlev, jm2 , jlat)
892 enddo
893 enddo
894 enddo
895 enddo
896 !$OMP END PARALLEL DO
897
898 nsize = gst(gstID)%maxmCount * 2 * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPEmax
899 if(mmpi_npey.gt.1) then
900 call rpn_comm_alltoall(gd_send, nsize, pre_specTransMpiReal, &
901 gd_recv, nsize, pre_specTransMpiReal, 'NS', ierr)
902 else
903 gd_recv(:,:,:,:,1) = gd_send(:,:,:,:,1)
904 endif
905
906 !$OMP PARALLEL DO PRIVATE(yourid,jlat,jlat2,jlev,icount,jm,jm2)
907 do yourid = 0, (mmpi_npey-1)
908 do jlat = gst(gstID)%myLatBeg, gst(gstID)%myLatEnd
909 jlat2 = jlat - gst(gstID)%myLatBeg + 1
910 icount = 0
911 do jm = gst(gstID)%allmBeg(yourid+1), gst(gstID)%allmEnd(yourid+1), gst(gstID)%allmSkip(yourid+1)
912 jm2 = 2*jm+1
913 icount = icount + 1
914 do jlev = 1, gst(gstID)%maxMyLevCount
915 pgd_out(jlev, jm2 , jlat) = gd_recv(jlev, icount, 1, jlat2, yourid+1)
916 pgd_out(jlev, jm2+1, jlat) = gd_recv(jlev, icount, 2, jlat2, yourid+1)
917 enddo
918 enddo
919 enddo
920 enddo
921 !$OMP END PARALLEL DO
922
923 call utl_tmg_stop(154)
924
925 end subroutine transpose2d_MtoLat_kij
926
927
928 subroutine transpose2d_LattoM(pgd_in,pgd_out)
929 implicit none
930
931 ! Arguments:
932 real(8), intent(in) :: pgd_in(gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, &
933 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
934 real(8), intent(out) :: pgd_out(2*gst(gstID)%maxmCount, gst(gstID)%nj, &
935 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
936
937 ! Locals:
938 real(pre_specTransReal) :: gd_send(gst(gstID)%maxmCount, 2, gst(gstID)%latPerPEmax, &
939 gst(gstID)%maxMyLevCount, mmpi_npey)
940 real(pre_specTransReal) :: gd_recv(gst(gstID)%maxmCount, 2, gst(gstID)%latPerPEmax, &
941 gst(gstID)%maxMyLevCount, mmpi_npey)
942 integer :: yourid,jm,jm2,icount,nsize,ierr,jlev,jlev2,jlat,jlat2
943
944 call utl_tmg_start(152,'low-level--gst_barr')
945 if(mmpi_doBarrier) call rpn_comm_barrier('NS',ierr)
946 call utl_tmg_stop(152)
947
948 call utl_tmg_start(154,'low-level--gst_transpose_MtoLAT')
949
950 !$OMP PARALLEL DO PRIVATE(yourid,jlat,jlat2,jlev,jlev2,icount,jm,jm2)
951 do yourid = 0, (mmpi_npey-1)
952 do jlev = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
953 jlev2 = jlev - gst(gstID)%myLevBeg + 1
954 gd_send(:, :, :, jlev2, yourid+1) = 0.0d0
955 do jlat = gst(gstID)%myLatBeg, gst(gstID)%myLatEnd
956 jlat2 = jlat - gst(gstID)%myLatBeg + 1
957 icount = 0
958 do jm = gst(gstID)%allmBeg(yourid+1), gst(gstID)%allmEnd(yourid+1), gst(gstID)%allmSkip(yourid+1)
959 jm2 = 2*jm+1
960 icount = icount + 1
961 gd_send(icount, 1, jlat2, jlev2, yourid+1) = pgd_in(jm2 , jlat, jlev)
962 gd_send(icount, 2, jlat2, jlev2, yourid+1) = pgd_in(jm2+1, jlat, jlev)
963 enddo
964 enddo
965 enddo
966 enddo
967 !$OMP END PARALLEL DO
968
969 nsize = gst(gstID)%maxmCount * 2 * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPEmax
970 if(mmpi_npey.gt.1) then
971 call rpn_comm_alltoall(gd_send, nsize, pre_specTransMpiReal, &
972 gd_recv, nsize, pre_specTransMpiReal, 'NS', ierr)
973 else
974 gd_recv(:,:,:,:,1) = gd_send(:,:,:,:,1)
975 endif
976
977 !$OMP PARALLEL DO PRIVATE(yourid,jlat,jlat2,jlev,jlev2,icount,jm,jm2)
978 do yourid = 0, (mmpi_npey-1)
979 do jlev = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
980 jlev2 = jlev - gst(gstID)%myLevBeg + 1
981 do jlat = gst(gstID)%allLatBeg(yourid+1), gst(gstID)%allLatEnd(yourid+1)
982 jlat2 = jlat - gst(gstID)%allLatBeg(yourid+1) + 1
983 icount = 0
984 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
985 jm2 = 2*gst(gstID)%mymIndex(jm)
986 icount = icount + 1
987 pgd_out(jm2-1,jlat,jlev) = gd_recv(icount,1,jlat2,jlev2,yourid+1)
988 pgd_out(jm2 ,jlat,jlev) = gd_recv(icount,2,jlat2,jlev2,yourid+1)
989 enddo
990 enddo
991 enddo
992 enddo
993 !$OMP END PARALLEL DO
994
995 call utl_tmg_stop(154)
996
997 end subroutine transpose2d_LattoM
998
999
1000 subroutine transpose2d_LattoM_kij(pgd_in,pgd_out)
1001 implicit none
1002
1003 ! Arguments:
1004 real(8), intent(in) :: pgd_in(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
1005 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1006 real(8), intent(out) :: pgd_out(gst(gstID)%maxMyLevCount, 2*gst(gstID)%maxmCount, &
1007 gst(gstID)%nj)
1008
1009 ! Locals:
1010 real(pre_specTransReal), allocatable, save :: gd_send(:,:,:,:,:)
1011 real(pre_specTransReal), allocatable, save :: gd_recv(:,:,:,:,:)
1012 integer :: yourid,jm,jm2,icount,nsize,ierr,jlev,jlat,jlat2
1013
1014 call utl_reAllocate(gd_send, gst(gstID)%maxMyLevCount, gst(gstID)%maxmCount, 2, gst(gstID)%latPerPEmax, mmpi_npey)
1015 call utl_reAllocate(gd_recv, gst(gstID)%maxMyLevCount, gst(gstID)%maxmCount, 2, gst(gstID)%latPerPEmax, mmpi_npey)
1016
1017 call utl_tmg_start(152,'low-level--gst_barr')
1018 if(mmpi_doBarrier) call rpn_comm_barrier('NS',ierr)
1019 call utl_tmg_stop(152)
1020
1021 call utl_tmg_start(154,'low-level--gst_transpose_MtoLAT')
1022
1023 !$OMP PARALLEL DO PRIVATE(yourid,jlat,jlat2,jlev,icount,jm,jm2)
1024 do yourid = 0, (mmpi_npey-1)
1025 gd_send(:, :, :, :, yourid+1) = 0.0d0
1026 do jlat = gst(gstID)%myLatBeg, gst(gstID)%myLatEnd
1027 jlat2 = jlat - gst(gstID)%myLatBeg + 1
1028 icount = 0
1029 do jm = gst(gstID)%allmBeg(yourid+1), gst(gstID)%allmEnd(yourid+1), gst(gstID)%allmSkip(yourid+1)
1030 jm2 = 2*jm+1
1031 icount = icount + 1
1032 do jlev = 1, gst(gstID)%maxMyLevCount
1033 gd_send(jlev, icount, 1, jlat2, yourid+1) = pgd_in(jlev, jm2 , jlat)
1034 gd_send(jlev, icount, 2, jlat2, yourid+1) = pgd_in(jlev, jm2+1, jlat)
1035 enddo
1036 enddo
1037 enddo
1038 enddo
1039 !$OMP END PARALLEL DO
1040
1041 nsize = gst(gstID)%maxmCount * 2 * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPEmax
1042 if(mmpi_npey.gt.1) then
1043 call rpn_comm_alltoall(gd_send, nsize, pre_specTransMpiReal, &
1044 gd_recv, nsize, pre_specTransMpiReal, 'NS', ierr)
1045 else
1046 gd_recv(:,:,:,:,1) = gd_send(:,:,:,:,1)
1047 endif
1048
1049 !$OMP PARALLEL DO PRIVATE(yourid,jlat,jlat2,jlev,icount,jm,jm2)
1050 do yourid = 0, (mmpi_npey-1)
1051 do jlat = gst(gstID)%allLatBeg(yourid+1), gst(gstID)%allLatEnd(yourid+1)
1052 jlat2 = jlat - gst(gstID)%allLatBeg(yourid+1) + 1
1053 icount = 0
1054 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
1055 jm2 = 2*gst(gstID)%mymIndex(jm)
1056 icount = icount + 1
1057 do jlev = 1, gst(gstID)%maxMyLevCount
1058 pgd_out(jlev, jm2-1, jlat) = gd_recv(jlev, icount, 1, jlat2, yourid+1)
1059 pgd_out(jlev, jm2 , jlat) = gd_recv(jlev, icount, 2, jlat2, yourid+1)
1060 enddo
1061 enddo
1062 enddo
1063 enddo
1064 !$OMP END PARALLEL DO
1065
1066 call utl_tmg_stop(154)
1067
1068 end subroutine transpose2d_LattoM_kij
1069
1070
1071 subroutine transpose2d_LevtoLon(pgd_in,pgd_out)
1072 implicit none
1073
1074 ! Arguments:
1075 real(8), intent(in) :: pgd_in(gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, &
1076 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1077 real(8), intent(out) :: pgd_out(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1078 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
1079
1080 ! Locals:
1081 real(pre_specTransReal) :: gd_send(gst(gstID)%lonPerPEmax, gst(gstID)%latPerPEmax, &
1082 gst(gstID)%maxMyLevCount, mmpi_npex)
1083 real(pre_specTransReal) :: gd_recv(gst(gstID)%lonPerPEmax, gst(gstID)%latPerPEmax, &
1084 gst(gstID)%maxMyLevCount, mmpi_npex)
1085 integer :: youridP1,nsize,ierr,jlev,jlev2
1086
1087 call utl_tmg_start(152,'low-level--gst_barr')
1088 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
1089 call utl_tmg_stop(152)
1090
1091 call utl_tmg_start(155,'low-level--gst_transpose_LEVtoLON')
1092
1093 !$OMP PARALLEL DO PRIVATE(youridP1,jlev,jlev2)
1094 do jlev = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
1095 jlev2 = jlev - gst(gstID)%myLevBeg + 1
1096 do youridP1 = 1, mmpi_npex
1097 gd_send(:, :, jlev2, youridP1) = 0.0d0
1098 gd_send(1:gst(gstID)%allLonPerPE(youridP1), 1:gst(gstID)%latPerPE, jlev2, youridP1) = &
1099 pgd_in(gst(gstID)%allLonBeg(youridP1):gst(gstID)%allLonEnd(youridP1), :, jlev)
1100 enddo
1101 enddo
1102 !$OMP END PARALLEL DO
1103
1104 nsize = gst(gstID)%lonPerPEmax * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPEmax
1105 if(mmpi_npex.gt.1) then
1106 call rpn_comm_alltoall(gd_send,nsize,pre_specTransMpiReal, &
1107 gd_recv,nsize,pre_specTransMpiReal,'EW',ierr)
1108 else
1109 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
1110 endif
1111
1112 !$OMP PARALLEL DO PRIVATE(youridP1,jlev,jlev2)
1113 do youridP1 = 1, mmpi_npex
1114 do jlev=gst(gstID)%allLevBeg(youridP1),gst(gstID)%allLevEnd(youridP1)
1115 jlev2=jlev-gst(gstID)%allLevBeg(youridP1)+1
1116 pgd_out(:, :, jlev) = gd_recv(1:gst(gstID)%lonPerPE, 1:gst(gstID)%latPerPE, jlev2, youridP1)
1117 enddo
1118 enddo
1119 !$OMP END PARALLEL DO
1120
1121 call utl_tmg_stop(155)
1122
1123 end subroutine transpose2d_LevtoLon
1124
1125
1126 subroutine transpose2d_LevtoLon_kij_mpitypes8(pgd_in,pgd_out)
1127 implicit none
1128
1129 ! Arguments:
1130 real(8), intent(in) :: pgd_in(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
1131 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1132 real(8), intent(out) :: pgd_out(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1133 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1134
1135 ! Locals:
1136 integer :: nsize,ierr
1137
1138 call utl_tmg_start(152,'low-level--gst_barr')
1139 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
1140 call utl_tmg_stop(152)
1141
1142 call utl_tmg_start(155,'low-level--gst_transpose_LEVtoLON')
1143
1144 nsize = gst(gstID)%lonPerPE * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPE
1145 if(mmpi_npex.gt.1) then
1146 call mpi_alltoall(pgd_in, 1, gst(gstID)%sendType_LevToLon, &
1147 pgd_out, 1, gst(gstID)%recvType_LevToLon, mmpi_comm_EW, ierr)
1148 else
1149 pgd_out(:,:,:) = pgd_in(:,:,:)
1150 endif
1151
1152 call utl_tmg_stop(155)
1153
1154 end subroutine transpose2d_LevtoLon_kij_mpitypes8
1155
1156
1157 subroutine transpose2d_LevtoLon_kij_mpitypes4(pgd_in,pgd_out)
1158 implicit none
1159
1160 ! Arguments:
1161 real(8), intent(in) :: pgd_in(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
1162 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1163 real(8), intent(out) :: pgd_out(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1164 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1165
1166 ! Locals:
1167 integer :: nsize,ierr
1168 real(4) :: pgd_in_r4(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
1169 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1170 real(4) :: pgd_out_r4(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1171 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1172
1173 call utl_tmg_start(152,'low-level--gst_barr')
1174 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
1175 call utl_tmg_stop(152)
1176
1177 call utl_tmg_start(155,'low-level--gst_transpose_LEVtoLON')
1178
1179 nsize = gst(gstID)%lonPerPE * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPE
1180 if(mmpi_npex.gt.1) then
1181 pgd_in_r4(:,:,:) = pgd_in(:,:,:)
1182 call mpi_alltoall(pgd_in_r4, 1, gst(gstID)%sendType_LevToLon, &
1183 pgd_out_r4, 1, gst(gstID)%recvType_LevToLon, mmpi_comm_EW, ierr)
1184 pgd_out(:,:,:) = pgd_out_r4(:,:,:)
1185 else
1186 pgd_out(:,:,:) = pgd_in(:,:,:)
1187 endif
1188
1189 call utl_tmg_stop(155)
1190
1191 end subroutine transpose2d_LevtoLon_kij_mpitypes4
1192
1193
1194 subroutine transpose2d_LevtoLon_kij(pgd_in,pgd_out)
1195 implicit none
1196
1197 ! Arguments:
1198 real(8), intent(in) :: pgd_in(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
1199 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1200 real(8), intent(out) :: pgd_out(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1201 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1202
1203 ! Locals:
1204 real(pre_specTransReal) :: gd_send(gst(gstID)%maxMyLevCount, gst(gstID)%lonPerPEmax,&
1205 gst(gstID)%latPerPEmax, mmpi_npex)
1206 real(pre_specTransReal) :: gd_recv(gst(gstID)%maxMyLevCount, gst(gstID)%lonPerPEmax,&
1207 gst(gstID)%latPerPEmax, mmpi_npex)
1208 integer :: youridP1, nsize, ierr, yourNumLev
1209
1210 call utl_tmg_start(152,'low-level--gst_barr')
1211 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
1212 call utl_tmg_stop(152)
1213
1214 call utl_tmg_start(155,'low-level--gst_transpose_LEVtoLON')
1215
1216 !$OMP PARALLEL DO PRIVATE(youridP1)
1217 do youridP1 = 1, mmpi_npex
1218 gd_send(:, :, :, youridP1) = 0.0d0
1219 gd_send(:, 1:gst(gstID)%allLonPerPE(youridP1), 1:gst(gstID)%latPerPE, youridP1) = &
1220 pgd_in(:, gst(gstID)%allLonBeg(youridP1):gst(gstID)%allLonEnd(youridP1), :)
1221 enddo
1222 !$OMP END PARALLEL DO
1223
1224 nsize = gst(gstID)%lonPerPEmax * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPEmax
1225 if(mmpi_npex.gt.1) then
1226 call rpn_comm_alltoall(gd_send, nsize, pre_specTransMpiReal, &
1227 gd_recv, nsize, pre_specTransMpiReal, 'EW', ierr)
1228 else
1229 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
1230 endif
1231
1232 !$OMP PARALLEL DO PRIVATE(youridP1,yourNumLev)
1233 do youridP1 = 1, mmpi_npex
1234 yourNumLev = gst(gstID)%allLevEnd(youridP1) - gst(gstID)%allLevBeg(youridP1) + 1
1235 pgd_out(gst(gstID)%allLevBeg(youridP1):gst(gstID)%allLevEnd(youridP1), :, :) = &
1236 gd_recv(1:yourNumLev, 1:gst(gstID)%lonPerPE, 1:gst(gstID)%latPerPE, youridP1)
1237 enddo
1238 !$OMP END PARALLEL DO
1239
1240 call utl_tmg_stop(155)
1241
1242 end subroutine transpose2d_LevtoLon_kij
1243
1244
1245 subroutine transpose2d_LontoLev(pgd_in,pgd_out)
1246 implicit none
1247
1248 ! Arguments:
1249 real(8), intent(in) :: pgd_in(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1250 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
1251 real(8), intent(out) :: pgd_out(gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, &
1252 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1253
1254 ! Locals:
1255 real(pre_specTransReal) :: gd_send(gst(gstID)%lonPerPEmax, gst(gstID)%latPerPEmax, &
1256 gst(gstID)%maxMyLevCount, mmpi_npex)
1257 real(pre_specTransReal) :: gd_recv(gst(gstID)%lonPerPEmax, gst(gstID)%latPerPEmax, &
1258 gst(gstID)%maxMyLevCount, mmpi_npex)
1259 integer :: youridP1,nsize,ierr,jlev,jlev2
1260
1261 call utl_tmg_start(152,'low-level--gst_barr')
1262 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
1263 call utl_tmg_stop(152)
1264
1265 call utl_tmg_start(155,'low-level--gst_transpose_LEVtoLON')
1266
1267 !$OMP PARALLEL DO PRIVATE(youridP1,jlev,jlev2)
1268 do youridP1 = 1, mmpi_npex
1269 do jlev=gst(gstID)%allLevBeg(youridP1),gst(gstID)%allLevEnd(youridP1)
1270 jlev2=jlev-gst(gstID)%allLevBeg(youridP1)+1
1271 gd_send(:, :, jlev2, youridP1) = 0.0d0
1272 gd_send(1:gst(gstID)%lonPerPE, 1:gst(gstID)%latPerPE, jlev2, youridP1) = &
1273 pgd_in(:,:,jlev)
1274 enddo
1275 enddo
1276 !$OMP END PARALLEL DO
1277
1278 nsize = gst(gstID)%lonPerPEmax * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPEmax
1279 if(mmpi_npex.gt.1) then
1280 call rpn_comm_alltoall(gd_send, nsize, pre_specTransMpiReal, &
1281 gd_recv, nsize, pre_specTransMpiReal, 'EW', ierr)
1282 else
1283 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
1284 endif
1285
1286 !$OMP PARALLEL DO PRIVATE(youridP1,jlev,jlev2)
1287 do jlev = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
1288 jlev2 = jlev - gst(gstID)%myLevBeg + 1
1289 do youridP1 = 1, mmpi_npex
1290 pgd_out(gst(gstID)%allLonBeg(youridP1):gst(gstID)%allLonEnd(youridP1), :, jlev) = &
1291 gd_recv(1:gst(gstID)%allLonPerPE(youridP1),1:gst(gstID)%latPerPE,jlev2,youridP1)
1292 enddo
1293 enddo
1294 !$OMP END PARALLEL DO
1295
1296 call utl_tmg_stop(155)
1297
1298 end subroutine transpose2d_LontoLev
1299
1300
1301 subroutine transpose2d_LontoLev_kij_mpitypes8(pgd_in,pgd_out)
1302 implicit none
1303
1304 ! Arguments:
1305 real(8), intent(in) :: pgd_in(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1306 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1307 real(8), intent(out) :: pgd_out(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
1308 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1309
1310 ! Locals:
1311 integer :: nsize, ierr
1312
1313 call utl_tmg_start(152,'low-level--gst_barr')
1314 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
1315 call utl_tmg_stop(152)
1316
1317 call utl_tmg_start(155,'low-level--gst_transpose_LEVtoLON')
1318
1319 nsize = gst(gstID)%lonPerPE * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPE
1320 if(mmpi_npex.gt.1) then
1321 call mpi_alltoall(pgd_in, 1, gst(gstID)%sendType_LonToLev, &
1322 pgd_out, 1, gst(gstID)%recvType_LonToLev, mmpi_comm_EW, ierr)
1323 else
1324 pgd_out(:,:,:) = pgd_in(:,:,:)
1325 endif
1326
1327 call utl_tmg_stop(155)
1328
1329 end subroutine transpose2d_LontoLev_kij_mpitypes8
1330
1331
1332 subroutine transpose2d_LontoLev_kij_mpitypes4(pgd_in,pgd_out)
1333 implicit none
1334
1335 ! Arguments:
1336 real(8), intent(in) :: pgd_in(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1337 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1338 real(8), intent(out) :: pgd_out(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
1339 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1340
1341 ! Locals:
1342 integer :: nsize, ierr
1343 real(4) :: pgd_in_r4(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1344 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1345 real(4) :: pgd_out_r4(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
1346 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1347
1348 call utl_tmg_start(152,'low-level--gst_barr')
1349 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
1350 call utl_tmg_stop(152)
1351
1352 call utl_tmg_start(155,'low-level--gst_transpose_LEVtoLON')
1353
1354 nsize = gst(gstID)%lonPerPE * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPE
1355 if(mmpi_npex.gt.1) then
1356 pgd_in_r4(:,:,:) = pgd_in(:,:,:)
1357 call mpi_alltoall(pgd_in_r4, 1, gst(gstID)%sendType_LonToLev, &
1358 pgd_out_r4, 1, gst(gstID)%recvType_LonToLev, mmpi_comm_EW, ierr)
1359 pgd_out(:,:,:) = pgd_out_r4(:,:,:)
1360 else
1361 pgd_out(:,:,:) = pgd_in(:,:,:)
1362 endif
1363
1364 call utl_tmg_stop(155)
1365
1366 end subroutine transpose2d_LontoLev_kij_mpitypes4
1367
1368
1369 subroutine transpose2d_LontoLev_kij(pgd_in,pgd_out)
1370 implicit none
1371
1372 ! Arguments:
1373 real(8), intent(in) :: pgd_in(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1374 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1375 real(8), intent(out) :: pgd_out(gst(gstID)%maxMyLevCount, gst(gstID)%ni, &
1376 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
1377
1378 ! Locals:
1379 real(pre_specTransReal) :: gd_send(gst(gstID)%maxMyLevCount, gst(gstID)%lonPerPEmax,&
1380 gst(gstID)%latPerPEmax, mmpi_npex)
1381 real(pre_specTransReal) :: gd_recv(gst(gstID)%maxMyLevCount, gst(gstID)%lonPerPEmax,&
1382 gst(gstID)%latPerPEmax, mmpi_npex)
1383 integer :: youridP1,nsize,ierr,jlev,jlev2,yourNumLev
1384
1385 call utl_tmg_start(152,'low-level--gst_barr')
1386 if(mmpi_doBarrier) call rpn_comm_barrier('EW',ierr)
1387 call utl_tmg_stop(152)
1388
1389 call utl_tmg_start(155,'low-level--gst_transpose_LEVtoLON')
1390
1391 !$OMP PARALLEL DO PRIVATE(youridP1,yourNumLev)
1392 do youridP1 = 1, mmpi_npex
1393 yourNumLev = gst(gstID)%allLevEnd(youridP1) - gst(gstID)%allLevBeg(youridP1) + 1
1394 gd_send(:, :, :, youridP1) = 0.0d0
1395 gd_send(1:yourNumLev, 1:gst(gstID)%lonPerPE, 1:gst(gstID)%latPerPE, youridP1) = &
1396 pgd_in(gst(gstID)%allLevBeg(youridP1):gst(gstID)%allLevEnd(youridP1),:,:)
1397 enddo
1398 !$OMP END PARALLEL DO
1399
1400 nsize = gst(gstID)%lonPerPEmax * gst(gstID)%maxMyLevCount * gst(gstID)%latPerPEmax
1401 if(mmpi_npex.gt.1) then
1402 call rpn_comm_alltoall(gd_send, nsize, pre_specTransMpiReal, &
1403 gd_recv, nsize, pre_specTransMpiReal, 'EW', ierr)
1404 else
1405 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
1406 endif
1407
1408 !$OMP PARALLEL DO PRIVATE(youridP1,jlev,jlev2)
1409 do youridP1 = 1, mmpi_npex
1410 pgd_out(:, gst(gstID)%allLonBeg(youridP1):gst(gstID)%allLonEnd(youridP1), :) = &
1411 gd_recv(:, 1:gst(gstID)%allLonPerPE(youridP1), 1:gst(gstID)%latPerPE, youridP1)
1412 enddo
1413 !$OMP END PARALLEL DO
1414
1415 call utl_tmg_stop(155)
1416
1417 end subroutine transpose2d_LontoLev_kij
1418
1419!-------------------------------------------------------------------------------
1420! Subroutines to re-order the u and v wind components for mpi version of spgd
1421! and spgda
1422!-------------------------------------------------------------------------------
1423
1424 subroutine interleaveWinds_sp(psp,nflev)
1425 implicit none
1426
1427 ! Arguments:
1428 integer, intent(in) :: nflev
1429 real(8), intent(inout) :: psp(gst(gstID)%myNla,2,gst(gstID)%nk)
1430
1431 ! Locals:
1432 real(8) :: tempvalues(2,nflev*2)
1433 integer :: jk, ila
1434
1435 !$OMP PARALLEL DO PRIVATE (ILA,JK,TEMPVALUES)
1436 do ila = 1, gst(gstID)%myNla
1437 do jk = 1, nflev
1438 ! place u in new position in temporary array
1439 tempvalues(:,(jk*2)-1) = psp(ila,:,jk)
1440 ! place v in new position in temporary array
1441 tempvalues(:,jk*2) = psp(ila,:,jk+nflev)
1442 enddo
1443 ! move contents of temporary array back to original array
1444 psp(ila,:,1:2*nflev) = tempvalues(:,1:2*nflev)
1445 enddo
1446 !$OMP END PARALLEL DO
1447
1448 end subroutine interleaveWinds_sp
1449
1450
1451 subroutine unInterleaveWinds_sp(psp,nflev)
1452 implicit none
1453
1454 ! Arguments:
1455 integer, intent(in) :: nflev
1456 real(8), intent(inout) :: psp(gst(gstID)%myNla,2,gst(gstID)%nk)
1457
1458 ! Locals:
1459 real(8) :: tempvalues(2,nflev*2)
1460 integer :: jk, ila
1461
1462 !$OMP PARALLEL DO PRIVATE (ILA,JK,TEMPVALUES)
1463 do ila = 1, gst(gstID)%myNla
1464 do jk = 1, nflev
1465 ! place u in original position in temporary array
1466 tempvalues(:,jk) = psp(ila,:,(jk*2)-1)
1467 ! place v in original position in temporary array
1468 tempvalues(:,jk+nflev) = psp(ila,:,jk*2)
1469 enddo
1470 ! move contents of temporary array back to original array
1471 psp(ila,:,1:2*nflev) = tempvalues(:,1:2*nflev)
1472 enddo
1473 !$OMP END PARALLEL DO
1474
1475 end subroutine unInterleaveWinds_sp
1476
1477
1478 subroutine interleaveWinds_gd(pgd,nflev)
1479 implicit none
1480
1481 ! Arguments:
1482 integer, intent(in) :: nflev
1483 real(8), intent(inout) :: pgd(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1484 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
1485
1486 ! Locals:
1487 real(8) :: tempvalues(nflev*2)
1488 integer :: jlat, jk, jlon
1489
1490 !$OMP PARALLEL DO PRIVATE (JLAT,JLON,JK,TEMPVALUES)
1491 do jlat = gst(gstID)%myLatBeg, gst(gstID)%myLatEnd
1492 do jlon = gst(gstID)%myLonBeg, gst(gstID)%myLonEnd
1493 do jk = 1, nflev
1494 ! place u in original position in temporary array
1495 tempvalues((jk*2)-1) = pgd(jlon,jlat,jk)
1496 ! place v in original position in temporary array
1497 tempvalues(jk*2) = pgd(jlon,jlat,jk+nflev)
1498 enddo
1499 ! move contents of temporary array back to original array
1500 pgd(jlon,jlat,1:2*nflev) = tempvalues(1:2*nflev)
1501 enddo
1502 enddo
1503 !$OMP END PARALLEL DO
1504
1505 end subroutine interleaveWinds_gd
1506
1507
1508 subroutine unInterleaveWinds_gd(pgd,nflev)
1509 implicit none
1510
1511 ! Arguments:
1512 integer, intent(in) :: nflev
1513 real(8), intent(inout) :: pgd(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1514 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
1515
1516 ! Locals:
1517 real(8) :: tempvalues(nflev*2)
1518 integer :: jlat, jk, jlon
1519
1520 !$OMP PARALLEL DO PRIVATE (JLAT,JLON,JK,TEMPVALUES)
1521 do jlat = gst(gstID)%myLatBeg, gst(gstID)%myLatEnd
1522 do jlon = gst(gstID)%myLonBeg, gst(gstID)%myLonEnd
1523 do jk = 1, nflev
1524 ! place u in original position in temporary array
1525 tempvalues(jk) = pgd(jlon,jlat,(jk*2)-1)
1526 ! place v in original position in temporary array
1527 tempvalues(jk+nflev) = pgd(jlon,jlat,jk*2)
1528 enddo
1529 ! move contents of temporary array back to original array
1530 pgd(jlon,jlat,1:2*nflev) = tempvalues(1:2*nflev)
1531 enddo
1532 enddo
1533 !$OMP END PARALLEL DO
1534
1535 end subroutine unInterleaveWinds_gd
1536
1537!-------------------------------------------------------------------------------
1538! Main spectral transform subroutines
1539!-------------------------------------------------------------------------------
1540
1541 subroutine gst_spgd(psp,pgd,nflev)
1542 implicit none
1543
1544 ! Arguments:
1545 integer, intent(in) :: nflev
1546 real(8), intent(inout) :: psp(gst(gstID)%myNla,2,gst(gstID)%nk)
1547 real(8), intent(out) :: pgd(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1548 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
1549
1550 ! Locals:
1551 real(8), allocatable :: psp2(:,:,:),pgd2(:,:,:),pgd3(:,:,:)
1552 integer :: jlat, jk, jlon
1553
1554 ! check if this mpi task will deal with winds during Legendre transform
1555 if(gst(gstID)%myLevBeg.le.2*nflev) then
1556 ! ensure that the number of levels on this mpi task is even to allow interleaving of u and v
1557 ! only necessary when number of levels on an mpi task is less than all wind levels (2nd condition)
1558 if( (mod(gst(gstID)%myLevCount,2).ne.0) .and. (gst(gstID)%myLevCount < 2*nflev) ) then
1559 write(*,*) 'GST_SPGD: myLevCount = ',gst(gstID)%myLevCount
1560 call utl_abort('GST_SPGD: Number of levels on this mpi task must be even!')
1561 endif
1562 endif
1563
1564 allocate(psp2(gst(gstID)%nla, 2, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
1565 allocate(pgd2(2*gst(gstID)%maxmcount, gst(gstID)%nj, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
1566 allocate(pgd3(gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
1567
1568 ! 1.0 First reorder wind components to have u and v for same level on same mpi task
1569 call interleaveWinds_sp(psp,nflev)
1570
1571 ! 1.1 Transpose data along npex from N to Levels
1572 call transpose2d_NtoLev(psp,psp2)
1573
1574 ! 1.2 Inverse Legendre transform
1575 call utl_tmg_start(150,'low-level--gst_lt')
1576 call spgdpar(psp2,pgd2,nflev)
1577 call utl_tmg_stop(150)
1578 deallocate(psp2)
1579
1580 ! 1.3 Transpose data along npey from M to Latitudes
1581 call transpose2d_MtoLat(pgd2,pgd3)
1582 deallocate(pgd2)
1583
1584 !$OMP PARALLEL DO PRIVATE (JLAT,JLON,JK)
1585 ! 2.1 Reset to zero the modes that are not part of the truncation
1586 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
1587 do jlat = gst(gstID)%myLatBeg, gst(gstID)%myLatEnd
1588 do jlon = 2*(gst(gstID)%ntrunc+1)+1, gst(gstID)%ni
1589 pgd3(jlon,jlat,jk) = 0.d0
1590 enddo
1591 enddo
1592 enddo
1593 !$OMP END PARALLEL DO
1594
1595 ! 2.2 Apply the FFT
1596 call utl_tmg_start(151,'low-level--gst_fft')
1597 call fft3dvar(pgd3,+1)
1598 call utl_tmg_stop(151)
1599
1600 ! 2.3 Transpose data along npex from Levels to Longitudes
1601 call transpose2d_LevtoLon(pgd3,pgd)
1602 deallocate(pgd3)
1603
1604 ! 2.4 Now undo reordering of wind components
1605 call unInterleaveWinds_gd(pgd,nflev)
1606
1607 end subroutine gst_spgd
1608
1609
1610 subroutine gst_gdsp(psp,pgd,nflev)
1611 implicit none
1612
1613 ! Arguments:
1614 integer, intent(in) :: nflev
1615 real(8), intent(out) :: psp(gst(gstID)%myNla,2,gst(gstID)%nk)
1616 real(8), intent(inout) :: pgd(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1617 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd,gst(gstID)%nk)
1618
1619 ! Locals:
1620 real(8), allocatable :: psp2(:,:,:),pgd2(:,:,:),pgd3(:,:,:)
1621
1622 ! check if this mpi task will deal with winds during Legendre transform
1623 if(gst(gstID)%myLevBeg.le.2*nflev) then
1624 ! ensure that the number of levels on this mpi task is even to allow interleaving of u and v
1625 ! only necessary when number of levels on an mpi task is less than all wind levels (2nd condition)
1626 if( (mod(gst(gstID)%myLevCount,2).ne.0) .and. (gst(gstID)%myLevCount < 2*nflev) ) then
1627 write(*,*) 'GST_GDSP: myLevCount = ',gst(gstID)%myLevCount
1628 call utl_abort('GST_GDSP: Number of levels on this mpi task must be even!')
1629 endif
1630 endif
1631
1632 allocate(psp2(gst(gstID)%nla, 2, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
1633 allocate(pgd2(2*gst(gstID)%maxmcount, gst(gstID)%nj, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
1634 allocate(pgd3(gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
1635
1636 ! 1.0 First reorder wind components to have u and v for same level on same mpi task
1637 call interleaveWinds_gd(pgd,nflev)
1638
1639 ! Transpose data along npex from Longitudes to Levels
1640 call transpose2d_LontoLev(pgd,pgd3)
1641
1642 ! 1. Fourier transform all fields for all latitudes
1643 call utl_tmg_start(151,'low-level--gst_fft')
1644 call fft3dvar(pgd3,-1)
1645 call utl_tmg_stop(151)
1646
1647 ! Transpose data along npey from Latitudes to M
1648 call transpose2d_LattoM(pgd3,pgd2)
1649 deallocate(pgd3)
1650
1651 ! 2. Direct Legendre transform including wind transformations
1652 call utl_tmg_start(150,'low-level--gst_lt')
1653 call gdsppar(psp2,pgd2,nflev)
1654 call utl_tmg_stop(150)
1655 deallocate(pgd2)
1656
1657 ! Transpose data along npex from Levels to N
1658 call transpose2d_LevtoN(psp2,psp)
1659 deallocate(psp2)
1660
1661 ! 2.4 Now undo reordering of wind components
1662 call unInterleaveWinds_sp(psp,nflev)
1663
1664 end subroutine gst_gdsp
1665
1666
1667 subroutine spgdpar(psp,pgd2,nflev)
1668 !
1669 !:Purpose: Inverse spectral transform(PARALLEL LOOP)
1670 !
1671 implicit none
1672
1673 ! Arguments:
1674 integer, intent(in) :: nflev
1675 real(8), intent(in) :: psp(gst(gstID)%nla,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1676 real(8), intent(out) :: pgd2(2*gst(gstID)%maxmcount,gst(gstID)%nj,&
1677 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1678
1679 ! Locals
1680 integer :: jj, jj2, jm, jn, ilonr, iloni, jk, jk2, ila, inm
1681 real(8) :: zjm, factor
1682 real(8) :: dlalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
1683 real(8) :: dldalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
1684 real(8) :: zfms(gst(gstID)%njlath+1,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1685 real(8) :: zfma(gst(gstID)%njlath+1,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1686 real(8) :: dlsp(0:gst(gstID)%ntrunc,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1687
1688 ! Inverse Legendre transform
1689
1690 !$OMP PARALLEL DO PRIVATE(DLALP,DLDALP,DLSP,ZFMS,ZFMA, &
1691 !$OMP INM,ILA,JM,JN,JK,JK2,JJ,JJ2,ZJM,ILONR,ILONI,FACTOR)
1692 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
1693
1694 ilonr = 2*gst(gstID)%mymIndex(jm)-1
1695 iloni = 2*gst(gstID)%mymIndex(jm)
1696 zjm = real(jm,8)
1697
1698 ! 2.1 Copy global spectral state into local spectral state
1699 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
1700 do jn = jm, gst(gstID)%ntrunc
1701 ila = gst(gstID)%nind(jm) + jn - jm
1702 inm = jn - jm
1703 if(jk > 2*nflev) then
1704 ! Scalar fields
1705 dlsp(inm,1,jk) = psp(ila,1,jk)
1706 dlsp(inm,2,jk) = psp(ila,2,jk)
1707 else
1708 ! Vector fields
1709 dlsp(inm,1,jk) = psp(ila,1,jk)*gst(gstID)%r1snp1(ila)
1710 dlsp(inm,2,jk) = psp(ila,2,jk)*gst(gstID)%r1snp1(ila)
1711 endif
1712 enddo
1713 enddo
1714
1715 ! 2.2 Get Legendre polynomial (and its derivative) for all latitudes
1716 ! but for the chosen value of "m" from the global array
1717 call getalp (dlalp,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc,jm)
1718
1719 ! 2.3 Perform the inverse Legendre transform for all fields
1720 call leginv2d(jm,zfms,zfma,dlsp,dlalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
1721
1722 ! 2.4 Passage to Fourier space
1723
1724 ! Scalar fields
1725 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
1726 if(jk > 2*nflev) then
1727 do jj = 1, gst(gstID)%nj
1728 jj2 = gst(gstID)%nj - jj + 1
1729 if(jj.le.gst(gstID)%njlath) then
1730 pgd2(ilonr,jj2,jk) = zfms(jj,1,jk) + zfma(jj,1,jk)
1731 pgd2(iloni,jj2,jk) = zfms(jj,2,jk) + zfma(jj,2,jk)
1732 else
1733 pgd2(ilonr,jj2,jk) = zfms(jj2,1,jk) - zfma(jj2,1,jk)
1734 pgd2(iloni,jj2,jk) = zfms(jj2,2,jk) - zfma(jj2,2,jk)
1735 endif
1736 enddo
1737 endif
1738 enddo
1739
1740 ! Vector fields: Note that u and v are interleaved in mode 5!
1741 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd, 2
1742 if(jk <= 2*nflev) then
1743 jk2 = jk + 1 ! jk is u, jk2 is v
1744 do jj = 1, gst(gstID)%nj
1745 jj2 = gst(gstID)%nj - jj + 1
1746 if(jj.le.gst(gstID)%njlath) then
1747 pgd2(ilonr,jj2,jk ) = -zjm*(zfms(jj,2,jk2) + zfma(jj,2,jk2))
1748 pgd2(iloni,jj2,jk ) = zjm*(zfms(jj,1,jk2) + zfma(jj,1,jk2))
1749 pgd2(ilonr,jj2,jk2) = -zjm*(zfms(jj,2,jk) + zfma(jj,2,jk))
1750 pgd2(iloni,jj2,jk2) = zjm*(zfms(jj,1,jk) + zfma(jj,1,jk))
1751 else
1752 pgd2(ilonr,jj2,jk) = -zjm*(zfms(jj2,2,jk2) - zfma(jj2,2,jk2))
1753 pgd2(iloni,jj2,jk) = zjm*(zfms(jj2,1,jk2) - zfma(jj2,1,jk2))
1754 pgd2(ilonr,jj2,jk2) = -zjm*(zfms(jj2,2,jk) - zfma(jj2,2,jk))
1755 pgd2(iloni,jj2,jk2) = zjm*(zfms(jj2,1,jk) - zfma(jj2,1,jk))
1756 endif
1757 enddo
1758 endif
1759 enddo
1760
1761 ! 2.5 Completion of the computation of the winds in Fourier space
1762 call leginv2d(jm,zfma,zfms,dlsp,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
1763
1764 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd, 2
1765 if(jk <= 2*nflev) then ! only for winds
1766 jk2 = jk + 1
1767 do jj = 1, gst(gstID)%nj
1768 jj2 = gst(gstID)%nj - jj + 1
1769 factor = ec_ra / cos(gst(gstID)%rlati(jj))
1770 if(jj.ne.jj2) then
1771 ! For latitudes not exactly at equator
1772 if(jj.le.gst(gstID)%njlath) then
1773 ! northern latitudes
1774 ! u component
1775 pgd2(ilonr,jj2,jk) = factor * ( pgd2(ilonr,jj2,jk) - (zfms(jj,1,jk) + zfma(jj,1,jk)) )
1776 pgd2(iloni,jj2,jk) = factor * ( pgd2(iloni,jj2,jk) - (zfms(jj,2,jk) + zfma(jj,2,jk)) )
1777 ! v component
1778 pgd2(ilonr,jj2,jk2) = factor * ( pgd2(ilonr,jj2,jk2) + (zfms(jj,1,jk2) + zfma(jj,1,jk2)) )
1779 pgd2(iloni,jj2,jk2) = factor * ( pgd2(iloni,jj2,jk2) + (zfms(jj,2,jk2) + zfma(jj,2,jk2)) )
1780 else
1781 ! southern latitudes
1782 ! u component
1783 pgd2(ilonr,jj2,jk ) = factor * ( pgd2(ilonr,jj2,jk ) -(zfms(jj2,1,jk ) - zfma(jj2,1,jk )) )
1784 pgd2(iloni,jj2,jk ) = factor * ( pgd2(iloni,jj2,jk ) -(zfms(jj2,2,jk ) - zfma(jj2,2,jk )) )
1785 ! v component
1786 pgd2(ilonr,jj2,jk2) = factor * ( pgd2(ilonr,jj2,jk2) +(zfms(jj2,1,jk2) - zfma(jj2,1,jk2)) )
1787 pgd2(iloni,jj2,jk2) = factor * ( pgd2(iloni,jj2,jk2) +(zfms(jj2,2,jk2) - zfma(jj2,2,jk2)) )
1788 endif
1789 else
1790 ! Special case for the equator (jj.eq.jj2)
1791 write(*,*) 'SPGDPAR: special case of jj.eq.jj2!!!'
1792 ! u component
1793 pgd2(ilonr,jj2,jk ) = factor * ( pgd2(ilonr,jj2,jk ) -(zfms(jj,1,jk ) + zfma(jj,1,jk )) )
1794 pgd2(iloni,jj2,jk ) = factor * ( pgd2(iloni,jj2,jk ) -(zfms(jj,2,jk ) + zfma(jj,2,jk )) )
1795 ! v component
1796 pgd2(ilonr,jj2,jk2) = factor * ( pgd2(ilonr,jj2,jk2) +(zfms(jj,1,jk2) + zfma(jj,1,jk2)) )
1797 pgd2(iloni,jj2,jk2) = factor * ( pgd2(iloni,jj2,jk2) +(zfms(jj,2,jk2) + zfma(jj,2,jk2)) )
1798 endif
1799 enddo ! jj
1800 endif
1801 enddo ! jk
1802 enddo ! end loop on m
1803 !$OMP END PARALLEL DO
1804
1805 end subroutine spgdpar
1806
1807
1808 subroutine gdsppar(psp,pgd2,nflev)
1809 implicit none
1810
1811 ! Arguments:
1812 integer, intent(in) :: nflev
1813 real(8), intent(out) :: psp(gst(gstID)%nla,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1814 real(8), intent(in) :: pgd2(2*gst(gstID)%maxmcount,gst(gstID)%nj, &
1815 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1816
1817 ! Locals:
1818 integer :: jj, jj2, jk, jk2, ilonr, iloni, jm ,ila, inm, jn
1819 real(8) :: zjm, dlrwt(gst(gstID)%nj), dlrwocs(gst(gstID)%nj)
1820 real(8) :: dlalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
1821 real(8) :: dldalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
1822 real(8) :: dlsp(0:gst(gstID)%ntrunc,2, &
1823 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1824 real(8) :: dlsp2(0:gst(gstID)%ntrunc,2, &
1825 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1826 real(8) :: zfms(gst(gstID)%njlath+1,2, &
1827 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1828 real(8) :: zfma(gst(gstID)%njlath+1,2, &
1829 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
1830
1831 ! 1. Adjustment needed when an odd number of latitudes is considered
1832 dlrwt(:) = gst(gstID)%rwt(:)
1833 !dlrwocs(:) = gst(gstID)%rwocs(:)
1834 do jj = 1, gst(gstID)%nj
1835 dlrwocs(jj) = gst(gstID)%rwt(jj)/(ec_ra*cos(gst(gstID)%rlati(jj)))
1836 enddo
1837 if (mod(gst(gstID)%nj,2).ne.0) then
1838 dlrwt(gst(gstID)%njlath) = dlrwt(gst(gstID)%njlath)/2.d0
1839 dlrwocs(gst(gstID)%njlath) = dlrwocs(gst(gstID)%njlath)/2.d0
1840 end if
1841
1842 !$OMP PARALLEL DO PRIVATE(DLALP,DLDALP,DLSP,DLSP2,ZFMS,ZFMA, &
1843 !$OMP INM,ILA,JM,JN,JK,JK2,JJ,JJ2,ZJM,ILONR,ILONI)
1844 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
1845
1846 ilonr = 2*gst(gstID)%mymIndex(jm)-1
1847 iloni = 2*gst(gstID)%mymIndex(jm)
1848 zjm = real(jm,8)
1849
1850 ! 2.1 Fetch the Legendre functions and their derivatives for this choice of "m"
1851 call getalp(dlalp,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc,jm)
1852
1853 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
1854 do jj = 1, gst(gstID)%njlath
1855 zfms(jj,1,jk) = 0.0d0
1856 zfms(jj,2,jk) = 0.0d0
1857 zfma(jj,1,jk) = 0.0d0
1858 zfma(jj,2,jk) = 0.0d0
1859 enddo
1860 enddo
1861
1862 ! 2.2 Build the symmetric and anti-symmetric Fourier coefficients including
1863 ! the appropriate quadrature weights (see scientific notes)
1864 do jj = 1, gst(gstID)%njlath
1865 jj2 = gst(gstID)%nj - jj + 1
1866
1867 ! 2.2.1 Coefficients for scalar fields
1868 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
1869 if(jk .gt. 2*nflev) then
1870 ! symmetric coefficients
1871 zfms(jj,1,jk) = dlrwt(jj)*(pgd2(ilonr,jj2,jk) + pgd2(ilonr,jj,jk))
1872 zfms(jj,2,jk) = dlrwt(jj)*(pgd2(iloni,jj2,jk) + pgd2(iloni,jj,jk))
1873 ! antisymmetric coefficients
1874 zfma(jj,1,jk) = dlrwt(jj)*(pgd2(ilonr,jj2,jk) - pgd2(ilonr,jj,jk))
1875 zfma(jj,2,jk) = dlrwt(jj)*(pgd2(iloni,jj2,jk) - pgd2(iloni,jj,jk))
1876 endif
1877 enddo
1878
1879 ! 2.2.2 Coefficients associated with the wind fields
1880 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd, 2
1881 if(jk .le. 2*nflev) then
1882 jk2 = jk + 1 ! jk is u, jk2 is v
1883 ! vorticity: symmetric coefficients
1884 zfms(jj,1,jk) = -zjm*dlrwocs(jj)*(pgd2(iloni,jj2,jk2) + pgd2(iloni,jj,jk2))
1885 zfms(jj,2,jk) = zjm*dlrwocs(jj)*(pgd2(ilonr,jj2,jk2) + pgd2(ilonr,jj,jk2))
1886 ! vorticity: antisymmetric coefficients
1887 zfma(jj,1,jk) = -zjm*dlrwocs(jj)*(pgd2(iloni,jj2,jk2) - pgd2(iloni,jj,jk2))
1888 zfma(jj,2,jk) = zjm*dlrwocs(jj)*(pgd2(ilonr,jj2,jk2) - pgd2(ilonr,jj,jk2))
1889 ! divergence: symmetric coefficients
1890 zfms(jj,1,jk2) = -zjm*dlrwocs(jj)*(pgd2(iloni,jj2,jk) + pgd2(iloni,jj,jk))
1891 zfms(jj,2,jk2) = zjm*dlrwocs(jj)*(pgd2(ilonr,jj2,jk) + pgd2(ilonr,jj,jk))
1892 ! divergence: antisymmetric coefficients
1893 zfma(jj,1,jk2) = -zjm*dlrwocs(jj)*(pgd2(iloni,jj2,jk) - pgd2(iloni,jj,jk))
1894 zfma(jj,2,jk2) = zjm*dlrwocs(jj)*(pgd2(ilonr,jj2,jk) - pgd2(ilonr,jj,jk))
1895 endif
1896 enddo
1897 enddo
1898
1899 ! 2.3 First one with ALP for all scalar fields and for half the terms
1900 ! required to define the divergence and vorticity
1901 call legdir2d(jm,zfms,zfma,dlsp,dlalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
1902
1903 ! 2.4 Second transform with DALP to complete the construction of the
1904 ! vorticity and divergence fields
1905 do jj = 1, gst(gstID)%njlath
1906 jj2 = gst(gstID)%nj - jj + 1
1907 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd, 2
1908 if(jk <= 2*nflev) then ! only for winds
1909 jk2 = jk + 1
1910
1911 ! symmetric coefficients for zonal wind
1912 zfms(jj,1,jk) = dlrwocs(jj)*(pgd2(ilonr,jj2,jk) + pgd2(ilonr,jj,jk))
1913 zfms(jj,2,jk) = dlrwocs(jj)*(pgd2(iloni,jj2,jk) + pgd2(iloni,jj,jk))
1914 ! antisymmetric coefficients for zonal wind
1915 zfma(jj,1,jk) = dlrwocs(jj)*(pgd2(ilonr,jj2,jk) - pgd2(ilonr,jj,jk))
1916 zfma(jj,2,jk) = dlrwocs(jj)*(pgd2(iloni,jj2,jk) - pgd2(iloni,jj,jk))
1917
1918 ! symmetric coefficients for zonal wind
1919 zfms(jj,1,jk2) = -dlrwocs(jj)*(pgd2(ilonr,jj2,jk2) + pgd2(ilonr,jj,jk2))
1920 zfms(jj,2,jk2) = -dlrwocs(jj)*(pgd2(iloni,jj2,jk2) + pgd2(iloni,jj,jk2))
1921 ! antisymmetric coefficients for zonal wind
1922 zfma(jj,1,jk2) = -dlrwocs(jj)*(pgd2(ilonr,jj2,jk2) - pgd2(ilonr,jj,jk2))
1923 zfma(jj,2,jk2) = -dlrwocs(jj)*(pgd2(iloni,jj2,jk2) - pgd2(iloni,jj,jk2))
1924
1925 endif
1926 enddo
1927 enddo
1928
1929 call legdir2d(jm,zfma,zfms,dlsp2,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
1930
1931 ! 2.5 Transfer the result in the global state
1932 do jn = jm, gst(gstID)%ntrunc
1933 ila = gst(gstid)%nind(jm) + jn - jm
1934 inm = jn - jm
1935 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
1936 if(jk <= 2*nflev) then ! for winds
1937 psp(ila,1,jk) = dlsp(inm,1,jk) + dlsp2(inm,1,jk)
1938 psp(ila,2,jk) = dlsp(inm,2,jk) + dlsp2(inm,2,jk)
1939 else ! for scalar fields
1940 psp(ila,1,jk) = dlsp(inm,1,jk)
1941 psp(ila,2,jk) = dlsp(inm,2,jk)
1942 endif
1943 enddo
1944 enddo
1945
1946 enddo ! jm
1947 !$OMP END PARALLEL DO
1948 end subroutine gdsppar
1949
1950
1951 subroutine gst_spgda(psp,pgd,nflev)
1952 implicit none
1953
1954 ! Arguments:
1955 integer, intent(in) :: nflev
1956 real(8), intent(inout) :: psp(gst(gstID)%myNla,2,gst(gstID)%nk)
1957 real(8), intent(inout) :: pgd(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
1958 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
1959
1960 ! Locals:
1961 real(8), allocatable :: psp2(:,:,:),pgd2(:,:,:),pgd3(:,:,:)
1962
1963 ! check if this mpi task will deal with winds during Legendre transform
1964 if(gst(gstID)%myLevBeg.le.2*nflev) then
1965 ! ensure that the number of levels on this mpi task is even to allow interleaving of u and v
1966 ! only necessary when number of levels on an mpi task is less than all wind levels (2nd condition)
1967 if( (mod(gst(gstID)%myLevCount,2).ne.0) .and. (gst(gstID)%myLevCount < 2*nflev) ) then
1968 write(*,*) 'GST_SPGDA: myLevCount = ',gst(gstID)%myLevCount
1969 call utl_abort('GST_SPGDA: Number of levels on this mpi task must be even!')
1970 endif
1971 endif
1972
1973 allocate(psp2(gst(gstID)%nla, 2, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
1974 allocate(pgd2(2*gst(gstID)%maxmcount, gst(gstID)%nj, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
1975 allocate(pgd3(gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
1976
1977 call adjnorm(pgd)
1978
1979 ! First reorder wind components to have u and v for same level on same mpi task
1980 call interleaveWinds_gd(pgd,nflev)
1981
1982 ! Transpose data along npex from Longitudes to Levels
1983 call transpose2d_LontoLev(pgd,pgd3)
1984
1985 ! Fourier transform all fields for all latitudes
1986 call utl_tmg_start(151,'low-level--gst_fft')
1987 call fft3dvar(pgd3,-1)
1988 call utl_tmg_stop(151)
1989
1990 ! Transpose data along npey from Latitudes to M
1991 call transpose2d_LattoM(pgd3,pgd2)
1992 deallocate(pgd3)
1993
1994 ! Direct Legendre transform including wind transformations
1995 call utl_tmg_start(150,'low-level--gst_lt')
1996 call spgdapar(psp2,pgd2,nflev)
1997 call utl_tmg_stop(150)
1998 deallocate(pgd2)
1999
2000 ! Transpose data along npex from Levels to N
2001 call transpose2d_LevtoN(psp2,psp)
2002 deallocate(psp2)
2003
2004 ! Now undo reordering of wind components
2005 call unInterleaveWinds_sp(psp,nflev)
2006
2007 end subroutine gst_spgda
2008
2009
2010 subroutine spgdapar(psp,pgd2,nflev)
2011 implicit none
2012
2013 ! Arguments:
2014 integer, intent(in) :: nflev
2015 real(8), intent(out) :: psp(gst(gstID)%nla,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2016 real(8), intent(in) :: pgd2(2*gst(gstID)%maxmCount,gst(gstID)%nj, &
2017 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2018
2019 ! Locals:
2020 integer :: jj, jj2, jk, jk2, ilonr, iloni, jm ,ila, inm, jn
2021 real(8) :: zjm,factor,dlrwt(gst(gstID)%nj)
2022 real(8) :: dlalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
2023 real(8) :: dldalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
2024 real(8) :: dlsp(0:gst(gstID)%ntrunc,2, &
2025 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2026 real(8) :: dlsp2(0:gst(gstID)%ntrunc,2, &
2027 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2028 real(8) :: zfms(gst(gstID)%njlath+1,2, &
2029 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2030 real(8) :: zfma(gst(gstID)%njlath+1,2, &
2031 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2032
2033 ! 1. Set up according to the desired grid
2034 ! ---------------------
2035 dlrwt(:) = gst(gstID)%rwt(:)
2036 if (mod(gst(gstID)%nj,2).ne.0) then
2037 dlrwt(gst(gstID)%njlath) = dlrwt(gst(gstID)%njlath)/2.d0
2038 end if
2039
2040 ! 2. Fourier transform all fields for all latitudes
2041 !$OMP PARALLEL DO PRIVATE(DLALP,DLDALP,DLSP,DLSP2,ZFMS,ZFMA, &
2042 !$OMP INM,ILA,JM,JN,JK,JK2,JJ,JJ2,ZJM,ILONR,ILONI,FACTOR)
2043 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
2044
2045 ilonr = 2*gst(gstID)%mymIndex(jm)-1
2046 iloni = 2*gst(gstID)%mymIndex(jm)
2047 zjm = real(jm,8)
2048
2049 ! 2.1 Fetch the Legendre functions and their derivatives for this choice of "m"
2050 call getalp(dlalp,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc,jm)
2051
2052 ! 2.2 Build the symmetric and anti-symmetric Fourier coefficients including
2053 ! the appropriate quadrature weights (see scientific notes)
2054 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2055 do jj = 1, gst(gstID)%njlath
2056 zfms(jj,1,jk) = 0.0d0
2057 zfms(jj,2,jk) = 0.0d0
2058 zfma(jj,1,jk) = 0.0d0
2059 zfma(jj,2,jk) = 0.0d0
2060 enddo
2061 enddo
2062
2063 ! 2.2.1 Coefficients associated with the scalar fields
2064 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2065 if(jk .gt. 2*nflev) then
2066 do jj = 1, gst(gstID)%nj
2067 jj2 = gst(gstID)%nj-jj+1
2068 if(jj.le.gst(gstID)%njlath) then
2069 ! Northern hemisphere
2070 zfms(jj,1,jk) = pgd2(ilonr,jj2,jk)
2071 zfms(jj,2,jk) = pgd2(iloni,jj2,jk)
2072 zfma(jj,1,jk) = pgd2(ilonr,jj2,jk)
2073 zfma(jj,2,jk) = pgd2(iloni,jj2,jk)
2074 else
2075 ! Southern hemisphere
2076 zfms(jj2,1,jk) = zfms(jj2,1,jk) + pgd2(ilonr,jj2,jk)
2077 zfms(jj2,2,jk) = zfms(jj2,2,jk) + pgd2(iloni,jj2,jk)
2078 zfma(jj2,1,jk) = zfma(jj2,1,jk) - pgd2(ilonr,jj2,jk)
2079 zfma(jj2,2,jk) = zfma(jj2,2,jk) - pgd2(iloni,jj2,jk)
2080 endif
2081 enddo
2082 endif
2083 enddo
2084
2085 ! 2.2.2 Coefficients associated with the wind fields
2086 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd, 2
2087 if(jk .le. 2*nflev) then
2088 jk2 = jk + 1
2089 do jj = 1, gst(gstID)%nj
2090 jj2 = gst(gstID)%nj-jj+1
2091 if(jj.le.gst(gstID)%njlath) then
2092 ! Northern hemisphere
2093 ! vorticity: symmetric coefficients
2094 zfms(jj,1,jk ) = -pgd2(iloni,jj2,jk2)
2095 zfms(jj,2,jk ) = pgd2(ilonr,jj2,jk2)
2096 ! vorticity: antisymmetric coefficients
2097 zfma(jj,1,jk ) = -pgd2(iloni,jj2,jk2)
2098 zfma(jj,2,jk ) = pgd2(ilonr,jj2,jk2)
2099 ! divergence: symmetric coefficients
2100 zfms(jj,1,jk2) = -pgd2(iloni,jj2,jk )
2101 zfms(jj,2,jk2) = pgd2(ilonr,jj2,jk )
2102 ! divergence: antisymmetric coefficients
2103 zfma(jj,1,jk2) = -pgd2(iloni,jj2,jk )
2104 zfma(jj,2,jk2) = pgd2(ilonr,jj2,jk )
2105 else
2106 ! Southern hemisphere
2107 ! vorticity: symmetric coefficients
2108 zfms(jj2,1,jk ) = zfms(jj2,1,jk ) - pgd2(iloni,jj2,jk2)
2109 zfms(jj2,2,jk ) = zfms(jj2,2,jk ) + pgd2(ilonr,jj2,jk2)
2110 ! vorticity: antisymmetric coefficients
2111 zfma(jj2,1,jk ) = zfma(jj2,1,jk ) + pgd2(iloni,jj2,jk2)
2112 zfma(jj2,2,jk ) = zfma(jj2,2,jk ) - pgd2(ilonr,jj2,jk2)
2113 ! divergence: symmetric coefficients
2114 zfms(jj2,1,jk2) = zfms(jj2,1,jk2) - pgd2(iloni,jj2,jk )
2115 zfms(jj2,2,jk2) = zfms(jj2,2,jk2) + pgd2(ilonr,jj2,jk )
2116 ! divergence: antisymmetric coefficients
2117 zfma(jj2,1,jk2) = zfma(jj2,1,jk2) + pgd2(iloni,jj2,jk )
2118 zfma(jj2,2,jk2) = zfma(jj2,2,jk2) - pgd2(ilonr,jj2,jk )
2119 endif
2120 enddo ! jj
2121 endif
2122 enddo ! jk
2123
2124 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2125 do jj = 1, gst(gstID)%njlath
2126 zfms(jj,1,jk) = dlrwt(jj)*zfms(jj,1,jk)
2127 zfms(jj,2,jk) = dlrwt(jj)*zfms(jj,2,jk)
2128 zfma(jj,1,jk) = dlrwt(jj)*zfma(jj,1,jk)
2129 zfma(jj,2,jk) = dlrwt(jj)*zfma(jj,2,jk)
2130 enddo
2131 if(jk .le. 2*nflev) then
2132 do jj = 1, gst(gstID)%njlath
2133 factor = ec_ra / cos(gst(gstID)%rlati(jj))
2134 zfms(jj,1,jk) = factor*zjm*zfms(jj,1,jk)
2135 zfms(jj,2,jk) = factor*zjm*zfms(jj,2,jk)
2136 zfma(jj,1,jk) = factor*zjm*zfma(jj,1,jk)
2137 zfma(jj,2,jk) = factor*zjm*zfma(jj,2,jk)
2138 enddo
2139 endif
2140 enddo ! jk
2141
2142 ! 2.3 First one with ALP for all scalar fields and for half the terms
2143 ! required to define the divergence and vorticity
2144 call legdir2d(jm,zfms,zfma,dlsp,dlalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
2145
2146 ! 2.4 Second transform with DALP to complete the construction of the
2147 ! vorticity and divergence fields
2148 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2149 if(jk .le. 2*nflev) then
2150 do jj = 1, gst(gstID)%njlath
2151 zfms(jj,1,jk) = 0.0d0
2152 zfms(jj,2,jk) = 0.0d0
2153 zfma(jj,1,jk) = 0.0d0
2154 zfma(jj,2,jk) = 0.0d0
2155 enddo
2156 endif
2157 enddo
2158
2159 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd, 2
2160 if(jk .le. 2*nflev) then
2161 jk2 = jk + 1
2162 do jj = 1, gst(gstID)%nj
2163 jj2 = gst(gstID)%nj-jj+1
2164 if(jj.le.gst(gstID)%njlath) then
2165 ! Northern hemisphere
2166 ! symmetric coefficients for zonal wind
2167 zfms(jj,1,jk ) = pgd2(ilonr,jj2,jk )
2168 zfms(jj,2,jk ) = pgd2(iloni,jj2,jk )
2169 ! antisymmetric coefficients for zonal wind
2170 zfma(jj,1,jk ) = pgd2(ilonr,jj2,jk )
2171 zfma(jj,2,jk ) = pgd2(iloni,jj2,jk )
2172 ! symmetric coefficients for meridional wind
2173 zfms(jj,1,jk2) = -pgd2(ilonr,jj2,jk2)
2174 zfms(jj,2,jk2) = -pgd2(iloni,jj2,jk2)
2175 ! antisymmetric coefficients for meridional wind
2176 zfma(jj,1,jk2) = -pgd2(ilonr,jj2,jk2)
2177 zfma(jj,2,jk2) = -pgd2(iloni,jj2,jk2)
2178 else
2179 ! Southern hemisphere
2180 ! symmetric coefficients for zonal wind
2181 zfms(jj2,1,jk ) = zfms(jj2,1,jk ) + pgd2(ilonr,jj2,jk )
2182 zfms(jj2,2,jk ) = zfms(jj2,2,jk ) + pgd2(iloni,jj2,jk )
2183 ! antisymmetric coefficients for zonal wind
2184 zfma(jj2,1,jk ) = zfma(jj2,1,jk ) - pgd2(ilonr,jj2,jk )
2185 zfma(jj2,2,jk ) = zfma(jj2,2,jk ) - pgd2(iloni,jj2,jk )
2186 ! symmetric coefficients for meridional wind
2187 zfms(jj2,1,jk2) = zfms(jj2,1,jk2) - pgd2(ilonr,jj2,jk2)
2188 zfms(jj2,2,jk2) = zfms(jj2,2,jk2) - pgd2(iloni,jj2,jk2)
2189 ! antisymmetric coefficients for meridional wind
2190 zfma(jj2,1,jk2) = zfma(jj2,1,jk2) + pgd2(ilonr,jj2,jk2)
2191 zfma(jj2,2,jk2) = zfma(jj2,2,jk2) + pgd2(iloni,jj2,jk2)
2192 endif
2193 enddo
2194 endif
2195 enddo
2196
2197 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2198 if(jk .le. 2*nflev) then
2199 do jj = 1, gst(gstID)%njlath
2200 factor = ec_ra / cos(gst(gstID)%rlati(jj))
2201 zfms(jj,1,jk) = factor*dlrwt(jj)*zfms(jj,1,jk)
2202 zfms(jj,2,jk) = factor*dlrwt(jj)*zfms(jj,2,jk)
2203 zfma(jj,1,jk) = factor*dlrwt(jj)*zfma(jj,1,jk)
2204 zfma(jj,2,jk) = factor*dlrwt(jj)*zfma(jj,2,jk)
2205 enddo
2206 endif
2207 enddo
2208
2209 call legdir2d(jm,zfma,zfms,dlsp2,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
2210
2211 ! 2.5 Transfer the result in the global state
2212 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2213 do jn = jm, gst(gstID)%ntrunc
2214 ila = gst(gstID)%nind(jm) + jn - jm
2215 inm = jn - jm
2216 if(jk .le. 2*nflev) then
2217 psp(ila,1,jk) = -gst(gstID)%r1snp1(ila)*(dlsp(inm,1,jk) + dlsp2(inm,1,jk))
2218 psp(ila,2,jk) = -gst(gstID)%r1snp1(ila)*(dlsp(inm,2,jk) + dlsp2(inm,2,jk))
2219 else
2220 psp(ila,1,jk) = dlsp(inm,1,jk)
2221 psp(ila,2,jk) = dlsp(inm,2,jk)
2222 endif
2223 enddo
2224 enddo
2225
2226 ! End of loop on zonal wavenumbers
2227 enddo
2228 !$OMP END PARALLEL DO
2229
2230 end subroutine spgdapar
2231
2232
2233 subroutine gst_speree(psp,pgd)
2234 implicit none
2235
2236 ! Arguments:
2237 real(8), intent(in) :: psp(gst(gstID)%myNla, 2, gst(gstID)%nk)
2238 real(8), intent(out) :: pgd(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
2239 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
2240
2241 ! Locals:
2242 real(8), allocatable :: psp2(:,:,:),pgd2(:,:,:),pgd3(:,:,:)
2243 integer :: jlat, jk, jlon
2244
2245 allocate(psp2(gst(gstID)%nla, 2, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
2246 allocate(pgd2(2*gst(gstID)%maxmcount, gst(gstID)%nj, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
2247 allocate(pgd3(gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
2248
2249 ! 1.0 Transpose data along npex from N to Levels
2250 call transpose2d_NtoLev(psp,psp2)
2251
2252 ! 1.1 Inverse Legendre transform (lon -> m)
2253 call utl_tmg_start(150,'low-level--gst_lt')
2254 call spereepar(psp2,pgd2)
2255 call utl_tmg_stop(150)
2256 deallocate(psp2)
2257
2258 ! 1.2 Transpose data along npey from M to Latitudes
2259 call transpose2d_MtoLat(pgd2,pgd3)
2260 deallocate(pgd2)
2261
2262 ! 2.1 Reset to zero the modes that are not part of the truncation
2263 !$OMP PARALLEL DO PRIVATE (JLAT,JLON,JK)
2264 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2265 do jlat = gst(gstID)%myLatBeg, gst(gstID)%myLatEnd
2266 do jlon = 2*(gst(gstID)%ntrunc+1)+1, gst(gstID)%ni
2267 pgd3(jlon,jlat,jk) = 0.d0
2268 enddo
2269 enddo
2270 enddo
2271 !$OMP END PARALLEL DO
2272
2273 ! 2.2 Apply the inverse FFT
2274 call utl_tmg_start(151,'low-level--gst_fft')
2275 call fft3dvar(pgd3,+1)
2276 call utl_tmg_stop(151)
2277
2278 ! 2.3 Transpose data along npex from Levels to Longitudes
2279 call transpose2d_LevtoLon(pgd3,pgd)
2280 deallocate(pgd3)
2281
2282 end subroutine gst_speree
2283
2284
2285 subroutine gst_speree_kij(psp,pgd)
2286 implicit none
2287
2288 ! Arguments:
2289 real(8), intent(in) :: psp(gst(gstID)%myNla, 2, gst(gstID)%nk)
2290 real(8), intent(out) :: pgd(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
2291 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
2292
2293 ! Locals:
2294 real(8), allocatable :: psp2(:,:,:),pgd2(:,:,:),pgd3(:,:,:)
2295 integer :: jlat, jk, jlon, ierr
2296
2297 call utl_tmg_start(152,'low-level--gst_barr')
2298 if(mmpi_doBarrier) call rpn_comm_barrier('GRID',ierr)
2299 call utl_tmg_stop(152)
2300
2301 allocate(psp2(gst(gstID)%nla, 2, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
2302 allocate(pgd2(gst(gstID)%maxMyLevCount, 2*gst(gstID)%maxmcount, gst(gstID)%nj))
2303 allocate(pgd3(gst(gstID)%maxMyLevCount, gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd))
2304
2305 pgd2( (gst(gstID)%myLevCount+1):gst(gstID)%maxMyLevCount, :, :) = 0.0d0
2306
2307 ! 1.0 Transpose data along npex from N to Levels
2308 call transpose2d_NtoLev(psp,psp2)
2309
2310 ! 1.1 Inverse Legendre transform (lon -> m)
2311 call utl_tmg_start(150,'low-level--gst_lt')
2312 call spereepar_kij(psp2,pgd2)
2313 call utl_tmg_stop(150)
2314 deallocate(psp2)
2315
2316 ! 1.2 Transpose data along npey from M to Latitudes
2317 call transpose2d_MtoLat_kij(pgd2,pgd3)
2318 deallocate(pgd2)
2319
2320 ! 2.1 Reset to zero the modes that are not part of the truncation
2321 !$OMP PARALLEL DO PRIVATE (JLAT,JLON,JK)
2322 do jlat = gst(gstID)%myLatBeg, gst(gstID)%myLatEnd
2323 do jlon = 2*(gst(gstID)%ntrunc+1)+1, gst(gstID)%ni
2324 do jk = 1, gst(gstID)%maxMyLevCount
2325 pgd3(jk,jlon,jlat) = 0.d0
2326 enddo
2327 enddo
2328 enddo
2329 !$OMP END PARALLEL DO
2330
2331 ! 2.2 Apply the inverse FFT
2332 call utl_tmg_start(151,'low-level--gst_fft')
2333 call fft3dvar_kij(pgd3,+1)
2334 call utl_tmg_stop(151)
2335
2336 ! 2.3 Transpose data along npex from Levels to Longitudes
2337 if( gst(gstID)%lonLatDivisible ) then
2338 if (pre_specTransReal == 4) then
2339 call transpose2d_LevtoLon_kij_mpitypes4(pgd3,pgd)
2340 else
2341 call transpose2d_LevtoLon_kij_mpitypes8(pgd3,pgd)
2342 end if
2343 else
2344 call transpose2d_LevtoLon_kij(pgd3,pgd)
2345 end if
2346 deallocate(pgd3)
2347
2348 call utl_tmg_start(152,'low-level--gst_barr')
2349 if(mmpi_doBarrier) call rpn_comm_barrier('GRID',ierr)
2350 call utl_tmg_stop(152)
2351
2352 end subroutine gst_speree_kij
2353
2354 subroutine gst_speree_ad(psp,pgd)
2355 implicit none
2356
2357 ! Arguments:
2358 real(8), intent(out) :: psp(gst(gstID)%myNla, 2, gst(gstID)%nk)
2359 real(8), intent(inout) :: pgd(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
2360 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
2361
2362 call adjnorm(pgd)
2363
2364 call gst_reespe(psp,pgd)
2365
2366 end subroutine gst_speree_ad
2367
2368
2369 subroutine gst_reespe(psp,pgd)
2370 implicit none
2371
2372 ! Arguments:
2373 real(8), intent(out) :: psp(gst(gstID)%myNla, 2, gst(gstID)%nk)
2374 real(8), intent(in) :: pgd(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
2375 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
2376
2377 ! Locals:
2378 real(8), allocatable :: psp2(:,:,:),pgd2(:,:,:),pgd3(:,:,:)
2379
2380 allocate(psp2(gst(gstID)%nla, 2, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
2381 allocate(pgd2(2*gst(gstID)%maxmcount, gst(gstID)%nj, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
2382 allocate(pgd3(gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
2383
2384 ! Transpose data along npex from Longitudes to Levels
2385 call transpose2d_LontoLev(pgd,pgd3)
2386
2387 ! 1. Apply the FFT
2388 call utl_tmg_start(151,'low-level--gst_fft')
2389 call fft3dvar(pgd3,-1)
2390 call utl_tmg_stop(151)
2391
2392 ! Transpose data along npey from Latitudes to M
2393 call transpose2d_LattoM(pgd3,pgd2)
2394 deallocate(pgd3)
2395
2396 ! 2. Direct Legendre transform
2397 call utl_tmg_start(150,'low-level--gst_lt')
2398 call reespepar(pgd2,psp2)
2399 call utl_tmg_stop(150)
2400 deallocate(pgd2)
2401
2402 ! Transpose data along npex from Levels to N
2403 call transpose2d_LevtoN(psp2,psp)
2404 deallocate(psp2)
2405
2406 end subroutine gst_reespe
2407
2408
2409 subroutine gst_reespe_kij(psp,pgd)
2410 implicit none
2411
2412 ! Arguments:
2413 real(8), intent(out) :: psp(gst(gstID)%myNla, 2, gst(gstID)%nk)
2414 real(8), intent(in) :: pgd(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
2415 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
2416
2417 ! Locals:
2418 real(8), allocatable :: psp2(:,:,:),pgd2(:,:,:),pgd3(:,:,:)
2419 integer :: ierr
2420
2421 call utl_tmg_start(152,'low-level--gst_barr')
2422 if(mmpi_doBarrier) call rpn_comm_barrier('GRID',ierr)
2423 call utl_tmg_stop(152)
2424
2425 allocate(psp2(gst(gstID)%nla, 2, gst(gstID)%myLevBeg:gst(gstID)%myLevEnd))
2426 allocate(pgd2(gst(gstID)%maxMyLevCount, 2*gst(gstID)%maxmcount, gst(gstID)%nj))
2427 allocate(pgd3(gst(gstID)%maxMyLevCount, gst(gstID)%ni, gst(gstID)%myLatBeg:gst(gstID)%myLatEnd))
2428
2429 ! Transpose data along npex from Longitudes to Levels
2430 if( gst(gstID)%lonLatDivisible ) then
2431 if (pre_specTransReal == 4) then
2432 call transpose2d_LontoLev_kij_mpitypes4(pgd,pgd3)
2433 else
2434 call transpose2d_LontoLev_kij_mpitypes8(pgd,pgd3)
2435 end if
2436 else
2437 call transpose2d_LontoLev_kij(pgd,pgd3)
2438 end if
2439
2440 ! 1. Apply the FFT
2441 call utl_tmg_start(151,'low-level--gst_fft')
2442 call fft3dvar_kij(pgd3,-1)
2443 call utl_tmg_stop(151)
2444
2445 ! Transpose data along npey from Latitudes to M
2446 call transpose2d_LattoM_kij(pgd3,pgd2)
2447 deallocate(pgd3)
2448
2449 ! 2. Direct Legendre transform
2450 call utl_tmg_start(150,'low-level--gst_lt')
2451 call reespepar_kij(pgd2,psp2)
2452 call utl_tmg_stop(150)
2453 deallocate(pgd2)
2454
2455 ! Transpose data along npex from Levels to N
2456 call transpose2d_LevtoN(psp2,psp)
2457 deallocate(psp2)
2458
2459 call utl_tmg_start(152,'low-level--gst_barr')
2460 if(mmpi_doBarrier) call rpn_comm_barrier('GRID',ierr)
2461 call utl_tmg_stop(152)
2462
2463 end subroutine gst_reespe_kij
2464
2465 subroutine gst_speree_kij_ad(psp,pgd)
2466 implicit none
2467
2468 ! Arguments:
2469 real(8), intent(out) :: psp(gst(gstID)%myNla, 2, gst(gstID)%nk)
2470 real(8), intent(inout) :: pgd(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
2471 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
2472
2473 call adjnorm_kij(pgd)
2474
2475 call gst_reespe_kij(psp,pgd)
2476
2477 end subroutine gst_speree_kij_ad
2478
2479 subroutine adjnorm(pgd)
2480 implicit none
2481
2482 ! Arguments:
2483 real(8), intent(inout) :: pgd(gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
2484 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd, gst(gstID)%nk)
2485
2486 ! Locals:
2487 integer :: jk, jlon, jlat
2488 integer :: lat1, lat2, lon1, lon2
2489 real(8) :: rwtinv(gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
2490
2491 lat1 = gst(gstID)%myLatBeg
2492 lat2 = gst(gstID)%myLatEnd
2493 lon1 = gst(gstID)%myLonBeg
2494 lon2 = gst(gstID)%myLonEnd
2495
2496 do jlat = lat1, lat2
2497 rwtinv(jlat) = real(gst(gstID)%ni,8) / gst_getRWT(jlat, gstID)
2498 enddo
2499
2500 !$OMP PARALLEL DO PRIVATE (jk,jlat,jlon)
2501 do jk = 1, gst(gstID)%nk
2502 do jlat = lat1, lat2
2503 do jlon = lon1, lon2
2504 pgd(jlon,jlat,jk) = rwtinv(jlat) * pgd(jlon,jlat,jk)
2505 end do
2506 end do
2507 end do
2508 !$OMP END PARALLEL DO
2509
2510 end subroutine adjnorm
2511
2512 subroutine adjnorm_kij(pgd)
2513 implicit none
2514
2515 ! Arguments:
2516 real(8), intent(inout) :: pgd(gst(gstID)%nk, gst(gstID)%myLonBeg:gst(gstID)%myLonEnd, &
2517 gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
2518
2519 ! Locals:
2520 integer :: jk, jlon, jlat
2521 integer :: lat1, lat2, lon1, lon2
2522 real(8) :: rwtinv(gst(gstID)%myLatBeg:gst(gstID)%myLatEnd)
2523
2524 lat1 = gst(gstID)%myLatBeg
2525 lat2 = gst(gstID)%myLatEnd
2526 lon1 = gst(gstID)%myLonBeg
2527 lon2 = gst(gstID)%myLonEnd
2528
2529 do jlat = lat1, lat2
2530 rwtinv(jlat) = real(gst(gstID)%ni,8) / gst_getRWT(jlat, gstID)
2531 enddo
2532
2533 !$OMP PARALLEL DO PRIVATE (jlat,jlon,jk)
2534 do jlat = lat1, lat2
2535 do jlon = lon1, lon2
2536 do jk = 1, gst(gstID)%nk
2537 pgd(jk,jlon,jlat) = rwtinv(jlat) * pgd(jk,jlon,jlat)
2538 end do
2539 end do
2540 end do
2541 !$OMP END PARALLEL DO
2542
2543 end subroutine adjnorm_kij
2544
2545 subroutine spereepar(psp,pgd2)
2546 !
2547 !:Purpose: Inverse spectral transform(MPI PARALLEL LOOP)
2548 implicit none
2549
2550 ! Arguments:
2551 real(8), intent(in) :: psp(gst(gstID)%nla,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2552 real(8), intent(out) :: pgd2(2*gst(gstID)%maxmcount,gst(gstID)%nj, &
2553 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2554
2555 ! Locals
2556 integer :: jj, jj2, jm, jn, ilonr, iloni, jk, ila, inm
2557 real(8) :: dlalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
2558 real(8) :: dldalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
2559 real(8) :: zfms(gst(gstID)%njlath+1,2, &
2560 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2561 real(8) :: zfma(gst(gstID)%njlath+1,2, &
2562 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2563 real(8) :: dlsp(0:gst(gstID)%ntrunc,2, &
2564 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2565
2566 ! Inverse Legendre transform
2567
2568 !$OMP PARALLEL DO PRIVATE(DLALP,DLDALP,DLSP,ZFMS,ZFMA, &
2569 !$OMP INM,ILA,JM,JN,JK,JJ,JJ2,ILONR,ILONI)
2570 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
2571
2572 ilonr = 2*gst(gstID)%mymIndex(jm)-1
2573 iloni = 2*gst(gstID)%mymIndex(jm)
2574
2575 ! 2.1 Copy global spectral state into local spectral state
2576 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2577 do jn = jm, gst(gstID)%ntrunc
2578 ila = gst(gstID)%nind(jm) + jn - jm
2579 inm = jn - jm
2580 dlsp(inm,1,jk) = psp(ila,1,jk)
2581 dlsp(inm,2,jk) = psp(ila,2,jk)
2582 enddo
2583 enddo
2584
2585 ! 2.2 Get Legendre polynomial (and its derivative) for all latitudes
2586 ! but for the chosen value of "m" from the global array
2587 call getalp(dlalp,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc,jm)
2588
2589 ! 2.3 Perform the inverse Legendre transform for all fields
2590 call leginv2d(jm,zfms,zfma,dlsp,dlalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
2591
2592 ! 2.4 Passage to Fourier space
2593
2594 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2595 do jj = 1, gst(gstID)%nj
2596 jj2 = gst(gstID)%nj - jj + 1
2597 if(jj.le.gst(gstID)%njlath) then
2598 pgd2(ilonr,jj2,jk) = zfms(jj,1,jk) + zfma(jj,1,jk)
2599 pgd2(iloni,jj2,jk) = zfms(jj,2,jk) + zfma(jj,2,jk)
2600 else
2601 pgd2(ilonr,jj2,jk) = zfms(jj2,1,jk) - zfma(jj2,1,jk)
2602 pgd2(iloni,jj2,jk) = zfms(jj2,2,jk) - zfma(jj2,2,jk)
2603 endif
2604 enddo
2605 enddo
2606 enddo
2607 !$OMP END PARALLEL DO
2608
2609 end subroutine spereepar
2610
2611
2612 subroutine spereepar_kij(psp,pgd2)
2613 !
2614 !:Purpose: Inverse spectral transform(MPI PARALLEL LOOP)
2615 implicit none
2616
2617 ! Arguments:
2618 real(8), intent(in) :: psp(gst(gstID)%nla,2,gst(gstID)%myLevCount)
2619 real(8), intent(out) :: pgd2(gst(gstID)%maxMyLevCount,2*gst(gstID)%maxmcount, &
2620 gst(gstID)%nj)
2621
2622 ! Locals
2623 integer :: jj, jj2, jm, jn, ilonr, iloni, jk, ila, inm
2624 real(8) :: dlalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
2625 real(8) :: dldalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
2626 real(8) :: zfms(gst(gstID)%myLevCount,gst(gstID)%njlath+1,2)
2627 real(8) :: zfma(gst(gstID)%myLevCount,gst(gstID)%njlath+1,2)
2628 real(8) :: dlsp(gst(gstID)%myLevCount,0:gst(gstID)%ntrunc,2)
2629
2630 ! Inverse Legendre transform
2631
2632 !$OMP PARALLEL DO PRIVATE(DLALP,DLDALP,DLSP,ZFMS,ZFMA, &
2633 !$OMP INM,ILA,JM,JN,JK,JJ,JJ2,ILONR,ILONI)
2634 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
2635
2636 ilonr = 2*gst(gstID)%mymIndex(jm)-1
2637 iloni = 2*gst(gstID)%mymIndex(jm)
2638
2639 ! 2.1 Copy global spectral state into local spectral state
2640 do jn = jm, gst(gstID)%ntrunc
2641 ila = gst(gstID)%nind(jm) + jn - jm
2642 inm = jn - jm
2643 do jk = 1, gst(gstID)%myLevCount
2644 dlsp(jk,inm,1) = psp(ila,1,jk)
2645 dlsp(jk,inm,2) = psp(ila,2,jk)
2646 enddo
2647 enddo
2648
2649 ! 2.2 Get Legendre polynomial (and its derivative) for all latitudes
2650 ! but for the chosen value of "m" from the global array
2651 call getalp(dlalp,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc,jm)
2652
2653 ! 2.3 Perform the inverse Legendre transform for all fields
2654 call leginv2d_kij(jm,zfms,zfma,dlsp,dlalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
2655
2656 ! 2.4 Passage to Fourier space
2657
2658 do jj = 1, gst(gstID)%nj
2659 jj2 = gst(gstID)%nj - jj + 1
2660 if(jj.le.gst(gstID)%njlath) then
2661 do jk = 1, gst(gstID)%myLevCount
2662 pgd2(jk,ilonr,jj2) = zfms(jk,jj,1) + zfma(jk,jj,1)
2663 pgd2(jk,iloni,jj2) = zfms(jk,jj,2) + zfma(jk,jj,2)
2664 enddo
2665 else
2666 do jk = 1, gst(gstID)%myLevCount
2667 pgd2(jk,ilonr,jj2) = zfms(jk,jj2,1) - zfma(jk,jj2,1)
2668 pgd2(jk,iloni,jj2) = zfms(jk,jj2,2) - zfma(jk,jj2,2)
2669 enddo
2670 endif
2671 enddo
2672
2673 enddo
2674 !$OMP END PARALLEL DO
2675
2676 end subroutine spereepar_kij
2677
2678
2679 subroutine reespepar(pgd2,psp)
2680 implicit none
2681
2682 ! Arguments:
2683 real(8), intent(out) :: psp(gst(gstID)%nla,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2684 real(8), intent(in) :: pgd2(2*gst(gstID)%maxmcount,gst(gstID)%nj, &
2685 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2686
2687 ! Locals:
2688 integer :: jj,jj2,jk,ilonr, iloni
2689 integer :: jm, ila, inm, jn
2690 real(8) :: dlalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
2691 real(8) :: dldalp(0:gst(gstID)%ntrunc, gst(gstID)%njlath)
2692 real(8) :: dlsp(0:gst(gstID)%ntrunc,2, &
2693 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2694 real(8) :: zfms(gst(gstID)%njlath+1,2, &
2695 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2696 real(8) :: zfma(gst(gstID)%njlath+1,2, &
2697 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2698 real(8) :: dlrwt(gst(gstID)%nj)
2699
2700 ! 1. Adjustment needed when an odd number of latitudes is considered
2701 dlrwt(:) = gst(gstID)%rwt(:)
2702 if (mod(gst(gstID)%nj,2).ne.0) then
2703 dlrwt(gst(gstID)%njlath) = dlrwt(gst(gstID)%njlath)/2.d0
2704 end if
2705
2706 !$OMP PARALLEL DO PRIVATE(DLALP,DLDALP,DLSP,ZFMS,ZFMA, &
2707 !$OMP INM,ILA,JM,JN,JK,JJ,JJ2,ILONR,ILONI)
2708 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
2709
2710 ilonr = 2*gst(gstID)%mymIndex(jm)-1
2711 iloni = 2*gst(gstID)%mymIndex(jm)
2712
2713 ! 2.1 Fetch the Legendre functions and their derivatives for this choice of "m"
2714 call getalp(dlalp,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc,jm)
2715
2716 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2717 ! 2.2 Build the symmetric and anti-symmetric Fourier coefficients including
2718 ! the appropriate quadrature weights (see scientific notes)
2719 do jj = 1, gst(gstID)%njlath
2720 zfms(jj,1,jk) = 0.0d0
2721 zfms(jj,2,jk) = 0.0d0
2722 zfma(jj,1,jk) = 0.0d0
2723 zfma(jj,2,jk) = 0.0d0
2724 enddo
2725
2726 do jj = 1, gst(gstID)%nj
2727 jj2 = gst(gstID)%nj-jj+1
2728 if(jj.le.gst(gstID)%njlath) then
2729 ! Northern hemisphere
2730 zfms(jj,1,jk) = pgd2(ilonr,jj2,jk)
2731 zfms(jj,2,jk) = pgd2(iloni,jj2,jk)
2732 zfma(jj,1,jk) = pgd2(ilonr,jj2,jk)
2733 zfma(jj,2,jk) = pgd2(iloni,jj2,jk)
2734 else
2735 ! Southern hemisphere
2736 zfms(jj2,1,jk) = zfms(jj2,1,jk) + pgd2(ilonr,jj2,jk)
2737 zfms(jj2,2,jk) = zfms(jj2,2,jk) + pgd2(iloni,jj2,jk)
2738 zfma(jj2,1,jk) = zfma(jj2,1,jk) - pgd2(ilonr,jj2,jk)
2739 zfma(jj2,2,jk) = zfma(jj2,2,jk) - pgd2(iloni,jj2,jk)
2740 endif
2741 enddo
2742
2743 do jj = 1,gst(gstID)%njlath
2744 zfms(jj,1,jk) = dlrwt(jj)*zfms(jj,1,jk)
2745 zfms(jj,2,jk) = dlrwt(jj)*zfms(jj,2,jk)
2746 zfma(jj,1,jk) = dlrwt(jj)*zfma(jj,1,jk)
2747 zfma(jj,2,jk) = dlrwt(jj)*zfma(jj,2,jk)
2748 enddo
2749
2750 enddo ! jk
2751
2752 ! 2.3 First one with ALP for all scalar fields and for half the terms
2753 ! required to define the divergence and vorticity
2754 call legdir2d(jm,zfms,zfma,dlsp,dlalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
2755
2756 ! 2.4 Transfer the result in the global state
2757 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2758 do jn = jm, gst(gstID)%ntrunc
2759 ila = gst(gstID)%nind(jm) + jn - jm
2760 inm = jn - jm
2761 psp(ila,1,jk) = dlsp(inm,1,jk)
2762 psp(ila,2,jk) = dlsp(inm,2,jk)
2763 enddo
2764 enddo ! jk
2765
2766 ! End of loop on zonal wavenumbers
2767 enddo
2768 !$OMP END PARALLEL DO
2769
2770 end subroutine reespepar
2771
2772
2773 subroutine reespepar_kij(pgd2,psp)
2774 implicit none
2775
2776 ! Arguments:
2777 real(8), intent(out) :: psp(gst(gstID)%nla,2,gst(gstID)%myLevCount)
2778 real(8), intent(in) :: pgd2(gst(gstID)%maxMyLevCount,2*gst(gstID)%maxmcount, &
2779 gst(gstID)%nj)
2780
2781 ! Locals:
2782 integer :: jj,jj2,jk,ilonr, iloni
2783 integer :: jm, ila, inm, jn
2784 real(8) :: dlalp(0:gst(gstID)%ntrunc,gst(gstID)%njlath)
2785 real(8) :: dldalp(0:gst(gstID)%ntrunc, gst(gstID)%njlath)
2786 real(8) :: dlsp(gst(gstID)%myLevCount,0:gst(gstID)%ntrunc,2)
2787 real(8) :: zfms(gst(gstID)%myLevCount,gst(gstID)%njlath+1,2)
2788 real(8) :: zfma(gst(gstID)%myLevCount,gst(gstID)%njlath+1,2)
2789 real(8) :: dlrwt(gst(gstID)%nj)
2790
2791 ! 1. Adjustment needed when an odd number of latitudes is considered
2792 dlrwt(:) = gst(gstID)%rwt(:)
2793 if (mod(gst(gstID)%nj,2).ne.0) then
2794 dlrwt(gst(gstID)%njlath) = dlrwt(gst(gstID)%njlath)/2.d0
2795 end if
2796
2797 !$OMP PARALLEL DO PRIVATE(DLALP,DLDALP,DLSP,ZFMS,ZFMA, &
2798 !$OMP INM,ILA,JM,JN,JK,JJ,JJ2,ILONR,ILONI)
2799 do jm = gst(gstID)%mymBeg, gst(gstID)%mymEnd, gst(gstID)%mymSkip
2800
2801 ilonr = 2*gst(gstID)%mymIndex(jm)-1
2802 iloni = 2*gst(gstID)%mymIndex(jm)
2803
2804 ! 2.1 Fetch the Legendre functions and their derivatives for this choice of "m"
2805 call getalp(dlalp,dldalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc,jm)
2806
2807 ! 2.2 Build the symmetric and anti-symmetric Fourier coefficients including
2808 ! the appropriate quadrature weights (see scientific notes)
2809 do jj = 1, gst(gstID)%njlath
2810 do jk = 1, gst(gstID)%myLevCount
2811 zfms(jk,jj,1) = 0.0d0
2812 zfms(jk,jj,2) = 0.0d0
2813 zfma(jk,jj,1) = 0.0d0
2814 zfma(jk,jj,2) = 0.0d0
2815 enddo
2816 enddo
2817
2818 do jj = 1, gst(gstID)%nj
2819 jj2 = gst(gstID)%nj-jj+1
2820 if(jj.le.gst(gstID)%njlath) then
2821 ! Northern hemisphere
2822 do jk = 1, gst(gstID)%myLevCount
2823 zfms(jk,jj,1) = pgd2(jk,ilonr,jj2)
2824 zfms(jk,jj,2) = pgd2(jk,iloni,jj2)
2825 zfma(jk,jj,1) = pgd2(jk,ilonr,jj2)
2826 zfma(jk,jj,2) = pgd2(jk,iloni,jj2)
2827 enddo
2828 else
2829 do jk = 1, gst(gstID)%myLevCount
2830 ! Southern hemisphere
2831 zfms(jk,jj2,1) = zfms(jk,jj2,1) + pgd2(jk,ilonr,jj2)
2832 zfms(jk,jj2,2) = zfms(jk,jj2,2) + pgd2(jk,iloni,jj2)
2833 zfma(jk,jj2,1) = zfma(jk,jj2,1) - pgd2(jk,ilonr,jj2)
2834 zfma(jk,jj2,2) = zfma(jk,jj2,2) - pgd2(jk,iloni,jj2)
2835 enddo
2836 endif
2837 enddo
2838
2839 do jj = 1,gst(gstID)%njlath
2840 do jk = 1, gst(gstID)%myLevCount
2841 zfms(jk,jj,1) = dlrwt(jj)*zfms(jk,jj,1)
2842 zfms(jk,jj,2) = dlrwt(jj)*zfms(jk,jj,2)
2843 zfma(jk,jj,1) = dlrwt(jj)*zfma(jk,jj,1)
2844 zfma(jk,jj,2) = dlrwt(jj)*zfma(jk,jj,2)
2845 enddo
2846 enddo
2847
2848
2849 ! 2.3 First one with ALP for all scalar fields and for half the terms
2850 ! required to define the divergence and vorticity
2851 call legdir2d_kij(jm,zfms,zfma,dlsp,dlalp,gst(gstID)%njlath,gst(gstID)%ntrunc,gst(gstID)%ntrunc)
2852
2853 ! 2.4 Transfer the result in the global state
2854 do jn = jm, gst(gstID)%ntrunc
2855 ila = gst(gstID)%nind(jm) + jn - jm
2856 inm = jn - jm
2857 do jk = 1, gst(gstID)%myLevCount
2858 psp(ila,1,jk) = dlsp(jk,inm,1)
2859 psp(ila,2,jk) = dlsp(jk,inm,2)
2860 enddo
2861 enddo
2862
2863 ! End of loop on zonal wavenumbers
2864 enddo
2865 !$OMP END PARALLEL DO
2866
2867 end subroutine reespepar_kij
2868
2869
2870 subroutine legdir2d(km,pfms,pfma,ddsp,ddalp,klath,ktrunc,ktruncdim)
2871 implicit none
2872
2873 ! Arguments:
2874 integer, intent(in) :: km
2875 integer, intent(in) :: ktrunc
2876 integer, intent(in) :: ktruncdim
2877 integer, intent(in) :: klath
2878 real(8), intent(in) :: pfms(gst(gstID)%njlath+1,2, &
2879 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2880 real(8), intent(in) :: pfma(gst(gstID)%njlath+1,2, &
2881 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2882 real(8), intent(in) :: ddalp(0:ktruncdim,klath)
2883 real(8), intent(out) :: ddsp(0:ktruncdim,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2884
2885 ! Locals:
2886 integer :: jk, jlat, jn, inm, itrunc, inmp1
2887
2888 itrunc = ktrunc
2889 if(mod(ktrunc-km+1,2).eq.1) itrunc = ktrunc-1
2890
2891 if(km.ne.ktrunc)then
2892 ddsp(0:ktrunc,:,:) = 0.d0
2893 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2894 do jlat = 1, klath
2895 do jn = km, itrunc, 2
2896 inm = jn - km
2897 inmp1 = inm + 1
2898 ddsp(inm, 1,jk) = ddsp(inm, 1,jk) + ddalp(inm, jlat)*pfms(jlat,1,jk)
2899 ddsp(inmp1,1,jk) = ddsp(inmp1,1,jk) + ddalp(inmp1,jlat)*pfma(jlat,1,jk)
2900 ddsp(inm, 2,jk) = ddsp(inm, 2,jk) + ddalp(inm, jlat)*pfms(jlat,2,jk)
2901 ddsp(inmp1,2,jk) = ddsp(inmp1,2,jk) + ddalp(inmp1,jlat)*pfma(jlat,2,jk)
2902 enddo
2903 enddo
2904 enddo
2905 end if
2906
2907 if(mod(ktrunc-km+1,2).eq.1) then
2908 jn = ktrunc
2909 inm = jn - km
2910 ddsp(inm,:,:) = 0.d0
2911 do jk = gst(gstID)%myLevBeg, gst(gstID)%myLevEnd
2912 do jlat = 1, klath
2913 ddsp(inm,1,jk) = ddsp(inm,1,jk) + ddalp(inm,jlat)*pfms(jlat,1,jk )
2914 ddsp(inm,2,jk) = ddsp(inm,2,jk) + ddalp(inm,jlat)*pfms(jlat,2,jk )
2915 enddo
2916 enddo
2917 end if
2918
2919 end subroutine legdir2d
2920
2921
2922 subroutine legdir2d_kij(km,pfms,pfma,ddsp,ddalp,klath,ktrunc,ktruncdim)
2923 implicit none
2924
2925 ! Arguments:
2926 integer, intent(in) :: km
2927 integer, intent(in) :: ktrunc
2928 integer, intent(in) :: ktruncdim
2929 integer, intent(in) :: klath
2930 real(8), intent(in) :: pfms(gst(gstID)%myLevCount,gst(gstID)%njlath+1,2)
2931 real(8), intent(in) :: pfma(gst(gstID)%myLevCount,gst(gstID)%njlath+1,2)
2932 real(8), intent(in) :: ddalp(0:ktruncdim,klath)
2933 real(8), intent(out) :: ddsp(gst(gstID)%myLevCount,0:ktruncdim,2)
2934
2935 ! Locals:
2936 integer :: jk, jlat, jn, inm, itrunc, inmp1
2937
2938 itrunc = ktrunc
2939 if(mod(ktrunc-km+1,2).eq.1) itrunc = ktrunc-1
2940
2941 if(km.ne.ktrunc)then
2942 ddsp(:,0:ktrunc,:) = 0.d0
2943 do jlat = 1, klath
2944 do jn = km, itrunc, 2
2945 inm = jn - km
2946 inmp1 = inm + 1
2947 do jk = 1, gst(gstID)%myLevCount
2948 ddsp(jk,inm, 1) = ddsp(jk,inm, 1) + ddalp(inm, jlat)*pfms(jk,jlat,1)
2949 ddsp(jk,inmp1,1) = ddsp(jk,inmp1,1) + ddalp(inmp1,jlat)*pfma(jk,jlat,1)
2950 ddsp(jk,inm, 2) = ddsp(jk,inm, 2) + ddalp(inm, jlat)*pfms(jk,jlat,2)
2951 ddsp(jk,inmp1,2) = ddsp(jk,inmp1,2) + ddalp(inmp1,jlat)*pfma(jk,jlat,2)
2952 enddo
2953 enddo
2954 enddo
2955 end if
2956
2957 if(mod(ktrunc-km+1,2).eq.1) then
2958 jn = ktrunc
2959 inm = jn - km
2960 ddsp(:,inm,:) = 0.d0
2961 do jlat = 1, klath
2962 do jk = 1, gst(gstID)%myLevCount
2963 ddsp(jk,inm,1) = ddsp(jk,inm,1) + ddalp(inm,jlat)*pfms(jk,jlat,1 )
2964 ddsp(jk,inm,2) = ddsp(jk,inm,2) + ddalp(inm,jlat)*pfms(jk,jlat,2 )
2965 enddo
2966 enddo
2967 end if
2968
2969 end subroutine legdir2d_kij
2970
2971
2972 subroutine leginv2d(km,pfms,pfma,ddsp,ddalp,klath,ktrunc,ktruncdim)
2973 implicit none
2974
2975 ! Arguments:
2976 integer, intent(in) :: km
2977 integer, intent(in) :: ktrunc
2978 integer, intent(in) :: ktruncdim
2979 integer, intent(in) :: klath
2980 real(8), intent(out) :: pfms(gst(gstID)%njlath+1,2, &
2981 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2982 real(8), intent(out) :: pfma(gst(gstID)%njlath+1,2, &
2983 gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2984 real(8), intent(in) :: ddalp(0:ktruncdim,klath)
2985 real(8), intent(in) :: ddsp(0:ktruncdim,2,gst(gstID)%myLevBeg:gst(gstID)%myLevEnd)
2986
2987 ! Locals:
2988 integer :: jk, jlat, jn, inm, itrunc, inmp1
2989
2990 itrunc = ktrunc
2991 if(mod(ktrunc-km+1,2).eq.1) itrunc = ktrunc-1
2992
2993 if(km .ne. ktrunc)then
2994 do jk = gst(gstID)%myLevBeg,gst(gstID)%myLevEnd
2995 pfms(:,:,jk) = 0.d0
2996 pfma(:,:,jk) = 0.d0
2997 do jn = km, itrunc, 2
2998 inm = jn - km
2999 inmp1 = inm + 1
3000 do jlat = 1, klath
3001 pfms(jlat,1,jk) = pfms(jlat,1,jk) + ddalp(inm, jlat) * ddsp(inm, 1,jk)
3002 pfma(jlat,1,jk) = pfma(jlat,1,jk) + ddalp(inmp1,jlat) * ddsp(inmp1,1,jk)
3003 pfms(jlat,2,jk) = pfms(jlat,2,jk) + ddalp(inm, jlat) * ddsp(inm, 2,jk)
3004 pfma(jlat,2,jk) = pfma(jlat,2,jk) + ddalp(inmp1,jlat) * ddsp(inmp1,2,jk)
3005 enddo
3006 enddo
3007 enddo
3008 end if
3009
3010 if(mod(ktrunc-km+1,2).eq.1) then
3011 jn = ktrunc
3012 if (km .ne. ktrunc) then
3013 inm = jn - km
3014 do jk = gst(gstID)%myLevBeg,gst(gstID)%myLevEnd
3015 do jlat = 1, klath
3016 pfms(jlat,1,jk) = pfms(jlat,1,jk) + ddalp(inm,jlat) * ddsp(inm,1,jk)
3017 pfms(jlat,2,jk) = pfms(jlat,2,jk) + ddalp(inm,jlat) * ddsp(inm,2,jk)
3018 enddo
3019 enddo
3020 else
3021 inm = jn - km
3022 do jk = gst(gstID)%myLevBeg,gst(gstID)%myLevEnd
3023 pfms(:,:,jk) = 0.d0
3024 pfma(:,:,jk) = 0.d0
3025 do jlat = 1, klath
3026 pfms(jlat,1,jk) = ddalp(inm,jlat) * ddsp(inm,1,jk)
3027 pfms(jlat,2,jk) = ddalp(inm,jlat) * ddsp(inm,2,jk)
3028 enddo
3029 enddo
3030 end if
3031 end if
3032
3033 end subroutine leginv2d
3034
3035
3036 subroutine leginv2d_kij(km,pfms,pfma,ddsp,ddalp,klath,ktrunc,ktruncdim)
3037 implicit none
3038
3039 ! Arguments:
3040 integer, intent(in) :: km
3041 integer, intent(in) :: ktrunc
3042 integer, intent(in) :: ktruncdim
3043 integer, intent(in) :: klath
3044 real(8), intent(out) :: pfms(gst(gstID)%myLevCount,gst(gstID)%njlath+1,2)
3045 real(8), intent(out) :: pfma(gst(gstID)%myLevCount,gst(gstID)%njlath+1,2)
3046 real(8), intent(in) :: ddalp(0:ktruncdim,klath)
3047 real(8), intent(in) :: ddsp(gst(gstID)%myLevCount,0:ktruncdim,2)
3048
3049 ! Locals:
3050 integer :: jk, jlat, jn, inm, itrunc, inmp1
3051
3052 itrunc = ktrunc
3053 if(mod(ktrunc-km+1,2).eq.1) itrunc = ktrunc-1
3054
3055 if(km .ne. ktrunc)then
3056 pfms(:,:,:) = 0.d0
3057 pfma(:,:,:) = 0.d0
3058 do jn = km, itrunc, 2
3059 inm = jn - km
3060 inmp1 = inm + 1
3061 do jlat = 1, klath
3062 do jk = 1, gst(gstID)%myLevCount
3063 pfms(jk,jlat,1) = pfms(jk,jlat,1) + ddalp(inm, jlat) * ddsp(jk,inm, 1)
3064 pfma(jk,jlat,1) = pfma(jk,jlat,1) + ddalp(inmp1,jlat) * ddsp(jk,inmp1,1)
3065 pfms(jk,jlat,2) = pfms(jk,jlat,2) + ddalp(inm, jlat) * ddsp(jk,inm, 2)
3066 pfma(jk,jlat,2) = pfma(jk,jlat,2) + ddalp(inmp1,jlat) * ddsp(jk,inmp1,2)
3067 enddo
3068 enddo
3069 enddo
3070 end if
3071
3072 if(mod(ktrunc-km+1,2).eq.1) then
3073 jn = ktrunc
3074 if (km .ne. ktrunc) then
3075 inm = jn - km
3076 do jlat = 1, klath
3077 do jk = 1, gst(gstID)%myLevCount
3078 pfms(jk,jlat,1) = pfms(jk,jlat,1) + ddalp(inm,jlat) * ddsp(jk,inm,1)
3079 pfms(jk,jlat,2) = pfms(jk,jlat,2) + ddalp(inm,jlat) * ddsp(jk,inm,2)
3080 enddo
3081 enddo
3082 else
3083 inm = jn - km
3084 pfms(:,:,:) = 0.d0
3085 pfma(:,:,:) = 0.d0
3086 do jlat = 1, klath
3087 do jk = 1, gst(gstID)%myLevCount
3088 pfms(jk,jlat,1) = ddalp(inm,jlat) * ddsp(jk,inm,1)
3089 pfms(jk,jlat,2) = ddalp(inm,jlat) * ddsp(jk,inm,2)
3090 enddo
3091 enddo
3092 end if
3093 end if
3094
3095 end subroutine leginv2d_kij
3096
3097
3098 subroutine allocate_comleg
3099 !
3100 !:Purpose: Subroutine for initializing the Legendre transform
3101 implicit none
3102
3103 allocate(gst(gstID)%rmu(gst(gstID)%nj))
3104 allocate(gst(gstID)%rwt(gst(gstID)%nj))
3105 allocate(gst(gstID)%rwocs(gst(gstID)%nj))
3106 allocate(gst(gstID)%r1mu2(gst(gstID)%nj))
3107 allocate(gst(gstID)%rsqm2(gst(gstID)%nj))
3108 allocate(gst(gstID)%rcolat(gst(gstID)%nj))
3109 allocate(gst(gstID)%r1qm2(gst(gstID)%nj))
3110 allocate(gst(gstID)%r1mui(gst(gstID)%nj))
3111 allocate(gst(gstID)%r1mua(gst(gstID)%nj))
3112 allocate(gst(gstID)%rlati((-1):(gst(gstID)%nj+2)))
3113 allocate(gst(gstID)%nind(0:gst(gstID)%ntrunc))
3114 allocate(gst(gstID)%nindrh(0:gst(gstID)%ntrunc))
3115 allocate(gst(gstID)%nclm(0:gst(gstID)%ntrunc))
3116
3117 end subroutine allocate_comleg
3118
3119
3120 subroutine suleg(lverbose_opt)
3121 !
3122 !:Purpose: To initializethe Gaussian latitudes, weights and related
3123 ! quantities
3124 implicit none
3125
3126 ! Arguments:
3127 logical, optional, intent(in) :: lverbose_opt
3128
3129 ! Locals:
3130 logical :: lverbose
3131 integer :: jlat, jm
3132 real(8) :: zpisu2
3133 external gauss
3134
3135 ! Some explanation:
3136 ! rmu = sin(latitude)
3137 ! colat = pi/2 - latitude
3138 ! rwt = gauss weight (complicated)
3139 ! rwocs = rwt / cos(latitude)^2
3140
3141 if(present(lverbose_opt)) then
3142 lverbose = lverbose_opt
3143 else
3144 lverbose = .false.
3145 endif
3146
3147 if(mmpi_myid.eq.0) write(*,fmt='(//,6(" ***********"))')
3148 if(mmpi_myid.eq.0) write(*,*)' SULEG: initialisation of Gaussian', &
3149 ' latitudes, weights, etc...'
3150 if(mmpi_myid.eq.0) write(*,fmt='(6(" ***********"))')
3151
3152 ! 1. GAUSSIAN LATITUDES AND WEIGHTS OVER AN HEMISPHERE
3153 ! -------------------------------------------------
3154
3155 call gauss8(gst(gstID)%njlath,gst(gstID)%rmu(1),gst(gstID)%rwt(1), &
3156 gst(gstID)%rsqm2(1),gst(gstID)%rcolat(1),gst(gstID)%rwocs(1), &
3157 gst(gstID)%r1qm2(1),gst(gstID)%r1mui(1),gst(gstID)%r1mu2(1))
3158
3159 do jlat = 1, gst(gstID)%njlath
3160 gst(gstID)%rlati(jlat) = asin(gst(gstID)%rmu(jlat))
3161 gst(gstID)%r1mua(jlat) = ec_r1sa*gst(gstID)%r1mui(jlat)
3162 enddo
3163
3164 ! 2. COMPLETION FOR THE SOUTHERN HEMISPHERE
3165 ! --------------------------------------
3166
3167 do jlat = gst(gstID)%njlath +1, gst(gstID)%nj
3168 gst(gstID)%rmu(jlat) = -gst(gstID)%rmu(2*gst(gstID)%njlath +1 - jlat)
3169 gst(gstID)%rwocs(jlat) = gst(gstID)%rwocs(2*gst(gstID)%njlath +1 - jlat)
3170 gst(gstID)%r1mu2(jlat) = gst(gstID)%r1mu2(2*gst(gstID)%njlath +1 - jlat)
3171 gst(gstID)%rsqm2(jlat) = gst(gstID)%rsqm2(2*gst(gstID)%njlath +1 - jlat)
3172 gst(gstID)%r1qm2(jlat) = gst(gstID)%r1qm2(2*gst(gstID)%njlath +1 - jlat)
3173 gst(gstID)%r1mui(jlat) = gst(gstID)%r1mui(2*gst(gstID)%njlath +1 - jlat)
3174 gst(gstID)%r1mua(jlat) = gst(gstID)%r1mua(2*gst(gstID)%njlath +1 - jlat)
3175 gst(gstID)%rwt(jlat) = gst(gstID)%rwt(2*gst(gstID)%njlath +1 - jlat)
3176 gst(gstID)%rlati(jlat) = - gst(gstID)%rlati (2*gst(gstID)%njlath +1 - jlat)
3177 enddo
3178
3179 zpisu2 = MPC_PI_R8/2.d0
3180 do jlat = 1, gst(gstID)%nj
3181 gst(gstID)%rcolat(jlat) = zpisu2 - gst(gstID)%rlati(jlat)
3182 enddo
3183
3184 !* 3. Overdimensioning for interpolation
3185
3186 gst(gstID)%rlati(-1) = MPC_PI_R8-gst(gstID)%rlati(1)
3187 gst(gstID)%rlati(0) = MPC_PI_R8*.5d0
3188 gst(gstID)%rlati(gst(gstID)%nj+1) =-MPC_PI_R8*.5d0
3189 gst(gstID)%rlati(gst(gstID)%nj+2) =-MPC_PI_R8-gst(gstID)%rlati(gst(gstID)%nj)
3190
3191 !* 4. Print the content of GAUS
3192
3193 if(lverbose.and.mmpi_myid.eq.0) write(*,fmt='(" JLAT:",4X," RLATI",8X,"RCOLAT",8X,"RMU",10X ,"RWT",12X,"RW0CS")')
3194 do jlat = 1, gst(gstID)%nj
3195 if(lverbose.and.mmpi_myid.eq.0) write(*,fmt='(2X,I4,5(2X,G23.16))') &
3196 jlat,gst(gstID)%rlati(jlat),gst(gstID)%rcolat(jlat), gst(gstID)%rmu(jlat) &
3197 ,gst(gstID)%rwt(jlat),gst(gstID)%rwocs(jlat)
3198 enddo
3199
3200 if(lverbose.and.mmpi_myid.eq.0) write(*,fmt='(//," JLAT:",4X,"R1MU2",8X,"RSQM2",9X,"R1QM2",10X,"R1MUI",10X,"R1MUA")')
3201
3202 do jlat = 1, gst(gstID)%nj
3203 if(lverbose.and.mmpi_myid.eq.0) &
3204 write(*,fmt='(2X,I4,5(2X,G23.16))') jlat,gst(gstID)%r1mu2(jlat),gst(gstID)%rsqm2(jlat),gst(gstID)%r1qm2(jlat) &
3205 ,gst(gstID)%r1mui(jlat),gst(gstID)%r1mua(jlat)
3206 enddo
3207
3208 !* 5. Positioning within spectral arrays
3209
3210 do jm = 0, gst(gstID)%ntrunc
3211 gst(gstID)%nind(jm) = jm*(gst(gstID)%ntrunc+1) - (jm*(jm-1))/2 + 1
3212 gst(gstID)%nindrh(jm) = jm*(gst(gstID)%ntrunc+1) + 1
3213 gst(gstID)%nclm(jm) = gst(gstID)%ntrunc - jm + 1
3214 enddo
3215
3216 if(lverbose.and.mmpi_myid.eq.0) write(*,fmt='(/," NIND(0:NTRUNC):",/,10(2X,I8))') &
3217 (gst(gstID)%nind(jm),jm=0,gst(gstID)%ntrunc)
3218 if(lverbose.and.mmpi_myid.eq.0) write(*,fmt='(" NINDRH(0:NTRUNC):",/,10(2X,I8))') &
3219 (gst(gstID)%nindrh(jm),jm=0,gst(gstID)%ntrunc)
3220 if(lverbose.and.mmpi_myid.eq.0) write(*,fmt='(" NCLM(0:NTRUNC):",/,10(2X,I8))') &
3221 (gst(gstID)%nclm(jm),jm=0,gst(gstID)%ntrunc)
3222
3223 end subroutine suleg
3224
3225
3226 subroutine gauss8(nracp,racp,pg,sia,rad,pgssin2,sinm1,sinm2,sin2)
3227 implicit none
3228
3229 ! Arguments:
3230 integer, intent(in) :: nracp
3231 real(8), intent(out) :: racp(*)
3232 real(8), intent(out) :: pg(*)
3233 real(8), intent(out) :: sia(*)
3234 real(8), intent(out) :: rad(*)
3235 real(8), intent(out) :: pgssin2(*)
3236 real(8), intent(out) :: sinm1(*)
3237 real(8), intent(out) :: sinm2(*)
3238 real(8), intent(out) :: sin2(*)
3239
3240 ! Locals:
3241 real(8) :: xlim,pi,fi,fi1,fn,dot,dn,dn1,a,b,c,g,gm,gp,gt,ractemp,gtemp
3242 integer :: i,ir,irm,irp
3243
3244 xlim = 1.d-13
3245 pi = 4.d0*atan(1.d0)
3246 ir = 2*nracp
3247 fi = dble(ir)
3248 fi1 = fi+1.d0
3249 fn = dble(nracp)
3250
3251 do i = 1,nracp
3252 dot = dble(i-1)
3253 racp(i) = -pi*.5d0*(dot+.5d0)/fn + pi*.5d0
3254 racp(i) = sin(racp(i))
3255 enddo
3256
3257 dn = fi/sqrt(4.d0*fi*fi-1.d0)
3258 dn1 = fi1/sqrt(4.d0*fi1*fi1-1.d0)
3259 a = dn1*fi
3260 b = dn*fi1
3261 irp = ir + 1
3262 irm = ir -1
3263
3264 do i = 1,nracp
326542 call ordleg8(g,racp(i),ir)
3266 call ordleg8(gm,racp(i),irm)
3267 call ordleg8(gp,racp(i),irp)
3268 gt = (a*gp-b*gm)/(racp(i)*racp(i)-1.d0)
3269 ractemp = racp(i) - g/gt
3270 gtemp = racp(i) - ractemp
3271 racp(i) = ractemp
3272 if( abs(gtemp).gt.xlim) go to 42
3273 enddo
3274
3275 do i = 1,nracp
3276 a = 2.d0*(1.d0-racp(i)**2)
3277 call ordleg8(b,racp(i),irm)
3278 b = b*b*fi*fi
3279 pg(i) = a*(fi-.5d0)/b
3280 rad(i) = acos(racp(i))
3281 sia(i) = sin(rad(i))
3282 c = (sia(i))**2
3283 sinm1(i) = 1.d0/sia(i)
3284 sinm2(i) = 1.d0/c
3285 pgssin2(i) = pg(i)/c
3286 sin2(i) = c
3287 enddo
3288
3289 end subroutine gauss8
3290
3291
3292 subroutine ordleg8(sx,coa,ir)
3293 implicit none
3294
3295 ! Arguments:
3296 real(8), intent(out) :: sx
3297 real(8), intent(in) :: coa
3298 integer, intent(in) :: ir
3299
3300 ! Locals:
3301 integer :: n,kk,k,n1,irpp,irppm
3302 real(8) :: pi,sqr2,delta,sia,theta,c1,c4,s1,ang,fk,fn,fn2,fn2sq,a,b
3303
3304 pi = 4.d0*atan(1.d0)
3305 sqr2 = sqrt(2.d0)
3306 irpp = ir + 1
3307 irppm = irpp - 1
3308 delta = acos(coa)
3309 sia = sin(delta)
3310
3311 theta = delta
3312 c1 = sqr2
3313
3314 do n = 1,irppm
3315 fn2 = dble(2*n)
3316 fn2sq = fn2*fn2
3317 c1 = c1*sqrt(1.d0 - 1.d0/fn2sq)
3318 enddo
3319
3320 n = irppm
3321 fn = dble(n)
3322 ang = fn*theta
3323 s1 = 0.d0
3324 c4 = 1.d0
3325 a =-1.d0
3326 b = 0.d0
3327 n1 = n+1
3328
3329 do kk = 1,n1,2
3330 k = kk-1
3331 if (k.eq.n) c4 = 0.5d0*c4
3332 s1 = s1+c4* cos(ang)
3333 a = a+2.d0
3334 b = b+1.d0
3335 fk = dble(k)
3336 ang = theta*(fn-fk-2.d0)
3337 c4 = ( a * (fn-b+1.d0) / (b*(fn2-a)) )*c4
3338 enddo
3339
3340 sx = s1*c1
3341
3342 end subroutine ordleg8
3343
3344
3345 subroutine sualp
3346 implicit none
3347
3348 ! Locals:
3349 integer :: jj,jlat,jm,jn,ilat
3350 integer :: ilarh,ila,ilatbd
3351 real(8) :: dlalp(gst(gstID)%nlarh,nlatbd)
3352 real(8) :: dldalp(gst(gstID)%nlarh,nlatbd)
3353 !
3354 ! Memory allocation for Legendre polynomials
3355 !
3356 if(mmpi_myid.eq.0) write(*,*) 'allocating dalp:',gst(gstID)%nla,gst(gstID)%njlath,gst(gstID)%nla*gst(gstID)%njlath
3357 allocate( gst(gstID)%dalp(gst(gstID)%nla,gst(gstID)%njlath) )
3358 allocate( gst(gstID)%dealp(gst(gstID)%nla,gst(gstID)%njlath))
3359 if(mmpi_myid.eq.0) write(*,*) 'succeeded'
3360
3361 latitudes: do jlat = 1, gst(gstID)%njlath, nlatbd
3362 ilatbd = min(nlatbd,gst(gstID)%njlath - jlat + 1)
3363
3364 if(ilatbd.eq.8) then
3365 call allp(dlalp,dldalp,gst(gstID)%rmu(jlat),gst(gstID)%nclm(0),gst(gstID)%ntrunc,ilatbd)
3366 else
3367 call allp2(dlalp,dldalp,gst(gstID)%rmu(jlat),gst(gstID)%ntrunc,ilatbd)
3368 endif
3369
3370 do jm = 0,gst(gstID)%ntrunc
3371 do jn = jm,gst(gstID)%ntrunc
3372 ila = gst(gstID)%nind(jm) + jn -jm
3373 ilarh = gst(gstID)%nindrh(jm) + jn-jm
3374 do jj = 1,ilatbd
3375 ilat = jlat+jj-1
3376 gst(gstID)%dalp (ila,jlat+jj-1) = dlalp (ilarh,jj)
3377 gst(gstID)%dealp(ila,jlat+jj-1) = dldalp(ilarh,jj)
3378 enddo
3379 enddo
3380 enddo
3381 enddo latitudes
3382
3383 end subroutine sualp
3384
3385
3386 subroutine getalp(ddalp,dddalp,klath,ktrunc,ktruncdim ,km)
3387 implicit none
3388
3389 ! Arguments:
3390 real(8) :: ddalp(0:ktruncdim,klath)
3391 real(8) :: dddalp(0:ktruncdim,klath)
3392 integer :: klath
3393 integer :: ktrunc
3394 integer :: ktruncdim
3395 integer :: km
3396
3397 ! Locals:
3398 integer :: ila,ind
3399 integer :: jlat,jn, jlen
3400
3401 do jlat = 1,klath
3402 do jlen = 0, ktrunc
3403 ddalp(jlen,jlat) = 0.d0
3404 dddalp(jlen,jlat)= 0.d0
3405 end do
3406 end do
3407
3408 do jlat = 1, klath
3409 do jn = km, ktrunc
3410 ila = gst(gstID)%nind(km) + jn-km
3411 ind = jn-km
3412 ddalp(ind,jlat) = gst(gstID)%dalp(ila,jlat)
3413 dddalp(ind,jlat) = gst(gstID)%dealp(ila,jlat)
3414 end do
3415 end do
3416
3417 end subroutine getalp
3418
3419
3420 subroutine allp( p , g , x , lr , r , nlatp)
3421
3422 implicit none
3423
3424 ! Arguments:
3425 integer :: r
3426 integer :: nlatp
3427 integer :: lr(0:r)
3428 real(8) :: p(0:r,0:r,nlatp)
3429 real(8) :: g(0:r,0:r,nlatp)
3430 real(8) :: x(nlatp)
3431
3432 ! Locals:
3433 real(8) :: onehalf
3434 real(8) :: xp , xp2, p0, enm, fnm
3435 integer :: ilat , m , l , n
3436
3437 data onehalf /0.5d0/
3438
3439 do ilat = 1,nlatp
3440 xp2 = sqrt( 1.0d0 - x(ilat) ** 2 )
3441 p(0,0,ilat) = sqrt(onehalf)
3442 do m = 1,r
3443 xp = real(m,8)
3444 p(0,m,ilat) = sqrt( (2.0d0*xp+1.0d0)/(2.0d0*xp) ) * xp2 * p(0,m-1,ilat)
3445 enddo
3446 enddo
3447
3448 do ilat = 1,nlatp
3449 do m = 0,r
3450 xp = real(m,8)
3451 g(0,m,ilat) = - x(ilat)*xp * p(0,m,ilat)
3452 enddo
3453 enddo
3454 do n = 1,r
3455 do m = 0,lr(n)-1
3456 l = 1
3457 p0 = real(m+n,8)
3458 xp = real(m,8)
3459 enm = sqrt( ((p0*p0-xp*xp)*(2.0d0*p0+1.0d0))/(2.0d0*p0-1.0d0) )
3460 fnm = sqrt( (2.0d0*p0+1.0d0)/((p0*p0-xp*xp)*(2.0d0*p0-1.0d0)) )
3461
3462 p(n,m,l) = ( x(l) * p0 * p(n-1,m,l) - g(n-1,m,l) ) * fnm
3463 g(n,m,l) = enm * p(n-1,m,l) - x(l) * p0 * p(n,m,l)
3464 l = l + 1
3465 p(n,m,l) = ( x(l) * p0 * p(n-1,m,l) - g(n-1,m,l) ) * fnm
3466 g(n,m,l) = enm * p(n-1,m,l) - x(l) * p0 * p(n,m,l)
3467 l = l + 1
3468 p(n,m,l) = ( x(l) * p0 * p(n-1,m,l) - g(n-1,m,l) ) * fnm
3469 g(n,m,l) = enm * p(n-1,m,l) - x(l) * p0 * p(n,m,l)
3470 l = l + 1
3471 p(n,m,l) = ( x(l) * p0 * p(n-1,m,l) - g(n-1,m,l) ) * fnm
3472 g(n,m,l) = enm * p(n-1,m,l) - x(l) * p0 * p(n,m,l)
3473 l = l + 1
3474 p(n,m,l) = ( x(l) * p0 * p(n-1,m,l) - g(n-1,m,l) ) * fnm
3475 g(n,m,l) = enm * p(n-1,m,l) - x(l) * p0 * p(n,m,l)
3476 l = l + 1
3477 p(n,m,l) = ( x(l) * p0 * p(n-1,m,l) - g(n-1,m,l) ) * fnm
3478 g(n,m,l) = enm * p(n-1,m,l) - x(l) * p0 * p(n,m,l)
3479 l = l + 1
3480 p(n,m,l) = ( x(l) * p0 * p(n-1,m,l) - g(n-1,m,l) ) * fnm
3481 g(n,m,l) = enm * p(n-1,m,l) - x(l) * p0 * p(n,m,l)
3482 l = l + 1
3483 p(n,m,l) = ( x(l) * p0 * p(n-1,m,l) - g(n-1,m,l) ) * fnm
3484 g(n,m,l) = enm * p(n-1,m,l) - x(l) * p0 * p(n,m,l)
3485 l = l + 1
3486 enddo
3487 enddo
3488
3489 end subroutine allp
3490
3491
3492 subroutine allp2( p , g , x , r , nlatp)
3493
3494 implicit none
3495
3496 ! Arguments:
3497 integer :: r
3498 integer :: nlatp
3499 real(8) :: p(0:r,0:r,nlatp)
3500 real(8) :: g(0:r,0:r,nlatp)
3501 real(8) :: x(nlatp)
3502
3503 ! Locals:
3504 real(8) :: onehalf
3505 real(8) :: xp , xp2, p0, enm, fnm
3506 integer :: ilat , m , l , n, jlat
3507
3508 data onehalf /0.5d0/
3509
3510 do ilat = 1,nlatp
3511 xp2 = sqrt( 1.0d0 - x(ilat) ** 2 )
3512 p(0,0,ilat) = sqrt(onehalf)
3513 do m = 1,r
3514 xp = real(m,8)
3515 p(0,m,ilat) = sqrt( (2.0d0*xp+1.0d0)/(2.0d0*xp) ) * xp2 * p(0,m-1,ilat)
3516 enddo
3517 enddo
3518
3519 do ilat = 1,nlatp
3520 do m = 0,r
3521 xp = real(m,8)
3522 g(0,m,ilat) = - x(ilat)*xp * p(0,m,ilat)
3523 enddo
3524 enddo
3525
3526 do n = 1,r
3527 do m = 0, r
3528 p0 = real(m+n,8)
3529 xp = real(m,8)
3530 enm = sqrt( ((p0*p0-xp*xp)*(2.0d0*p0+1.0d0))/(2.0d0*p0-1.0d0) )
3531 fnm = sqrt( (2.0d0*p0+1.0d0)/((p0*p0-xp*xp)*(2.0d0*p0-1.0d0)) )
3532
3533 do jlat = 1, nlatp
3534 l = jlat
3535 p(n,m,l) = ( x(l) * p0 * p(n-1,m,l) - g(n-1,m,l) ) * fnm
3536 g(n,m,l) = enm * p(n-1,m,l) - x(l) * p0 * p(n,m,l)
3537 enddo
3538 enddo
3539 enddo
3540
3541 end subroutine allp2
3542
3543
3544 subroutine gst_zlegpol(gstID_in)
3545 !
3546 !:Purpose: To evaluate Legendre polynomials restricted to (n,m) = (n,0)
3547 implicit none
3548
3549 ! Arguments:
3550 integer :: gstID_in
3551
3552 ! Loclas:
3553 integer :: jn, jlat
3554 real(8) :: dlfact1, dlfact2, dln
3555 real(8) :: dlnorm(0:gst(gstID)%ntrunc)
3556
3557 allocate(gst(gstID_in)%zleg(0:gst(gstID)%ntrunc,gst(gstID)%nj))
3558
3559 do jlat = 1, gst(gstID_in)%nj
3560 gst(gstID_in)%zleg(0,gst(gstID_in)%nj-jlat+1) = sqrt(0.5d0)
3561 gst(gstID_in)%zleg(1,gst(gstID_in)%nj-jlat+1) = sqrt(1.5d0)*gst(gstID_in)%rmu(jlat)
3562 enddo
3563
3564 do jn = 0, gst(gstID_in)%ntrunc
3565 dln = 1.d0*real(jn,8)
3566 dlnorm(jn) = dsqrt((2.d0*dln + 1.d0)/2.d0)
3567 enddo
3568
3569 do jn = 1, gst(gstID_in)%ntrunc-1
3570 dln = real(jn,8)
3571 dlfact1 = ((2.d0*dln+1.d0)/(dln+1.d0))*(dlnorm(jn+1)/dlnorm(jn))
3572 dlfact2 = (dln/(dln+1.d0))*(dlnorm(jn+1)/dlnorm(jn-1))
3573 do jlat = 1,gst(gstID_in)%nj
3574 gst(gstID_in)%zleg(jn+1,gst(gstID_in)%nj-jlat+1) = &
3575 dlfact1*gst(gstID_in)%rmu(jlat)*dble(gst(gstID_in)%zleg(jn,gst(gstID_in)%nj-jlat+1)) &
3576 - dlfact2*dble(gst(gstID_in)%zleg(jn-1,gst(gstID_in)%nj-jlat+1))
3577 enddo
3578 enddo
3579
3580 end subroutine gst_zlegpol
3581
3582
3583 subroutine gst_zlegdir(gstID_in,pf,pn,klev)
3584 !
3585 !:Purpose: Direct Legendre transform restricted to
3586 !
3587 implicit none
3588
3589 ! Arguments:
3590 integer :: gstID_in
3591 real(8) :: pf(gst(gstID_in)%nj,klev) ! PF(NJ,KLEV): field in physical space
3592 real(8) :: pn(0:gst(gstID_in)%ntrunc,klev) ! PN(0:ntrunc, KLEV): spectral coefficients
3593 integer :: klev ! number of fields to transform
3594
3595 ! Locals:
3596 integer :: jlat, jn
3597 real(8), allocatable :: zwork(:,:)
3598
3599 allocate(zwork(0:gst(gstID_in)%ntrunc,gst(gstID_in)%nj))
3600
3601 do jlat = 1, gst(gstID_in)%nj
3602 do jn = 0, gst(gstID_in)%ntrunc
3603 zwork(jn,jlat) = gst(gstID_in)%zleg(jn,jlat)*gst_getRWT(jlat,gstID_in)
3604 end do
3605 end do
3606
3607 call dgemm('N','N',gst(gstID_in)%ntrunc+1, klev, gst(gstID_in)%nj, 1.0d0, zwork(0,1), &
3608 gst(gstID_in)%ntrunc+1, pf(1,1), &
3609 gst(gstID_in)%nj, 0.0d0, pn(0,1), gst(gstID_in)%ntrunc+1)
3610
3611 deallocate(zwork)
3612
3613 end subroutine gst_zlegdir
3614
3615
3616 subroutine gst_zleginv(gstID_in,pf,pn,klev)
3617 !
3618 !:Purpose: Direct Legendre transform restricted to fields that vary with
3619 ! latitude only
3620 !
3621 implicit none
3622
3623 ! Arguments:
3624 integer :: gstID_in
3625 real(8) :: pf(gst(gstID_in)%nj,klev) ! PF(KNJDIM,KLEVDIM) : field in physical space
3626 real(8) :: pn(0:gst(gstID_in)%ntrunc,klev) ! PN(0:KNDIM, KLEVDIM): spectral coefficients
3627 integer :: klev ! number of fields to transform
3628
3629 ! Locals:
3630 integer :: jlat, jn
3631 real(8), allocatable :: zwork(:,:)
3632
3633 allocate(zwork(0:gst(gstID_in)%ntrunc,gst(gstID_in)%nj))
3634
3635 do jlat = 1, gst(gstID_in)%nj
3636 do jn = 0, gst(gstID_in)%ntrunc
3637 zwork(jn,jlat) = gst(gstID_in)%zleg(jn,jlat)
3638 end do
3639 end do
3640
3641 call dgemm('T','N',gst(gstID_in)%nj, klev, gst(gstID_in)%ntrunc+1, 1.0d0, zwork(0,1), &
3642 gst(gstID_in)%ntrunc+1, pn(0,1), &
3643 gst(gstID_in)%ntrunc+1, 0.0d0, pf(1,1), gst(gstID_in)%nj)
3644
3645 deallocate(zwork)
3646
3647 end subroutine gst_zleginv
3648
3649
3650! ---------------------------------------------
3651! FFT subroutines
3652! ---------------------------------------------
3653
3654 subroutine fft3dvar(pgd,kdir)
3655 implicit none
3656
3657 ! Arguments:
3658 real(8) :: pgd(:,:,:)
3659 integer :: kdir
3660
3661 ! Locals:
3662 integer :: kfield,ni,nj
3663 real(8), allocatable :: pgd2(:,:)
3664 integer :: ji,jj,jk,ijump,i
3665
3666 ni = size(pgd,1)
3667 nj = size(pgd,2)
3668 kfield = size(pgd,3)
3669 ijump = ni + 2
3670
3671 i = ni
3672 call ngfft( i )
3673 if ( i.ne.ni ) then
3674 write(*,*) 'fft3dvar: NI = ',ni,' I = ',i
3675 call utl_abort('fft3dvar: vector length is not compatible with FFT')
3676 endif
3677 call setfft8(ni)
3678
3679 allocate(pgd2(ni+2,nj))
3680
3681 ! Copy over input data into over-dimensioned array
3682 !$OMP PARALLEL DO PRIVATE (jj,jk,ji,pgd2)
3683 do jk=1,kfield
3684 do jj=1, nj
3685 do ji=1,ni
3686 pgd2(ji,jj)=pgd(ji,jj,jk)
3687 enddo
3688 do ji=ni+1,ni+2
3689 pgd2(ji,jj)=0.0d0
3690 enddo
3691 enddo
3692
3693 call ffft8(pgd2(1,1),1,ijump,nj,kdir)
3694 !* subroutine ffft8( a, inc, jump, lot, isign )
3695 !* a is the array containing input & output data
3696 !* inc is the increment within each data 'vector'
3697 !* (e.g. inc=1 for consecutively stored data)
3698 !* jump is the increment between the start of each data vector
3699 !* lot is the number of data vectors
3700 !* isign = +1 for transform from spectral to gridpoint
3701 !* = -1 for transform from gridpoint to spectral
3702
3703 do jj=1,nj
3704 do ji=1,ni
3705 pgd(ji,jj,jk)=pgd2(ji,jj)
3706 enddo
3707 enddo
3708 enddo
3709 !$OMP END PARALLEL DO
3710
3711 deallocate(pgd2)
3712
3713 end subroutine fft3dvar
3714
3715 subroutine fft3dvar_kij(pgd,kdir)
3716 implicit none
3717
3718 ! Arguments:
3719 real(8) :: pgd(:,:,:)
3720 integer :: kdir
3721
3722 ! Locals:
3723 integer :: kfield,ni,nj
3724 real(8), allocatable :: pgd2(:,:)
3725 integer :: ji,jj,jk,inc,ijump,i
3726
3727 kfield = size(pgd,1)
3728 ni = size(pgd,2)
3729 nj = size(pgd,3)
3730
3731 i = ni
3732 call ngfft( i )
3733 if ( i.ne.ni ) then
3734 write(*,*) 'fft3dvar: NI = ',ni,' I = ',i
3735 call utl_abort('fft3dvar: vector length is not compatible with FFT')
3736 endif
3737 call setfft8(ni)
3738
3739 inc = kfield
3740 ijump = 1
3741 allocate(pgd2(kfield,ni+2))
3742
3743 ! Copy over input data into over-dimensioned array
3744 !$OMP PARALLEL DO PRIVATE (jj,jk,ji,pgd2)
3745 do jj=1, nj
3746 do ji=1,ni
3747 do jk=1,kfield
3748 pgd2(jk,ji)=pgd(jk,ji,jj)
3749 enddo
3750 enddo
3751 do ji=ni+1,ni+2
3752 do jk=1,kfield
3753 pgd2(jk,ji)=0.0d0
3754 enddo
3755 enddo
3756
3757 call ffft8(pgd2(1,1),inc,ijump,kfield,kdir)
3758 !* subroutine ffft8( a, inc, jump, lot, isign )
3759 !* a is the array containing input & output data
3760 !* inc is the increment within each data 'vector'
3761 !* (e.g. inc=1 for consecutively stored data)
3762 !* jump is the increment between the start of each data vector
3763 !* lot is the number of data vectors
3764 !* isign = +1 for transform from spectral to gridpoint
3765 !* = -1 for transform from gridpoint to spectral
3766
3767 do ji=1,ni
3768 do jk=1,kfield
3769 pgd(jk,ji,jj)=pgd2(jk,ji)
3770 enddo
3771 enddo
3772 enddo
3773 !$OMP END PARALLEL DO
3774
3775 deallocate(pgd2)
3776
3777 end subroutine fft3dvar_kij
3778
3779 subroutine ngfft( n )
3780 implicit none
3781
3782 ! Arguments:
3783 integer :: n
3784
3785 ! Locals:
3786 integer, parameter :: l = 3
3787 integer :: k(l), m
3788 data m , k / 8 , 2 , 3 , 5 /
3789 integer :: i,j
3790
3791 if ( n.le.m ) n = m + 1
3792 n = n - 1
37931 n = n + 1
3794 i = n
37952 do 3 j=1,l
3796 if( mod(i,k(j)) .eq. 0 ) go to 4
37973 continue
3798 go to 1
37994 i = i/k(j)
3800 if( i .ne. 1 ) go to 2
3801
3802 end subroutine ngfft
3803
3804
3805end module globalSpectralTransform_mod