m_GlobalSegMap.F90 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434
  1. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2. ! Math and Computer Science Division, Argonne National Laboratory !
  3. !-----------------------------------------------------------------------
  4. ! CVS m_GlobalSegMap.F90,v 1.56 2009-03-17 16:51:49 jacob Exp
  5. ! CVS MCT_2_8_0
  6. !BOP -------------------------------------------------------------------
  7. !
  8. ! !MODULE: m_GlobalSegMap - a nontrivial 1-D decomposition of an array.
  9. !
  10. ! !DESCRIPTION:
  11. ! Consider the problem of the 1-dimensional decomposition of an array
  12. ! across multiple processes. If each process owns only one contiguous
  13. ! segment, then the {\tt GlobalMap} (see {\tt m\_GlobalMap} or details)
  14. ! is sufficient to describe the decomposition. If, however, each
  15. ! process owns multiple, non-adjacent segments of the array, a more
  16. ! sophisticated approach is needed. The {\tt GlobalSegMap} data type
  17. ! allows one to describe a one-dimensional decomposition of an array
  18. ! with each process owning multiple, non-adjacent segments of the array.
  19. !
  20. ! In the current implementation of the {\tt GlobalSegMap}, there is no
  21. ! santity check to guarantee that
  22. !$${\tt GlobalSegMap\%gsize} = \sum_{{\tt i}=1}^{\tt ngseg}
  23. ! {\tt GlobalSegMap\%length(i)} . $$
  24. ! The reason we have not implemented such a check is to allow the user
  25. ! to use the {\tt GlobalSegMap} type to support decompositions of both
  26. ! {\em haloed} and {\em masked} data.
  27. !
  28. ! !INTERFACE:
  29. module m_GlobalSegMap
  30. implicit none
  31. private ! except
  32. ! !PUBLIC MEMBER FUNCTIONS:
  33. public :: GlobalSegMap ! The class data structure
  34. public :: init ! Create
  35. public :: clean ! Destroy
  36. public :: comp_id ! Return component ID number
  37. public :: gsize ! Return global vector size (excl. halos)
  38. public :: GlobalStorage ! Return total number of points in map,
  39. ! including halo points (if present).
  40. public :: ProcessStorage ! Return local storage on a given process.
  41. public :: OrderedPoints ! Return grid points of a given process in
  42. ! MCT-assumed order.
  43. public :: lsize ! Return local--that is, on-process--storage
  44. ! size (incl. halos)
  45. public :: ngseg ! Return global number of segments
  46. public :: nlseg ! Return local number of segments
  47. public :: max_nlseg ! Return max local number of segments
  48. public :: active_pes ! Return number of pes with at least 1
  49. ! datum, and if requested, a list of them.
  50. public :: peLocs ! Given an input list of point indices,
  51. ! return its (unique) process ID.
  52. public :: haloed ! Is the input GlobalSegMap haloed?
  53. public :: rank ! Rank which process owns a datum
  54. public :: Sort ! compute index permutation to re-order
  55. ! GlobalSegMap%start, GlobalSegMap%length,
  56. ! and GlobalSegMap%pe_loc
  57. public :: Permute ! apply index permutation to re-order
  58. ! GlobalSegMap%start, GlobalSegMap%length,
  59. ! and GlobalSegMap%pe_loc
  60. public :: SortPermute ! compute index permutation and apply it to
  61. ! re-order the GlobalSegMap components
  62. ! GlobalSegMap%start, GlobalSegMap%length,
  63. ! and GlobalSegMap%pe_loc
  64. public :: increasing ! Are the indices for each pe strictly
  65. ! increasing?
  66. public :: copy ! Copy the gsmap
  67. ! !PUBLIC TYPES:
  68. type GlobalSegMap
  69. #ifdef SEQUENCE
  70. sequence
  71. #endif
  72. integer :: comp_id ! Component ID number
  73. integer :: ngseg ! No. of Global segments
  74. integer :: gsize ! No. of Global elements
  75. integer,dimension(:),pointer :: start ! global seg. start index
  76. integer,dimension(:),pointer :: length ! segment lengths
  77. integer,dimension(:),pointer :: pe_loc ! PE locations
  78. end type GlobalSegMap
  79. interface init ; module procedure &
  80. initd_, & ! initialize from all PEs
  81. initr_, & ! initialize from the root
  82. initp_, & ! initialize in parallel from replicated arrays
  83. initp1_, & ! initialize in parallel from 1 replicated array
  84. initp0_, & ! null constructor using replicated data
  85. init_index_ ! initialize from local index arrays
  86. end interface
  87. interface clean ; module procedure clean_ ; end interface
  88. interface comp_id ; module procedure comp_id_ ; end interface
  89. interface gsize ; module procedure gsize_ ; end interface
  90. interface GlobalStorage ; module procedure &
  91. GlobalStorage_
  92. end interface
  93. interface ProcessStorage ; module procedure &
  94. ProcessStorage_
  95. end interface
  96. interface OrderedPoints ; module procedure &
  97. OrderedPoints_
  98. end interface
  99. interface lsize ; module procedure lsize_ ; end interface
  100. interface ngseg ; module procedure ngseg_ ; end interface
  101. interface nlseg ; module procedure nlseg_ ; end interface
  102. interface max_nlseg ; module procedure max_nlseg_ ; end interface
  103. interface active_pes ; module procedure active_pes_ ; end interface
  104. interface peLocs ; module procedure peLocs_ ; end interface
  105. interface haloed ; module procedure haloed_ ; end interface
  106. interface rank ; module procedure &
  107. rank1_ , & ! single rank case
  108. rankm_ ! degenerate (multiple) ranks for halo case
  109. end interface
  110. interface Sort ; module procedure Sort_ ; end interface
  111. interface Permute ; module procedure &
  112. PermuteInPlace_
  113. end interface
  114. interface SortPermute ; module procedure &
  115. SortPermuteInPlace_
  116. end interface
  117. interface increasing ; module procedure increasing_ ; end interface
  118. interface copy ; module procedure copy_ ; end interface
  119. ! !REVISION HISTORY:
  120. ! 28Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  121. ! 26Jan01 - J.W. Larson <larson@mcs.anl.gov> - replaced the component
  122. ! GlobalSegMap%comm with GlobalSegMap%comp_id.
  123. ! 06Feb01 - J.W. Larson <larson@mcs.anl.gov> - removed the
  124. ! GlobalSegMap%lsize component. Also, added the
  125. ! GlobalStorage query function.
  126. ! 24Feb01 - J.W. Larson <larson@mcs.anl.gov> - Added the replicated
  127. ! initialization routines initp_() and initp1().
  128. ! 25Feb01 - J.W. Larson <larson@mcs.anl.gov> - Added the routine
  129. ! ProcessStorage_().
  130. ! 18Apr01 - J.W. Larson <larson@mcs.anl.gov> - Added the routine
  131. ! peLocs().
  132. ! 26Apr01 - R. Jacob <jacob@mcs.anl.gov> - Added the routine
  133. ! OrderedPoints_().
  134. ! 03Aug01 - E. Ong <eong@mcs.anl.gov> - In initd_, call initr_
  135. ! with actual shaped arguments on non-root processes to satisfy
  136. ! F90 standard. See comments in initd.
  137. ! 18Oct01 - J.W. Larson <larson@mcs.anl.gov> - Added the routine
  138. ! bcast(), and also cleaned up prologues.
  139. !EOP ___________________________________________________________________
  140. character(len=*),parameter :: myname='m_GlobalSegMap'
  141. contains
  142. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  143. ! Math and Computer Science Division, Argonne National Laboratory !
  144. !BOP -------------------------------------------------------------------
  145. !
  146. ! !IROUTINE: initd_ - define the map from distributed data
  147. !
  148. ! !DESCRIPTION:
  149. ! This routine takes the {\em scattered} input {\tt INTEGER} arrays
  150. ! {\tt start}, {\tt length}, and {\tt pe\_loc}, gathers these data to
  151. ! the {\tt root} process, and from them creates a {\em global} set of
  152. ! segment information for the output {\tt GlobalSegMap} argument
  153. ! {\tt GSMap}. The input {\tt INTEGER} arguments {\tt comp\_id},
  154. ! {\tt gsize} provide the {\tt GlobalSegMap} component ID number and
  155. ! global grid size, respectively. The input argument {\tt my\_comm} is
  156. ! the F90 {\tt INTEGER} handle for the MPI communicator. If the input
  157. ! arrays are overdimensioned, optional argument {\em numel} can be
  158. ! used to specify how many elements should be used.
  159. !
  160. !
  161. ! !INTERFACE:
  162. subroutine initd_(GSMap, start, length, root, my_comm, &
  163. comp_id, pe_loc, gsize, numel)
  164. !
  165. ! !USES:
  166. !
  167. use m_mpif90
  168. use m_die
  169. use m_stdio
  170. use m_FcComms, only : fc_gather_int, fc_gatherv_int
  171. implicit none
  172. ! !INPUT PARAMETERS:
  173. integer,dimension(:),intent(in) :: start ! segment local start
  174. ! indices
  175. integer,dimension(:),intent(in) :: length ! segment local lengths
  176. integer,intent(in) :: root ! root on my_com
  177. integer,intent(in) :: my_comm ! local communicatior
  178. integer,intent(in) :: comp_id ! component model ID
  179. integer,dimension(:), pointer, optional :: pe_loc ! process location
  180. integer,intent(in), optional :: gsize ! global vector size
  181. ! (optional). It can
  182. ! be computed by this
  183. ! routine if no haloing
  184. ! is assumed.
  185. integer,intent(in), optional :: numel ! specify number of elements
  186. ! to use in start, length
  187. ! !OUTPUT PARAMETERS:
  188. type(GlobalSegMap),intent(out) :: GSMap ! Output GlobalSegMap
  189. ! !REVISION HISTORY:
  190. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  191. ! 14Nov00 - J.W. Larson <larson@mcs.anl.gov> - final working version
  192. ! 09Jan01 - J.W. Larson <larson@mcs.anl.gov> - repaired: a subtle
  193. ! bug concerning the usage of the argument pe_loc (result
  194. ! was the new pointer variable my_pe_loc); a mistake in
  195. ! the tag arguments to MPI_IRECV; a bug in the declaration
  196. ! of the array status used by MPI_WAITALL.
  197. ! 26Jan01 - J.W. Larson <larson@mcs.anl.gov> - replaced optional
  198. ! argument gsm_comm with required argument comp_id.
  199. ! 23Sep02 - Add optional argument numel to allow start, length
  200. ! arrays to be overdimensioned.
  201. ! 31Jan09 - P.H. Worley <worleyph@ornl.gov> - replaced irecv/send/waitall
  202. ! logic with calls to flow controlled gather routines
  203. !EOP ___________________________________________________________________
  204. character(len=*),parameter :: myname_=myname//'::initd_'
  205. integer :: nPEs, myID, ier, l, i
  206. integer :: ngseg ! number of global segments
  207. integer :: nlseg ! number of local segments
  208. integer :: nlseg_tmp(1) ! workaround for explicit interface expecting an array
  209. ! arrays allocated on the root to which data are gathered
  210. integer, dimension(:), allocatable :: root_start, root_length, root_pe_loc
  211. ! arrays allocated on the root to coordinate gathering of
  212. ! data and non-blocking receives by the root
  213. integer, dimension(:), allocatable :: counts, displs
  214. ! data and non-blocking receives by the root
  215. integer, dimension(:), pointer :: my_pe_loc
  216. ! Determine local process ID:
  217. call MP_COMM_RANK(my_comm, myID, ier)
  218. if(ier /= 0) call MP_perr_die(myname_,'MP_comm_rank()',ier)
  219. ! Check consistency of sizes of input arrays:
  220. if(size(length) /= size(start)) then
  221. ier = -1
  222. call die(myname_,'length/start array size mismatch',ier)
  223. endif
  224. if(present(pe_loc)) then
  225. if(size(pe_loc) /= size(start)) then
  226. ier = -1
  227. call die(myname_,'pe_loc/start array size mismatch',ier)
  228. endif
  229. endif
  230. ! Store in the variable nlseg the local size
  231. ! array start(:)
  232. if(present(numel)) then
  233. nlseg=numel
  234. else
  235. nlseg = size(start)
  236. endif
  237. ! If the argument pe_loc is not present, then we are
  238. ! initializing the GlobalSegMap on the communicator
  239. ! my_comm. We will need pe_loc to be allocated and
  240. ! with local size given by the input value of nlseg,
  241. ! and then initialize it with the local process id myID.
  242. if(present(pe_loc)) then
  243. my_pe_loc => pe_loc
  244. else
  245. allocate(my_pe_loc(nlseg), stat=ier)
  246. if(ier /= 0) call die(myname_,'allocate(my_pe_loc)',ier)
  247. my_pe_loc = myID
  248. endif
  249. call MPI_COMM_SIZE(my_comm, npes, ier)
  250. if(ier /= 0) call MP_perr_die(myname_,'MPI_COMM_SIZE()',ier)
  251. ! Allocate an array of displacements (displs) and counts
  252. ! to hold the local values of nlseg on the root
  253. if(myID == root) then
  254. allocate(counts(0:npes-1), displs(0:npes-1), stat=ier)
  255. if (ier /= 0) then
  256. call die(myname_, 'allocate(counts,...',ier)
  257. endif
  258. else
  259. allocate(counts(1), displs(1), stat=ier)
  260. if (ier /= 0) then
  261. call die(myname_, 'allocate(counts,...',ier)
  262. endif
  263. endif
  264. ! Send local number of segments to the root.
  265. nlseg_tmp(1) = nlseg
  266. call fc_gather_int(nlseg_tmp, 1, MP_INTEGER, counts, 1, MP_INTEGER, &
  267. root, my_comm)
  268. ! On the root compute the value of ngseg, along with
  269. ! the entries of counts and displs.
  270. if(myID == root) then
  271. ngseg = 0
  272. do i=0,npes-1
  273. ngseg = ngseg + counts(i)
  274. if(i == 0) then
  275. displs(i) = 0
  276. else
  277. displs(i) = displs(i-1) + counts(i-1)
  278. endif
  279. end do
  280. endif
  281. ! Now only the root has the correct value of ngseg.
  282. ! On the root, allocate memory for the arrays root_start,
  283. ! and root_length. If the argument pe_loc is present,
  284. ! allocate root_pe_loc, too.
  285. ! Non-root processes call initr_ with root_start, root_length,
  286. ! and root_pe_loc, although these arguments are not used in the
  287. ! subroutine. Since these correspond to dummy shaped array arguments
  288. ! in initr_, the Fortran 90 standard dictates that the actual
  289. ! arguments must contain complete shape information. Therefore,
  290. ! these array arguments must be allocated on all processes.
  291. if(myID == root) then
  292. allocate(root_start(ngseg), root_length(ngseg), &
  293. root_pe_loc(ngseg), stat=ier)
  294. if (ier /= 0) then
  295. call die(myname_, 'allocate(root_start...',ier)
  296. endif
  297. else
  298. allocate(root_start(1), root_length(1), &
  299. root_pe_loc(1), stat=ier)
  300. if (ier /= 0) then
  301. call die(myname_, 'allocate((non)root_start...',ier)
  302. endif
  303. endif
  304. ! Now, each process sends its values of start(:) to fill in
  305. ! the appropriate portion of root_start(:y) on the root.
  306. call fc_gatherv_int(start, nlseg, MP_INTEGER, &
  307. root_start, counts, displs, MP_INTEGER, &
  308. root, my_comm)
  309. ! Next, each process sends its values of length(:) to fill in
  310. ! the appropriate portion of root_length(:) on the root.
  311. call fc_gatherv_int(length, nlseg, MP_INTEGER, &
  312. root_length, counts, displs, MP_INTEGER, &
  313. root, my_comm)
  314. ! Finally, if the argument pe_loc is present, each process sends
  315. ! its values of pe_loc(:) to fill in the appropriate portion of
  316. ! root_pe_loc(:) on the root.
  317. call fc_gatherv_int(my_pe_loc, nlseg, MP_INTEGER, &
  318. root_pe_loc, counts, displs, MP_INTEGER, &
  319. root, my_comm)
  320. call MPI_BARRIER(my_comm, ier)
  321. if(ier /= 0) call MP_perr_die(myname_,'MPI_BARRIER my_pe_loc',ier)
  322. ! Now, we have everything on the root needed to call initr_().
  323. if(present(gsize)) then
  324. call initr_(GSMap, ngseg, root_start, root_length, &
  325. root_pe_loc, root, my_comm, comp_id, gsize)
  326. else
  327. call initr_(GSMap, ngseg, root_start, root_length, &
  328. root_pe_loc, root, my_comm, comp_id)
  329. endif
  330. ! Clean up the array pe_loc(:) if it was allocated
  331. if(present(pe_loc)) then
  332. nullify(my_pe_loc)
  333. else
  334. deallocate(my_pe_loc, stat=ier)
  335. if(ier /= 0) call die(myname_, 'deallocate(my_pe_loc)', ier)
  336. endif
  337. ! Clean up the arrays root_start(:), et cetera...
  338. deallocate(root_start, root_length, root_pe_loc, stat=ier)
  339. if(ier /= 0) then
  340. call die(myname_, 'deallocate(root_start,...)', ier)
  341. endif
  342. ! Clean up the arrays counts(:) and displs(:)
  343. deallocate(counts, displs, stat=ier)
  344. if(ier /= 0) then
  345. call die(myname_, 'deallocate(counts,...)', ier)
  346. endif
  347. end subroutine initd_
  348. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  349. ! Math and Computer Science Division, Argonne National Laboratory !
  350. !BOP -------------------------------------------------------------------
  351. !
  352. ! !IROUTINE: initr_ initialize the map from the root
  353. !
  354. ! !DESCRIPTION:
  355. ! This routine takes the input {\tt INTEGER} arrays {\tt start},
  356. ! {\tt length}, and {\tt pe\_loc} (all valid only on the {\tt root}
  357. ! process), and from them creates a {\em global} set of segment
  358. ! information for the output {\tt GlobalSegMap} argument
  359. ! {\tt GSMap}. The input {\tt INTEGER} arguments {\tt ngseg},
  360. ! {\tt comp\_id}, {\tt gsize} (again, valid only on the {\tt root}
  361. ! process) provide the {\tt GlobalSegMap} global segment count, component
  362. ! ID number, and global grid size, respectively. The input argument
  363. ! {\tt my\_comm} is the F90 {\tt INTEGER} handle for the MPI communicator.
  364. !
  365. ! !INTERFACE:
  366. subroutine initr_(GSMap, ngseg, start, length, pe_loc, root, &
  367. my_comm, comp_id, gsize)
  368. !
  369. ! !USES:
  370. !
  371. use m_mpif90
  372. use m_die
  373. use m_stdio
  374. implicit none
  375. ! !INPUT PARAMETERS:
  376. integer, intent(in) :: ngseg ! no. of global segments
  377. integer,dimension(:),intent(in) :: start ! segment local start index
  378. integer,dimension(:),intent(in) :: length ! the distributed sizes
  379. integer,dimension(:),intent(in) :: pe_loc ! process location
  380. integer,intent(in) :: root ! root on my_com
  381. integer,intent(in) :: my_comm ! local communicatior
  382. integer,intent(in) :: comp_id ! component id number
  383. integer,intent(in), optional :: gsize ! global vector size
  384. ! (optional). It can
  385. ! be computed by this
  386. ! routine if no haloing
  387. ! is assumed.
  388. ! !OUTPUT PARAMETERS:
  389. type(GlobalSegMap),intent(out) :: GSMap ! Output GlobalSegMap
  390. ! !REVISION HISTORY:
  391. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  392. ! 09Nov00 - J.W. Larson <larson@mcs.anl.gov> - final working version
  393. ! 10Jan01 - J.W. Larson <larson@mcs.anl.gov> - minor bug fix
  394. ! 12Jan01 - J.W. Larson <larson@mcs.anl.gov> - minor bug fix regarding
  395. ! disparities in ngseg on
  396. ! the root and other
  397. ! processes
  398. ! 26Jan01 - J.W. Larson <larson@mcs.anl.gov> - replaced optional
  399. ! argument gsm_comm with required argument comp_id.
  400. !EOP ___________________________________________________________________
  401. character(len=*),parameter :: myname_=myname//'::initr_'
  402. integer :: myID,ier,l,i
  403. ! Determine the local process ID myID:
  404. call MPI_COMM_RANK(my_comm, myID, ier)
  405. if(ier/=0) call MP_perr_die(myname_,'MPI_COMM_RANK()',ier)
  406. ! Argument checking: check to make sure the arrays
  407. ! start, length, and pe_loc each have ngseg elements.
  408. ! If not, stop with an error. This is done on the
  409. ! root process since it owns the initialization data.
  410. if(myID == root) then
  411. if( size(start(:)) /= ngseg ) then
  412. write(stderr,'(2a,2(a,i4))') myname_, &
  413. ': _root_ argument error', &
  414. ', size(start) =',size(start), &
  415. ', ngseg =',ngseg
  416. call die(myname_)
  417. endif
  418. if( size(length(:)) /= ngseg ) then
  419. write(stderr,'(2a,2(a,i4))') myname_, &
  420. ': _root_ argument error', &
  421. ', size(length) =',size(length), &
  422. ', ngseg =',ngseg
  423. call die(myname_)
  424. endif
  425. if( size(pe_loc(:)) /= ngseg ) then
  426. write(stderr,'(2a,2(a,i4))') myname_, &
  427. ': _root_ argument error', &
  428. ', size(pe_loc) =',size(pe_loc), &
  429. ', ngseg =',ngseg
  430. call die(myname_)
  431. endif
  432. endif
  433. ! Initialize GSMap%ngseg and GSMap%comp_id on the root:
  434. if(myID == root) then
  435. GSMap%ngseg = ngseg
  436. GSMap%comp_id = comp_id
  437. endif
  438. ! Broadcast the value of GSMap%ngseg
  439. call MPI_BCAST(GSMap%ngseg, 1, MP_INTEGER, root, my_comm, ier)
  440. if(ier/=0) call MP_perr_die(myname_,'MPI_BCAST(GSmap%ngseg)',ier)
  441. ! Broadcast the value of GSMap%comp_id
  442. call MPI_BCAST(GSMap%comp_id, 1, MP_INTEGER, root, my_comm, ier)
  443. if(ier/=0) call MP_perr_die(myname_,'MPI_BCAST(GSmap%comp_id)',ier)
  444. ! Allocate the components GSMap%start(:), GSMap%length(:),
  445. ! and GSMap%pe_loc(:)
  446. allocate(GSMap%start(GSMap%ngseg), GSMap%length(GSMap%ngseg), &
  447. GSMap%pe_loc(GSMap%ngseg), stat = ier)
  448. if(ier/=0) call die(myname_,'allocate(GSmap%start(:),...',ier)
  449. #ifdef MALL_ON
  450. call mall_ci(size(transfer(GSMap%start,(/1/))),myname_)
  451. call mall_ci(size(transfer(GSMap%length,(/1/))),myname_)
  452. call mall_ci(size(transfer(GSMap%pe_loc,(/1/))),myname_)
  453. #endif
  454. ! On the root process, initialize GSMap%start(:), GSMap%length(:),
  455. ! and GSMap%pe_loc(:) with the data contained in start(:),
  456. ! length(:) and pe_loc(:), respectively
  457. if(myID == root) then
  458. GSMap%start(1:GSMap%ngseg) = start(1:GSMap%ngseg)
  459. GSMap%length(1:GSMap%ngseg) = length(1:GSMap%ngseg)
  460. GSMap%pe_loc(1:GSMap%ngseg) = pe_loc(1:GSMap%ngseg)
  461. endif
  462. ! Broadcast the root values of GSMap%start(:), GSMap%length(:),
  463. ! and GSMap%pe_loc(:)
  464. call MPI_BCAST(GSMap%start, GSMap%ngseg, MP_INTEGER, root, my_comm, ier)
  465. if(ier/=0) call MP_perr_die(myname_,'MPI_BCAST(GSMap%start)',ier)
  466. call MPI_BCAST(GSMap%length, GSMap%ngseg, MP_INTEGER, root, my_comm, ier)
  467. if(ier/=0) call MP_perr_die(myname_,'MPI_BCAST(GSMap%length)',ier)
  468. call MPI_BCAST(GSMap%pe_loc, GSMap%ngseg, MP_INTEGER, root, my_comm, ier)
  469. if(ier/=0) call MP_perr_die(myname_,'MPI_BCAST(GSMap%pe_loc)',ier)
  470. ! If the argument gsize is present, use the root value to
  471. ! set GSMap%gsize and broadcast it. If it is not present,
  472. ! this will be computed by summing the entries of GSM%length(:).
  473. ! Again, note that if one is storing halo points, the sum will
  474. ! produce a result larger than the actual global vector. If
  475. ! halo points are to be used in the mapping we advise strongly
  476. ! that the user specify the value gsize as an argument.
  477. if(present(gsize)) then
  478. if(myID == root) then
  479. GSMap%gsize = gsize
  480. endif
  481. call MPI_BCAST(GSMap%gsize, 1, MP_INTEGER, root, my_comm, ier)
  482. if(ier/=0) call MP_perr_die(myname_, 'MPI_BCAST(GSMap%gsize)', ier)
  483. else
  484. GSMap%gsize = 0
  485. do i=1,GSMap%ngseg
  486. GSMap%gsize = GSMap%gsize + GSMap%length(i)
  487. end do
  488. endif
  489. end subroutine initr_
  490. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  491. ! Math and Computer Science Division, Argonne National Laboratory !
  492. !BOP -------------------------------------------------------------------
  493. !
  494. ! !IROUTINE: initp_ - define the map from replicated data.
  495. !
  496. ! !DESCRIPTION:
  497. !
  498. ! The routine {\tt initp\_()} takes the input {\em replicated} arguments
  499. ! {\tt comp\_id}, {\tt ngseg}, {\tt gsize}, {\tt start(:)},
  500. ! {\tt length(:)}, and {\tt pe\_loc(:)}, and uses them to initialize an
  501. ! output {\tt GlobalSegMap} {\tt GSMap}. This routine operates on the
  502. ! assumption that these data are replicated across the communicator on
  503. ! which the {\tt GlobalSegMap} is being created.
  504. !
  505. ! !INTERFACE:
  506. subroutine initp_(GSMap, comp_id, ngseg, gsize, start, length, pe_loc)
  507. !
  508. ! !USES:
  509. !
  510. use m_mpif90
  511. use m_die, only : die
  512. use m_stdio
  513. implicit none
  514. ! !INPUT PARAMETERS:
  515. integer,intent(in) :: comp_id ! component model ID
  516. integer,intent(in) :: ngseg ! global number of segments
  517. integer,intent(in) :: gsize ! global vector size
  518. integer,dimension(:),intent(in) :: start ! segment local start index
  519. integer,dimension(:),intent(in) :: length ! the distributed sizes
  520. integer,dimension(:),intent(in) :: pe_loc ! process location
  521. ! !OUTPUT PARAMETERS:
  522. type(GlobalSegMap),intent(out) :: GSMap ! Output GlobalSegMap
  523. ! !REVISION HISTORY:
  524. ! 24Feb01 - J.W. Larson <larson@mcs.anl.gov> - Initial version.
  525. !EOP ___________________________________________________________________
  526. character(len=*),parameter :: myname_=myname//'::initp_'
  527. integer :: ierr, n
  528. ! Argument Checks -- Is comp_id positive?
  529. if(comp_id <= 0) then
  530. call die(myname_,'non-positive value of comp_id',comp_id)
  531. endif
  532. ! Is gsize positive?
  533. if(gsize <= 0) then
  534. call die(myname_,'non-positive value of gsize',gsize)
  535. endif
  536. ! Is ngseg positive?
  537. if(ngseg <= 0) then
  538. call die(myname_,'non-positive value of ngseg',ngseg)
  539. endif
  540. ! Are the arrays start(:), length(:), and pe_loc(:) the
  541. !correct size?
  542. if(size(start) /= ngseg) then
  543. call die(myname_,'start(:)/ngseg size mismatch',ngseg)
  544. endif
  545. if (size(length) /= ngseg) then
  546. call die(myname_,'length(:)/ngseg size mismatch',ngseg)
  547. endif
  548. if (size(pe_loc) /= ngseg) then
  549. call die(myname_,'pe_loc(:)/ngseg size mismatch',ngseg)
  550. endif
  551. ! Allocate index and location arrays for GSMap:
  552. allocate(GSMap%start(ngseg), GSMap%length(ngseg), GSMap%pe_loc(ngseg), &
  553. stat = ierr)
  554. if (ierr /= 0) then
  555. call die(myname_,'allocate(GSMap%start...',ngseg)
  556. endif
  557. ! Assign the components of GSMap:
  558. GSMap%comp_id = comp_id
  559. GSMap%ngseg = ngseg
  560. GSMap%gsize = gsize
  561. do n=1,ngseg
  562. GSMap%start(n) = start(n)
  563. GSMap%length(n) = length(n)
  564. GSMap%pe_loc(n) = pe_loc(n)
  565. end do
  566. end subroutine initp_
  567. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  568. ! Math and Computer Science Division, Argonne National Laboratory !
  569. !BOP -------------------------------------------------------------------
  570. !
  571. ! !IROUTINE: initp1_ - define the map from replicated data using 1 array.
  572. !
  573. ! !DESCRIPTION:
  574. !
  575. ! The routine {\tt initp1\_()} takes the input {\em replicated} arguments
  576. ! {\tt comp\_id}, {\tt ngseg}, {\tt gsize}, and {\tt all\_arrays(:)},
  577. ! and uses them to initialize an output {\tt GlobalSegMap} {\tt GSMap}.
  578. ! This routine operates on the assumption that these data are replicated
  579. ! across the communicator on which the {\tt GlobalSegMap} is being created.
  580. ! The input array {\tt all\_arrays(:)} should be of length {\tt 2 * ngseg},
  581. ! and is packed so that
  582. ! $$ {\tt all\_arrays(1:ngseg)} = {\tt GSMap\%start(1:ngseg)} $$
  583. ! $$ {\tt all\_arrays(ngseg+1:2*ngseg)} = {\tt GSMap\%length(1:ngseg)} $$
  584. ! $$ {\tt all\_arrays(2*ngseg+1:3*ngseg)} = {\tt GSMap\%pe\_loc(1:ngseg)} .$$
  585. !
  586. ! !INTERFACE:
  587. subroutine initp1_(GSMap, comp_id, ngseg, gsize, all_arrays)
  588. !
  589. ! !USES:
  590. !
  591. use m_mpif90
  592. use m_die, only : die
  593. use m_stdio
  594. implicit none
  595. ! !INPUT PARAMETERS:
  596. integer,intent(in) :: comp_id ! component model ID
  597. integer,intent(in) :: ngseg ! global no. of segments
  598. integer,intent(in) :: gsize ! global vector size
  599. integer,dimension(:),intent(in) :: all_arrays ! packed array of length
  600. ! 3*ngseg containing (in
  601. ! this order): start(:),
  602. ! length(:), and pe_loc(:)
  603. ! !OUTPUT PARAMETERS:
  604. type(GlobalSegMap),intent(out) :: GSMap ! Output GlobalSegMap
  605. ! !REVISION HISTORY:
  606. ! 24Feb01 - J.W. Larson <larson@mcs.anl.gov> - Initial version.
  607. !EOP ___________________________________________________________________
  608. character(len=*),parameter :: myname_=myname//'::initp1_'
  609. integer :: ierr, n
  610. ! Argument Checks -- Is comp_id positive?
  611. if(comp_id <= 0) then
  612. call die(myname_,'non-positive value of comp_id',comp_id)
  613. endif
  614. ! Is gsize positive?
  615. if(gsize <= 0) then
  616. call die(myname_,'non-positive value of gsize',gsize)
  617. endif
  618. ! Is ngseg positive?
  619. if(ngseg <= 0) then
  620. call die(myname_,'non-positive value of ngseg',ngseg)
  621. endif
  622. ! Is the array all_arrays(:) the right length?
  623. if(size(all_arrays) /= 3*ngseg) then
  624. call die(myname_,'all_arrays(:)/3*ngseg size mismatch',ngseg)
  625. endif
  626. ! Allocate index and location arrays for GSMap:
  627. allocate(GSMap%start(ngseg), GSMap%length(ngseg), GSMap%pe_loc(ngseg), &
  628. stat = ierr)
  629. if (ierr /= 0) then
  630. call die(myname_,'allocate(GSMap%start...',ngseg)
  631. endif
  632. ! Assign the components of GSMap:
  633. GSMap%comp_id = comp_id
  634. GSMap%ngseg = ngseg
  635. GSMap%gsize = gsize
  636. do n=1,ngseg
  637. GSMap%start(n) = all_arrays(n)
  638. GSMap%length(n) = all_arrays(ngseg + n)
  639. GSMap%pe_loc(n) = all_arrays(2*ngseg + n)
  640. end do
  641. end subroutine initp1_
  642. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  643. ! Math and Computer Science Division, Argonne National Laboratory !
  644. !BOP -------------------------------------------------------------------
  645. !
  646. ! !IROUTINE: initp0_ - Null Constructor Using Replicated Data
  647. !
  648. ! !DESCRIPTION:
  649. !
  650. ! The routine {\tt initp0\_()} takes the input {\em replicated} arguments
  651. ! {\tt comp\_id}, {\tt ngseg}, {\tt gsize}, and uses them perform null
  652. ! construction of the output {\tt GlobalSegMap} {\tt GSMap}. This is a
  653. ! null constructor in the sense that we are not filling in the segment
  654. ! information arrays. This routine operates on the assumption that these
  655. ! data are replicated across the communicator on which the
  656. ! {\tt GlobalSegMap} is being created.
  657. !
  658. ! !INTERFACE:
  659. subroutine initp0_(GSMap, comp_id, ngseg, gsize)
  660. !
  661. ! !USES:
  662. !
  663. use m_die, only : die
  664. use m_stdio
  665. implicit none
  666. ! !INPUT PARAMETERS:
  667. integer,intent(in) :: comp_id ! component model ID
  668. integer,intent(in) :: ngseg ! global number of segments
  669. integer,intent(in) :: gsize ! global vector size
  670. ! !OUTPUT PARAMETERS:
  671. type(GlobalSegMap),intent(out) :: GSMap ! Output GlobalSegMap
  672. ! !REVISION HISTORY:
  673. ! 13Aug03 - J.W. Larson <larson@mcs.anl.gov> - Initial version.
  674. !EOP ___________________________________________________________________
  675. character(len=*),parameter :: myname_=myname//'::initp0_'
  676. integer :: ierr
  677. nullify(GSMap%start)
  678. nullify(GSMap%length)
  679. nullify(GSMap%pe_loc)
  680. GSMap%comp_id = comp_id
  681. GSMap%ngseg = ngseg
  682. GSMap%gsize = gsize
  683. allocate(GSMap%start(ngseg), GSMap%length(ngseg), GSMap%pe_loc(ngseg), &
  684. stat=ierr)
  685. if(ierr /= 0) then
  686. write(stderr,'(3a,i8)') myname_, &
  687. ':: FATAL--allocate of segment information storage space failed.', &
  688. ' ierr = ',ierr
  689. call die(myname_)
  690. endif
  691. end subroutine initp0_
  692. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  693. ! Math and Computer Science Division, Argonne National Laboratory !
  694. !BOP -------------------------------------------------------------------
  695. !
  696. ! !IROUTINE: init_index_ - initialize GSM from local index arrays
  697. !
  698. ! !DESCRIPTION:
  699. !
  700. ! The routine {\tt init\_index\_()} takes a local array of indices
  701. ! {\tt lindx} and uses them to create a {\tt GlobalSegMap}.
  702. ! {\tt lindx} is parsed to determine the lengths of the runs, and
  703. ! then a call is made to {\tt initd\_}. The optional argument
  704. ! {\tt lsize} can be used if only the first {\tt lsize} number
  705. ! of elements of {\tt lindx} are valid. The optional argument
  706. ! {\tt gsize} is used to specify the global number of unique points
  707. ! if this can not be determined from the collective {\tt lindx}.
  708. !
  709. !
  710. ! !INTERFACE:
  711. subroutine init_index_(GSMap, lindx, my_comm, comp_id, lsize, gsize)
  712. !
  713. ! !USES:
  714. !
  715. ! use m_GlobalSegMap,only: GlobalSegMap
  716. ! use m_GlobalSegMap,only: MCT_GSMap_init => init
  717. ! use shr_sys_mod
  718. use m_die
  719. implicit none
  720. ! !INPUT PARAMETERS:
  721. integer , dimension(:),intent(in) :: lindx ! index buffer
  722. integer , intent(in) :: my_comm ! mpi communicator group (mine)
  723. integer , intent(in) :: comp_id ! component id (mine)
  724. integer , intent(in),optional :: lsize ! size of index buffer
  725. integer , intent(in),optional :: gsize ! global vector size
  726. ! !OUTPUT PARAMETERS:
  727. type(GlobalSegMap),intent(out) :: GSMap ! Output GlobalSegMap
  728. ! !REVISION HISTORY:
  729. ! 30Jul02 - T. Craig - initial version in cpl6.
  730. ! 17Nov05 - R. Loy <rloy@mcs.anl.gov> - install into MCT
  731. ! 18Nov05 - R. Loy <rloy@mcs.anl.gov> - make lsize optional
  732. ! 25Jul06 - R. Loy <rloy@mcs.anl.gov> - error check on lindex/alloc/dealloc
  733. !EOP ___________________________________________________________________
  734. !--- local ---
  735. character(len=*),parameter :: myname_=myname//'::init_index_'
  736. integer :: i,j,k,n ! generic indicies
  737. integer :: nseg ! counts number of segments for GSMap
  738. integer,allocatable :: start(:) ! used to init GSMap
  739. integer,allocatable :: count(:) ! used to init GSMap
  740. integer,parameter :: pid0=0 ! mpi process id for root pe
  741. integer,parameter :: debug=0 !
  742. integer rank,ierr
  743. integer mysize
  744. if (present(lsize)) then
  745. mysize=lsize
  746. else
  747. mysize=size(lindx)
  748. endif
  749. if (mysize<0) call die(myname_, &
  750. 'lindx size is negative (you may have run out of points)')
  751. !!
  752. !! Special case if this processor doesn't have any data indices
  753. !!
  754. if (mysize==0) then
  755. allocate(start(0),count(0),stat=ierr)
  756. if(ierr/=0) call die(myname_,'allocate(start,count)',ierr)
  757. nseg=0
  758. else
  759. call MPI_COMM_RANK(my_comm,rank, ierr)
  760. ! compute segment's start indicies and length counts
  761. ! first pass - count how many runs of consecutive numbers
  762. nseg=1
  763. do n = 2,mysize
  764. i = lindx(n-1)
  765. j = lindx(n)
  766. if ( j-i /= 1) nseg=nseg+1
  767. end do
  768. allocate(start(nseg),count(nseg),stat=ierr)
  769. if(ierr/=0) call die(myname_,'allocate(start,count)',ierr)
  770. ! second pass - determine how long each run is
  771. nseg = 1
  772. start(nseg) = lindx(1)
  773. count(nseg) = 1
  774. do n = 2,mysize
  775. i = lindx(n-1)
  776. j = lindx(n)
  777. if ( j-i /= 1) then
  778. nseg = nseg+1
  779. start(nseg) = lindx(n)
  780. count(nseg) = 1
  781. else
  782. count(nseg) = count(nseg)+1
  783. end if
  784. end do
  785. endif ! if mysize==0
  786. if (debug.ne.0) then
  787. write(6,*) rank,'init_index: SIZE ',nseg
  788. do n=1,nseg
  789. write(6,*) rank,'init_index: START,COUNT ',start(n),count(n)
  790. end do
  791. endif
  792. if (present(gsize)) then
  793. call initd_( GSMap, start, count, pid0, my_comm, &
  794. comp_id, gsize=gsize)
  795. else
  796. call initd_( GSMap, start, count, pid0, my_comm, &
  797. comp_id)
  798. endif
  799. deallocate(start, count, stat=ierr)
  800. if(ierr/=0) call warn(myname_,'deallocate(start,count)',ierr)
  801. end subroutine init_index_
  802. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  803. ! Math and Computer Science Division, Argonne National Laboratory !
  804. !BOP -------------------------------------------------------------------
  805. !
  806. ! !IROUTINE: clean_ - clean the map
  807. !
  808. ! !DESCRIPTION:
  809. ! This routine deallocates the array components of the {\tt GlobalSegMap}
  810. ! argument {\tt GSMap}: {\tt GSMap\%start}, {\tt GSMap\%length}, and
  811. ! {\tt GSMap\%pe\_loc}. It also zeroes out the values of the integer
  812. ! components {\tt GSMap\%ngseg}, {\tt GSMap\%comp\_id}, and
  813. ! {\tt GSMap\%gsize}.
  814. !
  815. ! !INTERFACE:
  816. subroutine clean_(GSMap,stat)
  817. !
  818. ! !USES:
  819. !
  820. use m_die
  821. implicit none
  822. ! !INPUT/OUTPUT PARAMETERS:
  823. type(GlobalSegMap), intent(inout) :: GSMap
  824. integer, optional, intent(out) :: stat
  825. ! !REVISION HISTORY:
  826. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  827. ! 01Mar02 - E.T. Ong <eong@mcs.anl.gov> - added stat argument.
  828. ! Removed dies to prevent crashing.
  829. !EOP ___________________________________________________________________
  830. character(len=*),parameter :: myname_=myname//'::clean_'
  831. integer :: ier
  832. #ifdef MALL_ON
  833. if( (associated(GSMap%start) .and. associated(GSMap%length)) &
  834. .and. associated(GSMap%pe_loc) )
  835. call mall_co(size(transfer(GSMap%start,(/1/))),myname_)
  836. call mall_co(size(transfer(GSMap%length,(/1/))),myname_)
  837. call mall_co(size(transfer(GSMap%pe_loc,(/1/))),myname_)
  838. endif
  839. #endif
  840. deallocate(GSMap%start, GSMap%length, GSMap%pe_loc, stat=ier)
  841. if(present(stat)) then
  842. stat=ier
  843. else
  844. if(ier /= 0) call warn(myname_,'deallocate(GSMap%start,...)',ier)
  845. endif
  846. GSMap%ngseg = 0
  847. GSMap%comp_id = 0
  848. GSMap%gsize = 0
  849. end subroutine clean_
  850. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  851. ! Math and Computer Science Division, Argonne National Laboratory !
  852. !BOP -------------------------------------------------------------------
  853. !
  854. ! !IROUTINE: ngseg_ - Return the global number of segments from the map
  855. !
  856. ! !DESCRIPTION:
  857. ! The function {\tt ngseg\_()} returns the global number of vector
  858. ! segments in the {\tt GlobalSegMap} argument {\tt GSMap}. This is
  859. ! merely the value of {\tt GSMap\%ngseg}.
  860. !
  861. ! !INTERFACE:
  862. integer function ngseg_(GSMap)
  863. implicit none
  864. ! !INPUT PARAMETERS:
  865. type(GlobalSegMap),intent(in) :: GSMap
  866. ! !REVISION HISTORY:
  867. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  868. !EOP ___________________________________________________________________
  869. character(len=*),parameter :: myname_=myname//'::ngseg_'
  870. ngseg_=GSMap%ngseg
  871. end function ngseg_
  872. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  873. ! Math and Computer Science Division, Argonne National Laboratory !
  874. !BOP -------------------------------------------------------------------
  875. !
  876. ! !IROUTINE: nlseg_ - Return the local number of segments from the map
  877. !
  878. ! !DESCRIPTION:
  879. ! The function {\tt nlseg\_()} returns the number of vector segments
  880. ! in the {\tt GlobalSegMap} argument {\tt GSMap} that reside on the
  881. ! process specified by the input argument {\tt pID}. This is the
  882. ! number of entries {\tt GSMap\%pe\_loc} whose value equals {\tt pID}.
  883. !
  884. ! !INTERFACE:
  885. integer function nlseg_(GSMap, pID)
  886. implicit none
  887. ! !INPUT PARAMETERS:
  888. type(GlobalSegMap),intent(in) :: GSMap
  889. integer, intent(in) :: pID
  890. ! !REVISION HISTORY:
  891. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  892. ! 14Jun01 - J.W. Larson <larson@mcs.anl.gov> - Bug fix in lower
  893. ! limit of loop over elements of GSMap%pe_loc(:). The
  894. ! original code had this lower limit set to 0, which
  895. ! was out-of-bounds (but uncaught). The correct lower
  896. ! index is 1. This bug was discovered by Everest Ong.
  897. !EOP ___________________________________________________________________
  898. character(len=*),parameter :: myname_=myname//'::nlseg_'
  899. integer :: i, nlocseg
  900. ! Initialize the number of segments residing on pID, nlocseg
  901. nlocseg = 0
  902. ! Compute the number of segments residing on pID, nlocseg
  903. do i=1,GSMap%ngseg
  904. if(GSMap%pe_loc(i) == pID) then
  905. nlocseg = nlocseg + 1
  906. endif
  907. end do
  908. ! Return the total
  909. nlseg_ = nlocseg
  910. end function nlseg_
  911. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  912. ! Math and Computer Science Division, Argonne National Laboratory !
  913. !BOP -------------------------------------------------------------------
  914. !
  915. ! !IROUTINE: max_nlseg_ - Return the max number of segments over all procs
  916. !
  917. ! !DESCRIPTION:
  918. ! The function {\tt max\_nlseg\_()} returns the maximum number
  919. ! over all processors of the vector
  920. ! segments in the {\tt GlobalSegMap} argument {\tt gsap}
  921. ! E.g. max\_p(nlseg(gsmap,p)) but computed more efficiently
  922. !
  923. ! !INTERFACE:
  924. integer function max_nlseg_(gsmap)
  925. ! !USES:
  926. use m_MCTWorld, only :ThisMCTWorld
  927. use m_mpif90
  928. use m_die
  929. use m_stdio ! rml
  930. implicit none
  931. ! !INPUT PARAMETERS:
  932. type(GlobalSegMap), intent(in) :: gsmap
  933. ! !REVISION HISTORY:
  934. ! 17Jan07 - R. Loy <rloy@mcs.anl.gov> - initial prototype
  935. !EOP ___________________________________________________________________
  936. ! Local variables
  937. character(len=*),parameter :: myname_=myname//'::max_local_segs'
  938. integer i
  939. integer this_comp_id
  940. integer nprocs
  941. integer, allocatable:: segcount(:) ! segments on proc i
  942. integer ier
  943. integer this_ngseg
  944. integer segment_pe
  945. integer max_segcount
  946. ! Start of routine
  947. this_comp_id = comp_id(gsmap)
  948. nprocs=ThisMCTWorld%nprocspid(this_comp_id)
  949. allocate( segcount(nprocs), stat=ier )
  950. if (ier/=0) call die(myname_,'allocate segcount')
  951. segcount=0
  952. this_ngseg=ngseg(gsmap)
  953. do i=1,this_ngseg
  954. segment_pe = gsmap%pe_loc(i) + 1 ! want value 1..nprocs
  955. if (segment_pe < 1 .OR. segment_pe > nprocs) then
  956. call die(myname_,'bad segment location',segment_pe)
  957. endif
  958. segcount(segment_pe) = segcount(segment_pe) + 1
  959. enddo
  960. max_segcount=0
  961. do i=1,nprocs
  962. max_segcount= max( max_segcount, segcount(i) )
  963. enddo
  964. deallocate(segcount, stat=ier)
  965. if (ier/=0) call die(myname_,'deallocate segcount')
  966. max_nlseg_=max_segcount
  967. end function max_nlseg_
  968. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  969. ! Math and Computer Science Division, Argonne National Laboratory !
  970. !BOP -------------------------------------------------------------------
  971. !
  972. ! !IROUTINE: comp_id_ - Return the commponent ID from the GlobalSegMap.
  973. !
  974. ! !DESCRIPTION:
  975. ! The function {\tt comp\_id\_()} returns component ID number stored in
  976. ! {\tt GSMap\%comp\_id}.
  977. !
  978. ! !INTERFACE:
  979. integer function comp_id_(GSMap)
  980. ! !USES:
  981. use m_die,only: die
  982. use m_stdio, only :stderr
  983. implicit none
  984. ! !INPUT PARAMETERS:
  985. type(GlobalSegMap),intent(in) :: GSMap
  986. ! !REVISION HISTORY:
  987. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  988. ! 26Jan01 - J.W. Larson <larson@mcs.anl.gov> - renamed comp_id_
  989. ! to fit within MCT_World component ID context.
  990. ! 01May01 - R.L. Jacob <jacob@mcs.anl.gov> - make sure GSMap
  991. ! is defined.
  992. !EOP ___________________________________________________________________
  993. character(len=*),parameter :: myname_=myname//'::comp_id_'
  994. if(.not.associated(GSMap%start) ) then
  995. write(stderr,'(2a)') myname_, &
  996. ' MCTERROR: GSMap argument not initialized...exiting'
  997. call die(myname_)
  998. endif
  999. comp_id_ = GSMap%comp_id
  1000. end function comp_id_
  1001. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1002. ! Math and Computer Science Division, Argonne National Laboratory !
  1003. !BOP -------------------------------------------------------------------
  1004. !
  1005. ! !IROUTINE: gsize_ - Return the global vector size from the GlobalSegMap.
  1006. !
  1007. ! !DESCRIPTION:
  1008. ! The function {\tt gsize\_()} takes the input {\tt GlobalSegMap}
  1009. ! arguement {\tt GSMap} and returns the global vector length stored
  1010. ! in {\tt GlobalSegMap\%gsize}.
  1011. !
  1012. ! !INTERFACE:
  1013. integer function gsize_(GSMap)
  1014. implicit none
  1015. ! !INPUT PARAMETERS:
  1016. type(GlobalSegMap),intent(in) :: GSMap
  1017. ! !REVISION HISTORY:
  1018. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  1019. !EOP ___________________________________________________________________
  1020. character(len=*),parameter :: myname_=myname//'::gsize_'
  1021. gsize_=GSMap%gsize
  1022. end function gsize_
  1023. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1024. ! Math and Computer Science Division, Argonne National Laboratory !
  1025. !BOP -------------------------------------------------------------------
  1026. !
  1027. ! !IROUTINE: GlobalStorage_ - Return global storage space required.
  1028. !
  1029. ! !DESCRIPTION:
  1030. ! The function {\tt GlobalStorage\_()} takes the input {\tt GlobalSegMap}
  1031. ! arguement {\tt GSMap} and returns the global storage space required
  1032. ! ({\em i.e.}, the vector length) to hold all the data specified by
  1033. ! {\tt GSMap}.
  1034. !
  1035. ! {\bf N.B.: } If {\tt GSMap} contains halo or masked points, the value
  1036. ! by {\tt GlobalStorage\_()} may differ from {\tt GSMap\%gsize}.
  1037. !
  1038. ! !INTERFACE:
  1039. integer function GlobalStorage_(GSMap)
  1040. implicit none
  1041. ! !INPUT PARAMETERS:
  1042. type(GlobalSegMap),intent(in) :: GSMap
  1043. ! !REVISION HISTORY:
  1044. ! 06Feb01 - J.W. Larson <larson@mcs.anl.gov> - initial version
  1045. !EOP ___________________________________________________________________
  1046. character(len=*),parameter :: myname_=myname//'::GlobalStorage_'
  1047. integer :: global_storage, ngseg, n
  1048. ! Return global number of segments:
  1049. ngseg = ngseg_(GSMap)
  1050. ! Initialize global_storage (the total number of points in the
  1051. ! GlobalSegMap:
  1052. global_storage = 0
  1053. ! Add up the number of points present in the GlobalSegMap:
  1054. do n=1,ngseg
  1055. global_storage = global_storage + GSMap%length(n)
  1056. end do
  1057. GlobalStorage_ = global_storage
  1058. end function GlobalStorage_
  1059. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1060. ! Math and Computer Science Division, Argonne National Laboratory !
  1061. !BOP -------------------------------------------------------------------
  1062. !
  1063. ! !IROUTINE: ProcessStorage_ - Number of points on a given process.
  1064. !
  1065. ! !DESCRIPTION:
  1066. ! The function {\tt ProcessStorage\_()} takes the input {\tt GlobalSegMap}
  1067. ! arguement {\tt GSMap} and returns the storage space required by process
  1068. ! {\tt PEno} ({\em i.e.}, the vector length) to hold all the data specified
  1069. ! by {\tt GSMap}.
  1070. !
  1071. ! !INTERFACE:
  1072. integer function ProcessStorage_(GSMap, PEno)
  1073. implicit none
  1074. ! !INPUT PARAMETERS:
  1075. type(GlobalSegMap),intent(in) :: GSMap
  1076. integer, intent(in) :: PEno
  1077. ! !REVISION HISTORY:
  1078. ! 06Feb01 - J.W. Larson <larson@mcs.anl.gov> - initial version
  1079. !EOP ___________________________________________________________________
  1080. character(len=*),parameter :: myname_=myname//'::ProcessStorage_'
  1081. integer :: pe_storage, ngseg, n
  1082. ! Return global number of segments:
  1083. ngseg = ngseg_(GSMap)
  1084. ! Initialize pe_storage (the total number of points on process
  1085. ! PEno in the GlobalSegMap):
  1086. pe_storage = 0
  1087. ! Add up the number of points on process PEno in the GlobalSegMap:
  1088. do n=1,ngseg
  1089. if(GSMap%pe_loc(n) == PEno) then
  1090. pe_storage = pe_storage + GSMap%length(n)
  1091. endif
  1092. end do
  1093. ProcessStorage_ = pe_storage
  1094. end function ProcessStorage_
  1095. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1096. ! Math and Computer Science Division, Argonne National Laboratory !
  1097. !BOP -------------------------------------------------------------------
  1098. !
  1099. ! !IROUTINE: OrderedPoints_ - The grid points on a given process
  1100. ! returned in the assumed MCT order.
  1101. !
  1102. ! !DESCRIPTION:
  1103. ! The function {\tt OrderedPoints\_()} takes the input {\tt GlobalSegMap}
  1104. ! arguement {\tt GSMap} and returns a vector of the points owned by
  1105. ! {\tt PEno}. {\tt Points} is allocated here. The calling process
  1106. ! is responsible for deallocating the space.
  1107. !
  1108. ! !INTERFACE:
  1109. subroutine OrderedPoints_(GSMap, PEno, Points)
  1110. !
  1111. ! !USES:
  1112. !
  1113. use m_die,only: die
  1114. implicit none
  1115. ! !INPUT PARAMETERS:
  1116. type(GlobalSegMap), intent(in) :: GSMap ! input GlobalSegMap
  1117. integer, intent(in) :: PEno ! input process number
  1118. integer,dimension(:),pointer :: Points ! the vector of points
  1119. ! !REVISION HISTORY:
  1120. ! 25Apr01 - R. Jacob <jacob@mcs.anl.gov> - initial prototype
  1121. !EOP ___________________________________________________________________
  1122. character(len=*),parameter :: myname_=myname//'::OrderedPoints_'
  1123. integer :: nlsegs,mysize,ier,i,j,k
  1124. integer,dimension(:),allocatable :: mystarts,mylengths
  1125. nlsegs = nlseg(GSMap,PEno)
  1126. mysize=ProcessStorage(GSMap,PEno)
  1127. allocate(mystarts(nlsegs),mylengths(nlsegs), &
  1128. Points(mysize),stat=ier)
  1129. if(ier/=0) call die(myname_,'allocate(mystarts,..)',ier)
  1130. ! pull out the starts and lengths that PEno owns in the order
  1131. ! they appear in the GSMap.
  1132. j=1
  1133. do i=1,GSMap%ngseg
  1134. if(GSMap%pe_loc(i)==PEno) then
  1135. mystarts(j)=GSMap%start(i)
  1136. mylengths(j)=GSMap%length(i)
  1137. j=j+1
  1138. endif
  1139. enddo
  1140. ! now recalculate the values of the grid point numbers
  1141. ! based on the starts and lengths
  1142. ! form one long vector which is all local GSMap points
  1143. i=1
  1144. do j=1,nlsegs
  1145. do k=1,mylengths(j)
  1146. Points(i)=mystarts(j)+k-1
  1147. i=i+1
  1148. enddo
  1149. enddo
  1150. deallocate(mystarts,mylengths, stat=ier)
  1151. if(ier/=0) call die(myname_,'deallocate(mystarts,..)',ier)
  1152. end subroutine OrderedPoints_
  1153. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1154. ! Math and Computer Science Division, Argonne National Laboratory !
  1155. !BOP -------------------------------------------------------------------
  1156. !
  1157. ! !IROUTINE: lsize_ - find the local storage size from the map
  1158. !
  1159. ! !DESCRIPTION:
  1160. ! This function returns the number of points owned by the local process,
  1161. ! as defined by the input {\tt GlobalSegMap} argument {\tt GSMap}. The
  1162. ! local process ID is determined through use of the input {\tt INTEGER}
  1163. ! argument {\tt comm}, which is the Fortran handle for the MPI
  1164. ! communicator.
  1165. !
  1166. ! !INTERFACE:
  1167. integer function lsize_(GSMap, comm)
  1168. !
  1169. ! !USES:
  1170. !
  1171. use m_mpif90
  1172. use m_die , only : MP_perr_die
  1173. implicit none
  1174. ! !INPUT PARAMETERS:
  1175. type(GlobalSegMap), intent(in) :: GSMap
  1176. integer, intent(in) :: comm
  1177. ! !REVISION HISTORY:
  1178. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  1179. ! 06Feb01 - J.W. Larson <larson@mcs.anl.gov> - Computed directly
  1180. ! from the GlobalSegMap, rather than returning a hard-
  1181. ! wired local attribute. This required the addition of
  1182. ! the communicator argument.
  1183. !EOP ___________________________________________________________________
  1184. character(len=*),parameter :: myname_=myname//'::lsize_'
  1185. integer :: ierr, local_size, myID, n, ngseg
  1186. ! Determine local rank myID:
  1187. call MP_COMM_RANK(comm, myID, ierr)
  1188. if(ierr /= 0) call MP_perr_die(myname_,'MP_COMM_RANK',ierr)
  1189. ! Determine global number of segments:
  1190. ngseg = ngseg_(GSMap)
  1191. ! Compute the local size of the distributed vector by summing
  1192. ! the entries of GSMap%length(:) whose corresponding values in
  1193. ! GSMap%pe_loc(:) equal the local process ID. This automatically
  1194. ! takes into account haloing (if present).
  1195. local_size = 0
  1196. do n=1,ngseg
  1197. if(GSMap%pe_loc(n) == myID) then
  1198. local_size = local_size + GSMap%length(n)
  1199. endif
  1200. end do
  1201. lsize_ = local_size
  1202. end function lsize_
  1203. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1204. ! Math and Computer Science Division, Argonne National Laboratory !
  1205. !BOP -------------------------------------------------------------------
  1206. !
  1207. ! !IROUTINE: rank1_ - rank which process owns a datum with given global
  1208. ! index.
  1209. !
  1210. ! !DESCRIPTION:
  1211. ! This routine assumes that there is one process that owns the datum with
  1212. ! a given global index. It should not be used when the input
  1213. ! {\tt GlobalSegMap} argument {\tt GSMap} has been built to incorporate
  1214. ! halo points.
  1215. !
  1216. ! !INTERFACE:
  1217. subroutine rank1_(GSMap, i_g, rank)
  1218. implicit none
  1219. ! !INPUT PARAMETERS:
  1220. type(GlobalSegMap), intent(in) :: GSMap ! input GlobalSegMap
  1221. integer, intent(in) :: i_g ! a global index
  1222. ! !OUTPUT PARAMETERS:
  1223. integer, intent(out) :: rank ! the pe on which this
  1224. ! element resides
  1225. ! !REVISION HISTORY:
  1226. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  1227. !EOP ___________________________________________________________________
  1228. character(len=*),parameter :: myname_=myname//'::rank1_'
  1229. integer :: i,ilc,ile
  1230. ! Initially, set the rank to -1 (invalid).
  1231. rank=-1
  1232. do i=1,size(GSMap%start)
  1233. ilc = GSMap%start(i)
  1234. ile = ilc + GSMap%length(i) - 1
  1235. ! If i_g in [ilc,ile]. Note that i_g := [1:..]
  1236. if(ilc <= i_g .and. i_g <= ile) then
  1237. rank = GSMap%pe_loc(i)
  1238. return
  1239. endif
  1240. end do
  1241. end subroutine rank1_
  1242. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1243. ! Math and Computer Science Division, Argonne National Laboratory !
  1244. !BOP -------------------------------------------------------------------
  1245. !
  1246. ! !IROUTINE: rankm_ - rank which processes own a datum with given global
  1247. ! index.
  1248. !
  1249. ! !DESCRIPTION:
  1250. ! This routine assumes that there may be more than one process that owns
  1251. ! the datum with a given global index. This routine should be used when
  1252. ! the input {\tt GlobalSegMap} argument {\tt GSMap} has been built to
  1253. ! incorporate ! halo points. {\em Nota Bene}: The output array {\tt rank}
  1254. ! is allocated in this routine and must be deallocated by the routine calling
  1255. ! {\tt rankm\_()}. Failure to do so could result in a memory leak.
  1256. !
  1257. ! !INTERFACE:
  1258. subroutine rankm_(GSMap, i_g, num_loc, rank)
  1259. implicit none
  1260. ! !INPUT PARAMETERS:
  1261. type(GlobalSegMap), intent(in) :: GSMap ! input GlobalSegMap
  1262. integer, intent(in) :: i_g ! a global index
  1263. ! !OUTPUT PARAMETERS:
  1264. integer, intent(out) :: num_loc ! the number of processes
  1265. ! which own element i_g
  1266. integer, dimension(:), pointer :: rank ! the process(es) on which
  1267. ! element i_g resides
  1268. ! !REVISION HISTORY:
  1269. ! 29Sep00 - J.W. Larson <larson@mcs.anl.gov> - initial prototype
  1270. !EOP ___________________________________________________________________
  1271. character(len=*),parameter :: myname_=myname//'::rankm_'
  1272. integer :: i, ilc, ile, ier, n
  1273. ! First sweep: determine the number of processes num_loc
  1274. ! that own the given datum:
  1275. num_loc = 0
  1276. do i=1,size(GSMap%start)
  1277. ilc = GSMap%start(i)
  1278. ile = ilc + GSMap%length(i) - 1
  1279. ! If i_g in [ilc,ile]. Note that i_g := [1:..]
  1280. if(ilc <= i_g .and. i_g <= ile) then
  1281. num_loc = num_loc + 1
  1282. endif
  1283. end do
  1284. if(num_loc == 0) then
  1285. ! If i_g is nowhere to be found in GSMap, set num_loc to
  1286. ! unity and return a null value for rank
  1287. num_loc = 1
  1288. allocate(rank(num_loc), stat=ier)
  1289. rank = -1 ! null value
  1290. return
  1291. else
  1292. ! Allocate output array rank(1:num_loc)
  1293. allocate(rank(num_loc), stat=ier)
  1294. ! Second sweep: fill in the entries to rank(:)
  1295. n = 0 ! counter
  1296. do i=1,size(GSMap%start)
  1297. ilc = GSMap%start(i)
  1298. ile = ilc + GSMap%length(i) - 1
  1299. ! If i_g in [ilc,ile]. Note that i_g := [1:..]
  1300. if(ilc <= i_g .and. i_g <= ile) then
  1301. n = n + 1
  1302. rank(n) = GSMap%pe_loc(i)
  1303. endif
  1304. end do
  1305. endif
  1306. end subroutine rankm_
  1307. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1308. ! Math and Computer Science Division, Argonne National Laboratory !
  1309. !BOP -------------------------------------------------------------------
  1310. !
  1311. ! !IROUTINE: active_pes_ - number of processes that own data.
  1312. ! index.
  1313. !
  1314. ! !DESCRIPTION:
  1315. ! This routine scans the pe location list of the input {\tt GlobalSegMap}
  1316. ! {\tt GSMap\%pe\_loc(:)}, and counts the number of pe locations that
  1317. ! own at least one datum. This value is returned in the {\tt INTEGER}
  1318. ! argument {\tt n\_active}. If the optional {\tt INTEGER} array argument
  1319. ! {\tt list} is included in the call, a sorted list (in ascending order) of
  1320. ! the active processes will be returned.
  1321. !
  1322. ! {\bf N.B.:} If {\tt active\_pes\_()} is invoked with the optional argument
  1323. ! {\tt pe\_list} included, this routine will allocate and return this array.
  1324. ! The user must deallocate this array once it is no longer needed. Failure
  1325. ! to do so will result in a memory leak.
  1326. !
  1327. ! !INTERFACE:
  1328. subroutine active_pes_(GSMap, n_active, pe_list)
  1329. !
  1330. ! !USES:
  1331. !
  1332. use m_die , only : die
  1333. use m_SortingTools , only : IndexSet
  1334. use m_SortingTools , only : IndexSort
  1335. use m_SortingTools , only : Permute
  1336. implicit none
  1337. ! !INPUT PARAMETERS:
  1338. type(GlobalSegMap), intent(in) :: GSMap
  1339. ! !OUTPUT PARAMETERS:
  1340. integer, intent(out) :: n_active
  1341. integer, dimension(:), pointer, optional :: pe_list
  1342. ! !REVISION HISTORY:
  1343. ! 03Feb01 - J.W. Larson <larson@mcs.anl.gov> - initial version.
  1344. !EOP ___________________________________________________________________
  1345. character(len=*),parameter :: myname_=myname//'::active_pes_'
  1346. integer :: count, i, n, ngseg, ierr
  1347. logical :: new
  1348. integer, dimension(:), allocatable :: temp_list
  1349. integer, dimension(:), allocatable :: perm
  1350. ! retrieve total number of segments in the map:
  1351. ngseg = ngseg_(GSMap)
  1352. ! allocate workspace to tally process id list:
  1353. allocate(temp_list(ngseg), stat=ierr)
  1354. if(ierr /= 0) call die(myname_,'allocate(temp_list...',ierr)
  1355. ! initialize temp_list to -1 (which can never be a process id)
  1356. temp_list = -1
  1357. ! initialize the distinct active process count:
  1358. count = 0
  1359. ! scan entries of GSMap%pe_loc to count active processes:
  1360. do n=1,ngseg
  1361. if(GSMap%pe_loc(n) >= 0) then ! a legitimate pe_location
  1362. ! assume initially that GSMap%pe_loc(n) is a process id previously
  1363. ! not encountered
  1364. new = .true.
  1365. ! test this proposition against the growing list of distinct
  1366. ! process ids stored in temp_list(:)
  1367. do i=1, count
  1368. if(GSMap%pe_loc(n) == temp_list(i)) new = .false.
  1369. end do
  1370. ! If GSMap%pe_loc(n) represents a previously unencountered
  1371. ! process id, increment the count, and add this id to the list
  1372. if(new) then
  1373. count = count + 1
  1374. temp_list(count) = GSMap%pe_loc(n)
  1375. endif
  1376. else ! a negative entry in GSMap%pe_loc(n)
  1377. ierr = 2
  1378. call die(myname_,'negative value of GSMap%pe_loc',ierr)
  1379. endif
  1380. end do
  1381. ! If the argument pe_list is present, we must allocate this
  1382. ! array, fill it, and sort it
  1383. if(present(pe_list)) then
  1384. ! allocate pe_list and permutation array perm
  1385. allocate(pe_list(count), perm(count), stat=ierr)
  1386. if (ierr /= 0) then
  1387. call die(myname_,'allocate(pe_list...',ierr)
  1388. endif
  1389. do n=1,count
  1390. pe_list(n) = temp_list(n)
  1391. end do
  1392. ! sorting and permutation...
  1393. call IndexSet(perm)
  1394. call IndexSort(count, perm, pe_list, descend=.false.)
  1395. call Permute(pe_list, perm, count)
  1396. ! deallocate permutation array...
  1397. deallocate(perm, stat=ierr)
  1398. if (ierr /= 0) then
  1399. call die(myname_,'deallocate(perm)',ierr)
  1400. endif
  1401. endif ! if(present(pe_list))...
  1402. ! deallocate work array temp_list...
  1403. deallocate(temp_list, stat=ierr)
  1404. if (ierr /= 0) then
  1405. call die(myname_,'deallocate(temp_list)',ierr)
  1406. endif
  1407. ! finally, store the active process count in output variable
  1408. ! n_active:
  1409. n_active = count
  1410. end subroutine active_pes_
  1411. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1412. ! Math and Computer Science Division, Argonne National Laboratory !
  1413. !BOP -------------------------------------------------------------------
  1414. !
  1415. ! !IROUTINE: peLocs_ - process ID locations for distributed points.
  1416. ! index.
  1417. !
  1418. ! !DESCRIPTION:
  1419. ! This routine takes an input {\tt INTEGER} array of point indices
  1420. ! {\tt points(:)}, compares them with an input {\tt GlobalSegMap}
  1421. ! {\tt pointGSMap}, and returns the {\em unique} process ID location
  1422. ! for each point. Note the emphasize on unique. The assumption here
  1423. ! (which is tested) is that {\tt pointGSMap} is not haloed. The process
  1424. ! ID locations for the points is returned in the array {\tt pe\_locs(:)}.
  1425. !
  1426. ! {\bf N.B.:} The test of {\tt pointGSMap} for halo points, and the
  1427. ! subsequent search for the process ID for each point is very slow. This
  1428. ! first version of the routine is serial. A parallel version of this
  1429. ! routine will need to be developed.
  1430. !
  1431. ! !INTERFACE:
  1432. subroutine peLocs_(pointGSMap, npoints, points, pe_locs)
  1433. !
  1434. ! !USES:
  1435. !
  1436. use m_die , only : die
  1437. implicit none
  1438. ! !INPUT PARAMETERS:
  1439. type(GlobalSegMap), intent(in) :: pointGSMap
  1440. integer, intent(in) :: npoints
  1441. integer, dimension(:), intent(in) :: points
  1442. ! !OUTPUT PARAMETERS:
  1443. integer, dimension(:), intent(out) :: pe_locs
  1444. ! !REVISION HISTORY:
  1445. ! 18Apr01 - J.W. Larson <larson@mcs.anl.gov> - initial version.
  1446. !EOP ___________________________________________________________________
  1447. character(len=*),parameter :: myname_=myname//'::peLocs_'
  1448. integer :: ierr
  1449. integer :: iseg, ngseg, ipoint
  1450. integer :: lower_index, upper_index
  1451. ! Input argument checks:
  1452. if(size(points) < npoints) then
  1453. ierr = size(points)
  1454. call die(myname_,'input points list array too small',ierr)
  1455. endif
  1456. if(size(pe_locs) < npoints) then
  1457. ierr = size(pe_locs)
  1458. call die(myname_,'output pe_locs array too small',ierr)
  1459. endif
  1460. if(haloed_(pointGSMap)) then
  1461. ierr = 1
  1462. call die(myname_,'input pointGSMap haloed--not valid',ierr)
  1463. endif
  1464. ! Brute-force indexing...no assumptions regarding sorting of points(:)
  1465. ! or pointGSMap%start(:)
  1466. ! Number of segments in pointGSMap:
  1467. ngseg = ngseg_(pointGSMap)
  1468. do ipoint=1,npoints ! loop over points
  1469. do iseg=1,ngseg ! loop over segments
  1470. lower_index = pointGSMap%start(iseg)
  1471. upper_index = lower_index + pointGSMap%length(iseg) - 1
  1472. if((points(ipoint) >= lower_index) .and. &
  1473. (points(ipoint) <= upper_index)) then
  1474. pe_locs(ipoint) = pointGSMap%pe_loc(iseg)
  1475. endif
  1476. end do ! do iseg=1, ngseg
  1477. end do ! do ipoint=1,npoints
  1478. end subroutine peLocs_
  1479. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1480. ! Math and Computer Science Division, Argonne National Laboratory !
  1481. !BOP -------------------------------------------------------------------
  1482. !
  1483. ! !IROUTINE: haloed_ - test GlobalSegMap for presence of halo points.
  1484. ! index.
  1485. !
  1486. ! !DESCRIPTION:
  1487. ! This {\tt LOGICAL} function tests the input {\tt GlobalSegMap}
  1488. ! {\tt GSMap} for the presence of halo points. Halo points are points
  1489. ! that appear in more than one segment of a {\tt GlobalSegMap}. If
  1490. ! {\em any} halo point is found, the function {\tt haloed\_()} returns
  1491. ! immediately with value {\tt .TRUE.} If, after an exhaustive search
  1492. ! of the map has been completed, no halo points are found, the function
  1493. ! {\tt haloed\_()} returns with value {\tt .FALSE.}
  1494. !
  1495. ! The search algorithm is:
  1496. !
  1497. ! \begin{enumerate}
  1498. ! \item Extract the segment start and length information from
  1499. ! {\tt GSMap\%start} and {\tt GSMap\%length} into the temporary
  1500. ! arrays {\tt start(:)} and {\tt length(:)}.
  1501. ! \item Sort these arrays in {\em ascending order} keyed by {\tt start}.
  1502. ! \item Scan the arrays {\tt start} and{\tt length}. A halo point is
  1503. ! present if for at least one value of the index
  1504. ! $1 \leq {\tt n} \leq {\tt GSMap\%ngseg}$
  1505. ! $${\tt start(n)} + {\tt length(n)} - 1 \geq {\tt start(n+1)}$$.
  1506. ! \end{enumerate}
  1507. !
  1508. ! {\bf N.B.:} Beware that the search for halo points is potentially
  1509. ! expensive.
  1510. !
  1511. ! !INTERFACE:
  1512. logical function haloed_(GSMap)
  1513. !
  1514. ! !USES:
  1515. !
  1516. use m_die , only : die
  1517. use m_SortingTools , only : IndexSet
  1518. use m_SortingTools , only : IndexSort
  1519. use m_SortingTools , only : Permute
  1520. implicit none
  1521. ! !INPUT PARAMETERS:
  1522. type(GlobalSegMap), intent(in) :: GSMap
  1523. ! !REVISION HISTORY:
  1524. ! 08Feb01 - J.W. Larson <larson@mcs.anl.gov> - initial version.
  1525. ! 26Apr01 - J.W. Larson <larson@mcs.anl.gov> - Bug fix.
  1526. !EOP ___________________________________________________________________
  1527. character(len=*),parameter :: myname_=myname//'::haloed_'
  1528. ! Error Flag
  1529. integer :: ierr
  1530. ! Loop index and storage for number of segments in GSMap
  1531. integer :: n, ngseg
  1532. ! Temporary storage for GSMap%start, GSMap%length, and index
  1533. ! permutation array:
  1534. integer, dimension(:), allocatable :: start, length, perm
  1535. ! Logical flag indicating segment overlap
  1536. logical :: overlap
  1537. ! How many segments in GSMap?
  1538. ngseg = ngseg_(GSMap)
  1539. ! allocate temporary arrays:
  1540. allocate(start(ngseg), length(ngseg), perm(ngseg), stat=ierr)
  1541. if (ierr /= 0) then
  1542. call die(myname_,'allocate(start...',ierr)
  1543. endif
  1544. ! Fill the temporary arrays start(:) and length(:)
  1545. do n=1,ngseg
  1546. start(n) = GSMap%start(n)
  1547. length(n) = GSMap%length(n)
  1548. end do
  1549. ! Initialize the index permutation array:
  1550. call IndexSet(perm)
  1551. ! Create the index permutation that will order the data so the
  1552. ! entries of start(:) appear in ascending order:
  1553. call IndexSort(ngseg, perm, start, descend=.false.)
  1554. ! Permute the data so the entries of start(:) are now in
  1555. ! ascending order:
  1556. call Permute(start,perm,ngseg)
  1557. ! Apply this same permutation to length(:)
  1558. call Permute(length,perm,ngseg)
  1559. ! Set LOGICAL flag indicating segment overlap to .FALSE.
  1560. overlap = .FALSE.
  1561. ! Now, scan the segments, looking for overlapping segments. Upon
  1562. ! discovery of the first overlapping pair of segments, set the
  1563. ! flag overlap to .TRUE. and exit.
  1564. n = 0
  1565. SCAN_LOOP: do
  1566. n = n + 1
  1567. if(n == ngseg) EXIT ! we are finished, and there were no halo pts.
  1568. if((start(n) + length(n) - 1) >= start(n+1)) then ! found overlap
  1569. overlap = .TRUE.
  1570. EXIT
  1571. endif
  1572. end do SCAN_LOOP
  1573. ! Clean up allocated memory:
  1574. deallocate(start, length, perm, stat=ierr)
  1575. if (ierr /= 0) then
  1576. call die(myname_,'deallocate(start...',ierr)
  1577. endif
  1578. ! Assign function return value:
  1579. haloed_ = overlap
  1580. end function haloed_
  1581. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1582. ! Math and Computer Science Division, Argonne National Laboratory !
  1583. !BOP -------------------------------------------------------------------
  1584. !
  1585. ! !IROUTINE: Sort_ - generate index permutation for GlobalSegMap.
  1586. !
  1587. ! !DESCRIPTION:
  1588. ! {\tt Sort\_()} uses the supplied keys {\tt key1} and {\tt key2} to
  1589. ! generate a permutation {\tt perm} that will put the entries of the
  1590. ! components {\tt GlobalSegMap\%start}, {\tt GlobalSegMap\%length} and
  1591. ! {\tt GlobalSegMap\%pe\_loc} in {\em ascending} lexicographic order.
  1592. !
  1593. ! {\bf N.B.:} {\tt Sort\_()} returns an allocated array {\tt perm(:)}. It
  1594. ! the user must deallocate this array once it is no longer needed. Failure
  1595. ! to do so could create a memory leak.
  1596. !
  1597. ! !INTERFACE:
  1598. subroutine Sort_(GSMap, key1, key2, perm)
  1599. !
  1600. ! !USES:
  1601. !
  1602. use m_die , only : die
  1603. use m_SortingTools , only : IndexSet
  1604. use m_SortingTools , only : IndexSort
  1605. implicit none
  1606. ! !INPUT PARAMETERS:
  1607. type(GlobalSegMap), intent(in) :: GSMap ! input GlobalSegMap
  1608. integer, dimension(:), intent(in) :: key1 ! first sort key
  1609. integer, dimension(:), intent(in), optional :: key2 ! second sort key
  1610. ! !OUTPUT PARAMETERS:
  1611. integer, dimension(:), pointer :: perm ! output index permutation
  1612. ! !REVISION HISTORY:
  1613. ! 02Feb01 - J.W. Larson <larson@mcs.anl.gov> - initial version
  1614. !EOP ___________________________________________________________________
  1615. character(len=*),parameter :: myname_=myname//'::Sort_'
  1616. integer :: ierr, length
  1617. length = ngseg_(GSMap)
  1618. ! Argument checking. are key1 and key2 (if supplied) the
  1619. ! same length as the components of GSMap? If not, stop with
  1620. ! an error.
  1621. ierr = 0
  1622. if(size(key1) /= length) then
  1623. ierr = 1
  1624. call die(myname_,'key1 GSMap size mismatch',ierr)
  1625. endif
  1626. if(present(key2)) then
  1627. if(size(key2) /= length) then
  1628. ierr = 2
  1629. call die(myname_,'key2 GSMap size mismatch',ierr)
  1630. endif
  1631. if(size(key1) /= size(key2)) then
  1632. ierr = 3
  1633. call die(myname_,'key1 key2 size mismatch',ierr)
  1634. endif
  1635. endif
  1636. ! allocate space for permutation array perm(:)
  1637. allocate(perm(length), stat=ierr)
  1638. if(ierr /= 0) call die(myname_,'allocate(perm)',ierr)
  1639. ! Initialize perm(i)=i, for i=1,length
  1640. call IndexSet(perm)
  1641. ! Index permutation is achieved by successive calls to IndexSort(),
  1642. ! with the keys supplied one at a time in the order reversed from
  1643. ! the desired sort order.
  1644. if(present(key2)) then
  1645. call IndexSort(length, perm, key2, descend=.false.)
  1646. endif
  1647. call IndexSort(length, perm, key1, descend=.false.)
  1648. ! Yes, it is that simple. The desired index permutation is now
  1649. ! stored in perm(:)
  1650. end subroutine Sort_
  1651. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1652. ! Math and Computer Science Division, Argonne National Laboratory !
  1653. !BOP -------------------------------------------------------------------
  1654. !
  1655. ! !IROUTINE: PermuteInPlace_ - apply index permutation to GlobalSegMap.
  1656. !
  1657. ! !DESCRIPTION:
  1658. ! {\tt PermuteInPlace\_()} uses a supplied index permutation {\tt perm}
  1659. ! to re-order {\tt GlobalSegMap\%start}, {\tt GlobalSegMap\%length} and
  1660. ! {\tt GlobalSegMap\%pe\_loc}.
  1661. !
  1662. ! !INTERFACE:
  1663. subroutine PermuteInPlace_(GSMap, perm)
  1664. !
  1665. ! !USES:
  1666. !
  1667. use m_die , only : die
  1668. use m_SortingTools , only : Permute
  1669. implicit none
  1670. ! !INPUT PARAMETERS:
  1671. integer, dimension(:), intent(in) :: perm
  1672. ! !INPUT/OUTPUT PARAMETERS:
  1673. type(GlobalSegMap), intent(inout) :: GSMap
  1674. ! !REVISION HISTORY:
  1675. ! 02Feb01 - J.W. Larson <larson@mcs.anl.gov> - initial version.
  1676. !EOP ___________________________________________________________________
  1677. character(len=*),parameter :: myname_=myname//'::PermuteInPlace_'
  1678. integer :: length, ierr
  1679. length = ngseg_(GSMap)
  1680. ! Argument checking. Do the components of GSMap
  1681. ! (e.g. GSMap%start) have the same length as the
  1682. ! permutation array perm? If not, stop with an error.
  1683. ierr = 0
  1684. if(size(perm) /= length) then
  1685. ierr = 1
  1686. call die(myname_,'perm GSMap size mismatch',ierr)
  1687. endif
  1688. ! In-place index permutation using perm(:) :
  1689. call Permute(GSMap%start,perm,length)
  1690. call Permute(GSMap%length,perm,length)
  1691. call Permute(GSMap%pe_loc,perm,length)
  1692. ! Now, the components of GSMap are ordered according to
  1693. ! perm(:).
  1694. end subroutine PermuteInPlace_
  1695. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1696. ! Math and Computer Science Division, Argonne National Laboratory !
  1697. !BOP -------------------------------------------------------------------
  1698. !
  1699. ! !IROUTINE: SortPermuteInPlace_ - Sort in-place GlobalSegMap components.
  1700. !
  1701. ! !DESCRIPTION:
  1702. ! {\tt SortPermuteInPlace\_()} uses a the supplied key(s) to generate
  1703. ! and apply an index permutation that will place the {\tt GlobalSegMap}
  1704. ! components {\tt GlobalSegMap\%start}, {\tt GlobalSegMap\%length} and
  1705. ! {\tt GlobalSegMap\%pe\_loc} in lexicographic order.
  1706. !
  1707. ! !INTERFACE:
  1708. subroutine SortPermuteInPlace_(GSMap, key1, key2)
  1709. !
  1710. ! !USES:
  1711. !
  1712. use m_die , only : die
  1713. implicit none
  1714. ! !INPUT PARAMETERS:
  1715. integer, dimension(:), intent(in) :: key1
  1716. integer, dimension(:), intent(in), optional :: key2
  1717. ! !INPUT/OUTPUT PARAMETERS:
  1718. type(GlobalSegMap), intent(inout) :: GSMap
  1719. ! !REVISION HISTORY:
  1720. ! 02Feb01 - J.W. Larson <larson@mcs.anl.gov> - initial version.
  1721. !EOP ___________________________________________________________________
  1722. character(len=*),parameter :: myname_=myname//'::SortPermuteInPlace_'
  1723. integer :: length, ierr
  1724. integer, dimension(:), pointer :: perm
  1725. length = ngseg_(GSMap)
  1726. ! Argument checking. are key1 and key2 (if supplied) the
  1727. ! same length as the components of GSMap? If not, stop with
  1728. ! an error.
  1729. ierr = 0
  1730. if(size(key1) /= length) then
  1731. ierr = 1
  1732. call die(myname_,'key1 GSMap size mismatch',ierr)
  1733. endif
  1734. if(present(key2)) then
  1735. if(size(key2) /= length) then
  1736. ierr = 2
  1737. call die(myname_,'key2 GSMap size mismatch',ierr)
  1738. endif
  1739. if(size(key1) /= size(key2)) then
  1740. ierr = 3
  1741. call die(myname_,'key1 key2 size mismatch',ierr)
  1742. endif
  1743. endif
  1744. ! Generate desired index permutation:
  1745. if(present(key2)) then
  1746. call Sort_(GSMap, key1, key2, perm)
  1747. else
  1748. call Sort_(GSMap, key1=key1, perm=perm)
  1749. endif
  1750. ! Apply index permutation:
  1751. call PermuteInPlace_(GSMap, perm)
  1752. ! Now the components of GSMap have been re-ordered.
  1753. ! Deallocate the index permutation array perm(:)
  1754. deallocate(perm, stat=ierr)
  1755. if(ierr /= 0) call die(myname_,'deallocate(perm...)',ierr)
  1756. end subroutine SortPermuteInPlace_
  1757. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1758. ! Math and Computer Science Division, Argonne National Laboratory !
  1759. !BOP -------------------------------------------------------------------
  1760. !
  1761. ! !IROUTINE: increasing_ - Return .TRUE. if GSMap has increasing indices
  1762. !
  1763. ! !DESCRIPTION:
  1764. ! The function {\tt increasing\_()} returns .TRUE. if each proc's
  1765. ! indices in the {\tt GlobalSegMap} argument {\tt GSMap} have
  1766. ! strictly increasing indices. I.e. the proc's segments have indices
  1767. ! in ascending order and are non-overlapping.
  1768. !
  1769. ! !INTERFACE:
  1770. logical function increasing_(gsmap)
  1771. ! !USES:
  1772. use m_MCTWorld, only: ThisMCTWorld
  1773. use m_die
  1774. implicit none
  1775. ! !INPUT PARAMETERS:
  1776. type(GlobalSegMap),intent(in) :: gsmap
  1777. ! !REVISION HISTORY:
  1778. ! 06Jun07 - R. Loy <rloy@mcs.anl.gov> - initial version
  1779. !EOP ___________________________________________________________________
  1780. character(len=*),parameter :: myname_=myname//'::increasing_'
  1781. integer comp_id
  1782. integer nprocs
  1783. integer i
  1784. integer this_ngseg
  1785. integer ier
  1786. integer, allocatable:: last_index(:)
  1787. integer pe_loc
  1788. comp_id = gsmap%comp_id
  1789. nprocs=ThisMCTWorld%nprocspid(comp_id)
  1790. allocate( last_index(nprocs), stat=ier )
  1791. if (ier/=0) call die(myname_,'allocate last_index')
  1792. last_index= -1
  1793. increasing_ = .TRUE.
  1794. this_ngseg=ngseg(gsmap)
  1795. iloop: do i=1,this_ngseg
  1796. pe_loc=gsmap%pe_loc(i)+1 ! want value 1..nprocs
  1797. if (gsmap%start(i) <= last_index(pe_loc)) then
  1798. increasing_ = .FALSE.
  1799. exit iloop
  1800. endif
  1801. last_index(pe_loc)=gsmap%start(i)+gsmap%length(i)-1
  1802. enddo iloop
  1803. deallocate( last_index, stat=ier )
  1804. if (ier/=0) call die(myname_,'deallocate last_index')
  1805. end function increasing_
  1806. !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1807. ! Math and Computer Science Division, Argonne National Laboratory !
  1808. !BOP -------------------------------------------------------------------
  1809. !
  1810. ! !IROUTINE: copy_ - Copy the gsmap to a new gsmap
  1811. !
  1812. ! !DESCRIPTION:
  1813. ! Make a copy of a gsmap.
  1814. ! Note this is a deep copy of all arrays.
  1815. !
  1816. ! !INTERFACE:
  1817. subroutine copy_(src,dest)
  1818. ! !USES:
  1819. use m_MCTWorld, only: ThisMCTWorld
  1820. use m_die
  1821. implicit none
  1822. ! !INPUT PARAMETERS:
  1823. type(GlobalSegMap),intent(in) :: src
  1824. ! !OUTPUT PARAMETERS:
  1825. type(GlobalSegMap),intent(out) :: dest
  1826. ! !REVISION HISTORY:
  1827. ! 27Jul07 - R. Loy <rloy@mcs.anl.gov> - initial version
  1828. !EOP ___________________________________________________________________
  1829. call initp_( dest, src%comp_id, src%ngseg, src%gsize, &
  1830. src%start, src%length, src%pe_loc )
  1831. end subroutine copy_
  1832. end module m_GlobalSegMap