FV3 Bundle
type_mpl.F90
Go to the documentation of this file.
1 !----------------------------------------------------------------------
2 ! Module: type_mpl
3 ! Purpose: MPI parameters derived type
4 ! Author: Benjamin Menetrier
5 ! Licensing: this code is distributed under the CeCILL-C license
6 ! Copyright © 2015-... UCAR, CERFACS, METEO-FRANCE and IRIT
7 !----------------------------------------------------------------------
8 module type_mpl
9 
10 use iso_fortran_env, only : output_unit
11 use iso_c_binding
12 use netcdf
13 !$ use omp_lib
14 use tools_const, only: msvali,msvalr
15 use tools_kinds, only: kind_real
16 use tools_missing, only: msi,isnotmsi
17 use fckit_mpi_module, only: fckit_mpi_comm,fckit_mpi_sum,fckit_mpi_status
18 
19 implicit none
20 
21 integer,parameter :: lunit_min=10 ! Minimum unit number
22 integer,parameter :: lunit_max=1000 ! Maximum unit number
23 integer,parameter :: ddis = 5 ! Progression display step
24 
26  ! MPI parameters
27  integer :: nproc ! Number of MPI tasks
28  integer :: myproc ! MPI task index
29  integer :: ioproc ! Main task index
30  logical :: main ! Main task logical
31  integer :: info ! Listing unit (info)
32  integer :: test ! Listing unit (test)
33  integer :: tag ! MPI tag
34  integer :: nthread ! Number of OpenMP threads
35 
36  type(fckit_mpi_comm) :: f_comm ! Interface to fckit
37 
38  ! Progression print
39  integer :: nprog ! Progression array size
40  integer :: progint ! Progression integer
41  logical,allocatable :: done(:) ! Progression array
42 
43  ! Display colors
44  character(len=1024) :: black ! Black color code
45  character(len=1024) :: green ! Green color code
46  character(len=1024) :: peach ! Peach color code
47  character(len=1024) :: aqua ! Aqua color code
48  character(len=1024) :: purple ! Purple color code
49  character(len=1024) :: err ! Error color code
50  character(len=1024) :: wng ! Warning color code
51 
52  ! Vertical unit
53  character(len=1024) :: vunitchar ! Vertical unit
54 contains
55  procedure :: newunit => mpl_newunit
56  procedure :: init => mpl_init
57  procedure :: final => mpl_final
58  procedure :: init_listing => mpl_init_listing
59  procedure :: abort => mpl_abort
60  procedure :: warning => mpl_warning
61  procedure :: prog_init => mpl_prog_init
62  procedure :: prog_print => mpl_prog_print
63  procedure :: ncerr => mpl_ncerr
64  procedure :: update_tag => mpl_update_tag
65  procedure :: bcast => mpl_bcast_string_1d
66  procedure :: mpl_dot_prod_1d
67  procedure :: mpl_dot_prod_2d
68  procedure :: mpl_dot_prod_3d
69  procedure :: mpl_dot_prod_4d
71  procedure :: split => mpl_split
72  procedure :: glb_to_loc_index => mpl_glb_to_loc_index
80 end type mpl_type
81 
82 private
83 public :: mpl_type
84 
85 contains
86 
87 !----------------------------------------------------------------------
88 ! Subroutine: mpl_newunit
89 ! Purpose: find a free unit
90 !----------------------------------------------------------------------
91 subroutine mpl_newunit(mpl,lunit)
92 
93 implicit none
94 
95 ! Passed variables
96 class(mpl_type),intent(in) :: mpl ! MPI data
97 integer,intent(out) :: lunit ! New unit
98 
99 ! Local variables
100 integer :: lun
101 logical :: lopened
102 
103 ! Loop over possible units
104 do lun=lunit_min,lunit_max
105  inquire(unit=lun,opened=lopened)
106  if (.not.lopened) then
107  lunit=lun
108  exit
109  end if
110 end do
111 
112 ! Check
113 if (lopened) call mpl%abort('cannot find a free unit')
114 
115 end subroutine mpl_newunit
116 
117 !----------------------------------------------------------------------
118 ! Subroutine: mpl_init
119 ! Purpose: initialize MPL object
120 !----------------------------------------------------------------------
121 subroutine mpl_init(mpl)
123 implicit none
124 
125 ! Passed variables
126 class(mpl_type),intent(inout) :: mpl ! MPI data
127 
128 ! Get MPI communicator
129 mpl%f_comm = fckit_mpi_comm()
130 
131 ! Get MPI size
132 mpl%nproc = mpl%f_comm%size()
133 
134 ! Get MPI rank
135 mpl%myproc = mpl%f_comm%rank()+1
136 
137 ! Define main task
138 mpl%ioproc = 1
139 mpl%main = (mpl%myproc==mpl%ioproc)
140 
141 ! Time-based tag
142 if (mpl%main) then
143  call system_clock(count=mpl%tag)
144  call mpl%update_tag(0)
145 end if
146 call mpl%f_comm%broadcast(mpl%tag,mpl%ioproc-1)
147 
148 ! Set max number of OpenMP threads
149 mpl%nthread = 1
150 !$ mpl%nthread = omp_get_max_threads()
151 !$ call omp_set_num_threads(mpl%nthread)
152 
153 end subroutine mpl_init
154 
155 !----------------------------------------------------------------------
156 ! Subroutine: mpl_final
157 ! Purpose: finalize MPI
158 !----------------------------------------------------------------------
159 subroutine mpl_final(mpl)
161 implicit none
162 
163 ! Passed variables
164 class(mpl_type),intent(inout) :: mpl ! MPI data
165 
166 ! Finalize MPI communicator
167 call mpl%f_comm%final
168 
169 end subroutine mpl_final
170 
171 !----------------------------------------------------------------------
172 ! Subroutine: mpl_init_listing
173 ! Purpose: initialize listings
174 !----------------------------------------------------------------------
175 subroutine mpl_init_listing(mpl,prefix,model,colorlog,logpres,lunit)
177 implicit none
178 
179 ! Passed variables
180 class(mpl_type),intent(inout) :: mpl ! MPI data
181 character(len=*),intent(in) :: prefix ! Output prefix
182 character(len=*),intent(in) :: model ! Model
183 logical,intent(in) :: colorlog ! Color listing flag
184 logical,intent(in) :: logpres ! Vertical unit flag
185 integer,intent(in),optional :: lunit ! Main listing unit
186 
187 ! Local variables
188 integer :: iproc
189 character(len=1024) :: filename
190 
191 ! Setup display colors
192 if (colorlog) then
193  mpl%black = char(27)//'[0;0m'
194  mpl%green = char(27)//'[0;32m'
195  mpl%peach = char(27)//'[1;91m'
196  mpl%aqua = char(27)//'[1;36m'
197  mpl%purple = char(27)//'[1;35m'
198  mpl%err = char(27)//'[0;37;41;1m'
199  mpl%wng = char(27)//'[0;37;42;1m'
200 else
201  mpl%black = ' '
202  mpl%green = ' '
203  mpl%peach = ' '
204  mpl%aqua = ' '
205  mpl%purple = ' '
206  mpl%err = ' '
207  mpl%wng = ' '
208 end if
209 
210 ! Vertical unit
211 if (trim(model)=='online') then
212  mpl%vunitchar = 'vert. unit'
213 else
214  if (logpres) then
215  mpl%vunitchar = 'log(Pa)'
216  else
217  mpl%vunitchar = 'lev.'
218  end if
219 end if
220 
221 ! Define info unit and open file
222 do iproc=1,mpl%nproc
223  if (mpl%main.and.present(lunit)) then
224  ! Specific listing unit
225  mpl%info = lunit
226  else
227  ! Deal with each proc sequentially
228  if (iproc==mpl%myproc) then
229  ! Find a free unit
230  call mpl%newunit(mpl%info)
231 
232  ! Open listing file
233  write(filename,'(a,i4.4)') trim(prefix)//'.info.',mpl%myproc-1
234  open(unit=mpl%info,file=trim(filename),action='write',status='replace')
235  end if
236  end if
237 
238  ! Wait
239  call mpl%f_comm%barrier
240 end do
241 
242 ! Define test unit and open file
243 do iproc=1,mpl%nproc
244  ! Deal with each proc sequentially
245  if (iproc==mpl%myproc) then
246  ! Find a free unit
247  call mpl%newunit(mpl%test)
248 
249  ! Open listing file
250  write(filename,'(a,i4.4)') trim(prefix)//'.test.',mpl%myproc-1
251  open(unit=mpl%test,file=trim(filename),action='write',status='replace')
252  end if
253 
254  ! Wait
255  call mpl%f_comm%barrier
256 end do
257 
258 end subroutine mpl_init_listing
259 
260 !----------------------------------------------------------------------
261 ! Subroutine: mpl_abort
262 ! Purpose: clean MPI abort
263 !----------------------------------------------------------------------
264 subroutine mpl_abort(mpl,message)
266 implicit none
267 
268 ! Passed variable
269 class(mpl_type),intent(in) :: mpl ! MPI data
270 character(len=*),intent(in) :: message ! Message
271 
272 ! Write message
273 write(mpl%info,'(a)') trim(mpl%err)//'!!! Error: '//trim(message)//trim(mpl%black)
274 call flush(mpl%info)
275 
276 ! Write message
277 write(output_unit,'(a,i4.4,a)') '!!! ABORT on task #',mpl%myproc,': '//trim(message)
278 call flush(output_unit)
279 
280 ! Flush test
281 call flush(mpl%test)
282 
283 ! Abort MPI
284 call mpl%f_comm%abort(1)
285 
286 end subroutine mpl_abort
287 
288 !----------------------------------------------------------------------
289 ! Subroutine: mpl_warning
290 ! Purpose: print warning message
291 !----------------------------------------------------------------------
292 subroutine mpl_warning(mpl,message)
294 implicit none
295 
296 ! Passed variables
297 class(mpl_type),intent(in) :: mpl ! MPI data
298 character(len=*),intent(in) :: message ! Message
299 
300 ! Print warning message
301 write(mpl%info,'(a)') trim(mpl%wng)//'!!! Warning: '//trim(message)//trim(mpl%black)
302 call flush(mpl%info)
303 
304 end subroutine mpl_warning
305 
306 !----------------------------------------------------------------------
307 ! Subroutine: prog_init
308 ! Purpose: initialize progression display
309 !----------------------------------------------------------------------
310 subroutine mpl_prog_init(mpl,nprog)
312 implicit none
313 
314 ! Passed variables
315 class(mpl_type),intent(inout) :: mpl ! MPI data
316 integer,intent(in) :: nprog ! Array size
317 
318 ! Print message
319 write(mpl%info,'(i3,a)',advance='no') 0,'%'
320 call flush(mpl%info)
321 
322 ! Allocation
323 if (allocated(mpl%done)) deallocate(mpl%done)
324 allocate(mpl%done(nprog))
325 
326 ! Initialization
327 mpl%nprog = nprog
328 mpl%progint = ddis
329 mpl%done = .false.
330 
331 end subroutine mpl_prog_init
332 
333 !----------------------------------------------------------------------
334 ! Subroutine: mpl_prog_print
335 ! Purpose: print progression display
336 !----------------------------------------------------------------------
337 subroutine mpl_prog_print(mpl,i)
339 implicit none
340 
341 ! Passed variables
342 class(mpl_type),intent(inout) :: mpl ! MPI data
343 integer,intent(in),optional :: i ! Index
344 
345 ! Local variables
346 real(kind_real) :: prog
347 
348 ! Update progression array
349 if (present(i)) mpl%done(i) = .true.
350 
351 ! Print message
352 prog = 100.0*real(count(mpl%done),kind_real)/real(mpl%nprog,kind_real)
353 if (int(prog)>mpl%progint) then
354  if (mpl%progint<100) then
355  write(mpl%info,'(i3,a)',advance='no') mpl%progint,'% '
356  call flush(mpl%info)
357  end if
358  mpl%progint = mpl%progint+ddis
359 end if
360 
361 end subroutine mpl_prog_print
362 
363 !----------------------------------------------------------------------
364 ! Subroutine: mpl_ncerr
365 ! Purpose: handle NetCDF error
366 !----------------------------------------------------------------------
367 subroutine mpl_ncerr(mpl,subr,info)
369 implicit none
370 
371 ! Passed variables
372 class(mpl_type),intent(in) :: mpl ! MPI data
373 character(len=*),intent(in) :: subr ! Calling subroutine
374 integer,intent(in) :: info ! Info index
375 
376 ! Check status
377 if (info/=nf90_noerr) call mpl%abort('in '//trim(subr)//': '//trim(nf90_strerror(info)))
378 
379 end subroutine mpl_ncerr
380 
381 !----------------------------------------------------------------------
382 ! Subroutine: mpl_update_tag
383 ! Purpose: update MPL tag
384 !----------------------------------------------------------------------
385 subroutine mpl_update_tag(mpl,add)
387 implicit none
388 
389 ! Passed variables
390 class(mpl_type),intent(inout) :: mpl ! MPI data
391 integer,intent(in) :: add ! Tag update incrememnt
392 
393 ! Update tag
394 mpl%tag = mpl%tag+add
395 
396 ! Apply bounds (between 1 and 10000)
397 mpl%tag = mod(mpl%tag,10000)
398 mpl%tag = max(mpl%tag,1)
399 
400 end subroutine mpl_update_tag
401 
402 !----------------------------------------------------------------------
403 ! Subroutine: mpl_bcast_string_1d
404 ! Purpose: broadcast 1d string array
405 !----------------------------------------------------------------------
406 subroutine mpl_bcast_string_1d(mpl,var,root)
408 implicit none
409 
410 ! Passed variables
411 class(mpl_type),intent(in) :: mpl ! MPI data
412 character(len=*),dimension(:),intent(inout) :: var ! Logical array, 1d
413 integer,intent(in) :: root ! Root task
414 
415 ! Local variable
416 integer :: i
417 
418 ! Broadcast one string at a time
419 do i=1,size(var)
420  call mpl%f_comm%broadcast(var(i),root)
421 end do
422 
423 end subroutine mpl_bcast_string_1d
424 
425 !----------------------------------------------------------------------
426 ! Subroutine: mpl_dot_prod_1d
427 ! Purpose: global dot product over local fields, 1d
428 !----------------------------------------------------------------------
429 subroutine mpl_dot_prod_1d(mpl,fld1,fld2,dp)
431 implicit none
432 
433 ! Passed variables
434 class(mpl_type),intent(in) :: mpl ! MPI data
435 real(kind_real),intent(in) :: fld1(:) ! Field 1
436 real(kind_real),intent(in) :: fld2(:) ! Field 2
437 real(kind_real),intent(out) :: dp ! Global dot product
438 
439 ! Local variable
440 real(kind_real) :: dp_loc(1),dp_out(1)
441 
442 ! Product and sum
443 dp_loc(1) = sum(fld1*fld2)
444 
445 ! Allreduce
446 call mpl%f_comm%allreduce(dp_loc,dp_out,fckit_mpi_sum())
447 
448 dp = dp_out(1)
449 
450 ! Broadcast
451 call mpl%f_comm%broadcast(dp,mpl%ioproc-1)
452 
453 end subroutine mpl_dot_prod_1d
454 
455 !----------------------------------------------------------------------
456 ! Subroutine: mpl_dot_prod_2d
457 ! Purpose: global dot product over local fields, 2d
458 !----------------------------------------------------------------------
459 subroutine mpl_dot_prod_2d(mpl,fld1,fld2,dp)
461 implicit none
462 
463 ! Passed variables
464 class(mpl_type),intent(in) :: mpl ! MPI data
465 real(kind_real),intent(in) :: fld1(:,:) ! Field 1
466 real(kind_real),intent(in) :: fld2(:,:) ! Field 2
467 real(kind_real),intent(out) :: dp ! Global dot product
468 
469 ! Local variable
470 real(kind_real) :: dp_loc(1),dp_out(1)
471 
472 ! Product and sum
473 dp_loc(1) = sum(fld1*fld2)
474 
475 ! Allreduce
476 call mpl%f_comm%allreduce(dp_loc,dp_out,fckit_mpi_sum())
477 dp = dp_out(1)
478 
479 ! Broadcast
480 call mpl%f_comm%broadcast(dp,mpl%ioproc-1)
481 
482 end subroutine mpl_dot_prod_2d
483 
484 !----------------------------------------------------------------------
485 ! Subroutine: mpl_dot_prod_3d
486 ! Purpose: global dot product over local fields, 3d
487 !----------------------------------------------------------------------
488 subroutine mpl_dot_prod_3d(mpl,fld1,fld2,dp)
490 implicit none
491 
492 ! Passed variables
493 class(mpl_type),intent(in) :: mpl ! MPI data
494 real(kind_real),intent(in) :: fld1(:,:,:) ! Field 1
495 real(kind_real),intent(in) :: fld2(:,:,:) ! Field 2
496 real(kind_real),intent(out) :: dp ! Global dot product
497 
498 ! Local variable
499 real(kind_real) :: dp_loc(1),dp_out(1)
500 
501 ! Product and sum
502 dp_loc(1) = sum(fld1*fld2)
503 
504 ! Allreduce
505 call mpl%f_comm%allreduce(dp_loc,dp_out,fckit_mpi_sum())
506 dp = dp_out(1)
507 
508 ! Broadcast
509 call mpl%f_comm%broadcast(dp,mpl%ioproc-1)
510 
511 end subroutine mpl_dot_prod_3d
512 
513 !----------------------------------------------------------------------
514 ! Subroutine: mpl_dot_prod_4d
515 ! Purpose: global dot product over local fields, 4d
516 !----------------------------------------------------------------------
517 subroutine mpl_dot_prod_4d(mpl,fld1,fld2,dp)
519 implicit none
520 
521 ! Passed variables
522 class(mpl_type),intent(in) :: mpl ! MPI data
523 real(kind_real),intent(in) :: fld1(:,:,:,:) ! Field 1
524 real(kind_real),intent(in) :: fld2(:,:,:,:) ! Field 2
525 real(kind_real),intent(out) :: dp ! Global dot product
526 
527 ! Local variable
528 real(kind_real) :: dp_loc(1),dp_out(1)
529 
530 ! Product and sum
531 dp_loc(1) = sum(fld1*fld2)
532 
533 ! Allreduce
534 call mpl%f_comm%allreduce(dp_loc,dp_out,fckit_mpi_sum())
535 dp = dp_out(1)
536 
537 ! Broadcast
538 call mpl%f_comm%broadcast(dp,mpl%ioproc-1)
539 
540 end subroutine mpl_dot_prod_4d
541 
542 !----------------------------------------------------------------------
543 ! Subroutine: mpl_split
544 ! Purpose: split array over different MPI tasks
545 !----------------------------------------------------------------------
546 subroutine mpl_split(mpl,n,i_s,i_e,n_loc)
548 implicit none
549 
550 ! Passed variables
551 class(mpl_type),intent(in) :: mpl ! MPI data
552 integer,intent(in) :: n ! Total array size
553 integer,intent(out) :: i_s(mpl%nproc) ! Index start
554 integer,intent(out) :: i_e(mpl%nproc) ! Index end
555 integer,intent(out) :: n_loc(mpl%nproc) ! Local array size
556 
557 ! Local variable
558 integer :: iproc,nres,delta
559 
560 ! MPI splitting
561 nres = n
562 do iproc=1,mpl%nproc
563  if (iproc==1) then
564  i_s(iproc) = 1
565  else
566  i_s(iproc) = i_e(iproc-1)+1
567  end if
568  delta = n/mpl%nproc
569  if (nres>(mpl%nproc-iproc+1)*delta) delta = delta+1
570  i_e(iproc) = i_s(iproc)+delta-1
571  n_loc(iproc) = delta
572  nres = nres-delta
573 end do
574 
575 end subroutine mpl_split
576 
577 !----------------------------------------------------------------------
578 ! Subroutine: mpl_glb_to_loc_index
579 ! Purpose: communicate global index to local index
580 !----------------------------------------------------------------------
581 subroutine mpl_glb_to_loc_index(mpl,n_loc,loc_to_glb,n_glb,glb_to_loc)
583 implicit none
584 
585 ! Passed variables
586 class(mpl_type),intent(inout) :: mpl ! MPI data
587 integer,intent(in) :: n_loc ! Local dimension
588 integer,intent(in) :: loc_to_glb(n_loc) ! Local to global index
589 integer,intent(in) :: n_glb ! Global dimension
590 integer,intent(out) :: glb_to_loc(n_glb) ! Global to local index
591 
592 ! Local variables
593 integer :: iproc,i_loc,n_loc_tmp
594 integer,allocatable :: loc_to_glb_tmp(:)
595 type(fckit_mpi_status) :: status
596 
597 if (mpl%main) then
598  do iproc=1,mpl%nproc
599  if (iproc==mpl%ioproc) then
600  ! Copy dimension
601  n_loc_tmp = n_loc
602  else
603  ! Receive dimension on ioproc
604  call mpl%f_comm%receive(n_loc_tmp,iproc-1,mpl%tag,status)
605  end if
606 
607  ! Allocation
608  allocate(loc_to_glb_tmp(n_loc_tmp))
609 
610  if (iproc==mpl%ioproc) then
611  ! Copy data
612  loc_to_glb_tmp = loc_to_glb
613  else
614  ! Receive data on ioproc
615  call mpl%f_comm%receive(loc_to_glb_tmp,iproc-1,mpl%tag+1,status)
616  end if
617 
618  ! Fill glb_to_loc
619  do i_loc=1,n_loc_tmp
620  glb_to_loc(loc_to_glb_tmp(i_loc)) = i_loc
621  end do
622 
623  ! Release memory
624  deallocate(loc_to_glb_tmp)
625  end do
626 else
627  ! Send dimensions to ioproc
628  call mpl%f_comm%send(n_loc,mpl%ioproc-1,mpl%tag)
629 
630  ! Send data to ioproc
631  call mpl%f_comm%send(loc_to_glb,mpl%ioproc-1,mpl%tag+1)
632 end if
633 call mpl%update_tag(2)
634 
635 ! Broadcast
636 call mpl%f_comm%broadcast(glb_to_loc,mpl%ioproc-1)
637 
638 end subroutine mpl_glb_to_loc_index
639 
640 !----------------------------------------------------------------------
641 ! Subroutine: mpl_glb_to_loc_real_1d
642 ! Purpose: global to local, 1d array
643 !----------------------------------------------------------------------
644 subroutine mpl_glb_to_loc_real_1d(mpl,n_glb,glb_to_proc,glb_to_loc,glb,n_loc,loc)
646 implicit none
647 
648 ! Passed variables
649 class(mpl_type),intent(inout) :: mpl ! MPI data
650 integer,intent(in) :: n_glb ! Global array size
651 integer,intent(in) :: glb_to_proc(n_glb) ! Global index to task index
652 integer,intent(in) :: glb_to_loc(n_glb) ! Global index to local index
653 real(kind_real),intent(in) :: glb(:) ! Global array
654 integer,intent(in) :: n_loc ! Local array size
655 real(kind_real),intent(out) :: loc(n_loc) ! Local array
656 type(fckit_mpi_status) :: status
657 
658 ! Local variables
659 integer :: iproc,jproc,i_glb,i_loc,n_loc_tmp
660 real(kind_real),allocatable :: sbuf(:)
661 
662 ! Check global array size
663 if (mpl%main) then
664  if (size(glb)/=n_glb) call mpl%abort('wrong dimension for the global array in mpl_glb_to_loc_real_1d')
665 end if
666 
667 if (mpl%main) then
668  do iproc=1,mpl%nproc
669  ! Allocation
670  n_loc_tmp = count(glb_to_proc==iproc)
671  allocate(sbuf(n_loc_tmp))
672 
673  ! Prepare buffers
674  do i_glb=1,n_glb
675  jproc = glb_to_proc(i_glb)
676  if (iproc==jproc) then
677  i_loc = glb_to_loc(i_glb)
678  sbuf(i_loc) = glb(i_glb)
679  end if
680  end do
681 
682  if (iproc==mpl%ioproc) then
683  ! Copy data
684  loc = sbuf
685  else
686  ! Send data to iproc
687  call mpl%f_comm%send(sbuf,iproc-1,mpl%tag)
688  end if
689 
690  ! Release memory
691  deallocate(sbuf)
692  end do
693 else
694  ! Receive data from ioproc
695  call mpl%f_comm%receive(loc,mpl%ioproc-1,mpl%tag,status)
696 end if
697 call mpl%update_tag(1)
698 
699 end subroutine mpl_glb_to_loc_real_1d
700 
701 !----------------------------------------------------------------------
702 ! Subroutine: mpl_glb_to_loc_real_2d
703 ! Purpose: global to local, 2d array
704 !----------------------------------------------------------------------
705 subroutine mpl_glb_to_loc_real_2d(mpl,nl,n_glb,glb_to_proc,glb_to_loc,glb,n_loc,loc)
707 implicit none
708 
709 ! Passed variables
710 class(mpl_type),intent(inout) :: mpl ! MPI data
711 integer,intent(in) :: nl ! Number of levels
712 integer,intent(in) :: n_glb ! Global array size
713 integer,intent(in) :: glb_to_proc(n_glb) ! Global index to task index
714 integer,intent(in) :: glb_to_loc(n_glb) ! Global index to local index
715 real(kind_real),intent(in) :: glb(:,:) ! Global array
716 integer,intent(in) :: n_loc ! Local array size
717 real(kind_real),intent(out) :: loc(n_loc,nl) ! Local array
718 
719 ! Local variables
720 integer :: iproc,jproc,i_glb,i_loc,n_loc_tmp,il
721 real(kind_real),allocatable :: sbuf(:),rbuf(:)
722 type(fckit_mpi_status) :: status
723 
724 ! Check global array size
725 if (mpl%main) then
726  if (size(glb,1)/=n_glb) call mpl%abort('wrong first dimension for the global array in mpl_glb_to_loc_real_2d')
727  if (size(glb,2)/=nl) call mpl%abort('wrong second dimension for the global array in mpl_glb_to_loc_real_2d')
728 end if
729 
730 ! Allocation
731 allocate(rbuf(n_loc*nl))
732 if (mpl%main) then
733  do iproc=1,mpl%nproc
734  ! Allocation
735  n_loc_tmp = count(glb_to_proc==iproc)
736  allocate(sbuf(n_loc_tmp*nl))
737 
738  ! Prepare buffers
739  do i_glb=1,n_glb
740  jproc = glb_to_proc(i_glb)
741  if (iproc==jproc) then
742  i_loc = glb_to_loc(i_glb)
743  do il=1,nl
744  sbuf((il-1)*n_loc_tmp+i_loc) = glb(i_glb,il)
745  end do
746  end if
747  end do
748 
749  if (iproc==mpl%ioproc) then
750  ! Copy data
751  rbuf = sbuf
752  else
753  ! Send data to iproc
754  call mpl%f_comm%send(sbuf,iproc-1,mpl%tag)
755  end if
756 
757  ! Release memory
758  deallocate(sbuf)
759  end do
760 else
761  ! Receive data from ioproc
762  call mpl%f_comm%receive(rbuf,mpl%ioproc-1,mpl%tag,status)
763 end if
764 call mpl%update_tag(1)
765 
766 ! Unpack buffer
767 do il=1,nl
768  do i_loc=1,n_loc
769  loc(i_loc,il) = rbuf((il-1)*n_loc+i_loc)
770  end do
771 end do
772 
773 end subroutine mpl_glb_to_loc_real_2d
774 
775 !----------------------------------------------------------------------
776 ! Subroutine: mpl_loc_to_glb_real_1d
777 ! Purpose: local to global, 1d array
778 !----------------------------------------------------------------------
779 subroutine mpl_loc_to_glb_real_1d(mpl,n_loc,loc,n_glb,glb_to_proc,glb_to_loc,bcast,glb)
781 implicit none
782 
783 ! Passed variables
784 class(mpl_type),intent(inout) :: mpl ! MPI data
785 integer,intent(in) :: n_loc ! Local array size
786 real(kind_real),intent(in) :: loc(n_loc) ! Local array
787 integer,intent(in) :: n_glb ! Global array size
788 integer,intent(in) :: glb_to_proc(n_glb) ! Global index to task index
789 integer,intent(in) :: glb_to_loc(n_glb) ! Global index to local index
790 logical,intent(in) :: bcast ! Broadcast option
791 real(kind_real),intent(out) :: glb(:) ! Global array
792 type(fckit_mpi_status) :: status
793 
794 ! Local variables
795 integer :: iproc,jproc,i_glb,i_loc,n_loc_tmp
796 real(kind_real),allocatable :: rbuf(:)
797 
798 ! Check global array size
799 if (mpl%main.or.bcast) then
800  if (size(glb)/=n_glb) call mpl%abort('wrong dimension for the global array in mpl_loc_to_glb_real_1d')
801 end if
802 
803 if (mpl%main) then
804  do iproc=1,mpl%nproc
805  ! Allocation
806  n_loc_tmp = count(glb_to_proc==iproc)
807  allocate(rbuf(n_loc_tmp))
808 
809  if (iproc==mpl%ioproc) then
810  ! Copy data
811  rbuf = loc
812  else
813  ! Receive data from iproc
814  call mpl%f_comm%receive(rbuf,iproc-1,mpl%tag,status)
815  end if
816 
817  ! Add data to glb
818  do i_glb=1,n_glb
819  jproc = glb_to_proc(i_glb)
820  if (iproc==jproc) then
821  i_loc = glb_to_loc(i_glb)
822  glb(i_glb) = rbuf(i_loc)
823  end if
824  end do
825 
826  ! Release memory
827  deallocate(rbuf)
828  end do
829 else
830  ! Send data to ioproc
831  call mpl%f_comm%send(loc,mpl%ioproc-1,mpl%tag)
832 end if
833 call mpl%update_tag(1)
834 
835 ! Broadcast
836 if (bcast) call mpl%f_comm%broadcast(glb,mpl%ioproc-1)
837 
838 end subroutine mpl_loc_to_glb_real_1d
839 
840 !----------------------------------------------------------------------
841 ! Subroutine: mpl_loc_to_glb_real_2d
842 ! Purpose: local to global, 2d array
843 !----------------------------------------------------------------------
844 subroutine mpl_loc_to_glb_real_2d(mpl,nl,n_loc,loc,n_glb,glb_to_proc,glb_to_loc,bcast,glb)
846 implicit none
847 
848 ! Passed variables
849 class(mpl_type),intent(inout) :: mpl ! MPI data
850 integer,intent(in) :: nl ! Number of levels
851 integer,intent(in) :: n_loc ! Local array size
852 real(kind_real),intent(in) :: loc(n_loc,nl) ! Local array
853 integer,intent(in) :: n_glb ! Global array size
854 integer,intent(in) :: glb_to_proc(n_glb) ! Global index to task index
855 integer,intent(in) :: glb_to_loc(n_glb) ! Global index to local index
856 logical,intent(in) :: bcast ! Broadcast option
857 real(kind_real),intent(out) :: glb(:,:) ! Global array
858 
859 ! Local variables
860 integer :: iproc,jproc,i_glb,i_loc,n_loc_tmp,il
861 real(kind_real),allocatable :: rbuf(:),sbuf(:)
862 type(fckit_mpi_status) :: status
863 
864 ! Check global array size
865 if (mpl%main.or.bcast) then
866  if (size(glb,1)/=n_glb) call mpl%abort('wrong first dimension for the global array in mpl_loc_to_glb_real_2d')
867  if (size(glb,2)/=nl) call mpl%abort('wrong second dimension for the global array in mpl_loc_to_glb_real_1d')
868 end if
869 
870 ! Allocation
871 allocate(sbuf(n_loc*nl))
872 
873 ! Prepare buffer
874 do il=1,nl
875  do i_loc=1,n_loc
876  sbuf((il-1)*n_loc+i_loc) = loc(i_loc,il)
877  end do
878 end do
879 
880 if (mpl%main) then
881  do iproc=1,mpl%nproc
882  ! Allocation
883  n_loc_tmp = count(glb_to_proc==iproc)
884  allocate(rbuf(n_loc_tmp*nl))
885 
886  if (iproc==mpl%ioproc) then
887  ! Copy data
888  rbuf = sbuf
889  else
890  ! Receive data from iproc
891  call mpl%f_comm%receive(rbuf,iproc-1,mpl%tag,status)
892  end if
893 
894  ! Add data to glb
895  do i_glb=1,n_glb
896  jproc = glb_to_proc(i_glb)
897  if (iproc==jproc) then
898  i_loc = glb_to_loc(i_glb)
899  do il=1,nl
900  glb(i_glb,il) = rbuf((il-1)*n_loc_tmp+i_loc)
901  end do
902  end if
903  end do
904 
905  ! Release memory
906  deallocate(rbuf)
907  end do
908 else
909  ! Send data to ioproc
910  call mpl%f_comm%send(sbuf,mpl%ioproc-1,mpl%tag)
911 end if
912 call mpl%update_tag(1)
913 
914 ! Broadcast
915 if (bcast) call mpl%f_comm%broadcast(glb,mpl%ioproc-1)
916 
917 end subroutine mpl_loc_to_glb_real_2d
918 
919 !----------------------------------------------------------------------
920 ! Subroutine: mpl_loc_to_glb_logical_2d
921 ! Purpose: local to global for a logical, 2d array
922 !----------------------------------------------------------------------
923 subroutine mpl_loc_to_glb_logical_2d(mpl,nl,n_loc,loc,n_glb,glb_to_proc,glb_to_loc,bcast,glb)
925 implicit none
926 
927 ! Passed variables
928 class(mpl_type),intent(inout) :: mpl ! MPI data
929 integer,intent(in) :: nl ! Number of levels
930 integer,intent(in) :: n_loc ! Local array size
931 logical,intent(in) :: loc(n_loc,nl) ! Local array
932 integer,intent(in) :: n_glb ! Global array size
933 integer,intent(in) :: glb_to_proc(n_glb) ! Global index to task index
934 integer,intent(in) :: glb_to_loc(n_glb) ! Global index to local index
935 logical,intent(in) :: bcast ! Broadcast option
936 logical,intent(out) :: glb(:,:) ! Global array
937 
938 ! Local variables
939 integer :: iproc,jproc,i_glb,i_loc,n_loc_tmp,il
940 logical,allocatable :: rbuf(:),sbuf(:)
941 type(fckit_mpi_status) :: status
942 
943 ! Check global array size
944 if (mpl%main.or.bcast) then
945  if (size(glb,1)/=n_glb) call mpl%abort('wrong first dimension for the global array in mpl_loc_to_glb_real_2d')
946  if (size(glb,2)/=nl) call mpl%abort('wrong second dimension for the global array in mpl_loc_to_glb_real_1d')
947 end if
948 
949 ! Allocation
950 allocate(sbuf(n_loc*nl))
951 
952 ! Prepare buffer
953 do il=1,nl
954  do i_loc=1,n_loc
955  sbuf((il-1)*n_loc+i_loc) = loc(i_loc,il)
956  end do
957 end do
958 
959 if (mpl%main) then
960  do iproc=1,mpl%nproc
961  ! Allocation
962  n_loc_tmp = count(glb_to_proc==iproc)
963  allocate(rbuf(n_loc_tmp*nl))
964 
965  if (iproc==mpl%ioproc) then
966  ! Copy data
967  rbuf = sbuf
968  else
969  ! Receive data from iproc
970  call mpl%f_comm%receive(rbuf,iproc-1,mpl%tag,status)
971  end if
972 
973  ! Add data to glb
974  do i_glb=1,n_glb
975  jproc = glb_to_proc(i_glb)
976  if (iproc==jproc) then
977  i_loc = glb_to_loc(i_glb)
978  do il=1,nl
979  glb(i_glb,il) = rbuf((il-1)*n_loc_tmp+i_loc)
980  end do
981  end if
982  end do
983 
984  ! Release memory
985  deallocate(rbuf)
986  end do
987 else
988  ! Send data to ioproc
989  call mpl%f_comm%send(sbuf,mpl%ioproc-1,mpl%tag)
990 end if
991 call mpl%update_tag(1)
992 
993 ! Broadcast
994 if (bcast) call mpl%f_comm%broadcast(glb,mpl%ioproc-1)
995 
996 end subroutine mpl_loc_to_glb_logical_2d
997 
998 end module type_mpl
subroutine mpl_newunit(mpl, lunit)
Definition: type_mpl.F90:92
subroutine mpl_bcast_string_1d(mpl, var, root)
Definition: type_mpl.F90:407
subroutine mpl_update_tag(mpl, add)
Definition: type_mpl.F90:386
subroutine mpl_init_listing(mpl, prefix, model, colorlog, logpres, lunit)
Definition: type_mpl.F90:176
integer, parameter, public msvali
Definition: tools_const.F90:23
subroutine mpl_prog_init(mpl, nprog)
Definition: type_mpl.F90:311
subroutine mpl_ncerr(mpl, subr, info)
Definition: type_mpl.F90:368
subroutine mpl_loc_to_glb_logical_2d(mpl, nl, n_loc, loc, n_glb, glb_to_proc, glb_to_loc, bcast, glb)
Definition: type_mpl.F90:924
subroutine mpl_dot_prod_1d(mpl, fld1, fld2, dp)
Definition: type_mpl.F90:430
subroutine mpl_loc_to_glb_real_2d(mpl, nl, n_loc, loc, n_glb, glb_to_proc, glb_to_loc, bcast, glb)
Definition: type_mpl.F90:845
real(kind_real), parameter, public msvalr
Definition: tools_const.F90:24
subroutine mpl_warning(mpl, message)
Definition: type_mpl.F90:293
subroutine mpl_dot_prod_3d(mpl, fld1, fld2, dp)
Definition: type_mpl.F90:489
subroutine mpl_prog_print(mpl, i)
Definition: type_mpl.F90:338
subroutine ncerr(info)
Definition: qg_fields.F90:1720
integer, parameter ddis
Definition: type_mpl.F90:23
subroutine mpl_dot_prod_2d(mpl, fld1, fld2, dp)
Definition: type_mpl.F90:460
subroutine mpl_loc_to_glb_real_1d(mpl, n_loc, loc, n_glb, glb_to_proc, glb_to_loc, bcast, glb)
Definition: type_mpl.F90:780
subroutine mpl_glb_to_loc_real_2d(mpl, nl, n_glb, glb_to_proc, glb_to_loc, glb, n_loc, loc)
Definition: type_mpl.F90:706
subroutine, public dot_prod(fld1, fld2, zprod)
Definition: qg_fields.F90:355
#define max(a, b)
Definition: mosaic_util.h:33
subroutine mpl_glb_to_loc_real_1d(mpl, n_glb, glb_to_proc, glb_to_loc, glb, n_loc, loc)
Definition: type_mpl.F90:645
subroutine mpl_glb_to_loc_index(mpl, n_loc, loc_to_glb, n_glb, glb_to_loc)
Definition: type_mpl.F90:582
subroutine mpl_split(mpl, n, i_s, i_e, n_loc)
Definition: type_mpl.F90:547
program main
Definition: xgrid.F90:5439
integer, parameter, public kind_real
subroutine mpl_dot_prod_4d(mpl, fld1, fld2, dp)
Definition: type_mpl.F90:518
integer, parameter lunit_max
Definition: type_mpl.F90:22
subroutine mpl_final(mpl)
Definition: type_mpl.F90:160
subroutine mpl_init(mpl)
Definition: type_mpl.F90:122
subroutine mpl_abort(mpl, message)
Definition: type_mpl.F90:265
integer, parameter lunit_min
Definition: type_mpl.F90:21