arr_decomp.F90 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368
  1. !
  2. #define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
  3. #define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
  4. #define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if
  5. !
  6. #define IF_NOTOK_MPI(action) if (ierr/=MPI_SUCCESS) then; TRACEBACK; action; return; end if
  7. !
  8. #include "tm5.inc"
  9. !
  10. !----------------------------------------------------------------------------
  11. ! TM5 !
  12. !----------------------------------------------------------------------------
  13. !BOP
  14. !
  15. ! !MODULE: ARR_DECOMP
  16. !
  17. ! !DESCRIPTION: Define a distributed ARRAY object and its methods.
  18. ! This is regardless of the lat/lon grid, i.e. can be applied
  19. ! to any 1- or 2D array.
  20. !
  21. ! ** ARRAYS ARE EVENLY DISRIBUTED ALONG THE 1ST DIMENSION ONLY **
  22. !
  23. ! See subroutine TESTDA for basic examples.
  24. !\\
  25. !\\
  26. ! !INTERFACE:
  27. !
  28. MODULE ARR_DECOMP
  29. !
  30. ! !USES:
  31. !
  32. use Go, only : goErr, goPr, gol ! go = general objects
  33. use dims, only : okdebug
  34. use partools ! to include mpif.h, ierr, localComm,...
  35. IMPLICIT NONE
  36. PRIVATE
  37. !
  38. ! !PUBLIC MEMBER FUNCTIONS:
  39. !
  40. public :: Set_Darr, Done_Darr ! life cycle routines
  41. public :: testda ! unit test
  42. public :: Get_Darr
  43. public :: GATHER, SCATTER ! communication routines
  44. !
  45. ! !PUBLIC TYPES:
  46. !
  47. TYPE, PUBLIC :: DIST_ARR
  48. PRIVATE
  49. integer :: im ! global size, 1st dim
  50. integer :: jm ! global size, 2nd dim if any
  51. integer :: i_strt ! begin local arr index
  52. integer :: i_stop ! end local arr index
  53. logical :: lactiv ! may be inactive if there are more processors than data
  54. ! i_start, i_stop of all PEs: (2,npes)
  55. integer, pointer :: bounds(:,:)
  56. END TYPE DIST_ARR
  57. !
  58. ! !PRIVATE DATA MEMBERS:
  59. !
  60. character(len=*), parameter :: mname='Arr_Decomp_MOD_'
  61. !
  62. ! !INTERFACE:
  63. !
  64. INTERFACE Gather
  65. MODULE PROCEDURE gather_1d_i
  66. MODULE PROCEDURE gather_1d_r
  67. MODULE PROCEDURE gather_2d_i
  68. MODULE PROCEDURE gather_2d_r
  69. END INTERFACE
  70. INTERFACE Scatter
  71. MODULE PROCEDURE scatter_1d_i
  72. MODULE PROCEDURE scatter_1d_r
  73. MODULE PROCEDURE scatter_2d_i
  74. MODULE PROCEDURE scatter_2d_r
  75. END INTERFACE
  76. !
  77. ! !REVISION HISTORY:
  78. ! Monday, May 28, 2018 - P. Le Sager - v0
  79. !
  80. ! !REMARKS:
  81. !
  82. ! (1) GATHER & SCATTER :
  83. ! - global arrays have to really be global on root only, and can be
  84. ! (1,1,..) on other processes.
  85. ! - if not using MPI, gather and scatter just copy arrays, so it may be
  86. ! better to not call them to save memory in that case.
  87. !
  88. ! (2) Be careful when passing a slice (or a pointer to a slice) as argument:
  89. !
  90. ! Passing a subarray will *NOT* work most of the time, unless it is a
  91. ! slice on the last dimension(s). This will give erroneous results:
  92. !
  93. ! allocate( gbl_arr(-3:imr, 1:jmr ))
  94. ! call gather( darr, local_arr, gbl_arr(1:imr,:), status)
  95. !
  96. ! but passing full size array will work:
  97. !
  98. ! allocate( gbl_arr(-3:imr, 1:jmr ))
  99. ! allocate( temp(1:imr,1:jmr) )
  100. ! call gather( darr, local_arr, temp, status)
  101. ! gbl_arr(1:imr,:) = temp
  102. !EOP
  103. !------------------------------------------------------------------------
  104. CONTAINS
  105. !--------------------------------------------------------------------------
  106. ! TM5 !
  107. !--------------------------------------------------------------------------
  108. !BOP
  109. !
  110. ! !IROUTINE: DARR_RANGE
  111. !
  112. ! !DESCRIPTION: Give range of indices covered by rank when using nprocs.
  113. ! This is used for one dimension.
  114. ! Distribution is done evenly. Eg: it will distribute 11 boxes
  115. ! across 3 processes as 4,4,3 on each pe.
  116. !\\
  117. !\\
  118. ! !INTERFACE:
  119. !
  120. SUBROUTINE DARR_RANGE(ij, rank, nprocs, istart, iend)
  121. !
  122. ! !INPUT PARAMETERS:
  123. !
  124. integer, intent(in) :: ij ! range (1,..,ij) to be distributed
  125. integer, intent(in) :: rank ! current process, in (0,.., nprocs-1)
  126. integer, intent(in) :: nprocs ! total # of processes
  127. !
  128. ! !OUTPUT PARAMETERS:
  129. !
  130. integer, intent(out):: istart, iend ! index range covered by rank
  131. !
  132. !EOP
  133. !------------------------------------------------------------------------
  134. !BOC
  135. integer :: iwork1, iwork2
  136. iwork1 = ij/nprocs
  137. iwork2 = mod(ij,nprocs)
  138. istart = rank * iwork1 + 1 + min(rank, iwork2)
  139. iend = istart + iwork1 - 1
  140. if (iwork2 > rank) iend = iend + 1
  141. END SUBROUTINE DARR_RANGE
  142. !EOC
  143. !--------------------------------------------------------------------------
  144. ! TM5 !
  145. !--------------------------------------------------------------------------
  146. !BOP
  147. !
  148. ! !IROUTINE: SET_DARR
  149. !
  150. ! !DESCRIPTION: initialize a distributed array object
  151. !\\
  152. !\\
  153. ! !INTERFACE:
  154. !
  155. SUBROUTINE SET_DARR( darr, im, istart, iend, status, jm)
  156. !
  157. ! !USES:
  158. !
  159. !
  160. ! !RETURN VALUE:
  161. !
  162. type(dist_arr), intent(inout) :: darr
  163. !
  164. ! !INPUT PARAMETERS:
  165. !
  166. integer, intent(in) :: im ! number of points to distribute - 1st dimension of global array
  167. integer, optional, intent(in) :: jm ! 2nd dimension of global array - default is 0
  168. !
  169. ! !OUTPUT PARAMETERS:
  170. !
  171. integer, intent(out) :: istart, iend, status
  172. !
  173. !EOP
  174. !------------------------------------------------------------------------
  175. !BOC
  176. character(len=*), parameter :: rname = mname//'set_darr'
  177. integer :: lshape(2)
  178. !---------------------------------------------
  179. ! initialize distributed array info
  180. !---------------------------------------------
  181. call done_darr(darr, status)
  182. call darr_range(im, myid, npes, istart, iend) ! index range covered by current process
  183. ! Need to acount for array size smaller than the number of available processor. Just inactivate
  184. ! the processors.
  185. darr%lactiv = .true.
  186. if ( (iend-istart+1) < 1 ) then
  187. write(gol,*)" Inactivate ", myid
  188. darr%lactiv = .false.
  189. end if
  190. darr%i_strt = istart
  191. darr%i_stop = iend
  192. darr%im = im
  193. darr%jm = 0
  194. if (present(jm)) darr%jm = jm
  195. !---------------------------------------------
  196. ! store local shapes info of all PE on all PE
  197. !---------------------------------------------
  198. #ifdef MPI
  199. allocate(darr%bounds(2,0:npes-1))
  200. lshape = (/ darr%i_strt, darr%i_stop /)
  201. call MPI_ALLGATHER(lshape, 2, MPI_INTEGER, darr%bounds, 2, MPI_INTEGER, localComm, ierr)
  202. #endif
  203. status = 0
  204. END SUBROUTINE SET_DARR
  205. !EOC
  206. !--------------------------------------------------------------------------
  207. ! TM5 !
  208. !--------------------------------------------------------------------------
  209. !BOP
  210. !
  211. ! !IROUTINE: DONE_DARR
  212. !
  213. ! !DESCRIPTION: deallocate distributed object elements
  214. !\\
  215. !\\
  216. ! !INTERFACE:
  217. !
  218. SUBROUTINE DONE_DARR( darr, status )
  219. !
  220. ! !INPUT PARAMETERS:
  221. !
  222. type(dist_arr), intent(inout) :: darr
  223. !
  224. ! !OUTPUT PARAMETERS:
  225. !
  226. integer, intent(out) :: status
  227. !
  228. !EOP
  229. !------------------------------------------------------------------------
  230. !BOC
  231. character(len=*), parameter :: rname = mname//'Done_Darr'
  232. if (associated(darr%bounds)) deallocate(darr%bounds)
  233. status=0
  234. END SUBROUTINE DONE_DARR
  235. !EOC
  236. !--------------------------------------------------------------------------
  237. ! TM5 !
  238. !--------------------------------------------------------------------------
  239. !BOP
  240. !
  241. ! !IROUTINE: GET_DARR
  242. !
  243. ! !DESCRIPTION: provide quick access to object elements (bounds and grids),
  244. ! while keeping them private.
  245. !\\
  246. !\\
  247. ! !INTERFACE:
  248. !
  249. SUBROUTINE GET_DARR(Darr, istart, istop, im)
  250. !
  251. ! !INPUT PARAMETERS:
  252. !
  253. type(dist_arr), intent(in) :: Darr
  254. integer, optional :: istart, istop, im
  255. !
  256. !EOP
  257. !------------------------------------------------------------------------
  258. !BOC
  259. if (present(istart)) istart = darr%i_strt
  260. if (present(istop)) istop = darr%i_stop
  261. if (present(im)) im = darr%im
  262. END SUBROUTINE GET_DARR
  263. !EOC
  264. #ifdef MPI /* MPI TYPES */
  265. !--------------------------------------------------------------------------
  266. ! TM5 !
  267. !--------------------------------------------------------------------------
  268. !BOP
  269. !
  270. ! !IROUTINE: GET_INTERIOR_TYPE
  271. !
  272. ! !DESCRIPTION: Returns derived MPI types that describe the interior arrs
  273. ! needed for collective communications.
  274. !\\
  275. !\\
  276. ! !INTERFACE:
  277. !
  278. SUBROUTINE GET_INTERIOR_TYPE( Darr, shp, datatype, linterior, ginterior, status )
  279. !
  280. ! !INPUT PARAMETERS:
  281. !
  282. type(dist_arr), intent(in) :: Darr
  283. integer, intent(in) :: shp(:) ! shape of local array
  284. integer, intent(in) :: datatype ! basic MPI datatype
  285. !
  286. ! !OUTPUT PARAMETERS:
  287. !
  288. ! derived MPI datatypes describing distributed interior arrs:
  289. integer, intent(out) :: ginterior(npes-1) ! within global array (used by root, as many as NPES-1)
  290. integer, intent(out) :: linterior ! within local array (used by non-root)
  291. integer, intent(out) :: status
  292. !
  293. ! !REVISION HISTORY:
  294. ! Monday, May 28, 2018 - P. Le Sager - v0
  295. !
  296. ! !REMARKS:
  297. ! (1) input must be checked beforehand by calling CHECK_DIST_ARR first
  298. !
  299. !EOP
  300. !------------------------------------------------------------------------
  301. !BOC
  302. character(len=*), parameter :: rname = mname//'get_interior_type'
  303. integer :: gslice, lslice ! intermediate datatypes
  304. integer :: n, m ! sizes to build datatypes
  305. integer :: hlstride, hgstride ! strides to build datatypes
  306. integer :: stack, sz, klm
  307. integer(kind=MPI_ADDRESS_KIND) :: sizeoftype, lb, vlstride, vgstride
  308. ! init : number of dimensions, default value
  309. sz = size(shp)
  310. ginterior = MPI_DATATYPE_NULL
  311. linterior = MPI_DATATYPE_NULL
  312. ! collapse third and above dimensions
  313. stack = 1
  314. if (sz > 2) stack = product(shp(3:))
  315. ! size of data slice to carry
  316. n = darr%I_STOP - darr%I_STRT + 1
  317. m = darr%jm
  318. CALL MPI_TYPE_GET_EXTENT( datatype, lb, sizeoftype, ierr)
  319. IF_NOTOK_MPI(status=1)
  320. ! horizontal global stride (in data)
  321. hgstride = darr%im
  322. ! vertical global stride (in byte)
  323. vgstride = darr%im * darr%jm * sizeoftype
  324. ! local strides (may be different than n and n*m because of halo)
  325. hlstride = shp(1) ! in data
  326. vlstride = shp(1)*shp(2)*sizeoftype ! in byte
  327. if ( isRoot ) then
  328. do klm=1,npes-1
  329. ! horizontal chunk is M lines of lenght N, separated by a global
  330. ! stride
  331. n = darr%bounds(2,klm) - darr%bounds(1,klm) + 1
  332. m = darr%jm
  333. call MPI_TYPE_VECTOR (m, n, hgstride, datatype, gslice, ierr)
  334. IF_NOTOK_MPI(status=1)
  335. ! stack 3rd and above dimensions
  336. if (stack == 1) then
  337. ginterior(klm) = gslice
  338. else
  339. ! note : also works with stack=1
  340. call MPI_TYPE_CREATE_HVECTOR(stack, 1, vgstride, gslice, ginterior(klm), ierr)
  341. IF_NOTOK_MPI(status=1)
  342. call MPI_TYPE_FREE(gslice, ierr)
  343. IF_NOTOK_MPI(status=1)
  344. end if
  345. call MPI_TYPE_COMMIT (ginterior(klm), ierr)
  346. IF_NOTOK_MPI(status=1)
  347. end do
  348. else
  349. ! local interior is basically M lines of lenght N, separated by a local
  350. ! stride
  351. call MPI_TYPE_VECTOR (m, n, hlstride, datatype, lslice, ierr)
  352. IF_NOTOK_MPI(status=1)
  353. ! stack 3rd and above dimensions
  354. if (stack == 1) then
  355. linterior = lslice
  356. else
  357. ! note : also works with stack=1
  358. call MPI_TYPE_CREATE_HVECTOR (stack, 1, vlstride, lslice, linterior, ierr)
  359. IF_NOTOK_MPI(status=1)
  360. call MPI_TYPE_FREE(lslice, ierr)
  361. IF_NOTOK_MPI(status=1)
  362. end if
  363. call MPI_TYPE_COMMIT (linterior, ierr)
  364. IF_NOTOK_MPI(status=1)
  365. end if
  366. status=0
  367. END SUBROUTINE GET_INTERIOR_TYPE
  368. !EOC
  369. !--------------------------------------------------------------------------
  370. ! TM5 !
  371. !--------------------------------------------------------------------------
  372. !BOP
  373. !
  374. ! !IROUTINE: FREE_DERIVED_TYPE
  375. !
  376. ! !DESCRIPTION: free all MPI derived datatypes in a vector
  377. !\\
  378. !\\
  379. ! !INTERFACE:
  380. !
  381. SUBROUTINE FREE_DERIVED_TYPE( datatype )
  382. !
  383. ! !INPUT/OUTPUT PARAMETERS:
  384. !
  385. integer, intent(inout) :: datatype(:) ! set of derived MPI datatypes
  386. !
  387. !EOP
  388. !------------------------------------------------------------------------
  389. !BOC
  390. integer :: i, j
  391. integer :: res(size(datatype)) ! hold unique elements
  392. integer :: k ! number of unique elements
  393. ! Get list of unique handle(s)
  394. ! ----------------------------
  395. k = 1
  396. res(1) = 1
  397. outer: do i=2,size(datatype)
  398. ! look for a match
  399. do j=1,k
  400. if (datatype(res(j)) == datatype(i)) cycle outer ! match
  401. end do
  402. ! no match : add it to the list
  403. k = k + 1
  404. res(k) = i
  405. end do outer
  406. ! Free handle(s)
  407. ! ---------------------------
  408. do i=1,k
  409. if (datatype(res(i)) /= MPI_DATATYPE_NULL) &
  410. call MPI_TYPE_FREE(datatype(res(i)), ierr)
  411. end do
  412. END SUBROUTINE FREE_DERIVED_TYPE
  413. !EOC
  414. #endif /* MPI TYPES */
  415. !--------------------------------------------------------------------------
  416. ! TM5 !
  417. !--------------------------------------------------------------------------
  418. !BOP
  419. !
  420. ! !IROUTINE: CHECK_DIST_ARR
  421. !
  422. ! !DESCRIPTION: Check that the shape of a local array correspond to an array
  423. ! distributed on current process. This check is done on the
  424. ! first 2 dimensions only, along which the arr
  425. ! decomposition is done.
  426. !
  427. ! Optionally: check shape of a global array. If arrays are 3D
  428. ! or more, the 3rd and above dimensions of local and global
  429. ! arrays are also compared.
  430. !\\
  431. !\\
  432. ! !INTERFACE:
  433. !
  434. SUBROUTINE CHECK_DIST_ARR( darr, shp, status, glbl_shp, has_global )
  435. !
  436. ! !INPUT PARAMETERS:
  437. !
  438. type(dist_arr), intent(in) :: darr
  439. integer, intent(in) :: shp(:) ! shape of local array
  440. !
  441. integer, intent(in), optional :: glbl_shp(:) ! shape of global array
  442. logical, intent(in), optional :: has_global ! current proc hold global array (default is root)
  443. !
  444. ! !OUTPUT PARAMETERS:
  445. !
  446. integer, intent(out) :: status
  447. !
  448. !EOP
  449. !------------------------------------------------------------------------
  450. !BOC
  451. character(len=*), parameter :: rname = mname//'check_dist_arr '
  452. integer :: n, m, sz, sg
  453. integer, allocatable :: glbsz(:)
  454. logical :: hold_global
  455. status = 0
  456. ! by default global array is expected on root
  457. hold_global = isRoot
  458. if (present(has_global)) hold_global=has_global
  459. ! required size
  460. n = darr%i_stop - darr%i_strt + 1
  461. ! check the 1st dimension, which is distributed
  462. if ((shp(1) /= n) ) then
  463. write (gol,*) "CHECK_DIST_ARR: local array shape does not conform" ; call goErr
  464. write (gol,'(" local array : ",2i4)') shp(1) ; call goErr
  465. write (gol,'(" should be : ",2i4)') n ; call goErr
  466. write (gol,'(" w/ start & stop : ", i4)') darr%i_strt, darr%i_stop ; call goErr
  467. TRACEBACK; status=1; return
  468. end if
  469. ! check shape of global array on root
  470. sz = size(shp)
  471. if ( present(glbl_shp) ) then
  472. sg = size(glbl_shp)
  473. if (sz /= sg ) then
  474. write (gol,'("CHECK_DIST_ARR : global and local arrays have different rank:")') ; call goErr
  475. write (gol,'(" local rank : ", i4)') sz ; call goErr
  476. write (gol,'(" global rank : ", i4)') sg ; call goErr
  477. TRACEBACK; status=1; return
  478. end if
  479. if ((sz == 2) .and. hold_global) then
  480. if (shp(2) /= glbl_shp(2)) then
  481. write (gol,'("CHECK_DIST_ARR : global and local arrays have different J-size:")') ; call goErr
  482. write (gol,'(" local size(2) : ", i4)') shp(2) ; call goErr
  483. write (gol,'(" global size(2) : ", i4)') glbl_shp(2) ; call goErr
  484. TRACEBACK; status=1; return
  485. end if
  486. end if
  487. end if
  488. END SUBROUTINE CHECK_DIST_ARR
  489. !EOC
  490. !--------------------------------------------------------------------------
  491. ! TM5 !
  492. !--------------------------------------------------------------------------
  493. !BOP
  494. !
  495. ! !IROUTINE: GATHER_1D_R
  496. !
  497. ! !DESCRIPTION: gather local 1D arrays into a global 1D array
  498. !\\
  499. !\\
  500. ! !INTERFACE:
  501. !
  502. SUBROUTINE GATHER_1D_R( darr, lcl_array, glbl_array, status )
  503. !
  504. ! !INPUT PARAMETERS:
  505. !
  506. type(dist_arr), intent(in) :: darr
  507. real, intent(in) :: lcl_array(darr%i_strt:)
  508. !
  509. ! !OUTPUT PARAMETERS:
  510. !
  511. real, intent(out) :: glbl_array(:)
  512. integer, intent(out) :: status
  513. !
  514. ! !REMARKS:
  515. ! (1) I have not use mpi_gatherv because of varying *receiving* size
  516. !
  517. !EOP
  518. !------------------------------------------------------------------------
  519. !BOC
  520. character(len=*), parameter :: rname = mname//'gather_1d_r'
  521. #ifndef MPI
  522. glbl_array = lcl_array( darr%i_strt:darr%i_stop)
  523. status = 0
  524. #else
  525. integer :: stat(MPI_STATUS_SIZE)
  526. integer :: i, j, klm, i0, j0, i1, j1, sz(1)
  527. status=0
  528. ! check input, get derived types
  529. !-------------------------------
  530. sz = shape(lcl_array)
  531. ! if(okdebug)then
  532. CALL CHECK_DIST_ARR( Darr, sz, status, shape(glbl_array))
  533. IF_NOTOK_RETURN(status=1)
  534. ! end if
  535. i0 = darr%i_strt
  536. i1 = darr%i_stop
  537. ! ------- GATHER -------------
  538. if ( isRoot ) then
  539. ! get first chunk locally
  540. glbl_array(i0:i1) = lcl_array(i0:i1)
  541. ! get remaining chunks from other pes
  542. do klm=1,npes-1
  543. i = darr%bounds(1,klm)
  544. j = darr%bounds(2,klm)
  545. call MPI_RECV( glbl_array(i), j-i+1, my_real, klm, 1, localComm, stat, ierr)
  546. end do
  547. else
  548. call MPI_SEND( lcl_array(i0), i1-i0+1, my_real, root, 1, localComm, ierr)
  549. end if
  550. #endif
  551. END SUBROUTINE GATHER_1D_R
  552. !--------------------------------------------------------------------------
  553. ! TM5 !
  554. !--------------------------------------------------------------------------
  555. !BOP
  556. !
  557. ! !IROUTINE: GATHER_2D_R
  558. !
  559. ! !DESCRIPTION: gather local 2D arrays into a global 2D array
  560. !\\
  561. !\\
  562. ! !INTERFACE:
  563. !
  564. SUBROUTINE GATHER_2D_R( darr, lcl_array, glbl_array, status )
  565. !
  566. ! !INPUT PARAMETERS:
  567. !
  568. type(dist_arr), intent(in) :: darr
  569. real, intent(in) :: lcl_array(darr%i_strt:,:)
  570. !
  571. ! !OUTPUT PARAMETERS:
  572. !
  573. real, intent(out) :: glbl_array(:,:)
  574. integer, intent(out) :: status
  575. !
  576. ! !REMARKS:
  577. ! (1) I have not use mpi_gatherv because of varying *receiving* size
  578. !
  579. !EOP
  580. !------------------------------------------------------------------------
  581. !BOC
  582. character(len=*), parameter :: rname = mname//'gather_2d_r'
  583. #ifndef MPI
  584. glbl_array = lcl_array( darr%i_strt:darr%i_stop,:)
  585. status = 0
  586. #else
  587. integer :: stat(MPI_STATUS_SIZE), linterior, ginterior(npes-1)
  588. integer :: i, j, klm, i0, j0, i1, j1, sz(2)
  589. status=0
  590. ! check input, get derived types
  591. !-------------------------------
  592. sz = shape(lcl_array)
  593. ! if(okdebug)then
  594. call check_dist_arr( darr, sz, status, shape(glbl_array))
  595. IF_NOTOK_RETURN(status=1)
  596. ! end if
  597. call get_interior_type( Darr, sz, my_real, linterior, ginterior, status )
  598. IF_NOTOK_RETURN(status=1)
  599. i0 = darr%i_strt
  600. ! ------- GATHER -------------
  601. if ( isRoot ) then
  602. ! get first chunk locally
  603. i1 = darr%i_stop
  604. glbl_array(i0:i1,:) = lcl_array(i0:i1,:)
  605. ! get remaining chunks from other pes
  606. do klm=1,npes-1
  607. i = darr%bounds(1,klm)
  608. call MPI_RECV( glbl_array(i,1), 1, ginterior(klm), klm, 1, &
  609. localComm, stat, ierr)
  610. end do
  611. call FREE_DERIVED_TYPE( ginterior )
  612. else
  613. call MPI_SEND( lcl_array(i0,1), 1, linterior, root, 1, localComm, ierr)
  614. call MPI_TYPE_FREE(linterior, ierr)
  615. end if
  616. #endif
  617. END SUBROUTINE GATHER_2D_R
  618. !EOC
  619. !--------------------------------------------------------------------------
  620. ! TM5 !
  621. !--------------------------------------------------------------------------
  622. !BOP
  623. !
  624. ! !IROUTINE: GATHER_1D_I
  625. !
  626. ! !DESCRIPTION: gather local 1D arrays into a global 1D array
  627. !\\
  628. !\\
  629. ! !INTERFACE:
  630. !
  631. SUBROUTINE GATHER_1D_I( darr, lcl_array, glbl_array, status )
  632. !
  633. ! !INPUT PARAMETERS:
  634. !
  635. type(dist_arr), intent(in) :: darr
  636. integer, intent(in) :: lcl_array(darr%i_strt:)
  637. !
  638. ! !OUTPUT PARAMETERS:
  639. !
  640. integer, intent(out) :: glbl_array(:)
  641. integer, intent(out) :: status
  642. !
  643. ! !REMARKS:
  644. ! (1) I have not use mpi_gatherv because of varying *receiving* size
  645. !
  646. !EOP
  647. !------------------------------------------------------------------------
  648. !BOC
  649. character(len=*), parameter :: rname = mname//'gather_1d_r'
  650. #ifndef MPI
  651. glbl_array = lcl_array( darr%i_strt:darr%i_stop)
  652. status = 0
  653. #else
  654. integer :: stat(MPI_STATUS_SIZE)
  655. integer :: i, j, klm, i0, j0, i1, j1, sz(1)
  656. status=0
  657. ! check input, get derived types
  658. !-------------------------------
  659. sz = shape(lcl_array)
  660. ! if(okdebug)then
  661. CALL CHECK_DIST_ARR( Darr, sz, status, shape(glbl_array))
  662. IF_NOTOK_RETURN(status=1)
  663. ! end if
  664. i0 = darr%i_strt
  665. i1 = darr%i_stop
  666. ! ------- GATHER -------------
  667. if ( isRoot ) then
  668. ! get first chunk locally
  669. glbl_array(i0:i1) = lcl_array(i0:i1)
  670. ! get remaining chunks from other pes
  671. do klm=1,npes-1
  672. i = darr%bounds(1,klm)
  673. j = darr%bounds(2,klm)
  674. call MPI_RECV( glbl_array(i), j-i+1, MPI_INTEGER, klm, 1, localComm, stat, ierr)
  675. end do
  676. else
  677. call MPI_SEND( lcl_array(i0), i1-i0+1, MPI_INTEGER, root, 1, localComm, ierr)
  678. end if
  679. #endif
  680. END SUBROUTINE GATHER_1D_I
  681. !--------------------------------------------------------------------------
  682. ! TM5 !
  683. !--------------------------------------------------------------------------
  684. !BOP
  685. !
  686. ! !IROUTINE: GATHER_2D_I
  687. !
  688. ! !DESCRIPTION: gather local 2D arrays into a global 2D array (integer version)
  689. !\\
  690. !\\
  691. ! !INTERFACE:
  692. !
  693. SUBROUTINE GATHER_2D_I( Darr, lcl_array, glbl_array, status )
  694. !
  695. ! !INPUT PARAMETERS:
  696. !
  697. type(dist_arr), intent(in) :: Darr
  698. integer, intent(in) :: lcl_array(darr%i_strt:,:)
  699. !
  700. ! !OUTPUT PARAMETERS:
  701. !
  702. integer, intent(out) :: glbl_array(:,:)
  703. integer, intent(out) :: status
  704. !
  705. ! !REVISION HISTORY:
  706. ! Monday, May 28, 2018 - P. Le Sager - v0
  707. !
  708. !EOP
  709. !------------------------------------------------------------------------
  710. !BOC
  711. character(len=*), parameter :: rname = mname//'gather_2d_i'
  712. #ifndef MPI
  713. glbl_array = lcl_array( darr%i_strt:darr%i_stop, : )
  714. status = 0
  715. #else
  716. integer :: stat(MPI_STATUS_SIZE), linterior, ginterior(npes-1)
  717. integer :: i, j, klm, i0, j0, i1, j1, sz(2)
  718. status=0
  719. ! check input, get derived types
  720. !-------------------------------
  721. sz = shape(lcl_array)
  722. ! if(okdebug)then
  723. call check_dist_arr( darr, sz, status, shape(glbl_array))
  724. IF_NOTOK_RETURN(status=1)
  725. ! end if
  726. call get_interior_type( darr, sz, MPI_INTEGER, linterior, ginterior, status )
  727. IF_NOTOK_RETURN(status=1)
  728. i0 = darr%i_strt
  729. ! ------- GATHER -------------
  730. if ( isRoot ) then
  731. ! get first chunk locally
  732. i1 = darr%i_stop
  733. glbl_array(i0:i1,:) = lcl_array(i0:i1,:)
  734. ! get remaining chunks from other pes
  735. do klm=1,npes-1
  736. i = darr%bounds(1,klm)
  737. call MPI_RECV( glbl_array(i,1), 1, ginterior(klm), klm, 1, &
  738. localComm, stat, ierr)
  739. end do
  740. call FREE_DERIVED_TYPE( ginterior )
  741. else
  742. call MPI_SEND( lcl_array(i0,1), 1, linterior, root, 1, localComm, ierr)
  743. call MPI_TYPE_FREE(linterior, ierr)
  744. end if
  745. #endif
  746. END SUBROUTINE GATHER_2D_I
  747. !EOC
  748. !--------------------------------------------------------------------------
  749. ! TM5 !
  750. !--------------------------------------------------------------------------
  751. !BOP
  752. !
  753. ! !IROUTINE: SCATTER_1D_R
  754. !
  755. ! !DESCRIPTION: scatter a 2D global real array
  756. !\\
  757. !\\
  758. ! !INTERFACE:
  759. !
  760. SUBROUTINE SCATTER_1D_R( darr, lcl_array, glbl_array, status )
  761. !
  762. ! !INPUT PARAMETERS:
  763. !
  764. type(dist_arr), intent(in) :: darr
  765. real, intent(in) :: glbl_array(:)
  766. !
  767. ! !OUTPUT PARAMETERS:
  768. !
  769. real, intent(out) :: lcl_array(darr%i_strt:)
  770. integer, intent(out) :: status
  771. !
  772. ! !REVISION HISTORY:
  773. ! Monday, May 28, 2018 - P. Le Sager - v0
  774. ! 21 Jun 2013 - P. Le Sager - MPI_SEND -> MPI_SSEND to avoid buffering
  775. !
  776. !EOP
  777. !------------------------------------------------------------------------
  778. !BOC
  779. character(len=*), parameter :: rname = mname//'scatter_1d_r'
  780. #ifndef MPI
  781. lcl_array( darr%i_strt:darr%i_stop) = glbl_array
  782. status = 0
  783. #else
  784. integer :: stat(MPI_STATUS_SIZE)
  785. integer :: i, j, klm, i0, j0, i1, j1, sz(1)
  786. status=0
  787. ! ------- Check input & get derived types
  788. sz = shape(lcl_array)
  789. ! if(okdebug)then
  790. CALL CHECK_DIST_ARR( darr, sz, status, shape(glbl_array))
  791. IF_NOTOK_RETURN(status=1)
  792. ! end if
  793. i0 = darr%i_strt
  794. i1 = darr%i_stop
  795. ! ------- SCATTER -------------
  796. if ( isRoot ) then ! send
  797. ! get first chunk locally
  798. lcl_array(i0:i1) = glbl_array(i0:i1)
  799. ! send remaining chunks to other pes
  800. do klm=1,npes-1
  801. i = darr%bounds(1,klm)
  802. j = darr%bounds(2,klm)
  803. call MPI_SSEND( glbl_array(i), j-i+1, my_real, klm, klm, localComm, ierr)
  804. IF_NOTOK_MPI(status=1)
  805. end do
  806. else
  807. call MPI_COMM_RANK(localComm, klm, ierr)
  808. IF_NOTOK_MPI(status=1)
  809. call MPI_RECV( lcl_array(i0), i1-i0+1, my_real, root, klm, localComm, stat, ierr)
  810. IF_NOTOK_MPI(status=1)
  811. end if
  812. #endif
  813. END SUBROUTINE SCATTER_1D_R
  814. !EOC
  815. !--------------------------------------------------------------------------
  816. ! TM5 !
  817. !--------------------------------------------------------------------------
  818. !BOP
  819. !
  820. ! !IROUTINE: SCATTER_2D_R
  821. !
  822. ! !DESCRIPTION: scatter a 2D global real array
  823. !\\
  824. !\\
  825. ! !INTERFACE:
  826. !
  827. SUBROUTINE SCATTER_2D_R( darr, lcl_array, glbl_array, status )
  828. !
  829. ! !INPUT PARAMETERS:
  830. !
  831. type(dist_arr), intent(in) :: darr
  832. real, intent(in) :: glbl_array(:,:)
  833. !
  834. ! !OUTPUT PARAMETERS:
  835. !
  836. real, intent(out) :: lcl_array(darr%i_strt:,:)
  837. integer, intent(out) :: status
  838. !
  839. ! !REVISION HISTORY:
  840. ! Monday, May 28, 2018 - P. Le Sager - v0
  841. ! 21 Jun 2013 - P. Le Sager - MPI_SEND -> MPI_SSEND to avoid buffering
  842. !
  843. !EOP
  844. !------------------------------------------------------------------------
  845. !BOC
  846. character(len=*), parameter :: rname = mname//'scatter_2d_r'
  847. #ifndef MPI
  848. lcl_array( darr%i_strt:darr%i_stop, : ) = glbl_array
  849. status = 0
  850. #else
  851. integer :: stat(MPI_STATUS_SIZE), linterior, ginterior(npes-1)
  852. integer :: i, j, klm, i0, j0, i1, j1, sz(2)
  853. status=0
  854. ! ------- Check input & get derived types
  855. sz = shape(lcl_array)
  856. ! if(okdebug)then
  857. call check_dist_arr( darr, sz, status, shape(glbl_array))
  858. IF_NOTOK_RETURN(status=1)
  859. ! end if
  860. call get_interior_type( darr, sz, my_real, linterior, ginterior, status )
  861. IF_NOTOK_RETURN(status=1)
  862. i0 = darr%i_strt
  863. ! ------- SCATTER -------------
  864. if ( isRoot ) then
  865. ! get first chunk locally
  866. i1 = darr%i_stop
  867. lcl_array(i0:i1,:) = glbl_array(i0:i1,:)
  868. ! send remaining chunks to other pes
  869. do klm=1,npes-1
  870. i = darr%bounds(1,klm)
  871. call MPI_SSEND( glbl_array(i,1), 1, ginterior(klm), klm, klm, localComm, ierr)
  872. IF_NOTOK_MPI(status=1)
  873. end do
  874. call FREE_DERIVED_TYPE( ginterior )
  875. else
  876. call MPI_COMM_RANK(localComm, klm, ierr)
  877. IF_NOTOK_MPI(status=1)
  878. call MPI_RECV( lcl_array(i0,1), 1, linterior, root, klm, localComm, stat, ierr)
  879. IF_NOTOK_MPI(status=1)
  880. call MPI_TYPE_FREE(linterior, ierr)
  881. IF_NOTOK_MPI(status=1)
  882. end if
  883. #endif
  884. END SUBROUTINE SCATTER_2D_R
  885. !EOC
  886. !--------------------------------------------------------------------------
  887. ! TM5 !
  888. !--------------------------------------------------------------------------
  889. !BOP
  890. !
  891. ! !IROUTINE: SCATTER_1D_I
  892. !
  893. ! !DESCRIPTION: scatter a 2D global integer array
  894. !\\
  895. !\\
  896. ! !INTERFACE:
  897. !
  898. SUBROUTINE SCATTER_1D_I( darr, lcl_array, glbl_array, status )
  899. !
  900. ! !INPUT PARAMETERS:
  901. !
  902. type(dist_arr), intent(in) :: darr
  903. integer, intent(in) :: glbl_array(:)
  904. !
  905. ! !OUTPUT PARAMETERS:
  906. !
  907. integer, intent(out) :: lcl_array(darr%i_strt:)
  908. integer, intent(out) :: status
  909. !
  910. ! !REVISION HISTORY:
  911. ! Monday, May 28, 2018 - P. Le Sager - v0
  912. ! 21 Jun 2013 - P. Le Sager - MPI_SEND -> MPI_SSEND to avoid buffering
  913. !
  914. !EOP
  915. !------------------------------------------------------------------------
  916. !BOC
  917. character(len=*), parameter :: rname = mname//'scatter_1d_i'
  918. #ifndef MPI
  919. lcl_array( darr%i_strt:darr%i_stop) = glbl_array
  920. status = 0
  921. #else
  922. integer :: stat(MPI_STATUS_SIZE)
  923. integer :: i, j, klm, i0, j0, i1, j1, sz(1)
  924. status=0
  925. ! ------- Check input & get derived types
  926. sz = shape(lcl_array)
  927. ! if(okdebug)then
  928. CALL CHECK_DIST_ARR( darr, sz, status, shape(glbl_array))
  929. IF_NOTOK_RETURN(status=1)
  930. ! end if
  931. i0 = darr%i_strt
  932. i1 = darr%i_stop
  933. ! ------- SCATTER -------------
  934. if ( isRoot ) then ! send
  935. ! get first chunk locally
  936. lcl_array(i0:i1) = glbl_array(i0:i1)
  937. ! send remaining chunks to other pes
  938. do klm=1,npes-1
  939. i = darr%bounds(1,klm)
  940. j = darr%bounds(2,klm)
  941. call MPI_SSEND( glbl_array(i), j-i+1, MPI_INTEGER, klm, klm, localComm, ierr)
  942. IF_NOTOK_MPI(status=1)
  943. end do
  944. else
  945. call MPI_COMM_RANK(localComm, klm, ierr)
  946. IF_NOTOK_MPI(status=1)
  947. call MPI_RECV( lcl_array(i0), i1-i0+1, MPI_INTEGER, root, klm, localComm, stat, ierr)
  948. IF_NOTOK_MPI(status=1)
  949. end if
  950. #endif
  951. END SUBROUTINE SCATTER_1D_I
  952. !EOC
  953. !--------------------------------------------------------------------------
  954. ! TM5 !
  955. !--------------------------------------------------------------------------
  956. !BOP
  957. !
  958. ! !IROUTINE: SCATTER_2D_I
  959. !
  960. ! !DESCRIPTION: scatter a 2D global integer array
  961. !\\
  962. !\\
  963. ! !INTERFACE:
  964. !
  965. SUBROUTINE SCATTER_2D_I( darr, lcl_array, glbl_array, status )
  966. !
  967. ! !INPUT PARAMETERS:
  968. !
  969. type(dist_arr), intent(in) :: darr
  970. integer, intent(in) :: glbl_array(:,:)
  971. !
  972. ! !OUTPUT PARAMETERS:
  973. !
  974. integer, intent(out) :: lcl_array(darr%i_strt:,:)
  975. integer, intent(out) :: status
  976. !
  977. ! !REVISION HISTORY:
  978. ! Monday, May 28, 2018 - P. Le Sager - v0
  979. ! 21 Jun 2013 - P. Le Sager - MPI_SEND -> MPI_SSEND to avoid buffering
  980. !
  981. !EOP
  982. !------------------------------------------------------------------------
  983. !BOC
  984. character(len=*), parameter :: rname = mname//'scatter_2d_i'
  985. #ifndef MPI
  986. lcl_array( darr%i_strt:darr%i_stop, : ) = glbl_array
  987. status = 0
  988. #else
  989. integer :: stat(MPI_STATUS_SIZE), linterior, ginterior(npes-1)
  990. integer :: i, j, klm, i0, j0, i1, j1, sz(2)
  991. status=0
  992. ! ------- Check input & get derived types
  993. sz = shape(lcl_array)
  994. ! if(okdebug)then
  995. call check_dist_arr( darr, sz, status, shape(glbl_array))
  996. IF_NOTOK_RETURN(status=1)
  997. ! end if
  998. call get_interior_type( darr, sz, MPI_INTEGER, linterior, ginterior, status )
  999. IF_NOTOK_RETURN(status=1)
  1000. i0 = darr%i_strt
  1001. ! ------- SCATTER -------------
  1002. if ( isRoot ) then
  1003. ! get first chunk locally
  1004. i1 = darr%i_stop
  1005. lcl_array(i0:i1,:) = glbl_array(i0:i1,:)
  1006. ! send remaining chunks to other pes
  1007. do klm=1,npes-1
  1008. i = darr%bounds(1,klm)
  1009. call MPI_SSEND( glbl_array(i,1), 1, ginterior(klm), klm, klm, localComm, ierr)
  1010. IF_NOTOK_MPI(status=1)
  1011. end do
  1012. call FREE_DERIVED_TYPE( ginterior )
  1013. else
  1014. call MPI_COMM_RANK(localComm, klm, ierr)
  1015. IF_NOTOK_MPI(status=1)
  1016. call MPI_RECV( lcl_array(i0,1), 1, linterior, root, klm, localComm, stat, ierr)
  1017. IF_NOTOK_MPI(status=1)
  1018. call MPI_TYPE_FREE(linterior, ierr)
  1019. IF_NOTOK_MPI(status=1)
  1020. end if
  1021. #endif
  1022. END SUBROUTINE SCATTER_2D_I
  1023. !EOC
  1024. !--------------------------------------------------------------------------
  1025. ! TM5 !
  1026. !--------------------------------------------------------------------------
  1027. !BOP
  1028. !
  1029. ! !IROUTINE: TESTDA
  1030. !
  1031. ! !DESCRIPTION: check if the communications are working as expected.
  1032. ! Currently checked:
  1033. ! - GATHER, SCATTER
  1034. !\\
  1035. !\\
  1036. ! !INTERFACE:
  1037. !
  1038. SUBROUTINE TESTDA( status )
  1039. !
  1040. ! !OUTPUT PARAMETERS:
  1041. !
  1042. integer, intent(out) :: status
  1043. !
  1044. ! !REMARKS:
  1045. !
  1046. !EOP
  1047. !------------------------------------------------------------------------
  1048. !BOC
  1049. character(len=*), parameter :: rname = mname//'testcomm'
  1050. real, allocatable :: glb(:), lcl(:), ttglb(:)
  1051. real, allocatable :: glb2(:,:), lcl2(:,:), ttglb2(:,:)
  1052. integer :: i, j, istrt, istop, gsize, jm
  1053. type(dist_arr) :: darr
  1054. ! General
  1055. gsize = 20
  1056. jm = 359
  1057. ! ----- 1D -------------------------------------------------------------
  1058. ! test array
  1059. if (isRoot) then
  1060. allocate(TTglb(gsize))
  1061. TTglb = (/(real(i)+0.123, i=1,gsize)/)
  1062. endif
  1063. call Set_Darr( darr, gsize, istrt, istop, status)
  1064. ! Global array (only on root it needs to be filled with data and be the full size)
  1065. if (isRoot) then
  1066. allocate(glb(gsize))
  1067. glb = (/(i, i=1,gsize)/)
  1068. else
  1069. allocate(glb(1))
  1070. endif
  1071. ! fill local array by scattering
  1072. allocate(lcl(istrt:istop))
  1073. call scatter(darr, lcl, glb, status)
  1074. ! do something on the local array
  1075. lcl = lcl + 0.123
  1076. call gather(darr, lcl, glb, status)
  1077. call done_darr(darr, status)
  1078. if (isRoot) then
  1079. if ( any(TTglb /= glb) ) then
  1080. write(gol,*) "1D: We have a problem!!!" ; call goPr
  1081. status=1
  1082. else
  1083. write(gol,*) "1D: SUCCESS !!!" ; call goPr
  1084. status=0
  1085. endif
  1086. endif
  1087. call Par_Broadcast_Status( status, root )
  1088. IF_NOTOK_RETURN(status=1)
  1089. deallocate(glb,lcl)
  1090. if (isRoot) deallocate(TTglb)
  1091. ! ----- 2D -------------------------------------------------------------
  1092. ! test array
  1093. if (isRoot) then
  1094. allocate(TTglb2(gsize,jm))
  1095. TTglb2 = reshape((/(real(i)+0.123, i=1,gsize*jm)/), shape(TTglb2))
  1096. endif
  1097. call Set_Darr( darr, gsize, istrt, istop, status, jm)
  1098. ! Global array (only on root it needs to be filled with data and be the full size)
  1099. if (isRoot) then
  1100. allocate(glb2(gsize,jm))
  1101. glb2 = reshape((/(i, i=1,gsize*jm)/), shape(glb2))
  1102. else
  1103. allocate(glb2(1,1))
  1104. endif
  1105. ! fill local array by scattering
  1106. allocate(lcl2(istrt:istop,jm))
  1107. call scatter(darr, lcl2, glb2, status)
  1108. ! do something on the local array
  1109. lcl2 = lcl2 + 0.123
  1110. call gather(darr, lcl2, glb2, status)
  1111. ! - test
  1112. if (isRoot) then
  1113. if ( any(TTglb2 /= glb2) ) then
  1114. write(gol,*) "2D: We have a problem!!!" ; call goPr
  1115. status=1
  1116. do i=1,gsize
  1117. do j=1,jm
  1118. write(gol,*) i,j, glb2(i,j), TTglb2(i,j); call goPr
  1119. enddo
  1120. enddo
  1121. write(gol,*)'--- FAIL TEST ----'; call goPr
  1122. else
  1123. write(gol,*) "2D: SUCCESS !!!" ; call goPr
  1124. status=0
  1125. endif
  1126. endif
  1127. call Par_Broadcast_Status( status, root )
  1128. IF_NOTOK_RETURN(status=1)
  1129. deallocate(glb2,lcl2)
  1130. if (isRoot) deallocate(TTglb2)
  1131. ! clean DA
  1132. call done_darr(darr, status)
  1133. END SUBROUTINE TESTDA
  1134. !EOC
  1135. END MODULE ARR_DECOMP