m_SparseMatrixDecomp.F90 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2. ! Math and Computer Science Division, Argonne National Laboratory !
  3. !-----------------------------------------------------------------------
  4. ! CVS m_SparseMatrixDecomp.F90,v 1.15 2008-05-12 01:59:32 jacob Exp
  5. ! CVS MCT_2_8_0
  6. !BOP -------------------------------------------------------------------
  7. !
  8. ! !MODULE: m_SparseMatrixDecomp -- Parallel sparse matrix decomposition.
  9. !
  10. ! !DESCRIPTION:
  11. ! The {\tt SparseMatrix} datatype provides sparse matrix storage for
  12. ! the parallel matrix-vector multiplication ${\bf y} = {\bf M} {\bf x}$.
  13. ! This module provides services to create decompositions for the
  14. ! {\tt SparseMatrix}. The matrix decompositions available are row
  15. ! and column decompositions. They are generated by invoking the
  16. ! appropriate routine in this module, and passing the corresponding
  17. ! {\em vector} decomposition. For a row (column) decomposition, one
  18. ! invokes the routine {\tt ByRow()} ({\tt ByColumn()}), passing the
  19. ! domain decomposition for the vector {\bf y} ({\bf x}).
  20. !
  21. ! !INTERFACE:
  22. module m_SparseMatrixDecomp
  23. private ! except
  24. ! !PUBLIC MEMBER FUNCTIONS:
  25. !
  26. public :: ByColumn
  27. public :: ByRow
  28. interface ByColumn ; module procedure &
  29. ByColumnGSMap_
  30. end interface
  31. interface ByRow ; module procedure &
  32. ByRowGSMap_
  33. end interface
  34. ! !REVISION HISTORY:
  35. ! 13Apr01 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  36. ! and API specifications.
  37. ! 03Aug01 - E. Ong <eong@mcs.anl.gov> - in ByRowGSMap and ByColumnGSMap,
  38. ! call GlobalSegMap_init on non-root processes with actual
  39. ! shaped arguments to satisfy Fortran 90 standard. See
  40. ! comments in ByRowGSMap/ByColumnGSMap.
  41. !EOP ___________________________________________________________________
  42. character(len=*),parameter :: myname='MCT::m_SparseMatrixDecomp'
  43. contains
  44. !-------------------------------------------------------------------------
  45. ! Math + Computer Science Division / Argonne National Laboratory !
  46. !-------------------------------------------------------------------------
  47. !BOP
  48. !
  49. ! !IROUTINE: ByColumnGSMap_ - Generate Row-based GlobalSegMap for SparseMatrix
  50. !
  51. ! !INTERFACE:
  52. subroutine ByColumnGSMap_(xGSMap, sMat, sMGSMap, root, comm)
  53. !
  54. ! !USES:
  55. !
  56. use m_die, only: MP_perr_die,die
  57. use m_List, only: List
  58. use m_List, only: List_init => init
  59. use m_List, only: List_clean => clean
  60. use m_AttrVect, only: AttrVect
  61. use m_AttrVect, only: AttrVect_init => init
  62. use m_AttrVect, only: AttrVect_zero => zero
  63. use m_AttrVect, only: AttrVect_lsize => lsize
  64. use m_AttrVect, only: AttrVect_indexIA => indexIA
  65. use m_AttrVect, only: AttrVect_copy => copy
  66. use m_AttrVect, only: AttrVect_clean => clean
  67. use m_AttrVectComms, only: AttrVect_scatter => scatter
  68. use m_AttrVectComms, only: AttrVect_gather => gather
  69. use m_GlobalMap, only : GlobalMap
  70. use m_GlobalMap, only : GlobalMap_init => init
  71. use m_GlobalMap, only : GlobalMap_clean => clean
  72. use m_GlobalSegMap, only: GlobalSegMap
  73. use m_GlobalSegMap, only: GlobalSegMap_init => init
  74. use m_GlobalSegMap, only: GlobalSegMap_peLocs => peLocs
  75. use m_GlobalSegMap, only: GlobalSegMap_comp_id => comp_id
  76. use m_SparseMatrix, only: SparseMatrix
  77. use m_SparseMatrix, only: SparseMatrix_lsize => lsize
  78. use m_SparseMatrix, only: SparseMatrix_SortPermute => SortPermute
  79. implicit none
  80. ! !INPUT PARAMETERS:
  81. !
  82. type(GlobalSegMap), intent(in) :: xGSMap
  83. integer, intent(in) :: root
  84. integer, intent(in) :: comm
  85. ! !INPUT/OUTPUT PARAMETERS:
  86. !
  87. type(SparseMatrix), intent(inout) :: sMat
  88. ! !OUTPUT PARAMETERS:
  89. !
  90. type(GlobalSegMap), intent(out) :: sMGSMap
  91. ! !DESCRIPTION: This routine is invoked from all processes on the
  92. ! communicator {\tt comm} to create from an input {\tt SparseMatrix}
  93. ! {\tt sMat} (valid only on the {\tt root} process) and an input
  94. ! {\bf x}-vector decomposition described by the {\tt GlobalSegMap}
  95. ! argument {\tt xGSMap} (valid at least on the {\tt root}) to create
  96. ! an output {\tt GlobalSegMap} decomposition of the matrix elements
  97. ! {\tt sMGSMap}, which is valid on all processes on the communicator.
  98. ! This matrix {\tt GlobalSegMap} describes the corresponding column
  99. ! decomposition of {\tt sMat}.
  100. !
  101. ! {\bf N.B.}: The argument {\tt sMat} is returned sorted in lexicographic
  102. ! order by column and row.
  103. !
  104. ! !REVISION HISTORY:
  105. !
  106. ! 13Apr01 - J.W. Larson <larson@mcs.anl.gov> - initial API spec.
  107. ! 26Apr01 - R.L. Jacob <jacob@mcs.anl.gov> - add use statements for
  108. ! GlobalSegMap_init and GSMap_peLocs.
  109. ! Add gsize argument required to GSMap_peLocs.
  110. ! Add underscore to ComputeSegments call so it matches
  111. ! the subroutine decleration.
  112. ! change attribute on starts,lengths, and pe_locs to
  113. ! pointer to match GSMap_init.
  114. ! add use m_die statement
  115. ! 26Apr01 - J.W. Larson <larson@mcs.anl.gov> - fixed major logic bug
  116. ! that had all processes executing some operations that
  117. ! should only occur on the root.
  118. ! 09Jul03 - E.T. Ong <eong@mcs.anl.gov> - call pe_locs in parallel.
  119. ! reduce the serial sort from gcol:grow to just gcol.
  120. !EOP
  121. !-------------------------------------------------------------------------
  122. character(len=*),parameter :: myname_=myname//'ByColumnGSMap_'
  123. ! Process ID number
  124. integer :: myID, mySIZE
  125. ! Attributes for the output GlobalSegMap
  126. integer :: gsize, comp_id, ngseg
  127. ! Temporary array for identifying each matrix element column and
  128. ! process ID destination
  129. type(AttrVect) :: gcol
  130. type(AttrVect) :: dist_gcol
  131. type(AttrVect) :: element_pe_locs
  132. type(AttrVect) :: dist_element_pe_locs
  133. ! Index variables for the AttrVects
  134. integer :: dist_gsize
  135. integer :: gcol_index
  136. integer :: element_pe_locs_index
  137. ! Temporary array for initializing GlobalMap Decomposition
  138. integer,dimension(:), allocatable :: counts
  139. ! GlobalMap for setting up decomposition to call pe_locs
  140. type(GlobalMap) :: dist_GMap
  141. ! Temporary arrays for matrix GlobalSegMap attributes
  142. integer, dimension(:), pointer :: starts, lengths, pe_locs
  143. ! List storage for sorting keys
  144. type(List) :: sort_keys
  145. ! Error flag
  146. integer :: ierr
  147. ! Loop index
  148. integer :: i
  149. ! Determine process id number myID
  150. call MPI_COMM_RANK(comm, myID, ierr)
  151. if(ierr /= 0) then
  152. call MP_perr_die(myname_,'call MPI_COMM_RANK(...',ierr)
  153. endif
  154. ! Determine the number of processors in communicator
  155. call MPI_COMM_SIZE(comm, mySIZE, ierr)
  156. if(ierr /= 0) then
  157. call MP_perr_die(myname_,'call MPI_COMM_SIZE(...',ierr)
  158. endif
  159. ! Allocate space for GlobalMap length information
  160. allocate(counts(0:mySIZE-1),stat=ierr)
  161. if(ierr/=0) call die(myname_,"allocate(counts)",ierr)
  162. ! First step: a lot of prep work on the root only:
  163. if(myID == root) then
  164. ! Sort the matrix entries in sMat by column.
  165. ! First, create the key list...
  166. call List_init(sort_keys,'gcol')
  167. ! Now perform the sort/permute...
  168. call SparseMatrix_SortPermute(sMat, sort_keys)
  169. call List_clean(sort_keys)
  170. ! The global size of matrix GlobalSegMap is the number nonzero
  171. ! elements in sMat.
  172. gsize = SparseMatrix_lsize(sMat)
  173. ! Allocate storage space for matrix element column indices and
  174. ! process ID destinations
  175. call AttrVect_init(aV=gcol, iList="gcol", lsize=gsize)
  176. ! Extract global column information and place in array gCol
  177. call AttrVect_copy(aVin=sMat%data, aVout=gcol, iList="gcol")
  178. ! Setup GlobalMap decomposition lengths:
  179. do i=0,mySIZE-1
  180. counts(i) = gsize/mySIZE
  181. enddo
  182. counts(mySIZE-1) = counts(mySIZE-1) + mod(gsize,mySIZE)
  183. endif
  184. ! Initialize GlobalMap so that we can scatter the global row
  185. ! information. The GlobalMap will inherit the component ID
  186. ! from xGSMap
  187. comp_id = GlobalSegMap_comp_id(xGSMap)
  188. call GlobalMap_init(GMap=dist_GMap, comp_id=comp_id, lns=counts, &
  189. root=root, comm=comm)
  190. call AttrVect_scatter(iV=gcol, oV=dist_gcol, GMap=dist_GMap, &
  191. root=root, comm=comm)
  192. ! Similarly, we want to scatter the element_pe_locs using the
  193. ! same decomposition
  194. dist_gsize = AttrVect_lsize(dist_gcol)
  195. call AttrVect_init(aV=dist_element_pe_locs, iList="element_pe_locs", &
  196. lsize=dist_gsize)
  197. call AttrVect_zero(dist_element_pe_locs)
  198. ! Compute process ID destination for each matrix element,
  199. ! and store in the AttrVect element_pe_locs
  200. gcol_index = AttrVect_indexIA(dist_gcol,"gcol", dieWith=myname_)
  201. element_pe_locs_index = AttrVect_indexIA(dist_element_pe_locs, &
  202. "element_pe_locs", dieWith=myname_)
  203. call GlobalSegMap_peLocs(xGSMap, dist_gsize, &
  204. dist_gcol%iAttr(gcol_index,1:dist_gsize), &
  205. dist_element_pe_locs%iAttr(element_pe_locs_index,1:dist_gsize))
  206. call AttrVect_gather(iV=dist_element_pe_locs, oV=element_pe_locs, &
  207. GMap=dist_GMap, root=root, comm=comm)
  208. ! Back to the root operations
  209. if(myID == root) then
  210. ! Sanity check: Is the globalsize of sMat the same as the
  211. ! gathered size of element_pe_locs?
  212. if(gsize /= AttrVect_lsize(element_pe_locs)) then
  213. call die(myname_,"gsize /= AttrVect_lsize(element_pe_locs) &
  214. & on root process")
  215. endif
  216. ! Using the entries of gCol and element_pe_locs, build the
  217. ! output GlobalSegMap attribute arrays starts(:), lengths(:),
  218. ! and pe_locs(:)
  219. gcol_index = AttrVect_indexIA(gcol,"gcol", dieWith=myname_)
  220. element_pe_locs_index = AttrVect_indexIA(element_pe_locs, &
  221. "element_pe_locs", dieWith=myname_)
  222. call ComputeSegments_(element_pe_locs%iAttr(element_pe_locs_index, &
  223. 1:gsize), &
  224. gcol%iAttr(gcol_index,1:gsize), &
  225. gsize, ngseg, starts, lengths, pe_locs)
  226. ! Clean up on the root
  227. call AttrVect_clean(gcol)
  228. call AttrVect_clean(element_pe_locs)
  229. endif ! if(myID == root)
  230. ! Non-root processes call GlobalSegMap_init with root_start,
  231. ! root_length, and root_pe_loc, although these arguments are
  232. ! not used in the subroutine. Since these correspond to dummy
  233. ! shaped array arguments in initr_, the Fortran 90 standard
  234. ! dictates that the actual arguments must contain complete shape
  235. ! information. Therefore, these array arguments must be
  236. ! allocated on all processes.
  237. if(myID /= root) then
  238. allocate(starts(0),lengths(0),pe_locs(0),stat=ierr)
  239. if(ierr /= 0) then
  240. call die(myname_,'non-root allocate(starts...',ierr)
  241. endif
  242. endif
  243. ! Using this local data on the root, create the SparseMatrix
  244. ! GlobalSegMap sMGSMap (which will be valid on all processes
  245. ! on the communicator:
  246. call GlobalSegMap_init(sMGSMap, ngseg, starts, lengths, pe_locs, &
  247. root, comm, comp_id, gsize)
  248. ! Clean up
  249. call GlobalMap_clean(dist_GMap)
  250. call AttrVect_clean(dist_gcol)
  251. call AttrVect_clean(dist_element_pe_locs)
  252. deallocate(starts, lengths, pe_locs, counts, stat=ierr)
  253. if(ierr /= 0) then
  254. call die(myname_,'deallocate(starts...',ierr)
  255. endif
  256. end subroutine ByColumnGSMap_
  257. !-------------------------------------------------------------------------
  258. ! Math + Computer Science Division / Argonne National Laboratory !
  259. !-------------------------------------------------------------------------
  260. !BOP
  261. !
  262. ! !IROUTINE: ByRowGSMap_ - Generate Row-based GlobalSegMap for SparseMatrix
  263. !
  264. ! !INTERFACE:
  265. subroutine ByRowGSMap_(yGSMap, sMat, sMGSMap, root, comm)
  266. !
  267. ! !USES:
  268. !
  269. use m_die, only: MP_perr_die,die
  270. use m_List, only: List
  271. use m_List, only: List_init => init
  272. use m_List, only: List_clean => clean
  273. use m_AttrVect, only: AttrVect
  274. use m_AttrVect, only: AttrVect_init => init
  275. use m_AttrVect, only: AttrVect_lsize => lsize
  276. use m_AttrVect, only: AttrVect_indexIA => indexIA
  277. use m_AttrVect, only: AttrVect_copy => copy
  278. use m_AttrVect, only: AttrVect_clean => clean
  279. use m_AttrVect, only: AttrVect_zero => zero
  280. use m_AttrVectComms, only: AttrVect_scatter => scatter
  281. use m_AttrVectComms, only: AttrVect_gather => gather
  282. use m_GlobalMap, only : GlobalMap
  283. use m_GlobalMap, only : GlobalMap_init => init
  284. use m_GlobalMap, only : GlobalMap_clean => clean
  285. use m_GlobalSegMap, only: GlobalSegMap
  286. use m_GlobalSegMap, only: GlobalSegMap_init => init
  287. use m_GlobalSegMap, only: GlobalSegMap_peLocs => peLocs
  288. use m_GlobalSegMap, only: GlobalSegMap_comp_id => comp_id
  289. use m_SparseMatrix, only: SparseMatrix
  290. use m_SparseMatrix, only: SparseMatrix_lsize => lsize
  291. use m_SparseMatrix, only: SparseMatrix_SortPermute => SortPermute
  292. implicit none
  293. ! !INPUT PARAMETERS:
  294. !
  295. type(GlobalSegMap), intent(in) :: yGSMap
  296. integer, intent(in) :: root
  297. integer, intent(in) :: comm
  298. ! !INPUT/OUTPUT PARAMETERS:
  299. !
  300. type(SparseMatrix), intent(inout) :: sMat
  301. ! !OUTPUT PARAMETERS:
  302. !
  303. type(GlobalSegMap), intent(out) :: sMGSMap
  304. ! !DESCRIPTION: This routine is invoked from all processes on the
  305. ! communicator {\tt comm} to create from an input {\tt SparseMatrix}
  306. ! {\tt sMat} (valid only on the {\tt root} process) and an input
  307. ! {\bf y}-vector decomposition described by the {\tt GlobalSegMap}
  308. ! argument {\tt yGSMap} (valid at least on the {\tt root}) to create
  309. ! an output {\tt GlobalSegMap} decomposition of the matrix elements
  310. ! {\tt sMGSMap}, which is valid on all processes on the communicator.
  311. ! This matrix {\tt GlobalSegMap} describes the corresponding row
  312. ! decomposition of {\tt sMat}.
  313. !
  314. ! {\bf N.B.}: The argument {\tt sMat} is returned sorted in lexicographic
  315. ! order by row and column.
  316. !
  317. ! !REVISION HISTORY:
  318. !
  319. ! 13Apr01 - J.W. Larson <larson@mcs.anl.gov> - initial API spec.
  320. ! 26Apr01 - R.L. Jacob <jacob@mcs.anl.gov> - add use statements for
  321. ! GlobalSegMap_init and GSMap_peLocs.
  322. ! Add gsize argument required to GSMap_peLocs.
  323. ! Add underscore to ComputeSegments call so it matches
  324. ! the subroutine decleration.
  325. ! change attribute on starts,lengths, and pe_locs to
  326. ! pointer to match GSMap_init.
  327. ! 26Apr01 - J.W. Larson <larson@mcs.anl.gov> - fixed major logic bug
  328. ! that had all processes executing some operations that
  329. ! should only occur on the root.
  330. ! 09Jun03 - E.T. Ong <eong@mcs.anl.gov> - call peLocs in parallel.
  331. ! reduce the serial sort from grow:gcol to just grow.
  332. !EOP
  333. !-------------------------------------------------------------------------
  334. character(len=*),parameter :: myname_=myname//'ByRowGSMap_'
  335. ! Process ID number and communicator size
  336. integer :: myID, mySIZE
  337. ! Attributes for the output GlobalSegMap
  338. integer :: gsize, comp_id, ngseg
  339. ! Temporary array for identifying each matrix element row and
  340. ! process ID destination
  341. type(AttrVect) :: grow
  342. type(AttrVect) :: dist_grow
  343. type(AttrVect) :: element_pe_locs
  344. type(AttrVect) :: dist_element_pe_locs
  345. ! Index variables for AttrVects
  346. integer :: dist_gsize
  347. integer :: grow_index
  348. integer :: element_pe_locs_index
  349. ! Temporary array for initializing GlobalMap Decomposition
  350. integer,dimension(:), allocatable :: counts
  351. ! GlobalMap for setting up decomposition to call pe_locs
  352. type(GlobalMap) :: dist_GMap
  353. ! Temporary arrays for matrix GlobalSegMap attributes
  354. integer, dimension(:), pointer :: starts, lengths, pe_locs
  355. ! List storage for sorting keys
  356. type(List) :: sort_keys
  357. ! Error flag
  358. integer :: ierr
  359. ! Loop index
  360. integer :: i
  361. ! Determine process id number myID
  362. call MPI_COMM_RANK(comm, myID, ierr)
  363. if(ierr /= 0) then
  364. call MP_perr_die(myname_,'call MPI_COMM_RANK(...',ierr)
  365. endif
  366. ! Determine the number of processors in communicator
  367. call MPI_COMM_SIZE(comm, mySIZE, ierr)
  368. if(ierr /= 0) then
  369. call MP_perr_die(myname_,'call MPI_COMM_SIZE(...',ierr)
  370. endif
  371. ! Allocate space for GlobalMap length information
  372. allocate(counts(0:mySIZE-1),stat=ierr)
  373. if(ierr/=0) call die(myname_,"allocate(counts)",ierr)
  374. ! First step: a lot of prep work on the root only:
  375. if(myID == root) then
  376. ! Sort the matrix entries in sMat by row.
  377. ! First, create the key list...
  378. call List_init(sort_keys,'grow')
  379. ! Now perform the sort/permute...
  380. call SparseMatrix_SortPermute(sMat, sort_keys)
  381. call List_clean(sort_keys)
  382. ! The global size of matrix GlobalSegMap is the number of rows.
  383. gsize = SparseMatrix_lsize(sMat)
  384. ! Allocate storage space for matrix element row indices and
  385. ! process ID destinations
  386. call AttrVect_init(aV=grow, iList="grow", lsize=gsize)
  387. ! Extract global row information and place in AttrVect grow
  388. call AttrVect_copy(aVin=sMat%data, aVout=grow, iList="grow")
  389. ! Setup GlobalMap decomposition lengths:
  390. ! Give any extra points to the last process
  391. do i=0,mySIZE-1
  392. counts(i) = gsize/mySIZE
  393. enddo
  394. counts(mySIZE-1) = counts(mySIZE-1) + mod(gsize,mySIZE)
  395. endif
  396. ! Initialize GlobalMap and scatter the global row information.
  397. ! The GlobalMap will inherit the component ID from yGSMap
  398. comp_id = GlobalSegMap_comp_id(yGSMap)
  399. call GlobalMap_init(GMap=dist_GMap, comp_id=comp_id, lns=counts, &
  400. root=root, comm=comm)
  401. call AttrVect_scatter(iV=grow, oV=dist_grow, GMap=dist_GMap, &
  402. root=root, comm=comm)
  403. ! Similarly, we want to scatter the element_pe_locs using the
  404. ! same decomposition
  405. dist_gsize = AttrVect_lsize(dist_grow)
  406. call AttrVect_init(aV=dist_element_pe_locs, iList="element_pe_locs", &
  407. lsize=dist_gsize)
  408. call AttrVect_zero(dist_element_pe_locs)
  409. ! Compute process ID destination for each matrix element,
  410. ! and store in the AttrVect element_pe_locs
  411. grow_index = AttrVect_indexIA(dist_grow,"grow", dieWith=myname_)
  412. element_pe_locs_index = AttrVect_indexIA(dist_element_pe_locs, &
  413. "element_pe_locs", dieWith=myname_)
  414. call GlobalSegMap_peLocs(yGSMap, dist_gsize, &
  415. dist_grow%iAttr(grow_index,1:dist_gsize), &
  416. dist_element_pe_locs%iAttr(element_pe_locs_index,1:dist_gsize))
  417. ! Gather element_pe_locs on root so that we can call compute_segments
  418. call AttrVect_gather(iV=dist_element_pe_locs, oV=element_pe_locs, &
  419. GMap=dist_GMap, root=root, comm=comm)
  420. ! Back to the root operations
  421. if(myID == root) then
  422. ! Sanity check: Is the globalsize of sMat the same as the
  423. ! gathered size of element_pe_locs?
  424. if(gsize /= AttrVect_lsize(element_pe_locs)) then
  425. call die(myname_,"gsize /= AttrVect_lsize(element_pe_locs) &
  426. & on root process")
  427. endif
  428. ! Using the entries of grow and element_pe_locs, build the
  429. ! output GlobalSegMap attribute arrays starts(:), lengths(:),
  430. ! and pe_locs(:)
  431. grow_index = AttrVect_indexIA(grow,"grow", dieWith=myname_)
  432. element_pe_locs_index = AttrVect_indexIA(element_pe_locs, &
  433. "element_pe_locs", dieWith=myname_)
  434. call ComputeSegments_(element_pe_locs%iAttr(element_pe_locs_index, &
  435. 1:gsize), &
  436. grow%iAttr(grow_index,1:gsize), &
  437. gsize, ngseg, starts, lengths, pe_locs)
  438. ! Clean up on the root
  439. call AttrVect_clean(grow)
  440. call AttrVect_clean(element_pe_locs)
  441. endif ! if(myID == root)
  442. ! Non-root processes call GlobalSegMap_init with root_start,
  443. ! root_length, and root_pe_loc, although these arguments are
  444. ! not used in the subroutine. Since these correspond to dummy
  445. ! shaped array arguments in initr_, the Fortran 90 standard
  446. ! dictates that the actual arguments must contain complete shape
  447. ! information. Therefore, these array arguments must be
  448. ! allocated on all processes.
  449. if(myID /= root) then
  450. allocate(starts(0),lengths(0),pe_locs(0),stat=ierr)
  451. if(ierr /= 0) then
  452. call die(myname_,'non-root allocate(starts...',ierr)
  453. endif
  454. endif
  455. ! Using this local data on the root, create the SparseMatrix
  456. ! GlobalSegMap sMGSMap (which will be valid on all processes
  457. ! on the communicator. The GlobalSegMap will inherit the
  458. ! component ID from yGSMap
  459. call GlobalSegMap_init(sMGSMap, ngseg, starts, lengths, pe_locs, &
  460. root, comm, comp_id, gsize)
  461. ! Clean up:
  462. call GlobalMap_clean(dist_GMap)
  463. call AttrVect_clean(dist_grow)
  464. call AttrVect_clean(dist_element_pe_locs)
  465. deallocate(starts, lengths, pe_locs, counts, stat=ierr)
  466. if(ierr /= 0) then
  467. call die(myname_,'deallocate(starts...',ierr)
  468. endif
  469. end subroutine ByRowGSMap_
  470. !-------------------------------------------------------------------------
  471. ! Math + Computer Science Division / Argonne National Laboratory !
  472. !-------------------------------------------------------------------------
  473. !BOP
  474. !
  475. ! !IROUTINE: ComputeSegments_ - Create segments from list data.
  476. !
  477. ! !INTERFACE:
  478. subroutine ComputeSegments_(element_pe_locs, elements, num_elements, &
  479. nsegs, seg_starts, seg_lengths, seg_pe_locs)
  480. !
  481. ! !USES:
  482. !
  483. use m_die, only: die
  484. implicit none
  485. ! !INPUT PARAMETERS:
  486. !
  487. integer, dimension(:), intent(in) :: element_pe_locs
  488. integer, dimension(:), intent(in) :: elements
  489. integer, intent(in) :: num_elements
  490. ! !OUTPUT PARAMETERS:
  491. !
  492. integer, intent(out) :: nsegs
  493. integer, dimension(:), pointer :: seg_starts
  494. integer, dimension(:), pointer :: seg_lengths
  495. integer, dimension(:), pointer :: seg_pe_locs
  496. ! !DESCRIPTION: This routine examins an input list of {\tt num\_elements}
  497. ! process ID locations stored in the array {\tt element\_pe\_locs}, counts
  498. ! the number of contiguous segments {\tt nsegs}, and returns the segment
  499. ! start index, length, and process ID location in the arrays {\tt seg\_starts(:)},
  500. ! {\tt seg\_lengths(:)}, and {\tt seg\_pe\_locs(:)}, respectively.
  501. !
  502. ! {\bf N.B.}: The argument {\tt sMat} is returned sorted in lexicographic
  503. ! order by row and column.
  504. !
  505. ! !REVISION HISTORY:
  506. !
  507. ! 18Apr01 - J.W. Larson <larson@mcs.anl.gov> - initial version.
  508. ! 28Aug01 - M.J. Zavislak <zavislak@mcs.anl.gov>
  509. ! Changed first sanity check to get size(element_pe_locs)
  510. ! instead of size(elements)
  511. !EOP
  512. !-------------------------------------------------------------------------
  513. character(len=*),parameter :: myname_=myname//'ComputeSegments_'
  514. integer :: i, ierr, iseg
  515. ! Input argument sanity checks:
  516. if(size(element_pe_locs) < num_elements) then
  517. call die(myname_,'input argument array element_pe_locs too small', &
  518. num_elements-size(element_pe_locs))
  519. endif
  520. if(size(elements) < num_elements) then
  521. call die(myname_,'input argument array elements too small', &
  522. num_elements-size(elements))
  523. endif
  524. ! First pass: how many segments?
  525. do i=1,num_elements
  526. if(i == 1) then ! bootstrap segment count
  527. nsegs = 1
  528. else ! usual point/segment processing
  529. ! New segment? If so, increment nsegs.
  530. if((elements(i) > elements(i-1) + 1) .or. &
  531. (element_pe_locs(i) /= element_pe_locs(i-1))) then ! new segment
  532. nsegs = nsegs + 1
  533. endif
  534. endif ! if(i == 1) block
  535. end do ! do i=1,num_elements
  536. allocate(seg_starts(nsegs), seg_lengths(nsegs), seg_pe_locs(nsegs), &
  537. stat=ierr)
  538. if(ierr /= 0) then
  539. call die(myname_,'allocate(seg_starts...',ierr)
  540. endif
  541. ! Second pass: fill in segment data.
  542. ! NOTE: Structure of this loop was changed from a for loop
  543. ! to avoid a faulty vectorization on the SUPER-UX compiler
  544. i=1
  545. ASSIGN_LOOP: do
  546. if(i == 1) then ! bootstrap first segment info.
  547. iseg = 1
  548. seg_starts(iseg) = 1
  549. seg_lengths(iseg) = 1
  550. seg_pe_locs(iseg) = element_pe_locs(iseg)
  551. else ! do usual point/segment processing
  552. ! New segment? This happens if 1) elements(i) > elements(i-1) + 1, or
  553. ! 2) element_pe_locs(i) /= element_pe_locs(i-1).
  554. if((elements(i) > elements(i-1) + 1) .or. &
  555. (element_pe_locs(i) /= element_pe_locs(i-1))) then ! new segment
  556. ! Initialize new segment
  557. iseg = iseg + 1
  558. seg_starts(iseg) = i
  559. seg_lengths(iseg) = 1
  560. seg_pe_locs(iseg) = element_pe_locs(i)
  561. else
  562. ! Increment current segment length
  563. seg_lengths(iseg) = seg_lengths(iseg) + 1
  564. endif ! If new segment block
  565. endif ! if(i == 1) block
  566. ! Prepare index i for the next loop around;
  567. if(i>=num_elements) EXIT
  568. i = i + 1
  569. end do ASSIGN_LOOP
  570. if(iseg /= nsegs) then
  571. call die(myname_,'segment number difference',iseg-nsegs)
  572. endif
  573. end subroutine ComputeSegments_
  574. end module m_SparseMatrixDecomp