xref: /petsc/src/vec/is/utils/isltog.c (revision 97f1f81f25e472dee20d72ba0c3543b434a70ae6)
12362add9SBarry Smith 
2e090d566SSatish Balay #include "petscsys.h"   /*I "petscsys.h" I*/
3e090d566SSatish Balay #include "src/vec/is/isimpl.h"    /*I "petscis.h"  I*/
42362add9SBarry Smith 
5dfbe8321SBarry Smith EXTERN PetscErrorCode VecInitializePackage(char *);
66849ba73SBarry Smith PetscCookie IS_LTOGM_COOKIE = -1;
78e58c17dSMatthew Knepley 
84a2ae208SSatish Balay #undef __FUNCT__
94a2ae208SSatish Balay #define __FUNCT__ "ISLocalToGlobalMappingGetSize"
103b9aefa3SBarry Smith /*@C
113b9aefa3SBarry Smith     ISLocalToGlobalMappingGetSize - Gets the local size of a local to global mapping.
123b9aefa3SBarry Smith 
133b9aefa3SBarry Smith     Not Collective
143b9aefa3SBarry Smith 
153b9aefa3SBarry Smith     Input Parameter:
163b9aefa3SBarry Smith .   ltog - local to global mapping
173b9aefa3SBarry Smith 
183b9aefa3SBarry Smith     Output Parameter:
193b9aefa3SBarry Smith .   n - the number of entries in the local mapping
203b9aefa3SBarry Smith 
213b9aefa3SBarry Smith     Level: advanced
223b9aefa3SBarry Smith 
23273d9f13SBarry Smith     Concepts: mapping^local to global
243b9aefa3SBarry Smith 
253b9aefa3SBarry Smith .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreate()
263b9aefa3SBarry Smith @*/
2732dcc486SBarry Smith PetscErrorCode ISLocalToGlobalMappingGetSize(ISLocalToGlobalMapping mapping,PetscInt *n)
283b9aefa3SBarry Smith {
293b9aefa3SBarry Smith   PetscFunctionBegin;
304482741eSBarry Smith   PetscValidHeaderSpecific(mapping,IS_LTOGM_COOKIE,1);
314482741eSBarry Smith   PetscValidIntPointer(n,2);
323b9aefa3SBarry Smith   *n = mapping->n;
333b9aefa3SBarry Smith   PetscFunctionReturn(0);
343b9aefa3SBarry Smith }
353b9aefa3SBarry Smith 
364a2ae208SSatish Balay #undef __FUNCT__
374a2ae208SSatish Balay #define __FUNCT__ "ISLocalToGlobalMappingView"
385a5d4f66SBarry Smith /*@C
395a5d4f66SBarry Smith     ISLocalToGlobalMappingView - View a local to global mapping
405a5d4f66SBarry Smith 
41b9cd556bSLois Curfman McInnes     Not Collective
42b9cd556bSLois Curfman McInnes 
435a5d4f66SBarry Smith     Input Parameters:
443b9aefa3SBarry Smith +   ltog - local to global mapping
453b9aefa3SBarry Smith -   viewer - viewer
465a5d4f66SBarry Smith 
47a997ad1aSLois Curfman McInnes     Level: advanced
48a997ad1aSLois Curfman McInnes 
49273d9f13SBarry Smith     Concepts: mapping^local to global
505a5d4f66SBarry Smith 
515a5d4f66SBarry Smith .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreate()
525a5d4f66SBarry Smith @*/
53dfbe8321SBarry Smith PetscErrorCode ISLocalToGlobalMappingView(ISLocalToGlobalMapping mapping,PetscViewer viewer)
545a5d4f66SBarry Smith {
5532dcc486SBarry Smith   PetscInt        i;
5632dcc486SBarry Smith   PetscMPIInt     rank;
5732077d6dSBarry Smith   PetscTruth      iascii;
586849ba73SBarry Smith   PetscErrorCode  ierr;
595a5d4f66SBarry Smith 
605a5d4f66SBarry Smith   PetscFunctionBegin;
614482741eSBarry Smith   PetscValidHeaderSpecific(mapping,IS_LTOGM_COOKIE,1);
62b0a32e0cSBarry Smith   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(mapping->comm);
634482741eSBarry Smith   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_COOKIE,2);
645a5d4f66SBarry Smith 
65f1af5d2fSBarry Smith   ierr = MPI_Comm_rank(mapping->comm,&rank);CHKERRQ(ierr);
6632077d6dSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
6732077d6dSBarry Smith   if (iascii) {
685a5d4f66SBarry Smith     for (i=0; i<mapping->n; i++) {
69b0a32e0cSBarry Smith       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] %d %d\n",rank,i,mapping->indices[i]);CHKERRQ(ierr);
706831982aSBarry Smith     }
71b0a32e0cSBarry Smith     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
726831982aSBarry Smith   } else {
73958c9bccSBarry Smith     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for ISLocalToGlobalMapping",((PetscObject)viewer)->type_name);
745a5d4f66SBarry Smith   }
755a5d4f66SBarry Smith 
765a5d4f66SBarry Smith   PetscFunctionReturn(0);
775a5d4f66SBarry Smith }
785a5d4f66SBarry Smith 
794a2ae208SSatish Balay #undef __FUNCT__
804a2ae208SSatish Balay #define __FUNCT__ "ISLocalToGlobalMappingCreateIS"
812bdab257SBarry Smith /*@C
822bdab257SBarry Smith     ISLocalToGlobalMappingCreateIS - Creates a mapping between a local (0 to n)
832bdab257SBarry Smith     ordering and a global parallel ordering.
842bdab257SBarry Smith 
850f5bd95cSBarry Smith     Not collective
86b9cd556bSLois Curfman McInnes 
87a997ad1aSLois Curfman McInnes     Input Parameter:
882bdab257SBarry Smith .   is - index set containing the global numbers for each local
892bdab257SBarry Smith 
90a997ad1aSLois Curfman McInnes     Output Parameter:
912bdab257SBarry Smith .   mapping - new mapping data structure
922bdab257SBarry Smith 
93a997ad1aSLois Curfman McInnes     Level: advanced
94a997ad1aSLois Curfman McInnes 
95273d9f13SBarry Smith     Concepts: mapping^local to global
962bdab257SBarry Smith 
972bdab257SBarry Smith .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreate()
982bdab257SBarry Smith @*/
99dfbe8321SBarry Smith PetscErrorCode ISLocalToGlobalMappingCreateIS(IS is,ISLocalToGlobalMapping *mapping)
1002bdab257SBarry Smith {
1016849ba73SBarry Smith   PetscErrorCode ierr;
10232dcc486SBarry Smith   PetscInt      n,*indices;
1032bdab257SBarry Smith   MPI_Comm comm;
1043a40ed3dSBarry Smith 
1053a40ed3dSBarry Smith   PetscFunctionBegin;
1064482741eSBarry Smith   PetscValidHeaderSpecific(is,IS_COOKIE,1);
1074482741eSBarry Smith   PetscValidPointer(mapping,2);
1082bdab257SBarry Smith 
1092bdab257SBarry Smith   ierr = PetscObjectGetComm((PetscObject)is,&comm);CHKERRQ(ierr);
1103b9aefa3SBarry Smith   ierr = ISGetLocalSize(is,&n);CHKERRQ(ierr);
1112bdab257SBarry Smith   ierr = ISGetIndices(is,&indices);CHKERRQ(ierr);
1122bdab257SBarry Smith   ierr = ISLocalToGlobalMappingCreate(comm,n,indices,mapping);CHKERRQ(ierr);
1132bdab257SBarry Smith   ierr = ISRestoreIndices(is,&indices);CHKERRQ(ierr);
1142bdab257SBarry Smith 
1153a40ed3dSBarry Smith   PetscFunctionReturn(0);
1162bdab257SBarry Smith }
1175a5d4f66SBarry Smith 
118b46b645bSBarry Smith 
1194a2ae208SSatish Balay #undef __FUNCT__
1204a2ae208SSatish Balay #define __FUNCT__ "ISLocalToGlobalMappingCreate"
121dd7157adSSatish Balay /*@C
12290f02eecSBarry Smith     ISLocalToGlobalMappingCreate - Creates a mapping between a local (0 to n)
12390f02eecSBarry Smith     ordering and a global parallel ordering.
1242362add9SBarry Smith 
12589d82c54SBarry Smith     Not Collective, but communicator may have more than one process
126b9cd556bSLois Curfman McInnes 
1272362add9SBarry Smith     Input Parameters:
12889d82c54SBarry Smith +   comm - MPI communicator
12990f02eecSBarry Smith .   n - the number of local elements
130b9cd556bSLois Curfman McInnes -   indices - the global index for each local element
1312362add9SBarry Smith 
132a997ad1aSLois Curfman McInnes     Output Parameter:
13390f02eecSBarry Smith .   mapping - new mapping data structure
1342362add9SBarry Smith 
135a997ad1aSLois Curfman McInnes     Level: advanced
136a997ad1aSLois Curfman McInnes 
137273d9f13SBarry Smith     Concepts: mapping^local to global
1382362add9SBarry Smith 
139b46b645bSBarry Smith .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreateIS(), ISLocalToGlobalMappingCreateNC()
1402362add9SBarry Smith @*/
14132dcc486SBarry Smith PetscErrorCode ISLocalToGlobalMappingCreate(MPI_Comm cm,PetscInt n,const PetscInt indices[],ISLocalToGlobalMapping *mapping)
1422362add9SBarry Smith {
1436849ba73SBarry Smith   PetscErrorCode ierr;
14432dcc486SBarry Smith   PetscInt *in;
145b46b645bSBarry Smith 
146b46b645bSBarry Smith   PetscFunctionBegin;
1474482741eSBarry Smith   PetscValidIntPointer(indices,3);
1484482741eSBarry Smith   PetscValidPointer(mapping,4);
14932dcc486SBarry Smith   ierr = PetscMalloc((n+1)*sizeof(PetscInt),&in);CHKERRQ(ierr);
15032dcc486SBarry Smith   ierr = PetscMemcpy(in,indices,n*sizeof(PetscInt));CHKERRQ(ierr);
151b46b645bSBarry Smith   ierr = ISLocalToGlobalMappingCreateNC(cm,n,in,mapping);CHKERRQ(ierr);
152b46b645bSBarry Smith   PetscFunctionReturn(0);
153b46b645bSBarry Smith }
154b46b645bSBarry Smith 
155b46b645bSBarry Smith #undef __FUNCT__
156b46b645bSBarry Smith #define __FUNCT__ "ISLocalToGlobalMappingCreateNC"
157b46b645bSBarry Smith /*@C
158b46b645bSBarry Smith     ISLocalToGlobalMappingCreateNC - Creates a mapping between a local (0 to n)
159b46b645bSBarry Smith     ordering and a global parallel ordering.
160b46b645bSBarry Smith 
161b46b645bSBarry Smith     Not Collective, but communicator may have more than one process
162b46b645bSBarry Smith 
163b46b645bSBarry Smith     Input Parameters:
164b46b645bSBarry Smith +   comm - MPI communicator
165b46b645bSBarry Smith .   n - the number of local elements
166b46b645bSBarry Smith -   indices - the global index for each local element
167b46b645bSBarry Smith 
168b46b645bSBarry Smith     Output Parameter:
169b46b645bSBarry Smith .   mapping - new mapping data structure
170b46b645bSBarry Smith 
171b46b645bSBarry Smith     Level: developer
172b46b645bSBarry Smith 
173b46b645bSBarry Smith     Notes: Does not copy the indices, just keeps the pointer to the indices. The ISLocalToGlobalMappingDestroy()
174b46b645bSBarry Smith     will free the space so it must be obtained with PetscMalloc() and it must not be freed elsewhere.
175b46b645bSBarry Smith 
176b46b645bSBarry Smith     Concepts: mapping^local to global
177b46b645bSBarry Smith 
178b46b645bSBarry Smith .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreateIS(), ISLocalToGlobalMappingCreate()
179b46b645bSBarry Smith @*/
18032dcc486SBarry Smith PetscErrorCode ISLocalToGlobalMappingCreateNC(MPI_Comm cm,PetscInt n,const PetscInt indices[],ISLocalToGlobalMapping *mapping)
181b46b645bSBarry Smith {
182dfbe8321SBarry Smith   PetscErrorCode ierr;
18323f7533aSBarry Smith 
1843a40ed3dSBarry Smith   PetscFunctionBegin;
1854482741eSBarry Smith   PetscValidIntPointer(indices,3);
1864482741eSBarry Smith   PetscValidPointer(mapping,4);
1878e58c17dSMatthew Knepley   *mapping = PETSC_NULL;
1888e58c17dSMatthew Knepley #ifndef PETSC_USE_DYNAMIC_LIBRARIES
18923f7533aSBarry Smith   ierr = VecInitializePackage(PETSC_NULL);CHKERRQ(ierr);
1908e58c17dSMatthew Knepley #endif
19123f7533aSBarry Smith   if (IS_LTOGM_COOKIE == -1) {
19223f7533aSBarry Smith     ierr = PetscLogClassRegister(&IS_LTOGM_COOKIE,"IS Local to global mapping");CHKERRQ(ierr);
19323f7533aSBarry Smith   }
1942362add9SBarry Smith 
1953f1db9ecSBarry Smith   PetscHeaderCreate(*mapping,_p_ISLocalToGlobalMapping,int,IS_LTOGM_COOKIE,0,"ISLocalToGlobalMapping",
1963f1db9ecSBarry Smith                     cm,ISLocalToGlobalMappingDestroy,ISLocalToGlobalMappingView);
197b0a32e0cSBarry Smith   PetscLogObjectCreate(*mapping);
19832dcc486SBarry Smith   PetscLogObjectMemory(*mapping,sizeof(struct _p_ISLocalToGlobalMapping)+n*sizeof(PetscInt));
199d4bb536fSBarry Smith 
200d4bb536fSBarry Smith   (*mapping)->n       = n;
20132dcc486SBarry Smith   (*mapping)->indices = (PetscInt*)indices;
202d4bb536fSBarry Smith 
203d4bb536fSBarry Smith   /*
204d4bb536fSBarry Smith       Do not create the global to local mapping. This is only created if
205d4bb536fSBarry Smith      ISGlobalToLocalMapping() is called
206d4bb536fSBarry Smith   */
207d4bb536fSBarry Smith   (*mapping)->globals = 0;
2083a40ed3dSBarry Smith   PetscFunctionReturn(0);
2092362add9SBarry Smith }
2102362add9SBarry Smith 
2114a2ae208SSatish Balay #undef __FUNCT__
2124a2ae208SSatish Balay #define __FUNCT__ "ISLocalToGlobalMappingBlock"
213323b833fSBarry Smith /*@C
214323b833fSBarry Smith     ISLocalToGlobalMappingBlock - Creates a blocked index version of an
215323b833fSBarry Smith        ISLocalToGlobalMapping that is appropriate for MatSetLocalToGlobalMappingBlock()
216323b833fSBarry Smith        and VecSetLocalToGlobalMappingBlock().
217323b833fSBarry Smith 
218323b833fSBarry Smith     Not Collective, but communicator may have more than one process
219323b833fSBarry Smith 
220323b833fSBarry Smith     Input Parameters:
221323b833fSBarry Smith +    inmap - original point-wise mapping
222323b833fSBarry Smith -    bs - block size
223323b833fSBarry Smith 
224323b833fSBarry Smith     Output Parameter:
225323b833fSBarry Smith .   outmap - block based mapping
226323b833fSBarry Smith 
227323b833fSBarry Smith     Level: advanced
228323b833fSBarry Smith 
229323b833fSBarry Smith     Concepts: mapping^local to global
230323b833fSBarry Smith 
231323b833fSBarry Smith .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreate(), ISLocalToGlobalMappingCreateIS()
232323b833fSBarry Smith @*/
23332dcc486SBarry Smith PetscErrorCode ISLocalToGlobalMappingBlock(ISLocalToGlobalMapping inmap,PetscInt bs,ISLocalToGlobalMapping *outmap)
234323b833fSBarry Smith {
2356849ba73SBarry Smith   PetscErrorCode ierr;
23632dcc486SBarry Smith   PetscInt            *ii,i,n;
237323b833fSBarry Smith 
238323b833fSBarry Smith   PetscFunctionBegin;
239323b833fSBarry Smith   if (bs > 1) {
240323b833fSBarry Smith     n    = inmap->n/bs;
24132dcc486SBarry Smith     ierr = PetscMalloc(n*sizeof(PetscInt),&ii);CHKERRQ(ierr);
242323b833fSBarry Smith     for (i=0; i<n; i++) {
243b8ee7809SBarry Smith       ii[i] = inmap->indices[bs*i]/bs;
244323b833fSBarry Smith     }
245323b833fSBarry Smith     ierr = ISLocalToGlobalMappingCreate(inmap->comm,n,ii,outmap);CHKERRQ(ierr);
246323b833fSBarry Smith     ierr = PetscFree(ii);CHKERRQ(ierr);
247323b833fSBarry Smith   } else {
248323b833fSBarry Smith     *outmap = inmap;
249323b833fSBarry Smith     ierr    = PetscObjectReference((PetscObject)inmap);CHKERRQ(ierr);
250323b833fSBarry Smith   }
251323b833fSBarry Smith   PetscFunctionReturn(0);
252323b833fSBarry Smith }
253323b833fSBarry Smith 
2544a2ae208SSatish Balay #undef __FUNCT__
2554a2ae208SSatish Balay #define __FUNCT__ "ISLocalToGlobalMappingDestroy"
25690f02eecSBarry Smith /*@
25790f02eecSBarry Smith    ISLocalToGlobalMappingDestroy - Destroys a mapping between a local (0 to n)
25890f02eecSBarry Smith    ordering and a global parallel ordering.
25990f02eecSBarry Smith 
2600f5bd95cSBarry Smith    Note Collective
261b9cd556bSLois Curfman McInnes 
26290f02eecSBarry Smith    Input Parameters:
26390f02eecSBarry Smith .  mapping - mapping data structure
26490f02eecSBarry Smith 
265a997ad1aSLois Curfman McInnes    Level: advanced
266a997ad1aSLois Curfman McInnes 
2673acfe500SLois Curfman McInnes .seealso: ISLocalToGlobalMappingCreate()
26890f02eecSBarry Smith @*/
269dfbe8321SBarry Smith PetscErrorCode ISLocalToGlobalMappingDestroy(ISLocalToGlobalMapping mapping)
27090f02eecSBarry Smith {
271dfbe8321SBarry Smith   PetscErrorCode ierr;
2723a40ed3dSBarry Smith   PetscFunctionBegin;
2734482741eSBarry Smith   PetscValidPointer(mapping,1);
2743a40ed3dSBarry Smith   if (--mapping->refct > 0) PetscFunctionReturn(0);
27585614651SBarry Smith   if (mapping->refct < 0) {
276634064b4SBarry Smith     SETERRQ(PETSC_ERR_PLIB,"Mapping already destroyed");
27785614651SBarry Smith   }
27890f02eecSBarry Smith 
279606d414cSSatish Balay   ierr = PetscFree(mapping->indices);CHKERRQ(ierr);
280606d414cSSatish Balay   if (mapping->globals) {ierr = PetscFree(mapping->globals);CHKERRQ(ierr);}
281b0a32e0cSBarry Smith   PetscLogObjectDestroy(mapping);
282d4bb536fSBarry Smith   PetscHeaderDestroy(mapping);
2833a40ed3dSBarry Smith   PetscFunctionReturn(0);
28490f02eecSBarry Smith }
28590f02eecSBarry Smith 
2864a2ae208SSatish Balay #undef __FUNCT__
2874a2ae208SSatish Balay #define __FUNCT__ "ISLocalToGlobalMappingApplyIS"
28890f02eecSBarry Smith /*@
2893acfe500SLois Curfman McInnes     ISLocalToGlobalMappingApplyIS - Creates from an IS in the local numbering
2903acfe500SLois Curfman McInnes     a new index set using the global numbering defined in an ISLocalToGlobalMapping
2913acfe500SLois Curfman McInnes     context.
29290f02eecSBarry Smith 
293b9cd556bSLois Curfman McInnes     Not collective
294b9cd556bSLois Curfman McInnes 
29590f02eecSBarry Smith     Input Parameters:
296b9cd556bSLois Curfman McInnes +   mapping - mapping between local and global numbering
297b9cd556bSLois Curfman McInnes -   is - index set in local numbering
29890f02eecSBarry Smith 
29990f02eecSBarry Smith     Output Parameters:
30090f02eecSBarry Smith .   newis - index set in global numbering
30190f02eecSBarry Smith 
302a997ad1aSLois Curfman McInnes     Level: advanced
303a997ad1aSLois Curfman McInnes 
304273d9f13SBarry Smith     Concepts: mapping^local to global
3053acfe500SLois Curfman McInnes 
30690f02eecSBarry Smith .seealso: ISLocalToGlobalMappingApply(), ISLocalToGlobalMappingCreate(),
307d4bb536fSBarry Smith           ISLocalToGlobalMappingDestroy(), ISGlobalToLocalMappingApply()
30890f02eecSBarry Smith @*/
309dfbe8321SBarry Smith PetscErrorCode ISLocalToGlobalMappingApplyIS(ISLocalToGlobalMapping mapping,IS is,IS *newis)
31090f02eecSBarry Smith {
3116849ba73SBarry Smith   PetscErrorCode ierr;
31232dcc486SBarry Smith   PetscInt            n,i,*idxin,*idxmap,*idxout,Nmax = mapping->n;
3133a40ed3dSBarry Smith 
3143a40ed3dSBarry Smith   PetscFunctionBegin;
3154482741eSBarry Smith   PetscValidPointer(mapping,1);
3164482741eSBarry Smith   PetscValidHeaderSpecific(is,IS_COOKIE,2);
3174482741eSBarry Smith   PetscValidPointer(newis,3);
31890f02eecSBarry Smith 
3193b9aefa3SBarry Smith   ierr   = ISGetLocalSize(is,&n);CHKERRQ(ierr);
32090f02eecSBarry Smith   ierr   = ISGetIndices(is,&idxin);CHKERRQ(ierr);
32190f02eecSBarry Smith   idxmap = mapping->indices;
32290f02eecSBarry Smith 
32332dcc486SBarry Smith   ierr = PetscMalloc((n+1)*sizeof(PetscInt),&idxout);CHKERRQ(ierr);
32490f02eecSBarry Smith   for (i=0; i<n; i++) {
325590ac198SBarry Smith     if (idxin[i] >= Nmax) SETERRQ3(PETSC_ERR_ARG_OUTOFRANGE,"Local index %d too large %d (max) at %d",idxin[i],Nmax-1,i);
32690f02eecSBarry Smith     idxout[i] = idxmap[idxin[i]];
32790f02eecSBarry Smith   }
3283b9aefa3SBarry Smith   ierr = ISRestoreIndices(is,&idxin);CHKERRQ(ierr);
329029af93fSBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,n,idxout,newis);CHKERRQ(ierr);
330606d414cSSatish Balay   ierr = PetscFree(idxout);CHKERRQ(ierr);
3313a40ed3dSBarry Smith   PetscFunctionReturn(0);
33290f02eecSBarry Smith }
33390f02eecSBarry Smith 
33489d82c54SBarry Smith /*MC
3353acfe500SLois Curfman McInnes    ISLocalToGlobalMappingApply - Takes a list of integers in a local numbering
3363acfe500SLois Curfman McInnes    and converts them to the global numbering.
33790f02eecSBarry Smith 
338b9cd556bSLois Curfman McInnes    Not collective
339b9cd556bSLois Curfman McInnes 
340bb25748dSBarry Smith    Input Parameters:
341b9cd556bSLois Curfman McInnes +  mapping - the local to global mapping context
342bb25748dSBarry Smith .  N - number of integers
343b9cd556bSLois Curfman McInnes -  in - input indices in local numbering
344bb25748dSBarry Smith 
345bb25748dSBarry Smith    Output Parameter:
346bb25748dSBarry Smith .  out - indices in global numbering
347bb25748dSBarry Smith 
3483b9aefa3SBarry Smith    Synopsis:
349216e7ba4SBarry Smith    int ISLocalToGlobalMappingApply(ISLocalToGlobalMapping mapping,int N,int in[],int out[])
3503b9aefa3SBarry Smith 
351b9cd556bSLois Curfman McInnes    Notes:
352b9cd556bSLois Curfman McInnes    The in and out array parameters may be identical.
353d4bb536fSBarry Smith 
354a997ad1aSLois Curfman McInnes    Level: advanced
355a997ad1aSLois Curfman McInnes 
356bb25748dSBarry Smith .seealso: ISLocalToGlobalMappingCreate(),ISLocalToGlobalMappingDestroy(),
3570752156aSBarry Smith           ISLocalToGlobalMappingApplyIS(),AOCreateBasic(),AOApplicationToPetsc(),
358d4bb536fSBarry Smith           AOPetscToApplication(), ISGlobalToLocalMappingApply()
359bb25748dSBarry Smith 
360273d9f13SBarry Smith     Concepts: mapping^local to global
361d4bb536fSBarry Smith 
36289d82c54SBarry Smith M*/
363d4bb536fSBarry Smith 
364d4bb536fSBarry Smith /* -----------------------------------------------------------------------------------------*/
365d4bb536fSBarry Smith 
3664a2ae208SSatish Balay #undef __FUNCT__
3674a2ae208SSatish Balay #define __FUNCT__ "ISGlobalToLocalMappingSetUp_Private"
368d4bb536fSBarry Smith /*
369d4bb536fSBarry Smith     Creates the global fields in the ISLocalToGlobalMapping structure
370d4bb536fSBarry Smith */
3716849ba73SBarry Smith static PetscErrorCode ISGlobalToLocalMappingSetUp_Private(ISLocalToGlobalMapping mapping)
372d4bb536fSBarry Smith {
3736849ba73SBarry Smith   PetscErrorCode ierr;
37432dcc486SBarry Smith   PetscInt            i,*idx = mapping->indices,n = mapping->n,end,start,*globals;
375d4bb536fSBarry Smith 
3763a40ed3dSBarry Smith   PetscFunctionBegin;
377d4bb536fSBarry Smith   end   = 0;
378d4bb536fSBarry Smith   start = 100000000;
379d4bb536fSBarry Smith 
380d4bb536fSBarry Smith   for (i=0; i<n; i++) {
381d4bb536fSBarry Smith     if (idx[i] < 0) continue;
382d4bb536fSBarry Smith     if (idx[i] < start) start = idx[i];
383d4bb536fSBarry Smith     if (idx[i] > end)   end   = idx[i];
384d4bb536fSBarry Smith   }
385d4bb536fSBarry Smith   if (start > end) {start = 0; end = -1;}
386d4bb536fSBarry Smith   mapping->globalstart = start;
387d4bb536fSBarry Smith   mapping->globalend   = end;
388d4bb536fSBarry Smith 
38932dcc486SBarry Smith   ierr             = PetscMalloc((end-start+2)*sizeof(PetscInt),&globals);CHKERRQ(ierr);
390b0a32e0cSBarry Smith   mapping->globals = globals;
391d4bb536fSBarry Smith   for (i=0; i<end-start+1; i++) {
392d4bb536fSBarry Smith     globals[i] = -1;
393d4bb536fSBarry Smith   }
394d4bb536fSBarry Smith   for (i=0; i<n; i++) {
395d4bb536fSBarry Smith     if (idx[i] < 0) continue;
396d4bb536fSBarry Smith     globals[idx[i] - start] = i;
397d4bb536fSBarry Smith   }
398d4bb536fSBarry Smith 
39932dcc486SBarry Smith   PetscLogObjectMemory(mapping,(end-start+1)*sizeof(PetscInt));
4003a40ed3dSBarry Smith   PetscFunctionReturn(0);
401d4bb536fSBarry Smith }
402d4bb536fSBarry Smith 
4034a2ae208SSatish Balay #undef __FUNCT__
4044a2ae208SSatish Balay #define __FUNCT__ "ISGlobalToLocalMappingApply"
405d4bb536fSBarry Smith /*@
406a997ad1aSLois Curfman McInnes     ISGlobalToLocalMappingApply - Provides the local numbering for a list of integers
407a997ad1aSLois Curfman McInnes     specified with a global numbering.
408d4bb536fSBarry Smith 
409b9cd556bSLois Curfman McInnes     Not collective
410b9cd556bSLois Curfman McInnes 
411d4bb536fSBarry Smith     Input Parameters:
412b9cd556bSLois Curfman McInnes +   mapping - mapping between local and global numbering
413d4bb536fSBarry Smith .   type - IS_GTOLM_MASK - replaces global indices with no local value with -1
414d4bb536fSBarry Smith            IS_GTOLM_DROP - drops the indices with no local value from the output list
415d4bb536fSBarry Smith .   n - number of global indices to map
416b9cd556bSLois Curfman McInnes -   idx - global indices to map
417d4bb536fSBarry Smith 
418d4bb536fSBarry Smith     Output Parameters:
419b9cd556bSLois Curfman McInnes +   nout - number of indices in output array (if type == IS_GTOLM_MASK then nout = n)
420b9cd556bSLois Curfman McInnes -   idxout - local index of each global index, one must pass in an array long enough
421e182c471SBarry Smith              to hold all the indices. You can call ISGlobalToLocalMappingApply() with
422e182c471SBarry Smith              idxout == PETSC_NULL to determine the required length (returned in nout)
423e182c471SBarry Smith              and then allocate the required space and call ISGlobalToLocalMappingApply()
424e182c471SBarry Smith              a second time to set the values.
425d4bb536fSBarry Smith 
426b9cd556bSLois Curfman McInnes     Notes:
427b9cd556bSLois Curfman McInnes     Either nout or idxout may be PETSC_NULL. idx and idxout may be identical.
428d4bb536fSBarry Smith 
4290f5bd95cSBarry Smith     This is not scalable in memory usage. Each processor requires O(Nglobal) size
4300f5bd95cSBarry Smith     array to compute these.
4310f5bd95cSBarry Smith 
432a997ad1aSLois Curfman McInnes     Level: advanced
433a997ad1aSLois Curfman McInnes 
434273d9f13SBarry Smith     Concepts: mapping^global to local
435d4bb536fSBarry Smith 
436d4bb536fSBarry Smith .seealso: ISLocalToGlobalMappingApply(), ISLocalToGlobalMappingCreate(),
437d4bb536fSBarry Smith           ISLocalToGlobalMappingDestroy()
438d4bb536fSBarry Smith @*/
439dfbe8321SBarry Smith PetscErrorCode ISGlobalToLocalMappingApply(ISLocalToGlobalMapping mapping,ISGlobalToLocalMappingType type,
44032dcc486SBarry Smith                                   PetscInt n,const PetscInt idx[],PetscInt *nout,PetscInt idxout[])
441d4bb536fSBarry Smith {
44232dcc486SBarry Smith   PetscInt i,*globals,nf = 0,tmp,start,end;
4436849ba73SBarry Smith   PetscErrorCode ierr;
444d4bb536fSBarry Smith 
4453a40ed3dSBarry Smith   PetscFunctionBegin;
446d4bb536fSBarry Smith   if (!mapping->globals) {
447d4bb536fSBarry Smith     ierr = ISGlobalToLocalMappingSetUp_Private(mapping);CHKERRQ(ierr);
448d4bb536fSBarry Smith   }
449d4bb536fSBarry Smith   globals = mapping->globals;
450d4bb536fSBarry Smith   start   = mapping->globalstart;
451d4bb536fSBarry Smith   end     = mapping->globalend;
452d4bb536fSBarry Smith 
453d4bb536fSBarry Smith   if (type == IS_GTOLM_MASK) {
454d4bb536fSBarry Smith     if (idxout) {
455d4bb536fSBarry Smith       for (i=0; i<n; i++) {
456d4bb536fSBarry Smith         if (idx[i] < 0) idxout[i] = idx[i];
457d4bb536fSBarry Smith         else if (idx[i] < start) idxout[i] = -1;
458d4bb536fSBarry Smith         else if (idx[i] > end)   idxout[i] = -1;
459d4bb536fSBarry Smith         else                     idxout[i] = globals[idx[i] - start];
460d4bb536fSBarry Smith       }
461d4bb536fSBarry Smith     }
462d4bb536fSBarry Smith     if (nout) *nout = n;
463d4bb536fSBarry Smith   } else {
464d4bb536fSBarry Smith     if (idxout) {
465d4bb536fSBarry Smith       for (i=0; i<n; i++) {
466d4bb536fSBarry Smith         if (idx[i] < 0) continue;
467d4bb536fSBarry Smith         if (idx[i] < start) continue;
468d4bb536fSBarry Smith         if (idx[i] > end) continue;
469d4bb536fSBarry Smith         tmp = globals[idx[i] - start];
470d4bb536fSBarry Smith         if (tmp < 0) continue;
471d4bb536fSBarry Smith         idxout[nf++] = tmp;
472d4bb536fSBarry Smith       }
473d4bb536fSBarry Smith     } else {
474d4bb536fSBarry Smith       for (i=0; i<n; i++) {
475d4bb536fSBarry Smith         if (idx[i] < 0) continue;
476d4bb536fSBarry Smith         if (idx[i] < start) continue;
477d4bb536fSBarry Smith         if (idx[i] > end) continue;
478d4bb536fSBarry Smith         tmp = globals[idx[i] - start];
479d4bb536fSBarry Smith         if (tmp < 0) continue;
480d4bb536fSBarry Smith         nf++;
481d4bb536fSBarry Smith       }
482d4bb536fSBarry Smith     }
483d4bb536fSBarry Smith     if (nout) *nout = nf;
484d4bb536fSBarry Smith   }
485d4bb536fSBarry Smith 
4863a40ed3dSBarry Smith   PetscFunctionReturn(0);
487d4bb536fSBarry Smith }
48890f02eecSBarry Smith 
4894a2ae208SSatish Balay #undef __FUNCT__
4904a2ae208SSatish Balay #define __FUNCT__ "ISLocalToGlobalMappingGetInfo"
49189d82c54SBarry Smith /*@C
49289d82c54SBarry Smith     ISLocalToGlobalMappingGetInfo - Gets the neighbor information for each processor and
49389d82c54SBarry Smith      each index shared by more than one processor
49489d82c54SBarry Smith 
49589d82c54SBarry Smith     Collective on ISLocalToGlobalMapping
49689d82c54SBarry Smith 
49789d82c54SBarry Smith     Input Parameters:
49889d82c54SBarry Smith .   mapping - the mapping from local to global indexing
49989d82c54SBarry Smith 
50089d82c54SBarry Smith     Output Parameter:
50189d82c54SBarry Smith +   nproc - number of processors that are connected to this one
50289d82c54SBarry Smith .   proc - neighboring processors
50307b52d57SBarry Smith .   numproc - number of indices for each subdomain (processor)
50407b52d57SBarry Smith -   indices - indices of local nodes shared with neighbor (sorted by global numbering)
50589d82c54SBarry Smith 
50689d82c54SBarry Smith     Level: advanced
50789d82c54SBarry Smith 
508273d9f13SBarry Smith     Concepts: mapping^local to global
50989d82c54SBarry Smith 
51007b52d57SBarry Smith .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreateIS(), ISLocalToGlobalMappingCreate(),
51107b52d57SBarry Smith           ISLocalToGlobalMappingRestoreInfo()
51289d82c54SBarry Smith @*/
51332dcc486SBarry Smith PetscErrorCode ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping mapping,PetscInt *nproc,PetscInt *procs[],PetscInt *numprocs[],PetscInt **indices[])
51489d82c54SBarry Smith {
5156849ba73SBarry Smith   PetscErrorCode ierr;
516*97f1f81fSBarry Smith   PetscMPIInt    size,rank,tag1,tag2,tag3,*len,*source,imdex;
51732dcc486SBarry Smith   PetscInt       i,n = mapping->n,Ng,ng,max = 0,*lindices = mapping->indices;
51832dcc486SBarry Smith   PetscInt       *nprocs,*owner,nsends,*sends,j,*starts,nmax,nrecvs,*recvs,proc;
519*97f1f81fSBarry Smith   PetscInt       cnt,scale,*ownedsenders,*nownedsenders,rstart,nowned;
52032dcc486SBarry Smith   PetscInt       node,nownedm,nt,*sends2,nsends2,*starts2,*lens2,*dest,nrecvs2,*starts3,*recvs2,k,*bprocs,*tmp;
52132dcc486SBarry Smith   PetscInt       first_procs,first_numprocs,*first_indices;
52289d82c54SBarry Smith   MPI_Request    *recv_waits,*send_waits;
52330dcb7c9SBarry Smith   MPI_Status     recv_status,*send_status,*recv_statuses;
52489d82c54SBarry Smith   MPI_Comm       comm = mapping->comm;
52507b52d57SBarry Smith   PetscTruth     debug = PETSC_FALSE;
52689d82c54SBarry Smith 
52789d82c54SBarry Smith   PetscFunctionBegin;
52824cf384cSBarry Smith   ierr   = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
52924cf384cSBarry Smith   ierr   = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
53024cf384cSBarry Smith   if (size == 1) {
53124cf384cSBarry Smith     *nproc         = 0;
53224cf384cSBarry Smith     *procs         = PETSC_NULL;
53332dcc486SBarry Smith     ierr           = PetscMalloc(sizeof(PetscInt),numprocs);CHKERRQ(ierr);
5341e2105dcSBarry Smith     (*numprocs)[0] = 0;
53532dcc486SBarry Smith     ierr           = PetscMalloc(sizeof(PetscInt*),indices);CHKERRQ(ierr);
5361e2105dcSBarry Smith     (*indices)[0]  = PETSC_NULL;
53724cf384cSBarry Smith     PetscFunctionReturn(0);
53824cf384cSBarry Smith   }
53924cf384cSBarry Smith 
540b0a32e0cSBarry Smith   ierr = PetscOptionsHasName(PETSC_NULL,"-islocaltoglobalmappinggetinfo_debug",&debug);CHKERRQ(ierr);
54107b52d57SBarry Smith 
5423677ff5aSBarry Smith   /*
5433677ff5aSBarry Smith     Notes on ISLocalToGlobalMappingGetInfo
5443677ff5aSBarry Smith 
5453677ff5aSBarry Smith     globally owned node - the nodes that have been assigned to this processor in global
5463677ff5aSBarry Smith            numbering, just for this routine.
5473677ff5aSBarry Smith 
5483677ff5aSBarry Smith     nontrivial globally owned node - node assigned to this processor that is on a subdomain
5493677ff5aSBarry Smith            boundary (i.e. is has more than one local owner)
5503677ff5aSBarry Smith 
5513677ff5aSBarry Smith     locally owned node - node that exists on this processors subdomain
5523677ff5aSBarry Smith 
5533677ff5aSBarry Smith     nontrivial locally owned node - node that is not in the interior (i.e. has more than one
5543677ff5aSBarry Smith            local subdomain
5553677ff5aSBarry Smith   */
55624cf384cSBarry Smith   ierr = PetscObjectGetNewTag((PetscObject)mapping,&tag1);CHKERRQ(ierr);
55724cf384cSBarry Smith   ierr = PetscObjectGetNewTag((PetscObject)mapping,&tag2);CHKERRQ(ierr);
55824cf384cSBarry Smith   ierr = PetscObjectGetNewTag((PetscObject)mapping,&tag3);CHKERRQ(ierr);
55989d82c54SBarry Smith 
56089d82c54SBarry Smith   for (i=0; i<n; i++) {
56189d82c54SBarry Smith     if (lindices[i] > max) max = lindices[i];
56289d82c54SBarry Smith   }
56332dcc486SBarry Smith   ierr   = MPI_Allreduce(&max,&Ng,1,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
56478058e43SBarry Smith   Ng++;
56589d82c54SBarry Smith   ierr   = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
56689d82c54SBarry Smith   ierr   = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
567bc8ff85bSBarry Smith   scale  = Ng/size + 1;
568a2e34c3dSBarry Smith   ng     = scale; if (rank == size-1) ng = Ng - scale*(size-1); ng = PetscMax(1,ng);
569caba0dd0SBarry Smith   rstart = scale*rank;
57089d82c54SBarry Smith 
57189d82c54SBarry Smith   /* determine ownership ranges of global indices */
57232dcc486SBarry Smith   ierr = PetscMalloc((2*size+1)*sizeof(PetscInt),&nprocs);CHKERRQ(ierr);
57332dcc486SBarry Smith   ierr = PetscMemzero(nprocs,2*size*sizeof(PetscInt));CHKERRQ(ierr);
57489d82c54SBarry Smith 
57589d82c54SBarry Smith   /* determine owners of each local node  */
57632dcc486SBarry Smith   ierr = PetscMalloc((n+1)*sizeof(PetscInt),&owner);CHKERRQ(ierr);
57789d82c54SBarry Smith   for (i=0; i<n; i++) {
5783677ff5aSBarry Smith     proc             = lindices[i]/scale; /* processor that globally owns this index */
57927c402fcSBarry Smith     nprocs[2*proc+1] = 1;                 /* processor globally owns at least one of ours */
5803677ff5aSBarry Smith     owner[i]         = proc;
58127c402fcSBarry Smith     nprocs[2*proc]++;                     /* count of how many that processor globally owns of ours */
58289d82c54SBarry Smith   }
58327c402fcSBarry Smith   nsends = 0; for (i=0; i<size; i++) nsends += nprocs[2*i+1];
584b0a32e0cSBarry Smith   PetscLogInfo(0,"ISLocalToGlobalMappingGetInfo: Number of global owners for my local data %d\n",nsends);
58589d82c54SBarry Smith 
58689d82c54SBarry Smith   /* inform other processors of number of messages and max length*/
58727c402fcSBarry Smith   ierr = PetscMaxSum(comm,nprocs,&nmax,&nrecvs);CHKERRQ(ierr);
588b0a32e0cSBarry Smith   PetscLogInfo(0,"ISLocalToGlobalMappingGetInfo: Number of local owners for my global data %d\n",nrecvs);
58989d82c54SBarry Smith 
59089d82c54SBarry Smith   /* post receives for owned rows */
59132dcc486SBarry Smith   ierr = PetscMalloc((2*nrecvs+1)*(nmax+1)*sizeof(PetscInt),&recvs);CHKERRQ(ierr);
592b0a32e0cSBarry Smith   ierr = PetscMalloc((nrecvs+1)*sizeof(MPI_Request),&recv_waits);CHKERRQ(ierr);
59389d82c54SBarry Smith   for (i=0; i<nrecvs; i++) {
59432dcc486SBarry Smith     ierr = MPI_Irecv(recvs+2*nmax*i,2*nmax,MPIU_INT,MPI_ANY_SOURCE,tag1,comm,recv_waits+i);CHKERRQ(ierr);
59589d82c54SBarry Smith   }
59689d82c54SBarry Smith 
59789d82c54SBarry Smith   /* pack messages containing lists of local nodes to owners */
59832dcc486SBarry Smith   ierr       = PetscMalloc((2*n+1)*sizeof(PetscInt),&sends);CHKERRQ(ierr);
59932dcc486SBarry Smith   ierr       = PetscMalloc((size+1)*sizeof(PetscInt),&starts);CHKERRQ(ierr);
60089d82c54SBarry Smith   starts[0]  = 0;
60127c402fcSBarry Smith   for (i=1; i<size; i++) { starts[i] = starts[i-1] + 2*nprocs[2*i-2];}
60289d82c54SBarry Smith   for (i=0; i<n; i++) {
60389d82c54SBarry Smith     sends[starts[owner[i]]++] = lindices[i];
60430dcb7c9SBarry Smith     sends[starts[owner[i]]++] = i;
60589d82c54SBarry Smith   }
60689d82c54SBarry Smith   ierr = PetscFree(owner);CHKERRQ(ierr);
60789d82c54SBarry Smith   starts[0]  = 0;
60827c402fcSBarry Smith   for (i=1; i<size; i++) { starts[i] = starts[i-1] + 2*nprocs[2*i-2];}
60989d82c54SBarry Smith 
61089d82c54SBarry Smith   /* send the messages */
611b0a32e0cSBarry Smith   ierr = PetscMalloc((nsends+1)*sizeof(MPI_Request),&send_waits);CHKERRQ(ierr);
61232dcc486SBarry Smith   ierr = PetscMalloc((nsends+1)*sizeof(PetscInt),&dest);CHKERRQ(ierr);
61389d82c54SBarry Smith   cnt = 0;
61489d82c54SBarry Smith   for (i=0; i<size; i++) {
61527c402fcSBarry Smith     if (nprocs[2*i]) {
61632dcc486SBarry Smith       ierr      = MPI_Isend(sends+starts[i],2*nprocs[2*i],MPIU_INT,i,tag1,comm,send_waits+cnt);CHKERRQ(ierr);
61730dcb7c9SBarry Smith       dest[cnt] = i;
61889d82c54SBarry Smith       cnt++;
61989d82c54SBarry Smith     }
62089d82c54SBarry Smith   }
62189d82c54SBarry Smith   ierr = PetscFree(starts);CHKERRQ(ierr);
62289d82c54SBarry Smith 
62389d82c54SBarry Smith   /* wait on receives */
624*97f1f81fSBarry Smith   ierr = PetscMalloc((nrecvs+1)*sizeof(PetscMPIInt),&source);CHKERRQ(ierr);
625*97f1f81fSBarry Smith   ierr = PetscMalloc((nrecvs+1)*sizeof(PetscMPIInt),&len);CHKERRQ(ierr);
62689d82c54SBarry Smith   cnt  = nrecvs;
62732dcc486SBarry Smith   ierr = PetscMalloc((ng+1)*sizeof(PetscInt),&nownedsenders);CHKERRQ(ierr);
62832dcc486SBarry Smith   ierr = PetscMemzero(nownedsenders,ng*sizeof(PetscInt));CHKERRQ(ierr);
62989d82c54SBarry Smith   while (cnt) {
63089d82c54SBarry Smith     ierr = MPI_Waitany(nrecvs,recv_waits,&imdex,&recv_status);CHKERRQ(ierr);
63189d82c54SBarry Smith     /* unpack receives into our local space */
63232dcc486SBarry Smith     ierr           = MPI_Get_count(&recv_status,MPIU_INT,&len[imdex]);CHKERRQ(ierr);
63389d82c54SBarry Smith     source[imdex]  = recv_status.MPI_SOURCE;
63430dcb7c9SBarry Smith     len[imdex]     = len[imdex]/2;
635caba0dd0SBarry Smith     /* count how many local owners for each of my global owned indices */
63630dcb7c9SBarry Smith     for (i=0; i<len[imdex]; i++) nownedsenders[recvs[2*imdex*nmax+2*i]-rstart]++;
63789d82c54SBarry Smith     cnt--;
63889d82c54SBarry Smith   }
63989d82c54SBarry Smith   ierr = PetscFree(recv_waits);CHKERRQ(ierr);
64089d82c54SBarry Smith 
64130dcb7c9SBarry Smith   /* count how many globally owned indices are on an edge multiplied by how many processors own them. */
642bc8ff85bSBarry Smith   nowned  = 0;
643bc8ff85bSBarry Smith   nownedm = 0;
644bc8ff85bSBarry Smith   for (i=0; i<ng; i++) {
645bc8ff85bSBarry Smith     if (nownedsenders[i] > 1) {nownedm += nownedsenders[i]; nowned++;}
646bc8ff85bSBarry Smith   }
647bc8ff85bSBarry Smith 
648bc8ff85bSBarry Smith   /* create single array to contain rank of all local owners of each globally owned index */
64932dcc486SBarry Smith   ierr      = PetscMalloc((nownedm+1)*sizeof(PetscInt),&ownedsenders);CHKERRQ(ierr);
65032dcc486SBarry Smith   ierr      = PetscMalloc((ng+1)*sizeof(PetscInt),&starts);CHKERRQ(ierr);
651bc8ff85bSBarry Smith   starts[0] = 0;
652bc8ff85bSBarry Smith   for (i=1; i<ng; i++) {
653bc8ff85bSBarry Smith     if (nownedsenders[i-1] > 1) starts[i] = starts[i-1] + nownedsenders[i-1];
654bc8ff85bSBarry Smith     else starts[i] = starts[i-1];
655bc8ff85bSBarry Smith   }
656bc8ff85bSBarry Smith 
65730dcb7c9SBarry Smith   /* for each nontrival globally owned node list all arriving processors */
658bc8ff85bSBarry Smith   for (i=0; i<nrecvs; i++) {
659bc8ff85bSBarry Smith     for (j=0; j<len[i]; j++) {
66030dcb7c9SBarry Smith       node = recvs[2*i*nmax+2*j]-rstart;
661bc8ff85bSBarry Smith       if (nownedsenders[node] > 1) {
662bc8ff85bSBarry Smith         ownedsenders[starts[node]++] = source[i];
663bc8ff85bSBarry Smith       }
664bc8ff85bSBarry Smith     }
665bc8ff85bSBarry Smith   }
666bc8ff85bSBarry Smith 
66707b52d57SBarry Smith   if (debug) { /* -----------------------------------  */
66830dcb7c9SBarry Smith     starts[0]    = 0;
66930dcb7c9SBarry Smith     for (i=1; i<ng; i++) {
67030dcb7c9SBarry Smith       if (nownedsenders[i-1] > 1) starts[i] = starts[i-1] + nownedsenders[i-1];
67130dcb7c9SBarry Smith       else starts[i] = starts[i-1];
67230dcb7c9SBarry Smith     }
67330dcb7c9SBarry Smith     for (i=0; i<ng; i++) {
67430dcb7c9SBarry Smith       if (nownedsenders[i] > 1) {
67530dcb7c9SBarry Smith         ierr = PetscSynchronizedPrintf(comm,"[%d] global node %d local owner processors: ",rank,i+rstart);CHKERRQ(ierr);
67630dcb7c9SBarry Smith         for (j=0; j<nownedsenders[i]; j++) {
67730dcb7c9SBarry Smith           ierr = PetscSynchronizedPrintf(comm,"%d ",ownedsenders[starts[i]+j]);CHKERRQ(ierr);
67830dcb7c9SBarry Smith         }
67930dcb7c9SBarry Smith         ierr = PetscSynchronizedPrintf(comm,"\n");CHKERRQ(ierr);
68030dcb7c9SBarry Smith       }
68130dcb7c9SBarry Smith     }
68230dcb7c9SBarry Smith     ierr = PetscSynchronizedFlush(comm);CHKERRQ(ierr);
68307b52d57SBarry Smith   }/* -----------------------------------  */
68430dcb7c9SBarry Smith 
6853677ff5aSBarry Smith   /* wait on original sends */
6863a96401aSBarry Smith   if (nsends) {
687b0a32e0cSBarry Smith     ierr = PetscMalloc(nsends*sizeof(MPI_Status),&send_status);CHKERRQ(ierr);
6883a96401aSBarry Smith     ierr = MPI_Waitall(nsends,send_waits,send_status);CHKERRQ(ierr);
6893a96401aSBarry Smith     ierr = PetscFree(send_status);CHKERRQ(ierr);
6903a96401aSBarry Smith   }
69189d82c54SBarry Smith   ierr = PetscFree(send_waits);CHKERRQ(ierr);
6923a96401aSBarry Smith   ierr = PetscFree(sends);CHKERRQ(ierr);
6933677ff5aSBarry Smith   ierr = PetscFree(nprocs);CHKERRQ(ierr);
6943677ff5aSBarry Smith 
6953677ff5aSBarry Smith   /* pack messages to send back to local owners */
69630dcb7c9SBarry Smith   starts[0]    = 0;
69730dcb7c9SBarry Smith   for (i=1; i<ng; i++) {
69830dcb7c9SBarry Smith     if (nownedsenders[i-1] > 1) starts[i] = starts[i-1] + nownedsenders[i-1];
69930dcb7c9SBarry Smith     else starts[i] = starts[i-1];
70030dcb7c9SBarry Smith   }
70130dcb7c9SBarry Smith   nsends2 = nrecvs;
70232dcc486SBarry Smith   ierr    = PetscMalloc((nsends2+1)*sizeof(PetscInt),&nprocs);CHKERRQ(ierr); /* length of each message */
70330dcb7c9SBarry Smith   for (i=0; i<nrecvs; i++) {
70430dcb7c9SBarry Smith     nprocs[i] = 1;
70530dcb7c9SBarry Smith     for (j=0; j<len[i]; j++) {
70630dcb7c9SBarry Smith       node = recvs[2*i*nmax+2*j]-rstart;
70730dcb7c9SBarry Smith       if (nownedsenders[node] > 1) {
70830dcb7c9SBarry Smith         nprocs[i] += 2 + nownedsenders[node];
70930dcb7c9SBarry Smith       }
71030dcb7c9SBarry Smith     }
71130dcb7c9SBarry Smith   }
71230dcb7c9SBarry Smith   nt = 0; for (i=0; i<nsends2; i++) nt += nprocs[i];
71332dcc486SBarry Smith   ierr = PetscMalloc((nt+1)*sizeof(PetscInt),&sends2);CHKERRQ(ierr);
71432dcc486SBarry Smith   ierr = PetscMalloc((nsends2+1)*sizeof(PetscInt),&starts2);CHKERRQ(ierr);
71530dcb7c9SBarry Smith   starts2[0] = 0; for (i=1; i<nsends2; i++) starts2[i] = starts2[i-1] + nprocs[i-1];
71630dcb7c9SBarry Smith   /*
71730dcb7c9SBarry Smith      Each message is 1 + nprocs[i] long, and consists of
71830dcb7c9SBarry Smith        (0) the number of nodes being sent back
71930dcb7c9SBarry Smith        (1) the local node number,
72030dcb7c9SBarry Smith        (2) the number of processors sharing it,
72130dcb7c9SBarry Smith        (3) the processors sharing it
72230dcb7c9SBarry Smith   */
72330dcb7c9SBarry Smith   for (i=0; i<nsends2; i++) {
72430dcb7c9SBarry Smith     cnt = 1;
72530dcb7c9SBarry Smith     sends2[starts2[i]] = 0;
72630dcb7c9SBarry Smith     for (j=0; j<len[i]; j++) {
72730dcb7c9SBarry Smith       node = recvs[2*i*nmax+2*j]-rstart;
72830dcb7c9SBarry Smith       if (nownedsenders[node] > 1) {
72930dcb7c9SBarry Smith         sends2[starts2[i]]++;
73030dcb7c9SBarry Smith         sends2[starts2[i]+cnt++] = recvs[2*i*nmax+2*j+1];
73130dcb7c9SBarry Smith         sends2[starts2[i]+cnt++] = nownedsenders[node];
73232dcc486SBarry Smith         ierr = PetscMemcpy(&sends2[starts2[i]+cnt],&ownedsenders[starts[node]],nownedsenders[node]*sizeof(PetscInt));CHKERRQ(ierr);
73330dcb7c9SBarry Smith         cnt += nownedsenders[node];
73430dcb7c9SBarry Smith       }
73530dcb7c9SBarry Smith     }
73630dcb7c9SBarry Smith   }
73730dcb7c9SBarry Smith 
73830dcb7c9SBarry Smith   /* send the message lengths */
73930dcb7c9SBarry Smith   for (i=0; i<nsends2; i++) {
74032dcc486SBarry Smith     ierr = MPI_Send(&nprocs[i],1,MPIU_INT,source[i],tag2,comm);CHKERRQ(ierr);
74130dcb7c9SBarry Smith   }
74230dcb7c9SBarry Smith 
74330dcb7c9SBarry Smith   /* receive the message lengths */
74430dcb7c9SBarry Smith   nrecvs2 = nsends;
74532dcc486SBarry Smith   ierr = PetscMalloc((nrecvs2+1)*sizeof(PetscInt),&lens2);CHKERRQ(ierr);
74632dcc486SBarry Smith   ierr = PetscMalloc((nrecvs2+1)*sizeof(PetscInt),&starts3);CHKERRQ(ierr);
74730dcb7c9SBarry Smith   nt      = 0;
74830dcb7c9SBarry Smith   for (i=0; i<nrecvs2; i++) {
74932dcc486SBarry Smith     ierr =  MPI_Recv(&lens2[i],1,MPIU_INT,dest[i],tag2,comm,&recv_status);CHKERRQ(ierr);
75030dcb7c9SBarry Smith     nt   += lens2[i];
75130dcb7c9SBarry Smith   }
75230dcb7c9SBarry Smith   starts3[0] = 0;
75330dcb7c9SBarry Smith   for (i=0; i<nrecvs2-1; i++) {
75430dcb7c9SBarry Smith     starts3[i+1] = starts3[i] + lens2[i];
75530dcb7c9SBarry Smith   }
75632dcc486SBarry Smith   ierr = PetscMalloc((nt+1)*sizeof(PetscInt),&recvs2);CHKERRQ(ierr);
757b0a32e0cSBarry Smith   ierr = PetscMalloc((nrecvs2+1)*sizeof(MPI_Request),&recv_waits);CHKERRQ(ierr);
75852b72c4aSBarry Smith   for (i=0; i<nrecvs2; i++) {
75932dcc486SBarry Smith     ierr = MPI_Irecv(recvs2+starts3[i],lens2[i],MPIU_INT,dest[i],tag3,comm,recv_waits+i);CHKERRQ(ierr);
76030dcb7c9SBarry Smith   }
76130dcb7c9SBarry Smith 
76230dcb7c9SBarry Smith   /* send the messages */
763b0a32e0cSBarry Smith   ierr = PetscMalloc((nsends2+1)*sizeof(MPI_Request),&send_waits);CHKERRQ(ierr);
76430dcb7c9SBarry Smith   for (i=0; i<nsends2; i++) {
76532dcc486SBarry Smith     ierr = MPI_Isend(sends2+starts2[i],nprocs[i],MPIU_INT,source[i],tag3,comm,send_waits+i);CHKERRQ(ierr);
76630dcb7c9SBarry Smith   }
76730dcb7c9SBarry Smith 
76830dcb7c9SBarry Smith   /* wait on receives */
769b0a32e0cSBarry Smith   ierr = PetscMalloc((nrecvs2+1)*sizeof(MPI_Status),&recv_statuses);CHKERRQ(ierr);
77030dcb7c9SBarry Smith   ierr = MPI_Waitall(nrecvs2,recv_waits,recv_statuses);CHKERRQ(ierr);
77130dcb7c9SBarry Smith   ierr = PetscFree(recv_statuses);CHKERRQ(ierr);
77230dcb7c9SBarry Smith   ierr = PetscFree(recv_waits);CHKERRQ(ierr);
77330dcb7c9SBarry Smith   ierr = PetscFree(nprocs);CHKERRQ(ierr);
77430dcb7c9SBarry Smith 
77507b52d57SBarry Smith   if (debug) { /* -----------------------------------  */
77630dcb7c9SBarry Smith     cnt = 0;
77730dcb7c9SBarry Smith     for (i=0; i<nrecvs2; i++) {
77830dcb7c9SBarry Smith       nt = recvs2[cnt++];
77930dcb7c9SBarry Smith       for (j=0; j<nt; j++) {
78030dcb7c9SBarry Smith         ierr = PetscSynchronizedPrintf(comm,"[%d] local node %d number of subdomains %d: ",rank,recvs2[cnt],recvs2[cnt+1]);CHKERRQ(ierr);
78130dcb7c9SBarry Smith         for (k=0; k<recvs2[cnt+1]; k++) {
78230dcb7c9SBarry Smith           ierr = PetscSynchronizedPrintf(comm,"%d ",recvs2[cnt+2+k]);CHKERRQ(ierr);
78330dcb7c9SBarry Smith         }
78430dcb7c9SBarry Smith         cnt += 2 + recvs2[cnt+1];
78530dcb7c9SBarry Smith         ierr = PetscSynchronizedPrintf(comm,"\n");CHKERRQ(ierr);
78630dcb7c9SBarry Smith       }
78730dcb7c9SBarry Smith     }
78830dcb7c9SBarry Smith     ierr = PetscSynchronizedFlush(comm);CHKERRQ(ierr);
78907b52d57SBarry Smith   } /* -----------------------------------  */
79030dcb7c9SBarry Smith 
79130dcb7c9SBarry Smith   /* count number subdomains for each local node */
79232dcc486SBarry Smith   ierr = PetscMalloc(size*sizeof(PetscInt),&nprocs);CHKERRQ(ierr);
79332dcc486SBarry Smith   ierr = PetscMemzero(nprocs,size*sizeof(PetscInt));CHKERRQ(ierr);
79430dcb7c9SBarry Smith   cnt  = 0;
79530dcb7c9SBarry Smith   for (i=0; i<nrecvs2; i++) {
79630dcb7c9SBarry Smith     nt = recvs2[cnt++];
79730dcb7c9SBarry Smith     for (j=0; j<nt; j++) {
79830dcb7c9SBarry Smith       for (k=0; k<recvs2[cnt+1]; k++) {
79930dcb7c9SBarry Smith         nprocs[recvs2[cnt+2+k]]++;
80030dcb7c9SBarry Smith       }
80130dcb7c9SBarry Smith       cnt += 2 + recvs2[cnt+1];
80230dcb7c9SBarry Smith     }
80330dcb7c9SBarry Smith   }
80430dcb7c9SBarry Smith   nt = 0; for (i=0; i<size; i++) nt += (nprocs[i] > 0);
80530dcb7c9SBarry Smith   *nproc    = nt;
80632dcc486SBarry Smith   ierr = PetscMalloc((nt+1)*sizeof(PetscInt),procs);CHKERRQ(ierr);
80732dcc486SBarry Smith   ierr = PetscMalloc((nt+1)*sizeof(PetscInt),numprocs);CHKERRQ(ierr);
80832dcc486SBarry Smith   ierr = PetscMalloc((nt+1)*sizeof(PetscInt*),indices);CHKERRQ(ierr);
80932dcc486SBarry Smith   ierr = PetscMalloc(size*sizeof(PetscInt),&bprocs);CHKERRQ(ierr);
81030dcb7c9SBarry Smith   cnt       = 0;
81130dcb7c9SBarry Smith   for (i=0; i<size; i++) {
81230dcb7c9SBarry Smith     if (nprocs[i] > 0) {
81330dcb7c9SBarry Smith       bprocs[i]        = cnt;
81430dcb7c9SBarry Smith       (*procs)[cnt]    = i;
81530dcb7c9SBarry Smith       (*numprocs)[cnt] = nprocs[i];
81632dcc486SBarry Smith       ierr             = PetscMalloc(nprocs[i]*sizeof(PetscInt),&(*indices)[cnt]);CHKERRQ(ierr);
81730dcb7c9SBarry Smith       cnt++;
81830dcb7c9SBarry Smith     }
81930dcb7c9SBarry Smith   }
82030dcb7c9SBarry Smith 
82130dcb7c9SBarry Smith   /* make the list of subdomains for each nontrivial local node */
82232dcc486SBarry Smith   ierr = PetscMemzero(*numprocs,nt*sizeof(PetscInt));CHKERRQ(ierr);
82330dcb7c9SBarry Smith   cnt  = 0;
82430dcb7c9SBarry Smith   for (i=0; i<nrecvs2; i++) {
82530dcb7c9SBarry Smith     nt = recvs2[cnt++];
82630dcb7c9SBarry Smith     for (j=0; j<nt; j++) {
82730dcb7c9SBarry Smith       for (k=0; k<recvs2[cnt+1]; k++) {
82830dcb7c9SBarry Smith         (*indices)[bprocs[recvs2[cnt+2+k]]][(*numprocs)[bprocs[recvs2[cnt+2+k]]]++] = recvs2[cnt];
82930dcb7c9SBarry Smith       }
83030dcb7c9SBarry Smith       cnt += 2 + recvs2[cnt+1];
83130dcb7c9SBarry Smith     }
83230dcb7c9SBarry Smith   }
83330dcb7c9SBarry Smith   ierr = PetscFree(bprocs);CHKERRQ(ierr);
83407b52d57SBarry Smith   ierr = PetscFree(recvs2);CHKERRQ(ierr);
83530dcb7c9SBarry Smith 
83607b52d57SBarry Smith   /* sort the node indexing by their global numbers */
83707b52d57SBarry Smith   nt = *nproc;
83807b52d57SBarry Smith   for (i=0; i<nt; i++) {
83932dcc486SBarry Smith     ierr = PetscMalloc(((*numprocs)[i])*sizeof(PetscInt),&tmp);CHKERRQ(ierr);
84007b52d57SBarry Smith     for (j=0; j<(*numprocs)[i]; j++) {
84107b52d57SBarry Smith       tmp[j] = lindices[(*indices)[i][j]];
84207b52d57SBarry Smith     }
84307b52d57SBarry Smith     ierr = PetscSortIntWithArray((*numprocs)[i],tmp,(*indices)[i]);CHKERRQ(ierr);
84407b52d57SBarry Smith     ierr = PetscFree(tmp);CHKERRQ(ierr);
84507b52d57SBarry Smith   }
84607b52d57SBarry Smith 
84707b52d57SBarry Smith   if (debug) { /* -----------------------------------  */
84830dcb7c9SBarry Smith     nt = *nproc;
84930dcb7c9SBarry Smith     for (i=0; i<nt; i++) {
85030dcb7c9SBarry Smith       ierr = PetscSynchronizedPrintf(comm,"[%d] subdomain %d number of indices %d: ",rank,(*procs)[i],(*numprocs)[i]);CHKERRQ(ierr);
85130dcb7c9SBarry Smith       for (j=0; j<(*numprocs)[i]; j++) {
85230dcb7c9SBarry Smith         ierr = PetscSynchronizedPrintf(comm,"%d ",(*indices)[i][j]);CHKERRQ(ierr);
85330dcb7c9SBarry Smith       }
85430dcb7c9SBarry Smith       ierr = PetscSynchronizedPrintf(comm,"\n");CHKERRQ(ierr);
85530dcb7c9SBarry Smith     }
85630dcb7c9SBarry Smith     ierr = PetscSynchronizedFlush(comm);CHKERRQ(ierr);
85707b52d57SBarry Smith   } /* -----------------------------------  */
85830dcb7c9SBarry Smith 
85930dcb7c9SBarry Smith   /* wait on sends */
86030dcb7c9SBarry Smith   if (nsends2) {
861b0a32e0cSBarry Smith     ierr = PetscMalloc(nsends2*sizeof(MPI_Status),&send_status);CHKERRQ(ierr);
86230dcb7c9SBarry Smith     ierr = MPI_Waitall(nsends2,send_waits,send_status);CHKERRQ(ierr);
86330dcb7c9SBarry Smith     ierr = PetscFree(send_status);CHKERRQ(ierr);
86430dcb7c9SBarry Smith   }
86530dcb7c9SBarry Smith 
86630dcb7c9SBarry Smith   ierr = PetscFree(starts3);CHKERRQ(ierr);
86730dcb7c9SBarry Smith   ierr = PetscFree(dest);CHKERRQ(ierr);
86830dcb7c9SBarry Smith   ierr = PetscFree(send_waits);CHKERRQ(ierr);
8693677ff5aSBarry Smith 
870bc8ff85bSBarry Smith   ierr = PetscFree(nownedsenders);CHKERRQ(ierr);
871bc8ff85bSBarry Smith   ierr = PetscFree(ownedsenders);CHKERRQ(ierr);
872bc8ff85bSBarry Smith   ierr = PetscFree(starts);CHKERRQ(ierr);
87330dcb7c9SBarry Smith   ierr = PetscFree(starts2);CHKERRQ(ierr);
87430dcb7c9SBarry Smith   ierr = PetscFree(lens2);CHKERRQ(ierr);
87589d82c54SBarry Smith 
87689d82c54SBarry Smith   ierr = PetscFree(source);CHKERRQ(ierr);
877*97f1f81fSBarry Smith   ierr = PetscFree(len);CHKERRQ(ierr);
87889d82c54SBarry Smith   ierr = PetscFree(recvs);CHKERRQ(ierr);
8793a96401aSBarry Smith   ierr = PetscFree(nprocs);CHKERRQ(ierr);
88030dcb7c9SBarry Smith   ierr = PetscFree(sends2);CHKERRQ(ierr);
88124cf384cSBarry Smith 
88224cf384cSBarry Smith   /* put the information about myself as the first entry in the list */
88324cf384cSBarry Smith   first_procs    = (*procs)[0];
88424cf384cSBarry Smith   first_numprocs = (*numprocs)[0];
88524cf384cSBarry Smith   first_indices  = (*indices)[0];
88624cf384cSBarry Smith   for (i=0; i<*nproc; i++) {
88724cf384cSBarry Smith     if ((*procs)[i] == rank) {
88824cf384cSBarry Smith       (*procs)[0]    = (*procs)[i];
88924cf384cSBarry Smith       (*numprocs)[0] = (*numprocs)[i];
89024cf384cSBarry Smith       (*indices)[0]  = (*indices)[i];
89124cf384cSBarry Smith       (*procs)[i]    = first_procs;
89224cf384cSBarry Smith       (*numprocs)[i] = first_numprocs;
89324cf384cSBarry Smith       (*indices)[i]  = first_indices;
89424cf384cSBarry Smith       break;
89524cf384cSBarry Smith     }
89624cf384cSBarry Smith   }
89724cf384cSBarry Smith 
89889d82c54SBarry Smith   PetscFunctionReturn(0);
89989d82c54SBarry Smith }
90089d82c54SBarry Smith 
9014a2ae208SSatish Balay #undef __FUNCT__
9024a2ae208SSatish Balay #define __FUNCT__ "ISLocalToGlobalMappingRestoreInfo"
90307b52d57SBarry Smith /*@C
90407b52d57SBarry Smith     ISLocalToGlobalMappingRestoreInfo - Frees the memory allocated by ISLocalToGlobalMappingGetInfo()
90589d82c54SBarry Smith 
90607b52d57SBarry Smith     Collective on ISLocalToGlobalMapping
90707b52d57SBarry Smith 
90807b52d57SBarry Smith     Input Parameters:
90907b52d57SBarry Smith .   mapping - the mapping from local to global indexing
91007b52d57SBarry Smith 
91107b52d57SBarry Smith     Output Parameter:
91207b52d57SBarry Smith +   nproc - number of processors that are connected to this one
91307b52d57SBarry Smith .   proc - neighboring processors
91407b52d57SBarry Smith .   numproc - number of indices for each processor
91507b52d57SBarry Smith -   indices - indices of local nodes shared with neighbor (sorted by global numbering)
91607b52d57SBarry Smith 
91707b52d57SBarry Smith     Level: advanced
91807b52d57SBarry Smith 
91907b52d57SBarry Smith .seealso: ISLocalToGlobalMappingDestroy(), ISLocalToGlobalMappingCreateIS(), ISLocalToGlobalMappingCreate(),
92007b52d57SBarry Smith           ISLocalToGlobalMappingGetInfo()
92107b52d57SBarry Smith @*/
92232dcc486SBarry Smith PetscErrorCode ISLocalToGlobalMappingRestoreInfo(ISLocalToGlobalMapping mapping,PetscInt *nproc,PetscInt *procs[],PetscInt *numprocs[],PetscInt **indices[])
92307b52d57SBarry Smith {
9246849ba73SBarry Smith   PetscErrorCode ierr;
92532dcc486SBarry Smith   PetscInt i;
92607b52d57SBarry Smith 
92707b52d57SBarry Smith   PetscFunctionBegin;
92800ff320aSBarry Smith   if (*procs) {ierr = PetscFree(*procs);CHKERRQ(ierr);}
92900ff320aSBarry Smith   if (*numprocs) {ierr = PetscFree(*numprocs);CHKERRQ(ierr);}
93000ff320aSBarry Smith   if (*indices) {
93100ff320aSBarry Smith     if ((*indices)[0]) {ierr = PetscFree((*indices)[0]);CHKERRQ(ierr);}
93200ff320aSBarry Smith     for (i=1; i<*nproc; i++) {
93324cf384cSBarry Smith       if ((*indices)[i]) {ierr = PetscFree((*indices)[i]);CHKERRQ(ierr);}
93407b52d57SBarry Smith     }
93507b52d57SBarry Smith     ierr = PetscFree(*indices);CHKERRQ(ierr);
93624cf384cSBarry Smith   }
93707b52d57SBarry Smith   PetscFunctionReturn(0);
93807b52d57SBarry Smith }
93989d82c54SBarry Smith 
940bc8ff85bSBarry Smith 
941bc8ff85bSBarry Smith 
942bc8ff85bSBarry Smith 
943bc8ff85bSBarry Smith 
944bc8ff85bSBarry Smith 
945bc8ff85bSBarry Smith 
946bc8ff85bSBarry Smith 
947bc8ff85bSBarry Smith 
948bc8ff85bSBarry Smith 
949bc8ff85bSBarry Smith 
950bc8ff85bSBarry Smith 
951bc8ff85bSBarry Smith 
952bc8ff85bSBarry Smith 
953bc8ff85bSBarry Smith 
954bc8ff85bSBarry Smith 
955bc8ff85bSBarry Smith 
95624cf384cSBarry Smith 
957