1module lamSpectralTransform_mod
2 ! MODULE lamSpectralTransform_mod (prefix='lst' category='4. Data Object transformations')
3 !
4 !:Purpose: Bi-Fourier spectral transform for limited-area applications.
5 ! Depends on ffft8 and setfft8 routines in ARMNLIB.
6 !
7 use mpi
8 use midasMpi_mod
9 use MathPhysConstants_mod
10 use earthConstants_mod
11 use utilities_mod
12 implicit none
13 save
14 private
15
16 ! public derived type
17 public :: struct_lst
18 ! public procedures
19 public :: lst_Setup, lst_Laplacian, lst_VarTransform
20 public :: lst_ReshapeTrunc ! only for standalone tests
21
22 type :: struct_lst
23 real(8), allocatable :: k_r8(:) ! (real) Total Wavenumber associated with each
24 ! nla spectral coefficient
25 integer, allocatable :: k(:) ! Total Wavenumber bin associated with each
26 ! nla spectral coefficient
27 integer, allocatable :: m(:) ! Wavenumber in x associated with each
28 ! nla spectral coefficient
29 integer, allocatable :: n(:) ! Wavenumber in y associated with each
30 ! nla spectral coefficient
31 real(8), allocatable :: Weight(:) ! Weight associated with each
32 ! nla spectral coefficient
33 integer, allocatable :: nePerK(:) ! Number of spectral element in each
34 ! total wavenumber bands
35 integer, allocatable :: nePerKglobal(:) ! Number of spectral element in each
36 ! total wavenumber bands over ALL PROCESSORS
37 integer, allocatable :: ilaFromEK(:,:) ! ila index associated to each spectral element
38 ! of total wavenumber band
39 real(8), allocatable :: NormFactor(:,:)
40 real(8), allocatable :: NormFactorAd(:,:)
41 integer :: nlaGlobal ! First dimension of VAR global spectral array
42 integer, allocatable :: ilaGlobal(:) ! Position of the local vector element in the global
43 ! vector
44 integer :: nphase ! Second dimension of VAR spectral array
45 integer :: ni
46 integer :: nj
47 integer :: nip
48 integer :: njp
49 integer :: mmax, nmax
50 integer :: ktrunc
51 integer :: nla ! First dimension of VAR spectral array
52 integer :: maxnla
53 integer :: mymBeg, mymEnd, mymSkip, mymCount, mymActiveCount,maxmActiveCount
54 integer :: mynBeg, mynEnd, mynSkip, mynCount
55 integer, allocatable :: nla_Index(:,:)
56 real(8), allocatable :: lapxy(:)
57 real(8), allocatable :: ilapxy(:)
58 integer, allocatable :: allmBeg(:), allmEnd(:), allmSkip(:)
59 integer, allocatable :: mymIndex(:)
60 integer, allocatable :: allnBeg(:), allnEnd(:), allnSkip(:)
61 integer, allocatable :: mynIndex(:)
62 logical :: allocated = .false.
63 integer :: latPerPE, latPerPEmax, myLatBeg, myLatEnd
64 integer :: lonPerPE, lonPerPEmax, myLonBeg, myLonEnd
65 integer :: myLevBeg, myLevEnd, myLevCount, maxLevCount
66 integer, allocatable :: allLatBeg(:), allLatEnd(:), allLatPerPE(:)
67 integer, allocatable :: allLonBeg(:), allLonEnd(:), allLonPerPE(:)
68 integer, allocatable :: allLevBeg(:), allLevEnd(:)
69 integer, allocatable :: KfromMNglb(:,:)
70 character(len=10) :: MpiMode
71 character(len=3) :: gridDataOrder ! Ordering the gridded data: 'ijk' or 'kij'
72 integer :: sendType_LevToLon, recvType_LevToLon
73 integer :: sendType_LonToLev, recvType_LonToLev
74 logical :: lonLatDivisible
75 end type struct_lst
76
77 ! TransformType = 'SinCos'
78 integer, parameter :: nip = 2 ! Padding
79 integer, parameter :: njp = 2 ! Padding
80 integer, parameter :: nphase = 4 ! For Sin&Cos we have a) sin(m)sin(n)
81 ! b) cos(m)cos(n)
82 ! c) sin(m)cos(n)
83 ! d) cos(m)sin(n)
84
85 logical, parameter :: verbose = .false.
86
87contains
88
89 !--------------------------------------------------------------------------
90 ! lst_setup
91 !--------------------------------------------------------------------------
92 subroutine lst_Setup(lst, ni_in, nj_in, dlon_in, ktrunc_in, &
93 MpiMode, maxlevels_opt, gridDataOrder_opt)
94 implicit none
95
96 ! Arguments:
97 type(struct_lst), intent(out) :: lst ! Parameters available to the outside world
98 integer, intent(in) :: ni_in ! Global Grid point data horizontal dimensions
99 integer, intent(in) :: nj_in ! Global Grid point data horizontal dimensions
100 character(len=*), intent(in) :: MpiMode ! MPI Strategy
101 real(8), intent(in) :: dlon_in ! Grid Spacing in Radians
102 integer, intent(in) :: ktrunc_in ! Spectral Truncation (global)
103 integer, optional, intent(in) :: maxlevels_opt ! Number of levels; Only needed when MpiMode = LatLev
104 character(len=*), optional, intent(in) :: gridDataOrder_opt ! 'ijk' or 'kij'
105
106 ! Locals:
107 real(8), allocatable :: Kr8fromMN(:,:)
108 integer, allocatable :: KfromMN(:,:)
109 integer, allocatable :: my_KfromMNglb(:,:)
110 integer :: kref, mref, nref
111 integer :: m, n, k, kMax, ila, nfact_lon, nfact_lat
112 integer :: ier, ilaglb, i, j, p
113 real(8) :: dlon, dx2, fac, ca, cp, cb, cq, r
114 real(8) :: NormFactor1, NormFactor2, NormFactor3
115 real(8) :: NormFactorAd1, NormFactorAd2, NormFactorAd3
116 real(8) :: factor, factorAd
117 character(len=60) :: kreftype
118 logical :: divisibleLon, divisibleLat
119 integer(kind=MPI_ADDRESS_KIND) :: lowerBound, extent
120 integer :: realSize, sendType, recvType, ierr
121
122 !
123 !- 1. Set variables needed by the LAM Spectral Transform in VAR
124 !
125 if (verbose) write(*,*) 'Entering lst_Setup'
126
127 if (lst%allocated) then
128 call utl_abort('lst_setup: this structure is already allocated')
129 end if
130
131 kreftype = 'MAX' ! hardwired
132
133 lst%ni = ni_in
134 lst%nj = nj_in
135 lst%nphase = nphase
136 lst%nip = nip
137 lst%njp = njp
138
139 ! 1.1 Check grid dimensions and set padding for the RPN DFT routines
140
141 ! We need to padd the input array such as ...
142 ! O O O O O O O O O
143 ! O O O O O O O O O
144 ! X X X X X X X O O
145 ! X X X X X X X O O
146 ! X X X X X X X O O
147 ! X X X X X X X O O
148
149 if (mod(lst%ni,2) /= 0 .or. mod(lst%nj,2) /= 0) then
150 write(*,*) ' The regular Sin & Cos Transform requires that', &
151 ' dimensions be EVEN. Fields MUST be periodic' , &
152 ' but the last colum and row MUST NOT BE a ' , &
153 ' repetition of the first colum and row. '
154 call utl_abort('lst_setup')
155 end if
156
157 nfact_lon = lst%ni
158 call ngfft(nfact_lon) ! INOUT
159 nfact_lat = lst%nj
160 call ngfft(nfact_lat) ! INOUT
161
162 if (nfact_lon /= lst%ni .or. nfact_lat /= lst%nj) then
163 if (nfact_lon /= lst%ni) then
164 write(*,*) 'Error: A fast transform cannot be used in X'
165 write(6,6130) lst%ni, nfact_lon
166 end if
167 if (nfact_lat /= lst%nj) then
168 write(*,*) 'Error: A fast transform cannot be used in Y'
169 write(6,6140) lst%nj, nfact_lat
170 end if
171 call utl_abort('lst_setup')
172 end if
173
1746130 FORMAT('N = ni = ', I4,' the nearest factorizable N = ',I4)
1756140 FORMAT('N = nj = ', I4,' the nearest factorizable N = ',I4)
176
177 !- 1.2 Maximum of integer wavenumbers in x and y directions
178 lst%mmax = lst%ni/2
179 lst%nmax = lst%nj/2
180
181 write(*,'(A,f8.1)') ' lst_Setup: Your grid spacing (in km) = ', ec_ra*dlon_in/1000.0
182 write(*,*) ' Max wavenumbers in x-axis = ', lst%mmax
183 write(*,*) ' Max wavenumbers in y-axis = ', lst%nmax
184
185 !- 1.3 MPI Strategy
186
187 lst%MpiMode = MpiMode
188 select case (trim(lst%MpiMode))
189 case ('NoMpi')
190 !- 1.3.1 No MPI
191
192 ! range of LONS handled by this processor (ALL) in GRIDPOINT SPACE
193 lst%lonPerPE = lst%ni
194 lst%myLonBeg = 1
195 lst%myLonEnd = lst%ni
196
197 ! range of LATS handled by this processor (ALL) in GRIDPOINT SPACE
198 lst%latPerPE = lst%nj
199 lst%myLatBeg = 1
200 lst%myLatEnd = lst%nj
201
202 ! range of M handled by this processor (ALL) in SPECTRAL SPACE
203 lst%mymBeg = 0
204 lst%mymEnd = lst%mmax
205 lst%mymSkip = 1
206 lst%mymCount = lst%mmax + 1
207
208 ! range of N handled by this processor (ALL) in SPECTRAL SPACE
209 lst%mynBeg = 0
210 lst%mynEnd = lst%nmax
211 lst%mynSkip = 1
212 lst%mynCount = lst%nmax + 1
213
214 ! set a dummy range of LEVELS handled by this processor
215 lst%myLevBeg = -1
216 lst%myLevEnd = -1
217 lst%myLevCount = 0
218
219 case ('LatLonMN')
220 !- 1.3.2 MPI 2D: Distribution of lon/lat tiles (gridpoint space) and n/m (spectral space)
221
222 ! range of LONS handled by this processor in GRIDPOINT SPACE
223 call mmpi_setup_lonbands(lst%ni, & ! IN
224 lst%lonPerPE, lst%lonPerPEmax, & ! OUT
225 lst%myLonBeg, lst%myLonEnd, & ! OUT
226 divisible_opt=divisibleLon) ! OUT
227
228 ! range of LATS handled by this processor in GRIDPOINT SPACE
229 call mmpi_setup_latbands(lst%nj, & ! IN
230 lst%latPerPE, lst%latPerPEmax, & ! OUT
231 lst%myLatBeg, lst%myLatEnd, & ! OUT
232 divisible_opt=divisibleLat) ! OUT
233
234 lst%lonLatDivisible = (divisibleLon .and. divisibleLat)
235 if(mmpi_myid == 0) write(*,*) 'lst_setup: lonLatDivisible = ', lst%lonLatDivisible
236
237 ! range of M handled by this processor in SPECTRAL SPACE
238 call mmpi_setup_m(lst%mmax, & ! IN
239 lst%mymBeg, lst%mymEnd, lst%mymSkip, lst%mymCount) ! OUT
240
241 ! range of N handled by this processor in SPECTRAL SPACE
242 call mmpi_setup_n(lst%nmax, & ! IN
243 lst%mynBeg, lst%mynEnd, lst%mynSkip, lst%mynCount) ! OUT
244
245 ! range of LEVELS TEMPORARILY handled by this processor DURING THE SPECTRAL TRANSFORM
246 if (.not.present(maxlevels_opt)) then
247 call utl_abort('lst_setup: ERROR, number of levels must be specified with MpiMode LatLonMN')
248 end if
249 ! 2D MPI decomposition: split levels across npex
250 call mmpi_setup_levels(maxlevels_opt, & ! IN
251 lst%myLevBeg,lst%myLevEnd,lst%myLevCount) ! OUT
252
253 case default
254 write(*,*)
255 write(*,*) 'Error: MpiMode Unknown ', trim(MpiMode)
256 call utl_abort('lst_setup')
257 end select
258
259 write(*,*)
260 write(*,*) ' I am processor ', mmpi_myid+1, ' on a total of ', mmpi_nprocs
261 write(*,*) ' mband info = ', lst%mymBeg, lst%mymEnd, lst%mymSkip, lst%mymCount
262 write(*,*) ' nband info = ', lst%mynBeg, lst%mynEnd, lst%mynSkip, lst%mynCount
263 write(*,*) ' level info = ', lst%myLevBeg, lst%myLevEnd, lst%myLevCount
264
265 ! Set M index
266 allocate(lst%mymIndex(lst%mymBeg:lst%mymEnd))
267 lst%mymIndex(:)=0
268 do m = lst%mymBeg, lst%mymEnd, lst%mymSkip
269 if (m == lst%mymBeg) then
270 lst%mymIndex(m) = 1
271 else
272 lst%mymIndex(m) = lst%mymIndex(m-lst%mymSkip) + 1
273 end if
274 end do
275
276 ! Set N index
277 allocate(lst%mynIndex(lst%mynBeg:lst%mynEnd))
278 lst%mynIndex(:)=0
279 do n = lst%mynBeg, lst%mynEnd, lst%mynSkip
280 if (n == lst%mynBeg) then
281 lst%mynIndex(n) = 1
282 else
283 lst%mynIndex(n) = lst%mynIndex(n-lst%mynSkip) + 1
284 end if
285 end do
286
287 if (trim(lst%MpiMode) /= 'NoMpi') then
288
289 ! Gathering with respect to Longitude
290 allocate(lst%allLonBeg(mmpi_npex))
291 call rpn_comm_allgather(lst%myLonBeg ,1,"mpi_integer", &
292 lst%allLonBeg,1,"mpi_integer","EW",ier)
293 if (mmpi_myid == 0) write(*,*) 'AllLonBeg =', lst%allLonBeg(:)
294
295 allocate(lst%allLonEnd(mmpi_npex))
296 call rpn_comm_allgather(lst%myLonEnd ,1,"mpi_integer", &
297 lst%allLonEnd,1,"mpi_integer","EW",ier)
298 if (mmpi_myid == 0) write(*,*) 'AllLonEnd =', lst%allLonEnd(:)
299
300 allocate(lst%allLonPerPE(mmpi_npex))
301 call rpn_comm_allgather(lst%lonPerPE ,1,"mpi_integer", &
302 lst%allLonPerPE,1,"mpi_integer","EW",ier)
303 if (mmpi_myid == 0) write(*,*) 'AllLonPerPE =', lst%allLonPerPE(:)
304
305 ! Gathering with respect to Latitude
306 allocate(lst%allLatBeg(mmpi_npey))
307 call rpn_comm_allgather(lst%myLatBeg ,1,"mpi_integer", &
308 lst%allLatBeg,1,"mpi_integer","NS",ier)
309 if (mmpi_myid == 0) write(*,*) 'AllLatBeg =', lst%allLatBeg(:)
310
311 allocate(lst%allLatEnd(mmpi_npey))
312 call rpn_comm_allgather(lst%myLatEnd ,1,"mpi_integer", &
313 lst%allLatEnd,1,"mpi_integer","NS",ier)
314 if (mmpi_myid == 0) write(*,*) 'AllLatEnd =', lst%allLatEnd(:)
315
316 allocate(lst%allLatPerPE(mmpi_npey))
317 call rpn_comm_allgather(lst%latPerPE ,1,"mpi_integer", &
318 lst%allLatPerPE,1,"mpi_integer","NS",ier)
319 if (mmpi_myid == 0) write(*,*) 'AllLatPerPE =', lst%allLatPerPE(:)
320
321 ! Gathering with respect to M
322 allocate(lst%allmBeg(mmpi_npey))
323 call rpn_comm_allgather(lst%mymBeg ,1,"mpi_integer", &
324 lst%allmBeg,1,"mpi_integer","NS",ier)
325 if (mmpi_myid == 0) write(*,*) 'AllmBeg =', lst%allmBeg(:)
326
327 allocate(lst%allmEnd(mmpi_npey))
328 call rpn_comm_allgather(lst%mymEnd ,1,"mpi_integer", &
329 lst%allmEnd,1,"mpi_integer","NS",ier)
330 if (mmpi_myid == 0) write(*,*) 'allmEnd =', lst%allmEnd(:)
331
332 allocate(lst%allmSkip(mmpi_npey))
333 call rpn_comm_allgather(lst%mymSkip ,1,"mpi_integer", &
334 lst%allmSkip,1,"mpi_integer","NS",ier)
335 if (mmpi_myid == 0) write(*,*) 'allmSkip = ', lst%allmSkip(:)
336
337 allocate(lst%allnBeg(mmpi_npex))
338 call rpn_comm_allgather(lst%mynBeg ,1,"mpi_integer", &
339 lst%allnBeg,1,"mpi_integer","EW",ier)
340 if (mmpi_myid == 0) write(*,*) 'AllnBeg =', lst%allnBeg(:)
341
342 allocate(lst%allnEnd(mmpi_npex))
343 call rpn_comm_allgather(lst%mynEnd ,1,"mpi_integer", &
344 lst%allnEnd,1,"mpi_integer","EW",ier)
345 if (mmpi_myid == 0) write(*,*) 'AllnEnd =', lst%allnEnd(:)
346
347 allocate(lst%allnSkip(mmpi_npex))
348 call rpn_comm_allgather(lst%mynSkip ,1,"mpi_integer", &
349 lst%allnSkip,1,"mpi_integer","EW",ier)
350 if (mmpi_myid == 0) write(*,*) 'AllnSkip = ', lst%allnSkip(:)
351
352 ! Gathering with respect to levels
353 call rpn_comm_allreduce(lst%myLevCount,lst%maxLevCount, &
354 1,"MPI_INTEGER","MPI_MAX","GRID",ier)
355 if (mmpi_myid == 0) write(*,*) 'MaxLevCount =',lst%maxLevCount
356
357 allocate(lst%allLevBeg(mmpi_npex))
358 call rpn_comm_allgather(lst%myLevBeg ,1,"mpi_integer", &
359 lst%allLevBeg,1,"mpi_integer","EW",ier)
360 if (mmpi_myid == 0) write(*,*) 'AllLevBeg =', lst%allLevBeg(:)
361
362 allocate(lst%allLevEnd(mmpi_npex))
363 call rpn_comm_allgather(lst%myLevEnd ,1,"mpi_integer", &
364 lst%allLevEnd,1,"mpi_integer","EW",ier)
365 if (mmpi_myid == 0) write(*,*) 'AllLevEnd =', lst%allLevEnd(:)
366
367 ! Setup mpi derived types used in transposes (only used when grid is divisible)
368 ! ... mpi_type_vector(count, blocklength, stride, ...)
369 ! ... mpi_type_create_resized(oldtype, lowerbound, extent(in bytes), newtype, ierr)
370
371 call mpi_type_size(MPI_REAL8, realSize, ierr)
372 lowerBound = 0
373
374 ! create the send type for LevToLon
375 extent = lst%maxLevCount * lst%lonPerPE * realSize
376 call mpi_type_vector(lst%latPerPE, lst%maxLevCount * lst%lonPerPE, &
377 lst%maxLevCount * lst%ni, MPI_REAL8, sendtype, ierr)
378 call mpi_type_create_resized(sendtype, lowerBound , extent, lst%sendType_LevToLon, ierr);
379 call mpi_type_commit(lst%sendType_LevToLon,ierr)
380
381 ! create the receive type for LevToLon
382 extent = lst%maxLevCount * realSize
383 call mpi_type_vector(lst%lonPerPE * lst%latPerPE , lst%maxLevCount, &
384 maxlevels_opt, MPI_REAL8, recvtype, ierr);
385 call mpi_type_create_resized(recvtype, lowerBound, extent, lst%recvType_LevToLon, ierr);
386 call mpi_type_commit(lst%recvType_LevToLon, ierr)
387
388 ! create the send type for LonToLev
389 extent = lst%maxLevCount * realSize
390 call mpi_type_vector(lst%lonPerPE * lst%latPerPE , lst%maxLevCount, &
391 maxlevels_opt, MPI_REAL8, sendtype, ierr);
392 call mpi_type_create_resized(sendtype, lowerBound, extent, lst%sendType_LonToLev, ierr);
393 call mpi_type_commit(lst%sendType_LonToLev, ierr)
394
395 ! create the recv type for LonToLev
396 extent = lst%maxLevCount * lst%lonPerPE * realSize
397 call mpi_type_vector(lst%latPerPE, lst%maxLevCount * lst%lonPerPE, &
398 lst%maxLevCount * lst%ni, MPI_REAL8, recvtype, ierr)
399 call mpi_type_create_resized(recvtype, lowerBound , extent, lst%recvType_LonToLev, ierr);
400 call mpi_type_commit(lst%recvType_LonToLev,ierr)
401
402 end if
403
404 !- 1.4 Compute the Total Wavenumber associated with weach m,n pairs and
405 ! the number of spectral element in the VAR array (nla)
406 ! FOR THE LOCAL PROCESSOR
407 allocate(Kr8fromMN(0:lst%mmax,0:lst%nmax))
408 Kr8FromMN(:,:) = -1.d0
409
410 allocate(KfromMN(0:lst%mmax,0:lst%nmax))
411 KFromMN(:,:) = -1
412
413 ! Denis et al., MWR, 2002
414 !mref = lst%mmax
415 !nref = lst%nmax
416
417 ! old var code (L. Fillion)
418 mref = lst%ni-1
419 nref = lst%nj-1
420
421 select case(trim(kreftype))
422 case ('MAX','max')
423 ! old var code (L. Fillion)
424 write(*,*)
425 write(*,*) 'lst_Setup: Using legacy (old var code) total wavenumber normalization'
426 kref = max(mref,nref)
427 case ('MIN','min')
428 ! Denis et al., MWR, 2002
429 write(*,*)
430 write(*,*) 'lst_Setup: Using Denis et al. total wavenumber normalization'
431 kref = min(mref,nref)
432 case default
433 write(*,*)
434 write(*,*) 'Unknown KREFTYPE in lst_setup : ', trim(kreftype)
435 call utl_abort('lst_setup')
436 end select
437
438 kMax = nint(lst_totalWaveNumber(lst%mmax,lst%nmax,mref,nref,kref))
439
440 if (ktrunc_in == -1) then ! no truncation case
441 lst%ktrunc = kMax
442 else
443 if (ktrunc_in > 0) then
444 lst%ktrunc = ktrunc_in
445 else
446 call utl_abort('lst_setup: invalid truncation')
447 end if
448 end if
449
450 if (lst%ktrunc >= kMax) then
451 write(*,*)
452 write(*,*) 'lst_Setup: Warning: Truncation is larger than kMax'
453 write(*,*) ' NO TRUNCATION will be applied'
454 else if (lst%ktrunc > min(lst%mmax,lst%nmax)) then
455 write(*,*)
456 if (lst%ktrunc > lst%mmax) then
457 write(*,*) 'lst_Setup: Warning: Truncation is larger than mmax only'
458 write(*,*) ' TRUNCATION will be applied only above nmax'
459 write(*,'(A,f8.1)') ' i.e., for wavelenght (in km) in y-axis smaller than ',&
460 (lst%nj*ec_ra*dlon_in/1000.0)/lst%ktrunc
461 else
462 write(*,*) 'lst_Setup: Warning: Truncation is larger than nmax only'
463 write(*,*) ' TRUNCATION will be applied only above mmax'
464 write(*,'(A,f8.1)') ' i.e., for wavelenght (in km) in x-axis smaller than ',&
465 (lst%ni*ec_ra*dlon_in/1000.0)/lst%ktrunc
466 end if
467 else
468 write(*,*)
469 write(*,*) 'lst_Setup: TRUNCATION will be applied above k = ',lst%ktrunc
470 write(*,'(A,f8.1)') ' i.e., for wavelenght (in km) in x-axis smaller than ',&
471 (lst%ni*ec_ra*dlon_in/1000.0)/lst%ktrunc
472 write(*,'(A,f8.1)') ' i.e., for wavelenght (in km) in y-axis smaller than ',&
473 (lst%nj*ec_ra*dlon_in/1000.0)/lst%ktrunc
474 end if
475
476 ila = 0
477 do n = lst%mynBeg, lst%mynEnd, lst%mynSkip
478 do m = lst%mymBeg, lst%mymEnd, lst%mymSkip
479 r = lst_totalWaveNumber(m,n,mref,nref,kref)
480 k = nint(r) ! or ceiling(r) as in Denis et al. ?
481 if (k <= lst%ktrunc) then
482 ila = ila +1
483 KFromMN(m,n) = k
484 Kr8FromMN(m,n) = r
485 end if
486 end do
487 end do
488
489 if (ila == 0) then
490 write(*,*)
491 write(*,*) 'There are no spectral elements associated to this mpi task!'
492 end if
493
494 lst%nla = ila ! Number of spectral element per phase in the VAR array
495 if (trim(lst%MpiMode) /= 'NoMpi') then
496 call rpn_comm_allreduce(lst%nla,lst%maxnla, &
497 1,"MPI_INTEGER","MPI_MAX","GRID",ier)
498 if (mmpi_myid == 0) write(*,*) 'MaxNLA =',lst%maxnla
499 end if
500
501 allocate(lst%KfromMNglb(0:lst%mmax,0:lst%nmax))
502 allocate(my_KfromMNglb(0:lst%mmax,0:lst%nmax))
503 my_KfromMNglb = 0
504 my_KFromMNglb(:,:) = KFromMN(:,:)
505 if (trim(lst%MpiMode) /= 'NoMpi') then
506 call rpn_comm_allreduce(my_KFromMNglb,lst%KFromMNglb, &
507 (lst%mmax+1)*(lst%nmax+1),"MPI_INTEGER","MPI_MAX","GRID",ier)
508 end if
509 deallocate(my_KfromMNglb)
510
511 lst%mymActiveCount=0
512 do m = lst%mymBeg, lst%mymEnd, lst%mymSkip
513 if (KfromMN(m,0) /= -1) lst%mymActiveCount = lst%mymActiveCount + 1
514 end do
515 if (trim(lst%MpiMode) /= 'NoMpi') then
516 call rpn_comm_allreduce(lst%mymActiveCount,lst%maxmActiveCount, &
517 1,"MPI_INTEGER","MPI_MAX","GRID",ier)
518 if (mmpi_myid == 0) write(*,*) 'MaxmActiveCount =',lst%maxmActiveCount
519 end if
520
521 !- 1.5 VAR spectral element ordering &
522 ! Total Wavenumbers and Weights associated with each spectral element
523 ! FOR THE LOCAL PROCESSOR
524 allocate(lst%nla_Index(0:lst%mmax,0:lst%nmax))
525
526 allocate(lst%k_r8(1:lst%nla))
527 allocate(lst%k(1:lst%nla))
528 allocate(lst%m(1:lst%nla))
529 allocate(lst%n(1:lst%nla))
530 allocate(lst%Weight(1:lst%nla))
531 allocate(lst%nePerK(0:lst%ktrunc))
532 allocate(lst%nePerKglobal(0:lst%ktrunc))
533 allocate(lst%ilaFromEK(1:lst%nla,0:lst%ktrunc))
534 allocate(lst%ilaGlobal(1:lst%nla))
535
536 lst%nla_Index(:,:) = -1
537 lst%ilaFromEK(:,:) = -1
538 lst%NEPerK(:) = 0
539 lst%NEPerKglobal(:)= 0
540
541 ila = 0
542 ilaglb = 0
543 do n = 0, lst%nmax
544 do m = 0, lst%mmax
545 k = KfromMN(m,n)
546
547 if (lst%KfromMNglb(m,n) /= -1) ilaglb = ilaglb + 1 ! Global Index
548
549 if (k /= -1) then
550 ila = ila+1
551
552 ! Internal index
553 lst%nla_Index(m,n) = ila
554
555 ! Outgoing (public) variables
556 lst%nePerK(k) = lst%nePerK(k) + 1
557 lst%ilaFromEK(lst%nePerK(k),k) = ila
558 lst%k_r8(ila) = Kr8fromMN(m,n)
559 lst%k(ila) = k
560 lst%m(ila) = m
561 lst%n(ila) = n
562 lst%ilaGlobal(ila) = ilaglb
563
564 ! Spectral coefficient weight associated with this index
565 if (m == 0 .and. n == 0) then
566 lst%Weight(ila) = 1.0d0
567 else if (m /= 0 .and. n /= 0) then
568 lst%Weight(ila) = 4.0d0
569 else
570 lst%Weight(ila) = 2.0d0
571 end if
572
573 end if
574
575 end do
576 end do
577
578 lst%nlaGlobal = ilaglb ! Number of spectral element per phase in the VAR mpi global array
579
580 if (trim(lst%MpiMode) /= 'NoMpi') then
581 call rpn_comm_allreduce(lst%nePerK, lst%nePerKglobal, lst%ktrunc+1, &
582 "mpi_integer", "mpi_sum", "GRID", ierr)
583 end if
584
585 deallocate(Kr8fromMN)
586 deallocate(KfromMN)
587
588 !- 1.7 Gridded data ordering (input/output)
589 if (present(gridDataOrder_opt)) then
590 lst%gridDataOrder = trim(gridDataOrder_opt)
591 else
592 lst%gridDataOrder = 'ijk' ! default value
593 end if
594
595 select case (trim(lst%gridDataOrder))
596 case ('ijk')
597 write(*,*) 'lst_setup: gridded data ordering = IJK'
598 case ('kij')
599 write(*,*) 'lst_setup: gridded data ordering = KIJ'
600 case default
601 write(*,*)
602 write(*,*) 'Error: gridDataOrder Unknown ', trim(gridDataOrder_opt)
603 call utl_abort('lst_setup')
604 end select
605
606 !
607 !- 2. Set factors for parseval identity
608 !
609 allocate(lst%NormFactor (lst%nla,lst%nphase))
610 allocate(lst%NormFactorAd(lst%nla,lst%nphase))
611
612 Normfactor1 = 1.0d0
613 Normfactor2 = 0.5d0 * sqrt(2.0d0)
614 Normfactor3 = 0.5d0
615 NormfactorAd1 = 1.0d0 * real((lst%ni * lst%nj),8)
616 NormfactorAd2 = sqrt(2.0d0) * real((lst%ni * lst%nj),8)
617 NormfactorAd3 = 2.0d0 * real((lst%ni * lst%nj),8)
618
619 do ila = 1,lst%nla
620
621 m = lst%m(ila)
622 n = lst%n(ila)
623
624 do p = 1, lst%nphase
625 if (p == 1) then
626 i = 2*m+1
627 j = 2*n+1
628 else if (p == 2) then
629 i = 2*m+1
630 j = 2*n+2
631 else if (p == 3) then
632 i = 2*m+2
633 j = 2*n+1
634 else if (p == 4) then
635 i = 2*m+2
636 j = 2*n+2
637 else
638 call utl_abort('lst_Setup: Error in NormFactor')
639 end if
640
641 if (i == 1 .or. j == 1) then
642 if (i == 1 .and. j == 1) then
643 factor = Normfactor1
644 factorAd = NormfactorAd1
645 else
646 factor = Normfactor2
647 factorAd = NormfactorAd2
648 end if
649 else
650 factor = Normfactor3
651 factorAd = NormfactorAd3
652 end if
653
654 lst%NormFactor (ila,p) = factor
655 lst%NormFactorAd(ila,p) = factorAd
656 end do
657
658 end do
659
660 !
661 !- 3. Set variables needed by Forward and Inverse Laplacian
662 !
663 allocate(lst%lapxy (lst%nla))
664 allocate(lst%ilapxy(lst%nla))
665
666 dlon = dlon_in
667 dx2 = (ec_ra*dlon)**2
668 fac = 2.d0/dx2
669
670 do ila = 1,lst%nla
671 ca = 2.d0*MPC_PI_R8 * lst%m(ila)
672 cp = cos(ca/lst%ni)
673 cb = 2.d0*MPC_PI_R8 * lst%n(ila)
674 cq = cos(cb/lst%nj)
675
676 lst%lapxy(ila) = fac * (cp + cq - 2.d0)
677 if (lst%lapxy(ila) /= 0.d0) then
678 lst%ilapxy(ila) = 1.d0 / lst%lapxy(ila)
679 else
680 lst%ilapxy(ila) = 0.d0
681 end if
682 end do
683
684 !
685 !- 4. Finalized
686 !
687 lst%allocated = .true.
688
689 end subroutine lst_Setup
690
691 !--------------------------------------------------------------------------
692 ! lst_totalWaveNumber
693 !--------------------------------------------------------------------------
694 function lst_totalWaveNumber(m,n,mref,nref,kref) result(r)
695 implicit none
696
697 ! Arguments:
698 integer, intent(in) :: m
699 integer, intent(in) :: n
700 integer, intent(in) :: mref
701 integer, intent(in) :: nref
702 integer, intent(in) :: kref
703 ! Result:
704 real(8) :: r
705
706 ! Locals:
707 real(8) :: a, b
708
709 a = real(m,8)/real(mref,8)
710 b = real(n,8)/real(nref,8)
711 r = real(kref,8) * sqrt((a**2) + (b**2)) ! Ellipse Shape if nref /= mref
712
713 end function lst_totalWaveNumber
714
715 !--------------------------------------------------------------------------
716 ! lst_VARTRANSFORM
717 !--------------------------------------------------------------------------
718 subroutine lst_VarTransform(lst, SpectralStateVar, GridState, &
719 TransformDirection, nk)
720 implicit none
721
722 ! Arguments:
723 type(struct_lst), intent(in) :: lst
724 integer, intent(in) :: nk ! Grid point data dimensions
725 character(len=*), intent(in) :: TransformDirection ! SpectralToGridPoint or GridPointToSpectral
726 real(8), intent(inout) :: GridState(:,:,:) ! 3D field in grid point space
727 real(8), intent(inout) :: SpectralStateVar(:,:,:) ! 3D spectral coefficients
728
729 !
730 !- 0. Some tests...
731 !
732 if (verbose) write(*,*) 'Entering lst_varTransform'
733
734 !
735 !- 1. Call the appropriate transform
736 !
737 if (trim(lst%gridDataOrder) == 'ijk') then
738 call lst_VarTransform_ijk(lst, SpectralStateVar, GridState, &
739 TransformDirection, nk)
740 else
741 call lst_VarTransform_kij(lst, SpectralStateVar, GridState, &
742 TransformDirection, nk)
743 end if
744
745 end subroutine lst_VarTransform
746
747 !--------------------------------------------------------------------------
748 ! lst_VARTRANSFORM_IJK
749 !--------------------------------------------------------------------------
750 subroutine lst_VarTransform_ijk(lst, SpectralStateVar, GridState, &
751 TransformDirection, nk)
752 implicit none
753
754 ! Arguments:
755 type(struct_lst), intent(in) :: lst
756 integer, intent(in) :: nk ! Grid point data dimensions
757 character(len=*), intent(in) :: TransformDirection ! SpectralToGridPoint or GridPointToSpectral
758 real(8), intent(inout) :: GridState(lst%myLonBeg:lst%myLonEnd,lst%myLatBeg:lst%myLatEnd,nk) ! 3D field in grid point space
759 real(8), intent(inout) :: SpectralStateVar(:,:,:) ! 3D spectral coefficients
760
761 ! Locals:
762 integer :: ni_l, nj_l, nip_l, njp_l
763 integer :: iStart, iEnd, jStart, jEnd, kStart, kEnd
764 real(8), allocatable :: Step0(:,:,:)
765 real(8), allocatable :: Step1(:,:,:)
766 real(8), allocatable :: Step2(:,:,:)
767 real(8), allocatable :: Step3(:,:,:)
768 character(len=1) :: TransformAxe
769
770 !
771 !- 1. Data pre-processing (Input -> Step0)
772 !
773 if (verbose) write(*,*) 'Entering lst_varTransform_ijk'
774
775 !- 1.1 Settings and Data Selection
776
777 if (trim(TransformDirection) == 'GridPointToSpectral') then
778 iStart = 1
779 iEnd = lst%ni
780 jStart = lst%myLatBeg
781 jEnd = lst%myLatEnd
782 if (trim(lst%MpiMode) == 'NoMpi') then
783 kStart= 1
784 kEnd = nk
785 else
786 kStart= lst%myLevBeg
787 kEnd = lst%myLevEnd
788 end if
789 allocate(Step0(iStart:iEnd,jStart:jEnd,kStart:kEnd))
790 if (trim(lst%MpiMode) == 'NoMpi') then
791 Step0(:,:,:) = GridState(:,:,:)
792 else
793 call transpose2d_LonToLev(Step0, & ! OUT
794 GridState, nk, lst) ! IN
795 end if
796 end if
797
798 !
799 !- 1. First pass (Step0 -> Step1)
800 !
801
802 !- 1.1 Settings and Data Selection
803 select case (trim(TransformDirection))
804 case ('GridPointToSpectral')
805 TransformAxe = 'i'
806 ni_l = lst%ni
807 nip_l = lst%nip
808 nj_l = lst%latPerPE
809 njp_l = 0
810 if (trim(lst%MpiMode) == 'NoMpi') then
811 kStart= 1
812 kEnd = nk
813 else
814 kStart= lst%myLevBeg
815 kEnd = lst%myLevEnd
816 end if
817 case ('SpectralToGridPoint')
818 TransformAxe = 'j'
819 ni_l = 2*lst%mymCount
820 nip_l = 0
821 nj_l = lst%nj
822 njp_l = lst%njp
823 if (trim(lst%MpiMode) == 'NoMpi') then
824 kStart= 1
825 kEnd = nk
826 else
827 kStart= lst%myLevBeg
828 kEnd = lst%myLevEnd
829 end if
830 case default
831 write(*,*)
832 write(*,*) 'Error: TranformDirection Unknown ', trim(TransformDirection)
833 call utl_abort('lst_VarTransform')
834 end select
835
836 allocate(Step1(ni_l+nip_l,nj_l+njp_l,kStart:kEnd))
837
838 !- 1.2 Spectral transform
839 if (trim(TransformDirection) == 'SpectralToGridPoint') then
840 if (trim(lst%MpiMode) == 'NoMpi') then
841 call lst_ReshapeTrunc(Step1, & ! OUT
842 SpectralStateVar, & ! IN
843 'ToRPN', kStart, kEnd, lst) ! IN
844 else
845 call transpose2d_NToLev(Step1, & ! OUT
846 SpectralStateVar, nk, lst) ! IN
847 end if
848 else
849 Step1(1:lst%ni,1:lst%latPerPE,:) = Step0(1:lst%ni,lst%myLatBeg:lst%myLatEnd,:)
850 deallocate(Step0)
851 end if
852
853 call lst_transform1d(Step1, & ! INOUT
854 TransformDirection, & ! IN
855 TransformAxe, & ! IN
856 ni_l, nj_l, nip_l, njp_l, & ! IN
857 kStart, kEnd) ! IN
858
859 !
860 !- 2.0 Second pass (Step1 -> Step2)
861 !
862
863 !- 2.1 Settings
864 if (trim(TransformDirection) == 'GridPointToSpectral') then
865 TransformAxe = 'j'
866 ni_l = 2*lst%mymCount
867 nip_l = 0
868 nj_l = lst%nj
869 njp_l = lst%njp
870 if (trim(lst%MpiMode) == 'NoMpi') then
871 kStart= 1
872 kEnd = nk
873 else
874 kStart= lst%myLevBeg
875 kEnd = lst%myLevEnd
876 end if
877 else
878 TransformAxe = 'i'
879 ni_l = lst%ni
880 nip_l = lst%nip
881 nj_l = lst%latPerPE
882 njp_l = 0
883 if (trim(lst%MpiMode) == 'NoMpi') then
884 kStart= 1
885 kEnd = nk
886 else
887 kStart= lst%myLevBeg
888 kEnd = lst%myLevEnd
889 end if
890 end if
891
892 allocate(Step2(ni_l+nip_l,nj_l+njp_l,kStart:kEnd))
893
894 !- 2.2 Communication between processors
895
896 if (trim(TransformDirection) == 'GridPointToSpectral') then
897 if (trim(lst%MpiMode) == 'NoMpi') then
898 Step2(:,1:lst%nj,:) = Step1(:,1:lst%nj,:)
899 else
900 call transpose2d_LatToM(Step2, & ! OUT
901 Step1, lst) ! IN
902 end if
903 else
904 if (trim(lst%MpiMode) == 'NoMpi') then
905 Step2(:,1:lst%nj,:) = Step1(:,1:lst%nj,:)
906 else
907 call transpose2d_MToLat(Step2, & ! OUT
908 Step1, lst) ! IN
909 end if
910 end if
911
912 deallocate(Step1)
913
914 !- 2.3 Spectral Transform
915 call lst_transform1d(Step2, & ! INOUT
916 TransformDirection, & ! IN
917 TransformAxe, & ! IN
918 ni_l, nj_l, nip_l, njp_l, & ! IN
919 kStart, kEnd) ! IN
920
921 !
922 !- 3.0 Post-processing (Step2 -> Step3 -> Output)
923 !
924
925 select case (trim(TransformDirection))
926 case ('GridPointToSpectral')
927 iStart = 1
928 iEnd = 2*lst%mymCount
929 jStart = 1
930 jEnd = 2*lst%mynCount
931 kStart= 1
932 kEnd = nk
933 case ('SpectralToGridPoint')
934 iStart = 1
935 iEnd = lst%lonPerPE
936 jStart = 1
937 jEnd = lst%latPerPE
938 kStart = 1
939 kEnd = nk
940 case default
941 write(*,*)
942 write(*,*) 'Error: TranformDirection Unknown ', trim(TransformDirection)
943 call utl_abort('lst_VarTransform')
944 end select
945
946 if (trim(TransformDirection) == 'GridPointToSpectral') then
947
948 ! Communication between processors (Truncation (if applicable) will occur in this step)
949 if (trim(lst%MpiMode) == 'NoMpi') then
950 call lst_ReshapeTrunc(Step2, & ! IN
951 SpectralStateVar, & ! OUT
952 'ToVAR', kStart, kEnd, lst) ! IN
953 else
954 call transpose2d_LevToN(SpectralStateVar, & ! OUT
955 Step2, nk, lst) ! IN
956 end if
957
958 else
959
960 allocate(Step3(iStart:iEnd,jStart:jEnd,kStart:kEnd))
961
962 ! Communication between processors
963 if (trim(lst%MpiMode) == 'NoMpi') then
964 Step3(:,:,:) = Step2(1:lst%ni,:,:)
965 else
966 call transpose2d_LevToLon(Step3, & ! OUT
967 Step2(1:lst%ni,:,:), nk, lst) ! IN
968 end if
969
970 GridState(lst%myLonBeg:lst%myLonEnd,lst%myLatBeg:lst%myLatEnd,:) = Step3(1:lst%lonPerPE,1:lst%latPerPE,:)
971
972 deallocate(Step3)
973
974 end if
975
976 deallocate(Step2)
977
978 end subroutine lst_VarTransform_ijk
979
980 !--------------------------------------------------------------------------
981 ! lst_VARTRANSFORM_KIJ
982 !--------------------------------------------------------------------------
983 subroutine lst_VarTransform_kij(lst, SpectralStateVar, GridState, &
984 TransformDirection, nk)
985 implicit none
986
987 ! Arguments:
988 type(struct_lst), intent(in) :: lst
989 integer, intent(in) :: nk ! Grid point data dimensions
990 character(len=*), intent(in) :: TransformDirection ! SpectralToGridPoint or GridPointToSpectral
991 real(8), intent(inout) :: GridState(nk,lst%myLonBeg:lst%myLonEnd,lst%myLatBeg:lst%myLatEnd) ! 3D field in grid point space
992 real(8), intent(inout) :: SpectralStateVar(:,:,:) ! 3D spectral coefficients
993
994 ! Locals:
995 integer :: ni_l, nj_l, nip_l, njp_l
996 integer :: iStart, iEnd, jStart, jEnd, kStart, kEnd
997 real(8), allocatable :: Step0(:,:,:)
998 real(8), allocatable :: Step1(:,:,:)
999 real(8), allocatable :: Step2(:,:,:)
1000 real(8), allocatable :: Step3(:,:,:)
1001 character(len=1) :: TransformAxe
1002
1003 !
1004 !- 1. Data pre-processing (Input -> Step0)
1005 !
1006 if (verbose) write(*,*) 'Entering lst_varTransform_kij'
1007
1008 !- 1.1 Settings and Data Selection
1009
1010 if (trim(TransformDirection) == 'GridPointToSpectral') then
1011 iStart = 1
1012 iEnd = lst%ni
1013 jStart = lst%myLatBeg
1014 jEnd = lst%myLatEnd
1015 if (trim(lst%MpiMode) == 'NoMpi') then
1016 kStart= 1
1017 kEnd = nk
1018 else
1019 kStart= lst%myLevBeg
1020 kEnd = lst%myLevEnd
1021 end if
1022 allocate(Step0(kStart:kEnd,iStart:iEnd,jStart:jEnd))
1023 if (trim(lst%MpiMode) == 'NoMpi') then
1024 Step0(:,:,:) = GridState(:,:,:)
1025 else
1026 if(lst%lonLatDivisible) then
1027 call transpose2d_LonToLev_kij_mpitypes(Step0, & ! OUT
1028 GridState, nk, lst) ! IN
1029 else
1030 call transpose2d_LonToLev_kij(Step0, & ! OUT
1031 GridState, nk, lst) ! IN
1032 end if
1033 end if
1034 end if
1035
1036 !
1037 !- 1. First pass (Step0 -> Step1)
1038 !
1039
1040 !- 1.1 Settings and Data Selection
1041 select case (trim(TransformDirection))
1042 case ('GridPointToSpectral')
1043 TransformAxe = 'i'
1044 ni_l = lst%ni
1045 nip_l = lst%nip
1046 nj_l = lst%latPerPE
1047 njp_l = 0
1048 if (trim(lst%MpiMode) == 'NoMpi') then
1049 kStart= 1
1050 kEnd = nk
1051 else
1052 kStart= lst%myLevBeg
1053 kEnd = lst%myLevEnd
1054 end if
1055 case ('SpectralToGridPoint')
1056 TransformAxe = 'j'
1057 ni_l = 2*lst%mymCount
1058 nip_l = 0
1059 nj_l = lst%nj
1060 njp_l = lst%njp
1061 if (trim(lst%MpiMode) == 'NoMpi') then
1062 kStart= 1
1063 kEnd = nk
1064 else
1065 kStart= lst%myLevBeg
1066 kEnd = lst%myLevEnd
1067 end if
1068 case default
1069 write(*,*)
1070 write(*,*) 'Error: TranformDirection Unknown ', trim(TransformDirection)
1071 call utl_abort('lst_VarTransform')
1072 end select
1073
1074 allocate(Step1(kStart:kEnd,ni_l+nip_l,nj_l+njp_l))
1075
1076 !- 1.2 Spectral transform
1077 if (trim(TransformDirection) == 'SpectralToGridPoint') then
1078 if (trim(lst%MpiMode) == 'NoMpi') then
1079 call lst_ReshapeTrunc_kij(Step1, & ! OUT
1080 SpectralStateVar, & ! IN
1081 'ToRPN', kStart, kEnd, lst) ! IN
1082 else
1083 call transpose2d_NToLev_kij(Step1, & ! OUT
1084 SpectralStateVar, nk, lst) ! IN
1085 end if
1086 else
1087 Step1(:,1:lst%ni,1:lst%latPerPE) = Step0(:,1:lst%ni,lst%myLatBeg:lst%myLatEnd)
1088 deallocate(Step0)
1089 end if
1090
1091 call lst_transform1d_kij(Step1, & ! INOUT
1092 TransformDirection, & ! IN
1093 TransformAxe, & ! IN
1094 ni_l, nj_l, nip_l, njp_l, & ! IN
1095 kStart, kEnd) ! IN
1096
1097 !
1098 !- 2.0 Second pass (Step1 -> Step2)
1099 !
1100
1101 !- 2.1 Settings
1102 if (trim(TransformDirection) == 'GridPointToSpectral') then
1103 TransformAxe = 'j'
1104 ni_l = 2*lst%mymCount
1105 nip_l = 0
1106 nj_l = lst%nj
1107 njp_l = lst%njp
1108 if (trim(lst%MpiMode) == 'NoMpi') then
1109 kStart= 1
1110 kEnd = nk
1111 else
1112 kStart= lst%myLevBeg
1113 kEnd = lst%myLevEnd
1114 end if
1115 else
1116 TransformAxe = 'i'
1117 ni_l = lst%ni
1118 nip_l = lst%nip
1119 nj_l = lst%latPerPE
1120 njp_l = 0
1121 if (trim(lst%MpiMode) == 'NoMpi') then
1122 kStart= 1
1123 kEnd = nk
1124 else
1125 kStart= lst%myLevBeg
1126 kEnd = lst%myLevEnd
1127 end if
1128 end if
1129
1130 allocate(Step2(kStart:kEnd,ni_l+nip_l,nj_l+njp_l))
1131
1132 !- 2.2 Communication between processors
1133
1134 if (trim(TransformDirection) == 'GridPointToSpectral') then
1135 if (trim(lst%MpiMode) == 'NoMpi') then
1136 Step2(:,1:lst%nj,:) = Step1(:,1:lst%nj,:)
1137 else
1138 call transpose2d_LatToM_kij(Step2, & ! OUT
1139 Step1, lst) ! IN
1140 end if
1141 else
1142 if (trim(lst%MpiMode) == 'NoMpi') then
1143 Step2(:,1:lst%nj,:) = Step1(:,1:lst%nj,:)
1144 else
1145 call transpose2d_MToLat_kij(Step2, & ! OUT
1146 Step1, lst) ! IN
1147 end if
1148 end if
1149
1150 deallocate(Step1)
1151
1152 !- 2.3 Spectral Transform
1153 call lst_transform1d_kij(Step2, & ! INOUT
1154 TransformDirection, & ! IN
1155 TransformAxe, & ! IN
1156 ni_l, nj_l, nip_l, njp_l, & ! IN
1157 kStart, kEnd) ! IN
1158
1159 !
1160 !- 3.0 Post-processing (Step2 -> Step3 -> Output)
1161 !
1162
1163 select case (trim(TransformDirection))
1164 case ('GridPointToSpectral')
1165 iStart = 1
1166 iEnd = 2*lst%mymCount
1167 jStart = 1
1168 jEnd = 2*lst%mynCount
1169 kStart= 1
1170 kEnd = nk
1171 case ('SpectralToGridPoint')
1172 iStart = 1
1173 iEnd = lst%lonPerPE
1174 jStart = 1
1175 jEnd = lst%latPerPE
1176 kStart = 1
1177 kEnd = nk
1178 case default
1179 write(*,*)
1180 write(*,*) 'Error: TranformDirection Unknown ', trim(TransformDirection)
1181 call utl_abort('lst_VarTransform')
1182 end select
1183
1184 if (trim(TransformDirection) == 'GridPointToSpectral') then
1185
1186 ! Communication between processors (Truncation (if applicable) will occur in this step)
1187 if (trim(lst%MpiMode) == 'NoMpi') then
1188 call lst_ReshapeTrunc_kij(Step2, & ! IN
1189 SpectralStateVar, & ! OUT
1190 'ToVAR', kStart, kEnd, lst) ! IN
1191 else
1192 call transpose2d_LevToN_kij(SpectralStateVar, & ! OUT
1193 Step2, nk, lst) ! IN
1194 end if
1195
1196 else
1197
1198 allocate(Step3(kStart:kEnd,iStart:iEnd,jStart:jEnd))
1199
1200 ! Communication between processors
1201 if (trim(lst%MpiMode) == 'NoMpi') then
1202 Step3(:,:,:) = Step2(:,1:lst%ni,:)
1203 else
1204 if(lst%lonLatDivisible) then
1205 call transpose2d_LevToLon_kij_mpitypes(Step3, & ! OUT
1206 Step2(:,1:lst%ni,:), nk, lst) ! IN
1207 else
1208 call transpose2d_LevToLon_kij(Step3, & ! OUT
1209 Step2(:,1:lst%ni,:), nk, lst) ! IN
1210 end if
1211 end if
1212
1213 GridState(:,lst%myLonBeg:lst%myLonEnd,lst%myLatBeg:lst%myLatEnd) = Step3(:,1:lst%lonPerPE,1:lst%latPerPE)
1214
1215 deallocate(Step3)
1216
1217 end if
1218
1219 deallocate(Step2)
1220
1221 end subroutine lst_VarTransform_kij
1222
1223 !--------------------------------------------------------------------------
1224 ! lst_TRANSFORM1D
1225 !--------------------------------------------------------------------------
1226 subroutine lst_transform1d(Field3d, &
1227 TransformDirection, &
1228 TransformAxe, &
1229 ni_l, nj_l, nip_l, njp_l, kStart, kEnd)
1230 implicit none
1231
1232 ! Arguments:
1233 integer, intent(in) :: ni_l ! Grid point data dimensions
1234 integer, intent(in) :: nj_l ! Grid point data dimensions
1235 integer, intent(in) :: kStart ! Grid point data dimensions
1236 integer, intent(in) :: kEnd ! Grid point data dimensions
1237 integer, intent(in) :: nip_l ! Extra point in spectral space
1238 integer, intent(in) :: njp_l ! Extra point in spectral space
1239 character(len=*), intent(in) :: TransformDirection ! SpectralToGridPoint or GridPointToSpectral
1240 character(len=*), intent(in) :: TransformAxe ! 'i' or 'j'
1241 real(8), intent(inout) :: Field3d(1:ni_l+nip_l,1:nj_l+njp_l,kStart:kEnd) ! InOut 3D field
1242
1243 ! Locals:
1244 integer :: way
1245 integer :: axe, n, nlot, nfact, np, lot, nk
1246
1247 !
1248 !- 1. Set some options
1249 !
1250 if (verbose) write(*,*) 'Entering lst_transform1d'
1251 call utl_tmg_start(151,'low-level--lst_fft')
1252
1253 !- 1.1 Transform Direction
1254 select case (trim(TransformDirection))
1255 case ('GridPointToSpectral')
1256 way = -1
1257 case ('SpectralToGridPoint')
1258 way = +1
1259 case default
1260 write(*,*)
1261 write(*,*) 'Error: TranformDirection Unknown ', trim(TransformDirection)
1262 call utl_abort('lst_VarTransform')
1263 end select
1264
1265 nk = kEnd - kStart + 1
1266
1267 !
1268 !- 2. Do the transforms in one direction
1269 !
1270 select case (trim(TransformAxe))
1271 case ('i')
1272 !- 2.1 First pass --> Along INDEX "I"
1273 axe = 0
1274 n = ni_l
1275 np = nip_l
1276 nlot= nj_l
1277 case ('j')
1278 !- 2.2 Second pass --> Along INDEX "J"
1279 axe = 1
1280 n = nj_l
1281 np = njp_l
1282 nlot= ni_l
1283 case default
1284 write(*,*)
1285 write(*,*) 'Error: TranformAxe Unknown ', trim(TransformAxe)
1286 call utl_abort('lst_VarTransform')
1287 end select
1288
1289 !- 1.2 Fast or Slow Fourier Transform ?
1290 nfact = n
1291 call ngfft(nfact) ! INOUT
1292
1293 if (nfact == n) then
1294 call setfft8(n) ! IN
1295 else
1296 call utl_abort('lst_VarTransform: This module can only handle fast sin&cos FFT')
1297 end if
1298
1299 select case (trim(TransformAxe))
1300 case ('i')
1301 !$OMP PARALLEL DO PRIVATE(lot)
1302 do lot = 1, nlot
1303 call ffft8(Field3d(:,lot,:), 1, n+np, nk, way)
1304 end do
1305 !$OMP END PARALLEL DO
1306 case ('j')
1307 !$OMP PARALLEL DO PRIVATE(lot)
1308 do lot = 1, nlot
1309 call ffft8(Field3d(lot,:,:), 1, n+np, nk, way)
1310 end do
1311 !$OMP END PARALLEL DO
1312 end select
1313
1314 !* subroutine ffft8( a, inc, jump, lot, isign )
1315 !* a is the array containing input & output data
1316 !* inc is the increment within each data 'vector'
1317 !* (e.g. inc=1 for consecutively stored data)
1318 !* jump is the increment between the start of each data vector
1319 !* lot is the number of data vectors
1320 !* isign = +1 for transform from spectral to gridpoint
1321 !* = -1 for transform from gridpoint to spectral
1322
1323 call utl_tmg_stop(151)
1324
1325 end subroutine lst_transform1d
1326
1327 !--------------------------------------------------------------------------
1328 ! lst_TRANSFORM1D_KIJ
1329 !--------------------------------------------------------------------------
1330 subroutine lst_transform1d_kij(Field3d, &
1331 TransformDirection, &
1332 TransformAxe, &
1333 ni_l, nj_l, nip_l, njp_l, kStart, kEnd)
1334 implicit none
1335
1336 ! Arguments:
1337 integer, intent(in) :: ni_l ! Grid point data dimensions
1338 integer, intent(in) :: nj_l ! Grid point data dimensions
1339 integer, intent(in) :: kStart ! Grid point data dimensions
1340 integer, intent(in) :: kEnd ! Grid point data dimensions
1341 integer, intent(in) :: nip_l ! Extra point in spectral space
1342 integer, intent(in) :: njp_l ! Extra point in spectral space
1343 character(len=*), intent(in) :: TransformDirection ! SpectralToGridPoint or GridPointToSpectral
1344 character(len=*), intent(in) :: TransformAxe ! 'i' or 'j'
1345 real(8), intent(inout) :: Field3d(kStart:kEnd,1:ni_l+nip_l,1:nj_l+njp_l) ! InOut 3D field
1346
1347 ! Locals:
1348 integer :: way
1349 integer :: axe, n, nlot, nfact, np, lot, nk, k
1350
1351 !
1352 !- 1. Set some options
1353 !
1354 if (verbose) write(*,*) 'Entering lst_transform1d_kij'
1355 call utl_tmg_start(151,'low-level--lst_fft')
1356
1357 !- 1.1 Transform Direction
1358 select case (trim(TransformDirection))
1359 case ('GridPointToSpectral')
1360 way = -1
1361 case ('SpectralToGridPoint')
1362 way = +1
1363 case default
1364 write(*,*)
1365 write(*,*) 'Error: TranformDirection Unknown ', trim(TransformDirection)
1366 call utl_abort('lst_VarTransform')
1367 end select
1368
1369 nk = kEnd - kStart + 1
1370
1371 !
1372 !- 2. Do the transforms in one direction
1373 !
1374 select case (trim(TransformAxe))
1375 case ('i')
1376 !- 2.1 First pass --> Along INDEX "I"
1377 axe = 0
1378 n = ni_l
1379 np = nip_l
1380 nlot= nj_l
1381 case ('j')
1382 !- 2.2 Second pass --> Along INDEX "J"
1383 axe = 1
1384 n = nj_l
1385 np = njp_l
1386 nlot= ni_l
1387 case default
1388 write(*,*)
1389 write(*,*) 'Error: TranformAxe Unknown ', trim(TransformAxe)
1390 call utl_abort('lst_VarTransform')
1391 end select
1392
1393 !- 1.2 Fast or Slow Fourier Transform ?
1394 nfact = n
1395 call ngfft(nfact) ! INOUT
1396
1397 if (nfact == n) then
1398 call setfft8(n) ! IN
1399 else
1400 call utl_abort('lst_VarTransform: This module can only handle fast sin&cos FFT')
1401 end if
1402
1403 select case (trim(TransformAxe))
1404 case ('i')
1405 !$OMP PARALLEL DO PRIVATE(lot,k)
1406 do lot = 1, nlot
1407 call ffft8(Field3d(:,:,lot), nk, 1, nk, way)
1408 end do
1409 !$OMP END PARALLEL DO
1410 case ('j')
1411 !$OMP PARALLEL DO PRIVATE(lot,k)
1412 do lot = 1, nlot
1413 call ffft8(Field3d(:,lot,:), nk, 1, nk, way)
1414 end do
1415 !$OMP END PARALLEL DO
1416 end select
1417
1418 !* subroutine ffft8( a, inc, jump, lot, isign )
1419 !* a is the array containing input & output data
1420 !* inc is the increment within each data 'vector'
1421 !* (e.g. inc=1 for consecutively stored data)
1422 !* jump is the increment between the start of each data vector
1423 !* lot is the number of data vectors
1424 !* isign = +1 for transform from spectral to gridpoint
1425 !* = -1 for transform from gridpoint to spectral
1426
1427 call utl_tmg_stop(151)
1428
1429 end subroutine lst_transform1d_kij
1430
1431 !--------------------------------------------------------------------------
1432 ! lst_Transpose2d_LonToLev
1433 !--------------------------------------------------------------------------
1434 subroutine transpose2d_LonToLev(gd_out, gd_in, nk, lst)
1435 implicit none
1436
1437 ! Arguments:
1438 type(struct_lst), intent(in) :: lst
1439 integer, intent(in) :: nk
1440 real(8), intent(in) :: gd_in(lst%myLonBeg:lst%myLonEnd, lst%myLatBeg:lst%myLatEnd, nk)
1441 real(8), intent(out) :: gd_out(lst%ni, lst%myLatBeg:lst%myLatEnd, lst%myLevBeg:lst%myLevEnd)
1442
1443 ! Locals:
1444 real(8) :: gd_send(lst%lonPerPEmax, lst%latPerPEmax, lst%maxLevCount, mmpi_npex)
1445 real(8) :: gd_recv(lst%lonPerPEmax, lst%latPerPEmax, lst%maxLevCount, mmpi_npex)
1446 integer :: yourid, nsize, ierr, levIndex, levIndex2
1447
1448 if (verbose) write(*,*) 'Entering transpose2d_LonToLev'
1449 call rpn_comm_barrier("GRID",ierr)
1450
1451 call utl_tmg_start(155,'low-level--lst_transpose_LEVtoLON')
1452
1453 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2)
1454 do yourid = 0, (mmpi_npex-1)
1455 gd_send(:,:,:,yourid+1) = 0.0d0
1456 do levIndex = lst%allLevBeg(yourid+1), lst%allLevEnd(yourid+1)
1457 levIndex2 = levIndex-lst%allLevBeg(yourid+1)+1
1458 gd_send(1:lst%lonPerPE,1:lst%latPerPE,levIndex2,yourid+1) = gd_in(:,:,levIndex)
1459 end do
1460 end do
1461 !$OMP END PARALLEL DO
1462
1463 nsize = lst%lonPerPEmax * lst%maxLevCount * lst%latPerPEmax
1464 if (mmpi_npex > 1) then
1465 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
1466 gd_recv,nsize,"mpi_double_precision","EW",ierr)
1467 else
1468 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
1469 end if
1470
1471 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2)
1472 do levIndex = lst%myLevBeg, lst%myLevEnd
1473 levIndex2 = levIndex - lst%myLevBeg + 1
1474 do yourid = 0, (mmpi_npex-1)
1475 gd_out(lst%allLonBeg(yourid+1):lst%allLonEnd(yourid+1),:,levIndex) = &
1476 gd_recv(1:lst%allLonPerPE(yourid+1),1:lst%latPerPE,levIndex2,yourid+1)
1477 end do
1478 end do
1479 !$OMP END PARALLEL DO
1480
1481 call utl_tmg_stop(155)
1482
1483 end subroutine transpose2d_LonToLev
1484
1485 !--------------------------------------------------------------------------
1486 ! lst_Transpose2d_LonToLev_kij_mpitypes
1487 !--------------------------------------------------------------------------
1488 subroutine transpose2d_LonToLev_kij_mpitypes(gd_out, gd_in, nk, lst)
1489 implicit none
1490
1491 ! Arguments:
1492 type(struct_lst), intent(in) :: lst
1493 integer, intent(in) :: nk
1494 real(8), intent(in) :: gd_in (nk,lst%myLonBeg:lst%myLonEnd, lst%myLatBeg:lst%myLatEnd)
1495 real(8), intent(out) :: gd_out(lst%myLevBeg:lst%myLevEnd,lst%ni, lst%myLatBeg:lst%myLatEnd)
1496
1497 ! Locals:
1498 integer :: nsize, ierr
1499
1500 if (verbose) write(*,*) 'Entering transpose2d_LonToLev_kij'
1501 call rpn_comm_barrier("GRID",ierr)
1502
1503 call utl_tmg_start(155,'low-level--lst_transpose_LEVtoLON')
1504
1505 nsize = lst%lonPerPE * lst%maxLevCount * lst%latPerPE
1506 if (mmpi_npex > 1) then
1507 call mpi_alltoall(gd_in, 1, lst%sendType_LonToLev, &
1508 gd_out, 1, lst%recvType_LonToLev, mmpi_comm_EW, ierr)
1509 else
1510 gd_out(:,:,:) = gd_in(:,:,:)
1511 end if
1512
1513 call utl_tmg_stop(155)
1514
1515 end subroutine transpose2d_LonToLev_kij_mpitypes
1516
1517 !--------------------------------------------------------------------------
1518 ! lst_Transpose2d_LonToLev_kij
1519 !--------------------------------------------------------------------------
1520 subroutine transpose2d_LonToLev_kij(gd_out, gd_in, nk, lst)
1521 implicit none
1522
1523 ! Arguments:
1524 type(struct_lst), intent(in) :: lst
1525 integer, intent(in) :: nk
1526 real(8), intent(in) :: gd_in (nk,lst%myLonBeg:lst%myLonEnd, lst%myLatBeg:lst%myLatEnd)
1527 real(8), intent(out) :: gd_out(lst%myLevBeg:lst%myLevEnd,lst%ni, lst%myLatBeg:lst%myLatEnd)
1528
1529 ! Locals:
1530 real(8) :: gd_send(lst%maxLevCount,lst%lonPerPEmax, lst%latPerPEmax, mmpi_npex)
1531 real(8) :: gd_recv(lst%maxLevCount,lst%lonPerPEmax, lst%latPerPEmax, mmpi_npex)
1532 integer :: yourid, nsize, ierr, levIndex, levIndex2, latIndex, latIndex2, lonIndex, lonIndex2
1533
1534 if (verbose) write(*,*) 'Entering transpose2d_LonToLev_kij'
1535 call rpn_comm_barrier("GRID",ierr)
1536
1537 call utl_tmg_start(155,'low-level--lst_transpose_LEVtoLON')
1538
1539 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,latIndex2,levIndex,levIndex2,lonIndex,lonIndex2)
1540 do yourid = 0, (mmpi_npex-1)
1541 gd_send(:,:,:,yourid+1) = 0.0d0
1542 do latIndex = lst%myLatBeg, lst%myLatEnd
1543 latIndex2 = latIndex - lst%myLatBeg + 1
1544 do lonIndex = lst%myLonBeg, lst%myLonEnd
1545 lonIndex2 = lonIndex - lst%myLonBeg + 1
1546 do levIndex = lst%allLevBeg(yourid+1), lst%allLevEnd(yourid+1)
1547 levIndex2 = levIndex-lst%allLevBeg(yourid+1)+1
1548 gd_send(levIndex2,lonIndex2,latIndex2,yourid+1) = gd_in(levIndex,lonIndex,latIndex)
1549 end do
1550 end do
1551 end do
1552 end do
1553 !$OMP END PARALLEL DO
1554
1555 nsize = lst%lonPerPEmax * lst%maxLevCount * lst%latPerPEmax
1556 if (mmpi_npex > 1) then
1557 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
1558 gd_recv,nsize,"mpi_double_precision","EW",ierr)
1559 else
1560 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
1561 end if
1562
1563 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2,lonIndex,lonIndex2,latIndex,latIndex2)
1564 do yourid = 0, (mmpi_npex-1)
1565 do latIndex = lst%myLatBeg, lst%myLatEnd
1566 latIndex2 = latIndex - lst%myLatBeg + 1
1567 do lonIndex = lst%allLonBeg(yourid+1), lst%allLonEnd(yourid+1)
1568 lonIndex2 = lonIndex - lst%allLonBeg(yourid+1) + 1
1569 do levIndex = lst%myLevBeg, lst%myLevEnd
1570 levIndex2 = levIndex - lst%myLevBeg + 1
1571 gd_out(levIndex,lonIndex,latIndex) = gd_recv(levIndex2,lonIndex2,latIndex2,yourid+1)
1572 end do
1573 end do
1574 end do
1575 end do
1576 !$OMP END PARALLEL DO
1577
1578 call utl_tmg_stop(155)
1579
1580 end subroutine transpose2d_LonToLev_kij
1581
1582 !--------------------------------------------------------------------------
1583 ! lst_Transpose2d_LevToLon
1584 !--------------------------------------------------------------------------
1585 subroutine transpose2d_LevToLon(gd_out,gd_in,nk,lst)
1586 implicit none
1587
1588 ! Arguments:
1589 type(struct_lst), intent(in) :: lst
1590 integer, intent(in) :: nk
1591 real(8), intent(out) :: gd_out(lst%myLonBeg:lst%myLonEnd, lst%myLatBeg:lst%myLatEnd, nk)
1592 real(8), intent(in) :: gd_in(lst%ni, lst%myLatBeg:lst%myLatEnd, lst%myLevBeg:lst%myLevEnd)
1593
1594 ! Locals:
1595 real(8) :: gd_send(lst%lonPerPEmax, lst%latPerPEmax, lst%maxLevCount, mmpi_npex)
1596 real(8) :: gd_recv(lst%lonPerPEmax, lst%latPerPEmax, lst%maxLevCount, mmpi_npex)
1597 integer :: yourid, nsize, ierr, levIndex, levIndex2
1598
1599 if (verbose) write(*,*) 'Entering transpose2d_LevToLon'
1600 call rpn_comm_barrier("GRID",ierr)
1601
1602 call utl_tmg_start(155,'low-level--lst_transpose_LEVtoLON')
1603
1604 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2)
1605 do levIndex = lst%myLevBeg, lst%myLevEnd
1606 levIndex2 = levIndex - lst%myLevBeg + 1
1607 do yourid = 0, (mmpi_npex-1)
1608 gd_send(:,:,levIndex2,yourid+1) = 0.0d0
1609 gd_send(1:lst%allLonPerPE(yourid+1),1:lst%latPerPE,levIndex2,yourid+1) = &
1610 gd_in(lst%allLonBeg(yourid+1):lst%allLonEnd(yourid+1),:,levIndex)
1611 end do
1612 end do
1613 !$OMP END PARALLEL DO
1614
1615 nsize = lst%lonPerPEmax * lst%maxLevCount * lst%latPerPEmax
1616 if (mmpi_npex > 1) then
1617 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
1618 gd_recv,nsize,"mpi_double_precision","EW",ierr)
1619 else
1620 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
1621 end if
1622
1623 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2)
1624 do yourid = 0, (mmpi_npex-1)
1625 do levIndex=lst%allLevBeg(yourid+1),lst%allLevEnd(yourid+1)
1626 levIndex2=levIndex-lst%allLevBeg(yourid+1)+1
1627 gd_out(:,:,levIndex) = gd_recv(1:lst%lonPerPE,1:lst%latPerPE,levIndex2,yourid+1)
1628 end do
1629 end do
1630 !$OMP END PARALLEL DO
1631
1632 call utl_tmg_stop(155)
1633
1634 end subroutine transpose2d_LevtoLon
1635
1636 !--------------------------------------------------------------------------
1637 ! lst_Transpose2d_LevToLon_kij_mpitypes
1638 !--------------------------------------------------------------------------
1639 subroutine transpose2d_LevToLon_kij_mpitypes(gd_out,gd_in,nk,lst)
1640 implicit none
1641
1642 ! Arguments:
1643 type(struct_lst), intent(in) :: lst
1644 integer, intent(in) :: nk
1645 real(8), intent(out) :: gd_out(nk,lst%myLonBeg:lst%myLonEnd, lst%myLatBeg:lst%myLatEnd)
1646 real(8), intent(in) :: gd_in(lst%myLevBeg:lst%myLevEnd,lst%ni, lst%myLatBeg:lst%myLatEnd)
1647
1648 ! Locals:
1649 integer :: nsize, ierr
1650
1651 if (verbose) write(*,*) 'Entering transpose2d_LevToLon_kij'
1652 call rpn_comm_barrier("GRID",ierr)
1653
1654 call utl_tmg_start(155,'low-level--lst_transpose_LEVtoLON')
1655
1656 nsize = lst%lonPerPE*lst%maxLevCount*lst%latPerPE
1657 if (mmpi_npex > 1) then
1658 call mpi_alltoall(gd_in, 1, lst%sendType_LevToLon, &
1659 gd_out, 1, lst%recvType_LevToLon, mmpi_comm_EW, ierr)
1660 else
1661 gd_out(:,:,:) = gd_in(:,:,:)
1662 end if
1663
1664 call utl_tmg_stop(155)
1665
1666 end subroutine transpose2d_LevtoLon_kij_mpitypes
1667
1668 !--------------------------------------------------------------------------
1669 ! lst_Transpose2d_LevToLon_kij
1670 !--------------------------------------------------------------------------
1671 subroutine transpose2d_LevToLon_kij(gd_out,gd_in,nk,lst)
1672 implicit none
1673
1674 ! Arguments:
1675 type(struct_lst), intent(in) :: lst
1676 integer, intent(in) :: nk
1677 real(8), intent(out) :: gd_out(nk,lst%myLonBeg:lst%myLonEnd, lst%myLatBeg:lst%myLatEnd)
1678 real(8), intent(in) :: gd_in(lst%myLevBeg:lst%myLevEnd,lst%ni, lst%myLatBeg:lst%myLatEnd)
1679
1680 ! Locals:
1681 real(8) :: gd_send(lst%maxLevCount, lst%lonPerPEmax, lst%latPerPEmax, mmpi_npex)
1682 real(8) :: gd_recv(lst%maxLevCount, lst%lonPerPEmax, lst%latPerPEmax, mmpi_npex)
1683 integer :: yourid, nsize, ierr, levIndex, levIndex2, latIndex, latIndex2, lonIndex, lonIndex2
1684
1685 if (verbose) write(*,*) 'Entering transpose2d_LevToLon_kij'
1686 call rpn_comm_barrier("GRID",ierr)
1687
1688 call utl_tmg_start(155,'low-level--lst_transpose_LEVtoLON')
1689
1690 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2,lonIndex,lonIndex2,latIndex,latIndex2)
1691 do yourid = 0, (mmpi_npex-1)
1692 gd_send(:,:,:,yourid+1) = 0.0d0
1693 do latIndex = lst%myLatBeg, lst%myLatEnd
1694 latIndex2 = latIndex - lst%myLatBeg + 1
1695 do lonIndex = lst%allLonBeg(yourid+1), lst%allLonEnd(yourid+1)
1696 lonIndex2 = lonIndex - lst%allLonBeg(yourid+1) + 1
1697 do levIndex = lst%myLevBeg, lst%myLevEnd
1698 levIndex2 = levIndex - lst%myLevBeg + 1
1699 gd_send(levIndex2,lonIndex2,latIndex2,yourid+1) = gd_in(levIndex,lonIndex,latIndex)
1700 end do
1701 end do
1702 end do
1703 end do
1704 !$OMP END PARALLEL DO
1705
1706 nsize = lst%lonPerPEmax * lst%maxLevCount * lst%latPerPEmax
1707 if (mmpi_npex > 1) then
1708 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
1709 gd_recv,nsize,"mpi_double_precision","EW",ierr)
1710 else
1711 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
1712 end if
1713
1714 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,latIndex2,levIndex,levIndex2,lonIndex,lonIndex2)
1715 do yourid = 0, (mmpi_npex-1)
1716 do latIndex = lst%myLatBeg, lst%myLatEnd
1717 latIndex2 = latIndex - lst%myLatBeg + 1
1718 do lonIndex = lst%myLonBeg, lst%myLonEnd
1719 lonIndex2 = lonIndex - lst%myLonBeg + 1
1720 do levIndex=lst%allLevBeg(yourid+1),lst%allLevEnd(yourid+1)
1721 levIndex2=levIndex-lst%allLevBeg(yourid+1)+1
1722 gd_out(levIndex,lonIndex,latIndex) = gd_recv(levIndex2,lonIndex2,latIndex2,yourid+1)
1723 end do
1724 end do
1725 end do
1726 end do
1727 !$OMP END PARALLEL DO
1728
1729 call utl_tmg_stop(155)
1730
1731 end subroutine transpose2d_LevtoLon_kij
1732
1733 !--------------------------------------------------------------------------
1734 ! lst_Transpose2d_LatToM
1735 !--------------------------------------------------------------------------
1736 subroutine transpose2d_LatToM(gd_out, gd_in, lst)
1737 implicit none
1738
1739 ! Arguments:
1740 type(struct_lst), intent(in) :: lst
1741 real(8), intent(out) :: gd_out(2*lst%mymCount,lst%nj+lst%njp,lst%myLevBeg:lst%myLevEnd)
1742 real(8), intent(in) :: gd_in (lst%ni+lst%nip,lst%latPerPE,lst%myLevBeg:lst%myLevEnd)
1743
1744 ! Locals:
1745 real(8) :: gd_recv(lst%maxmActiveCount,2,lst%latPerPEmax, lst%maxLevCount, mmpi_npey)
1746 real(8) :: gd_send(lst%maxmActiveCount,2,lst%latPerPEmax, lst%maxLevCount, mmpi_npey)
1747 integer :: yourid, mIndex, icount, nsize, ierr, levIndex, levIndex2, latIndex, latIndex2
1748
1749 if (verbose) write(*,*) 'Entering transpose2d_LatToM'
1750 call rpn_comm_barrier("GRID",ierr)
1751
1752 call utl_tmg_start(154,'low-level--lst_transpose_MtoLAT')
1753
1754 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,levIndex,levIndex2,icount,mIndex)
1755 do yourid = 0, (mmpi_npey-1)
1756 do levIndex = lst%myLevBeg, lst%myLevEnd
1757 levIndex2 = levIndex - lst%myLevBeg + 1
1758 gd_send(:,:,:,levIndex2,yourid+1) = 0.d0
1759 do latIndex = 1, lst%latPerPE
1760 icount = 0
1761 do mIndex = lst%allmBeg(yourid+1), lst%allmEnd(yourid+1), lst%allmSkip(yourid+1)
1762 if (lst%KfromMNglb(mIndex,0) /= -1) then
1763 icount = icount + 1
1764 gd_send(icount,1,latIndex,levIndex2,yourid+1) = gd_in(2*mIndex+1, latIndex, levIndex)
1765 gd_send(icount,2,latIndex,levIndex2,yourid+1) = gd_in(2*mIndex+2, latIndex, levIndex)
1766 end if
1767 end do
1768 end do
1769 end do
1770 end do
1771 !$OMP END PARALLEL DO
1772
1773 nsize = lst%maxmActiveCount * 2 * lst%maxLevCount * lst%latPerPEmax
1774 if (mmpi_npey > 1) then
1775 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
1776 gd_recv,nsize,"mpi_double_precision","NS",ierr)
1777 else
1778 gd_recv(:,:,:,:,1) = gd_send(:,:,:,:,1)
1779 end if
1780
1781 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,latIndex2,levIndex,levIndex2,icount,mIndex)
1782 do yourid = 0, (mmpi_npey-1)
1783 do levIndex = lst%myLevBeg, lst%myLevEnd
1784 levIndex2 = levIndex - lst%myLevBeg + 1
1785 do latIndex = lst%allLatBeg(yourid+1), lst%allLatEnd(yourid+1)
1786 latIndex2 = latIndex - lst%allLatBeg(yourid+1) + 1
1787 icount = 0
1788 do mIndex = lst%mymBeg, lst%mymEnd, lst%mymSkip
1789 if (lst%KfromMNglb(mIndex,0) /= -1) then
1790 icount = icount + 1
1791 gd_out(2*lst%mymIndex(mIndex)-1,latIndex,levIndex) = gd_recv(icount,1,latIndex2,levIndex2,yourid+1)
1792 gd_out(2*lst%mymIndex(mIndex) ,latIndex,levIndex) = gd_recv(icount,2,latIndex2,levIndex2,yourid+1)
1793 else
1794 gd_out(2*lst%mymIndex(mIndex)-1,latIndex,levIndex) = 0.d0
1795 gd_out(2*lst%mymIndex(mIndex) ,latIndex,levIndex) = 0.d0
1796 end if
1797 end do
1798 end do
1799 end do
1800 end do
1801 !$OMP END PARALLEL DO
1802
1803 call utl_tmg_stop(154)
1804
1805 end subroutine transpose2d_LatToM
1806
1807 !--------------------------------------------------------------------------
1808 ! lst_Transpose2d_LatToM_kij
1809 !--------------------------------------------------------------------------
1810 subroutine transpose2d_LatToM_kij(gd_out, gd_in, lst)
1811 implicit none
1812
1813 ! Arguments:
1814 type(struct_lst), intent(in) :: lst
1815 real(8), intent(out) :: gd_out(lst%myLevBeg:lst%myLevEnd,2*lst%mymCount,lst%nj+lst%njp )
1816 real(8), intent(in) :: gd_in (lst%myLevBeg:lst%myLevEnd,lst%ni+lst%nip,lst%latPerPE)
1817
1818 ! Locals:
1819 real(8) :: gd_recv(lst%maxLevCount,lst%maxmActiveCount,2,lst%latPerPEmax, mmpi_npey)
1820 real(8) :: gd_send(lst%maxLevCount,lst%maxmActiveCount,2,lst%latPerPEmax, mmpi_npey)
1821 integer :: yourid, mIndex, icount, nsize, ierr, levIndex, levIndex2, latIndex, latIndex2
1822
1823 if (verbose) write(*,*) 'Entering transpose2d_LatToM_kij'
1824 call rpn_comm_barrier("GRID",ierr)
1825
1826 call utl_tmg_start(154,'low-level--lst_transpose_MtoLAT')
1827
1828 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,levIndex,levIndex2,icount,mIndex)
1829 do yourid = 0, (mmpi_npey-1)
1830 gd_send(:,:,:,:,yourid+1) = 0.d0
1831 do latIndex = 1, lst%latPerPE
1832 icount = 0
1833 do mIndex = lst%allmBeg(yourid+1), lst%allmEnd(yourid+1), lst%allmSkip(yourid+1)
1834 if (lst%KfromMNglb(mIndex,0) /= -1) then
1835 icount = icount + 1
1836 do levIndex = lst%myLevBeg, lst%myLevEnd
1837 levIndex2 = levIndex - lst%myLevBeg + 1
1838 gd_send(levIndex2,icount,1,latIndex,yourid+1) = gd_in(levIndex,2*mIndex+1, latIndex)
1839 gd_send(levIndex2,icount,2,latIndex,yourid+1) = gd_in(levIndex,2*mIndex+2, latIndex)
1840 end do
1841 end if
1842 end do
1843 end do
1844 end do
1845 !$OMP END PARALLEL DO
1846
1847 nsize = lst%maxmActiveCount * 2 * lst%maxLevCount * lst%latPerPEmax
1848 if (mmpi_npey > 1) then
1849 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
1850 gd_recv,nsize,"mpi_double_precision","NS",ierr)
1851 else
1852 gd_recv(:,:,:,:,1) = gd_send(:,:,:,:,1)
1853 end if
1854
1855 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,latIndex2,levIndex,levIndex2,icount,mIndex)
1856 do yourid = 0, (mmpi_npey-1)
1857 do latIndex = lst%allLatBeg(yourid+1), lst%allLatEnd(yourid+1)
1858 latIndex2 = latIndex - lst%allLatBeg(yourid+1) + 1
1859 icount = 0
1860 do mIndex = lst%mymBeg, lst%mymEnd, lst%mymSkip
1861 if (lst%KfromMNglb(mIndex,0) /= -1) then
1862 icount = icount + 1
1863 do levIndex = lst%myLevBeg, lst%myLevEnd
1864 levIndex2 = levIndex - lst%myLevBeg + 1
1865 gd_out(levIndex,2*lst%mymIndex(mIndex)-1,latIndex) = gd_recv(levIndex2,icount,1,latIndex2,yourid+1)
1866 gd_out(levIndex,2*lst%mymIndex(mIndex) ,latIndex) = gd_recv(levIndex2,icount,2,latIndex2,yourid+1)
1867 end do
1868 else
1869 gd_out(:,2*lst%mymIndex(mIndex)-1,latIndex) = 0.d0
1870 gd_out(:,2*lst%mymIndex(mIndex) ,latIndex) = 0.d0
1871 end if
1872 end do
1873 end do
1874 end do
1875 !$OMP END PARALLEL DO
1876
1877 call utl_tmg_stop(154)
1878
1879 end subroutine transpose2d_LatToM_kij
1880
1881 !--------------------------------------------------------------------------
1882 ! Transpose2d_MToLat
1883 !--------------------------------------------------------------------------
1884 subroutine transpose2d_MtoLat(gd_out, gd_in, lst)
1885 implicit none
1886
1887 ! Arguments:
1888 type(struct_lst), intent(in) :: lst
1889 real(8), intent(in) :: gd_in (2*lst%mymCount,lst%nj+lst%njp,lst%myLevBeg:lst%myLevEnd)
1890 real(8), intent(out) :: gd_out(lst%ni+lst%nip,lst%latPerPE,lst%myLevBeg:lst%myLevEnd)
1891
1892 ! Locals:
1893 real(8) :: gd_recv(lst%maxmActiveCount,2,lst%latPerPEmax,lst%maxLevCount, mmpi_npey)
1894 real(8) :: gd_send(lst%maxmActiveCount,2,lst%latPerPEmax,lst%maxLevCount, mmpi_npey)
1895 integer :: yourid, mIndex, icount, nsize, ierr, levIndex, levIndex2, latIndex, latIndex2
1896
1897 if (verbose) write(*,*) 'Entering transpose2d_MToLat'
1898 call rpn_comm_barrier("GRID",ierr)
1899
1900 call utl_tmg_start(154,'low-level--lst_transpose_MtoLAT')
1901
1902 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,latIndex2,levIndex,levIndex2,icount,mIndex)
1903 do yourid = 0, (mmpi_npey-1)
1904 do levIndex = lst%myLevBeg, lst%myLevEnd
1905 levIndex2 = levIndex - lst%myLevBeg + 1
1906 gd_send(:,:,:,levIndex2,yourid+1) = 0.d0
1907 do latIndex = lst%allLatBeg(yourid+1), lst%allLatEnd(yourid+1)
1908 latIndex2 = latIndex - lst%allLatBeg(yourid+1) + 1
1909 icount = 0
1910 do mIndex = lst%mymBeg, lst%mymEnd, lst%mymSkip
1911 if (lst%KfromMNglb(mIndex,0) /= -1) then
1912 icount = icount+1
1913 gd_send(icount,1,latIndex2,levIndex2,yourid+1) = gd_in(2*lst%mymIndex(mIndex)-1,latIndex,levIndex)
1914 gd_send(icount,2,latIndex2,levIndex2,yourid+1) = gd_in(2*lst%mymIndex(mIndex) ,latIndex,levIndex)
1915 end if
1916 end do
1917 end do
1918 end do
1919 end do
1920 !$OMP END PARALLEL DO
1921
1922 nsize = lst%maxmActiveCount * 2 * lst%maxLevCount * lst%latPerPEmax
1923 if (mmpi_npey > 1) then
1924 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
1925 gd_recv,nsize,"mpi_double_precision","NS",ierr)
1926 else
1927 gd_recv(:,:,:,:,1) = gd_send(:,:,:,:,1)
1928 end if
1929
1930 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,levIndex,levIndex2,icount,mIndex)
1931 do yourid = 0, (mmpi_npey-1)
1932 do levIndex = lst%myLevBeg, lst%myLevEnd
1933 levIndex2 = levIndex - lst%myLevBeg + 1
1934 do latIndex = 1, lst%latPerPE
1935 icount = 0
1936 do mIndex = lst%allmBeg(yourid+1), lst%allmEnd(yourid+1), lst%allmSkip(yourid+1)
1937 if (lst%KfromMNglb(mIndex,0) /= -1) then
1938 icount = icount+1
1939 gd_out(2*mIndex+1,latIndex,levIndex) = gd_recv(icount,1,latIndex,levIndex2,yourid+1)
1940 gd_out(2*mIndex+2,latIndex,levIndex) = gd_recv(icount,2,latIndex,levIndex2,yourid+1)
1941 else
1942 gd_out(2*mIndex+1,latIndex,levIndex) = 0.d0
1943 gd_out(2*mIndex+2,latIndex,levIndex) = 0.d0
1944 end if
1945 end do
1946 end do
1947 end do
1948 end do
1949 !$OMP END PARALLEL DO
1950
1951 call utl_tmg_stop(154)
1952
1953 end subroutine transpose2d_MtoLat
1954
1955 !--------------------------------------------------------------------------
1956 ! Transpose2d_MToLat_kij
1957 !--------------------------------------------------------------------------
1958 subroutine transpose2d_MtoLat_kij(gd_out, gd_in, lst)
1959 implicit none
1960
1961 ! Arguments:
1962 type(struct_lst), intent(in) :: lst
1963 real(8), intent(in) :: gd_in (lst%myLevBeg:lst%myLevEnd,2*lst%mymCount,lst%nj+lst%njp)
1964 real(8), intent(out) :: gd_out(lst%myLevBeg:lst%myLevEnd,lst%ni+lst%nip,lst%latPerPE)
1965
1966 ! Locals:
1967 real(8) :: gd_recv(lst%maxLevCount,lst%maxmActiveCount,2,lst%latPerPEmax, mmpi_npey)
1968 real(8) :: gd_send(lst%maxLevCount,lst%maxmActiveCount,2,lst%latPerPEmax, mmpi_npey)
1969 integer :: yourid, mIndex, icount, nsize, ierr, levIndex, levIndex2, latIndex, latIndex2
1970
1971 if (verbose) write(*,*) 'Entering transpose2d_MToLat_kij'
1972 call rpn_comm_barrier("GRID",ierr)
1973
1974 call utl_tmg_start(154,'low-level--lst_transpose_MtoLAT')
1975
1976 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,latIndex2,levIndex,levIndex2,icount,mIndex)
1977 do yourid = 0, (mmpi_npey-1)
1978 gd_send(:,:,:,:,yourid+1) = 0.d0
1979 do latIndex = lst%allLatBeg(yourid+1), lst%allLatEnd(yourid+1)
1980 latIndex2 = latIndex - lst%allLatBeg(yourid+1) + 1
1981 icount = 0
1982 do mIndex = lst%mymBeg, lst%mymEnd, lst%mymSkip
1983 if (lst%KfromMNglb(mIndex,0) /= -1) then
1984 icount = icount+1
1985 do levIndex = lst%myLevBeg, lst%myLevEnd
1986 levIndex2 = levIndex - lst%myLevBeg + 1
1987 gd_send(levIndex2,icount,1,latIndex2,yourid+1) = gd_in(levIndex,2*lst%mymIndex(mIndex)-1,latIndex)
1988 gd_send(levIndex2,icount,2,latIndex2,yourid+1) = gd_in(levIndex,2*lst%mymIndex(mIndex) ,latIndex)
1989 end do
1990 end if
1991 end do
1992 end do
1993 end do
1994 !$OMP END PARALLEL DO
1995
1996 nsize = lst%maxmActiveCount * 2 * lst%maxLevCount * lst%latPerPEmax
1997 if (mmpi_npey > 1) then
1998 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
1999 gd_recv,nsize,"mpi_double_precision","NS",ierr)
2000 else
2001 gd_recv(:,:,:,:,1) = gd_send(:,:,:,:,1)
2002 end if
2003
2004 !$OMP PARALLEL DO PRIVATE(yourid,latIndex,levIndex,levIndex2,icount,mIndex)
2005 do yourid = 0, (mmpi_npey-1)
2006 do latIndex = 1, lst%latPerPE
2007 icount = 0
2008 do mIndex = lst%allmBeg(yourid+1), lst%allmEnd(yourid+1), lst%allmSkip(yourid+1)
2009 if (lst%KfromMNglb(mIndex,0) /= -1) then
2010 icount = icount+1
2011 do levIndex = lst%myLevBeg, lst%myLevEnd
2012 levIndex2 = levIndex - lst%myLevBeg + 1
2013 gd_out(levIndex,2*mIndex+1,latIndex) = gd_recv(levIndex2,icount,1,latIndex,yourid+1)
2014 gd_out(levIndex,2*mIndex+2,latIndex) = gd_recv(levIndex2,icount,2,latIndex,yourid+1)
2015 end do
2016 else
2017 gd_out(:,2*mIndex+1,latIndex) = 0.d0
2018 gd_out(:,2*mIndex+2,latIndex) = 0.d0
2019 end if
2020 end do
2021 end do
2022 end do
2023 !$OMP END PARALLEL DO
2024
2025 call utl_tmg_stop(154)
2026
2027 end subroutine transpose2d_MtoLat_kij
2028
2029 !--------------------------------------------------------------------------
2030 ! lst_Transpose2d_LevToN
2031 !--------------------------------------------------------------------------
2032 subroutine transpose2d_LevToN(SpectralStateVar, gd_in, nk, lst)
2033 implicit none
2034
2035 ! Arguments:
2036 type(struct_lst), intent(in) :: lst
2037 integer, intent(in) :: nk
2038 real(8), intent(out) :: SpectralStateVar(lst%nla,lst%nphase,nk)
2039 real(8), intent(in) :: gd_in (2*lst%mymCount, lst%nj+lst%njp, lst%myLevBeg:lst%myLevEnd)
2040
2041 ! Locals:
2042 real(8) :: gd_send(lst%maxnla, 4, lst%maxLevCount, mmpi_npex)
2043 real(8) :: gd_recv(lst%maxnla, 4, lst%maxLevCount, mmpi_npex)
2044 integer :: yourid, nsize, ierr, levIndex, levIndex2, nIndex, mIndex, icount
2045
2046 if (verbose) write(*,*) 'Entering transpose2d_LevToN'
2047 call rpn_comm_barrier("GRID",ierr)
2048
2049 call utl_tmg_start(153,'low-level--lst_transpose_NtoLEV')
2050
2051 !$OMP PARALLEL DO PRIVATE(yourid,mIndex,levIndex,levIndex2,nIndex,icount)
2052 do yourid = 0, (mmpi_npex-1)
2053 do levIndex = lst%myLevBeg, lst%myLevEnd
2054 levIndex2 = levIndex - lst%myLevBeg + 1
2055 gd_send(:,:,levIndex2,yourid+1) = 0.d0
2056 icount = 0
2057 do nIndex = lst%allnBeg(yourid+1), lst%allnEnd(yourid+1), lst%allnSkip(yourid+1)
2058 do mIndex = lst%mymBeg, lst%mymEnd, lst%mymSkip
2059 if (lst%KfromMNglb(mIndex,nIndex) /= -1) then
2060 icount = icount + 1
2061 gd_send(icount,1,levIndex2,yourid+1) = gd_in(2*lst%mymIndex(mIndex)-1,2*nIndex+1,levIndex)
2062 gd_send(icount,2,levIndex2,yourid+1) = gd_in(2*lst%mymIndex(mIndex)-1,2*nIndex+2,levIndex)
2063 gd_send(icount,3,levIndex2,yourid+1) = gd_in(2*lst%mymIndex(mIndex) ,2*nIndex+1,levIndex)
2064 gd_send(icount,4,levIndex2,yourid+1) = gd_in(2*lst%mymIndex(mIndex) ,2*nIndex+2,levIndex)
2065 end if
2066 end do
2067 end do
2068 end do
2069 end do
2070 !$OMP END PARALLEL DO
2071
2072 nsize = lst%maxnla * 4 * lst%maxLevCount
2073 if (mmpi_npex > 1) then
2074 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
2075 gd_recv,nsize,"mpi_double_precision","EW",ierr)
2076 else
2077 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
2078 end if
2079
2080 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2)
2081 do yourid = 0, (mmpi_npex-1)
2082 do levIndex = lst%allLevBeg(yourid+1), lst%allLevEnd(yourid+1)
2083 levIndex2 = levIndex - lst%allLevBeg(yourid+1) + 1
2084 SpectralStateVar(:,:,levIndex) = gd_recv(1:lst%nla,:,levIndex2,yourid+1)
2085 end do
2086 end do
2087 !$OMP END PARALLEL DO
2088
2089 call utl_tmg_stop(153)
2090
2091 end subroutine transpose2d_LevToN
2092
2093 !--------------------------------------------------------------------------
2094 ! lst_Transpose2d_LevToN_kij
2095 !--------------------------------------------------------------------------
2096 subroutine transpose2d_LevToN_kij(SpectralStateVar, gd_in, nk, lst)
2097 implicit none
2098
2099 ! Arguments:
2100 type(struct_lst), intent(in) :: lst
2101 integer, intent(in) :: nk
2102 real(8), intent(out) :: SpectralStateVar(lst%nla,lst%nphase,nk)
2103 real(8), intent(in) :: gd_in (lst%myLevBeg:lst%myLevEnd,2*lst%mymCount, lst%nj+lst%njp)
2104
2105 ! Locals:
2106 real(8) :: gd_send(lst%maxnla, 4, lst%maxLevCount, mmpi_npex)
2107 real(8) :: gd_recv(lst%maxnla, 4, lst%maxLevCount, mmpi_npex)
2108 integer :: yourid, nsize, ierr, levIndex, levIndex2, nIndex, mIndex, icount
2109
2110 if (verbose) write(*,*) 'Entering transpose2d_LevToN_kij'
2111 call rpn_comm_barrier("GRID",ierr)
2112
2113 call utl_tmg_start(153,'low-level--lst_transpose_NtoLEV')
2114
2115 !$OMP PARALLEL DO PRIVATE(yourid,mIndex,levIndex,levIndex2,nIndex,icount)
2116 do yourid = 0, (mmpi_npex-1)
2117 do levIndex = lst%myLevBeg, lst%myLevEnd
2118 levIndex2 = levIndex - lst%myLevBeg + 1
2119 gd_send(:,:,levIndex2,yourid+1) = 0.d0
2120 icount = 0
2121 do nIndex = lst%allnBeg(yourid+1), lst%allnEnd(yourid+1), lst%allnSkip(yourid+1)
2122 do mIndex = lst%mymBeg, lst%mymEnd, lst%mymSkip
2123 if (lst%KfromMNglb(mIndex,nIndex) /= -1) then
2124 icount = icount + 1
2125 gd_send(icount,1,levIndex2,yourid+1) = gd_in(levIndex,2*lst%mymIndex(mIndex)-1,2*nIndex+1)
2126 gd_send(icount,2,levIndex2,yourid+1) = gd_in(levIndex,2*lst%mymIndex(mIndex)-1,2*nIndex+2)
2127 gd_send(icount,3,levIndex2,yourid+1) = gd_in(levIndex,2*lst%mymIndex(mIndex) ,2*nIndex+1)
2128 gd_send(icount,4,levIndex2,yourid+1) = gd_in(levIndex,2*lst%mymIndex(mIndex) ,2*nIndex+2)
2129 end if
2130 end do
2131 end do
2132 end do
2133 end do
2134 !$OMP END PARALLEL DO
2135
2136 nsize = lst%maxnla * 4 * lst%maxLevCount
2137 if (mmpi_npex > 1) then
2138 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
2139 gd_recv,nsize,"mpi_double_precision","EW",ierr)
2140 else
2141 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
2142 end if
2143
2144 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2)
2145 do yourid = 0, (mmpi_npex-1)
2146 do levIndex = lst%allLevBeg(yourid+1), lst%allLevEnd(yourid+1)
2147 levIndex2 = levIndex - lst%allLevBeg(yourid+1) + 1
2148 SpectralStateVar(:,:,levIndex) = gd_recv(1:lst%nla,:,levIndex2,yourid+1)
2149 end do
2150 end do
2151 !$OMP END PARALLEL DO
2152
2153 call utl_tmg_stop(153)
2154
2155 end subroutine transpose2d_LevToN_kij
2156
2157 !--------------------------------------------------------------------------
2158 ! lst_Transpose2d_NToLev
2159 !--------------------------------------------------------------------------
2160 subroutine transpose2d_NToLev(gd_out, SpectralStateVar, nk, lst)
2161 implicit none
2162
2163 ! Arguments:
2164 type(struct_lst), intent(in) :: lst
2165 integer, intent(in) :: nk
2166 real(8), intent(in) :: SpectralStateVar(lst%nla,lst%nphase,nk)
2167 real(8), intent(out) :: gd_out(2*lst%mymCount, lst%nj+lst%njp, lst%myLevBeg:lst%myLevEnd)
2168
2169 ! Locals:
2170 real(8) :: gd_send(lst%maxnla, 4, lst%maxLevCount, mmpi_npex)
2171 real(8) :: gd_recv(lst%maxnla, 4, lst%maxLevCount, mmpi_npex)
2172 integer :: yourid, nsize, ierr, levIndex, levIndex2, nIndex, mIndex, icount
2173
2174 if (verbose) write(*,*) 'Entering transpose2d_NToLev'
2175 call rpn_comm_barrier("GRID",ierr)
2176
2177 call utl_tmg_start(153,'low-level--lst_transpose_NtoLEV')
2178
2179 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2)
2180 do yourid = 0, (mmpi_npex-1)
2181 do levIndex = lst%allLevBeg(yourid+1), lst%allLevEnd(yourid+1)
2182 levIndex2 = levIndex - lst%allLevBeg(yourid+1) + 1
2183 gd_send(1:lst%nla,:,levIndex2,yourid+1) = SpectralStateVar(:,:,levIndex)
2184 if (lst%nla < lst%maxnla) gd_send(lst%nla+1:lst%maxnla,:,levIndex2,yourid+1) = 0.d0
2185 end do
2186 end do
2187 !$OMP END PARALLEL DO
2188
2189 nsize = lst%maxnla * 4* lst%maxLevCount
2190 if (mmpi_npex > 1) then
2191 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
2192 gd_recv,nsize,"mpi_double_precision","EW",ierr)
2193 else
2194 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
2195 end if
2196
2197 !$OMP PARALLEL DO PRIVATE(yourid,nIndex,levIndex,levIndex2,mIndex,icount)
2198 do yourid = 0, (mmpi_npex-1)
2199 do levIndex = lst%myLevBeg, lst%myLevEnd
2200 levIndex2 = levIndex - lst%myLevBeg + 1
2201 icount = 0
2202 do nIndex = lst%allnBeg(yourid+1), lst%allnEnd(yourid+1), lst%allnSkip(yourid+1)
2203 do mIndex = lst%mymBeg, lst%mymEnd, lst%mymSkip
2204 if (lst%KfromMNglb(mIndex,nIndex) /= -1) then
2205 icount = icount + 1
2206 gd_out(2*lst%mymIndex(mIndex)-1,2*nIndex+1,levIndex) = gd_recv(icount,1,levIndex2,yourid+1)
2207 gd_out(2*lst%mymIndex(mIndex)-1,2*nIndex+2,levIndex) = gd_recv(icount,2,levIndex2,yourid+1)
2208 gd_out(2*lst%mymIndex(mIndex) ,2*nIndex+1,levIndex) = gd_recv(icount,3,levIndex2,yourid+1)
2209 gd_out(2*lst%mymIndex(mIndex) ,2*nIndex+2,levIndex) = gd_recv(icount,4,levIndex2,yourid+1)
2210 else
2211 gd_out(2*lst%mymIndex(mIndex)-1,2*nIndex+1,levIndex) = 0.d0
2212 gd_out(2*lst%mymIndex(mIndex)-1,2*nIndex+2,levIndex) = 0.d0
2213 gd_out(2*lst%mymIndex(mIndex) ,2*nIndex+1,levIndex) = 0.d0
2214 gd_out(2*lst%mymIndex(mIndex) ,2*nIndex+2,levIndex) = 0.d0
2215 end if
2216 end do
2217 end do
2218 end do
2219 end do
2220 !$OMP END PARALLEL DO
2221
2222 call utl_tmg_stop(153)
2223
2224 end subroutine transpose2d_NToLev
2225
2226 !--------------------------------------------------------------------------
2227 ! lst_Transpose2d_NToLev_kij
2228 !--------------------------------------------------------------------------
2229 subroutine transpose2d_NToLev_kij(gd_out, SpectralStateVar, nk, lst)
2230 implicit none
2231
2232 ! Arguments:
2233 type(struct_lst), intent(in) :: lst
2234 integer, intent(in) :: nk
2235 real(8), intent(in) :: SpectralStateVar(lst%nla,lst%nphase,nk)
2236 real(8), intent(out) :: gd_out(lst%myLevBeg:lst%myLevEnd,2*lst%mymCount,lst%nj+lst%njp)
2237
2238 ! Locals:
2239 real(8) :: gd_send(lst%maxnla, 4, lst%maxLevCount, mmpi_npex)
2240 real(8) :: gd_recv(lst%maxnla, 4, lst%maxLevCount, mmpi_npex)
2241 integer :: yourid, nsize, ierr, levIndex, levIndex2, nIndex, mIndex, icount
2242
2243 if (verbose) write(*,*) 'Entering transpose2d_NToLev_kij'
2244 call rpn_comm_barrier("GRID",ierr)
2245
2246 call utl_tmg_start(153,'low-level--lst_transpose_NtoLEV')
2247
2248 !$OMP PARALLEL DO PRIVATE(yourid,levIndex,levIndex2)
2249 do yourid = 0, (mmpi_npex-1)
2250 do levIndex = lst%allLevBeg(yourid+1), lst%allLevEnd(yourid+1)
2251 levIndex2 = levIndex - lst%allLevBeg(yourid+1) + 1
2252 gd_send(1:lst%nla,:,levIndex2,yourid+1) = SpectralStateVar(:,:,levIndex)
2253 if (lst%nla < lst%maxnla) gd_send(lst%nla+1:lst%maxnla,:,levIndex2,yourid+1) = 0.d0
2254 end do
2255 end do
2256 !$OMP END PARALLEL DO
2257
2258 nsize = lst%maxnla * 4 * lst%maxLevCount
2259 if (mmpi_npex > 1) then
2260 call rpn_comm_alltoall(gd_send,nsize,"mpi_double_precision", &
2261 gd_recv,nsize,"mpi_double_precision","EW",ierr)
2262 else
2263 gd_recv(:,:,:,1) = gd_send(:,:,:,1)
2264 end if
2265
2266 !$OMP PARALLEL DO PRIVATE(yourid,nIndex,levIndex,levIndex2,mIndex,icount)
2267 do yourid = 0, (mmpi_npex-1)
2268 do levIndex = lst%myLevBeg, lst%myLevEnd
2269 levIndex2 = levIndex - lst%myLevBeg + 1
2270 icount = 0
2271 do nIndex = lst%allnBeg(yourid+1), lst%allnEnd(yourid+1), lst%allnSkip(yourid+1)
2272 do mIndex = lst%mymBeg, lst%mymEnd, lst%mymSkip
2273 if (lst%KfromMNglb(mIndex,nIndex) /= -1) then
2274 icount = icount + 1
2275 gd_out(levIndex,2*lst%mymIndex(mIndex)-1,2*nIndex+1) = gd_recv(icount,1,levIndex2,yourid+1)
2276 gd_out(levIndex,2*lst%mymIndex(mIndex)-1,2*nIndex+2) = gd_recv(icount,2,levIndex2,yourid+1)
2277 gd_out(levIndex,2*lst%mymIndex(mIndex) ,2*nIndex+1) = gd_recv(icount,3,levIndex2,yourid+1)
2278 gd_out(levIndex,2*lst%mymIndex(mIndex) ,2*nIndex+2) = gd_recv(icount,4,levIndex2,yourid+1)
2279 else
2280 gd_out(levIndex,2*lst%mymIndex(mIndex)-1,2*nIndex+1) = 0.d0
2281 gd_out(levIndex,2*lst%mymIndex(mIndex)-1,2*nIndex+2) = 0.d0
2282 gd_out(levIndex,2*lst%mymIndex(mIndex) ,2*nIndex+1) = 0.d0
2283 gd_out(levIndex,2*lst%mymIndex(mIndex) ,2*nIndex+2) = 0.d0
2284 end if
2285 end do
2286 end do
2287 end do
2288 end do
2289 !$OMP END PARALLEL DO
2290
2291 call utl_tmg_stop(153)
2292
2293 end subroutine transpose2d_NToLev_kij
2294
2295 !--------------------------------------------------------------------------
2296 ! lst_ReshapeTrunc
2297 !--------------------------------------------------------------------------
2298 subroutine lst_ReshapeTrunc(SpectralStateRpn, SpectralStateVar, &
2299 Direction, kStart, kEnd, lst)
2300 implicit none
2301
2302 ! Arguments:
2303 type(struct_lst), intent(in) :: lst
2304 integer, intent(in) :: kStart
2305 integer, intent(in) :: kEnd
2306 character(len=*), intent(in) :: Direction ! ToVAR or ToRPN
2307 real(8), intent(inout) :: SpectralStateRpn(2*lst%mymCount,2*lst%mynCount,kStart:kEnd)
2308 real(8), intent(inout) :: SpectralStateVar(lst%nla ,lst%nphase,kStart:kEnd)
2309
2310 ! Locals:
2311 integer k, m, n, ila
2312
2313 if (verbose) write(*,*) 'Entering lst_ReshapeTrunc'
2314
2315 select case (trim(Direction))
2316 case ('ToVAR')
2317 ! Truncation (if applicable) will be applied here
2318 !$OMP PARALLEL DO PRIVATE (n,m,ila,k)
2319 do n = lst%mynBeg, lst%mynEnd, lst%mynSkip
2320 do m = lst%mymBeg, lst%mymEnd, lst%mymSkip
2321 ila = lst%nla_Index(m,n)
2322 if (ila /= -1) then
2323 do k = kStart, kEnd
2324 SpectralStateVar(ila,1,k) = SpectralStateRpn(2*lst%mymIndex(m)-1,2*lst%mynIndex(n)-1,k)
2325 SpectralStateVar(ila,2,k) = SpectralStateRpn(2*lst%mymIndex(m)-1,2*lst%mynIndex(n) ,k)
2326 SpectralStateVar(ila,3,k) = SpectralStateRpn(2*lst%mymIndex(m) ,2*lst%mynIndex(n)-1,k)
2327 SpectralStateVar(ila,4,k) = SpectralStateRpn(2*lst%mymIndex(m) ,2*lst%mynIndex(n), k)
2328 end do
2329 end if
2330 end do
2331 end do
2332 !$OMP END PARALLEL DO
2333
2334 case ('ToRPN')
2335 SpectralStateRpn(:,:,:) = 0.0d0
2336 !$OMP PARALLEL DO PRIVATE (n,m,ila,k)
2337 do n = lst%mynBeg, lst%mynEnd, lst%mynSkip
2338 do m = lst%mymBeg, lst%mymEnd, lst%mymSkip
2339 ila = lst%nla_Index(m,n)
2340 if (ila /= -1) then
2341 do k = kStart, kEnd
2342 SpectralStateRpn(2*lst%mymIndex(m)-1,2*lst%mynIndex(n)-1,k) = SpectralStateVar(ila,1,k)
2343 SpectralStateRpn(2*lst%mymIndex(m)-1,2*lst%mynIndex(n) ,k) = SpectralStateVar(ila,2,k)
2344 SpectralStateRpn(2*lst%mymIndex(m) ,2*lst%mynIndex(n)-1,k) = SpectralStateVar(ila,3,k)
2345 SpectralStateRpn(2*lst%mymIndex(m) ,2*lst%mynIndex(n) ,k) = SpectralStateVar(ila,4,k)
2346 end do
2347 end if
2348 end do
2349 end do
2350 !$OMP END PARALLEL DO
2351
2352 case default
2353 write(*,*)
2354 write(*,*) 'lst_ReshapeTrunc: Unknown Direction', trim(Direction)
2355 call utl_abort('lst_ReshapeTrunc')
2356 end select
2357
2358 end subroutine lst_ReshapeTrunc
2359
2360 !--------------------------------------------------------------------------
2361 ! lst_ReshapeTrunc_kij
2362 !--------------------------------------------------------------------------
2363 subroutine lst_ReshapeTrunc_kij(SpectralStateRpn, SpectralStateVar, &
2364 Direction, kStart, kEnd, lst)
2365 implicit none
2366
2367 ! Arguments:
2368 type(struct_lst), intent(in) :: lst
2369 integer, intent(in) :: kStart
2370 integer, intent(in) :: kEnd
2371 character(len=*), intent(in) :: Direction ! ToVAR or ToRPN
2372 real(8), intent(inout) :: SpectralStateRpn(kStart:kEnd,2*lst%mymCount,2*lst%mynCount)
2373 real(8), intent(inout) :: SpectralStateVar(lst%nla ,lst%nphase,kStart:kEnd)
2374
2375 ! Locals:
2376 integer k, m, n, ila
2377
2378 if (verbose) write(*,*) 'Entering lst_ReshapeTrunc_kij'
2379
2380 select case (trim(Direction))
2381 case ('ToVAR')
2382 ! Truncation (if applicable) will be applied here
2383 !$OMP PARALLEL DO PRIVATE (n,m,ila,k)
2384 do n = lst%mynBeg, lst%mynEnd, lst%mynSkip
2385 do m = lst%mymBeg, lst%mymEnd, lst%mymSkip
2386 ila = lst%nla_Index(m,n)
2387 if (ila /= -1) then
2388 do k = kStart, kEnd
2389 SpectralStateVar(ila,1,k) = SpectralStateRpn(k,2*lst%mymIndex(m)-1,2*lst%mynIndex(n)-1)
2390 SpectralStateVar(ila,2,k) = SpectralStateRpn(k,2*lst%mymIndex(m)-1,2*lst%mynIndex(n) )
2391 SpectralStateVar(ila,3,k) = SpectralStateRpn(k,2*lst%mymIndex(m) ,2*lst%mynIndex(n)-1)
2392 SpectralStateVar(ila,4,k) = SpectralStateRpn(k,2*lst%mymIndex(m) ,2*lst%mynIndex(n) )
2393 end do
2394 end if
2395 end do
2396 end do
2397 !$OMP END PARALLEL DO
2398
2399 case ('ToRPN')
2400 SpectralStateRpn(:,:,:) = 0.0d0
2401 !$OMP PARALLEL DO PRIVATE (n,m,ila,k)
2402 do n = lst%mynBeg, lst%mynEnd, lst%mynSkip
2403 do m = lst%mymBeg, lst%mymEnd, lst%mymSkip
2404 ila = lst%nla_Index(m,n)
2405 if (ila /= -1) then
2406 do k = kStart, kEnd
2407 SpectralStateRpn(k,2*lst%mymIndex(m)-1,2*lst%mynIndex(n)-1) = SpectralStateVar(ila,1,k)
2408 SpectralStateRpn(k,2*lst%mymIndex(m)-1,2*lst%mynIndex(n) ) = SpectralStateVar(ila,2,k)
2409 SpectralStateRpn(k,2*lst%mymIndex(m) ,2*lst%mynIndex(n)-1) = SpectralStateVar(ila,3,k)
2410 SpectralStateRpn(k,2*lst%mymIndex(m) ,2*lst%mynIndex(n) ) = SpectralStateVar(ila,4,k)
2411 end do
2412 end if
2413 end do
2414 end do
2415 !$OMP END PARALLEL DO
2416
2417 case default
2418 write(*,*)
2419 write(*,*) 'lst_ReshapeTrunc_kij: Unknown Direction', trim(Direction)
2420 call utl_abort('lst_ReshapeTrunc_kij')
2421 end select
2422
2423 end subroutine lst_ReshapeTrunc_kij
2424
2425 !--------------------------------------------------------------------------
2426 ! lst_Laplacian
2427 !--------------------------------------------------------------------------
2428 subroutine lst_Laplacian(lst, GridState, Mode, nk)
2429 implicit none
2430
2431 ! Arguments:
2432 type(struct_lst), intent(in) :: lst
2433 integer, intent(in) :: nk ! Grid point data dimensions
2434 real(8), intent(inout) :: GridState(lst%myLonBeg:lst%myLonEnd,lst%myLatBeg:lst%myLatEnd,nk) ! 3D field in grid point space
2435 character(len=*), intent(in) :: Mode ! Forward or Inverse
2436
2437 ! Locals:
2438 real(8), allocatable :: SpectralStateVar(:,:,:)
2439 real(8), allocatable :: factor(:)
2440 integer :: k, ila, p
2441 character(len=24) :: kind
2442
2443 if (verbose) write(*,*) 'Entering lst_Laplacian'
2444
2445 allocate(SpectralStateVar(lst%nla,lst%nphase,nk))
2446 allocate(factor(lst%nla))
2447
2448 !
2449 !- 1. Set Mode-dependent factors
2450 !
2451 select case (trim(Mode))
2452 case ('Forward')
2453 factor(:) = lst%lapxy(:)
2454 case ('Inverse')
2455 factor(:) = lst%ilapxy(:)
2456 case default
2457 write(*,*)
2458 write(*,*) 'lst_Laplacian: Error: Mode Unknown ', trim(Mode)
2459 call utl_abort('lst_Laplacian')
2460 end select
2461
2462 !
2463 !- 2. Grid Point Space -> Spectral Space
2464 !
2465 kind = 'GridPointToSpectral'
2466 call lst_VarTransform(lst, & ! IN
2467 SpectralStateVar, & ! OUT
2468 GridState, & ! IN
2469 kind, nk) ! IN
2470
2471 !
2472 !- 3. Laplacian (forward or inverse) Transform
2473 !
2474 !$OMP PARALLEL DO PRIVATE (k,ila,p)
2475 do k = 1, nk
2476 do ila = 1, lst%nla
2477 do p = 1, lst%nphase
2478 SpectralStateVar(ila,p,k) = factor(ila) * SpectralStateVar(ila,p,k)
2479 end do
2480 end do
2481 end do
2482 !$OMP END PARALLEL DO
2483
2484 !
2485 !- 4. Spectral Space -> Grid Point Space
2486 !
2487 kind = 'SpectralToGridPoint'
2488 call lst_VarTransform(lst, & ! IN
2489 SpectralStateVar, & ! IN
2490 GridState, & ! OUT
2491 kind, nk) ! IN
2492
2493 deallocate(SpectralStateVar)
2494 deallocate(factor)
2495
2496 end subroutine lst_Laplacian
2497
2498 !--------------------------------------------------------------------------
2499 ! NGFFT
2500 !--------------------------------------------------------------------------
2501 subroutine ngfft(n)
2502 implicit none
2503
2504 ! Arguments:
2505 integer, intent(inout) :: n ! le plus petit entier >= n qui factorise
2506
2507 ! Locals:
2508 integer, parameter :: l = 3
2509 integer :: k(l) , m
2510 data m , k / 8 , 2 , 3 , 5 /
2511 integer :: i, j
2512
2513 if (n <= m) n = m + 1
2514 n = n - 1
25151 n = n + 1
2516 i = n
25172 do j = 1, l
2518 if (mod(i,k(j)) == 0) go to 4
2519 end do
2520 go to 1
25214 i = i/k(j)
2522 if (i /= 1) go to 2
2523
2524 end subroutine ngfft
2525
2526end module lamSpectralTransform_mod