xref: /petsc/src/sys/utils/psplit.c (revision b3480c8141127d67566193c1958929f926c40d1c)
1c6db04a5SJed Brown #include <petscsys.h> /*I    "petscsys.h" I*/
2e5c89e4eSSatish Balay 
3e30d2299SSatish Balay /*@
4e5c89e4eSSatish Balay   PetscSplitOwnershipBlock - Given a global (or local) length determines a local
5e5c89e4eSSatish Balay   (or global) length via a simple formula. Splits so each processors local size
6e5c89e4eSSatish Balay   is divisible by the block size.
7e5c89e4eSSatish Balay 
8667f096bSBarry Smith   Collective (if `N` is `PETSC_DECIDE`)
9e5c89e4eSSatish Balay 
10e5c89e4eSSatish Balay   Input Parameters:
11e5c89e4eSSatish Balay + comm - MPI communicator that shares the object being divided
12e5c89e4eSSatish Balay . bs   - block size
13811af0c4SBarry Smith . n    - local length (or `PETSC_DECIDE` to have it set)
14811af0c4SBarry Smith - N    - global length (or `PETSC_DECIDE`)
15e5c89e4eSSatish Balay 
16e5c89e4eSSatish Balay   Level: developer
17e5c89e4eSSatish Balay 
18e5c89e4eSSatish Balay   Notes:
19667f096bSBarry Smith   `n` and `N` cannot be both `PETSC_DECIDE`
20e5c89e4eSSatish Balay 
21667f096bSBarry Smith   If one processor calls this with `N` of `PETSC_DECIDE` then all processors
22e5c89e4eSSatish Balay   must, otherwise the program will hang.
23e5c89e4eSSatish Balay 
24811af0c4SBarry Smith .seealso: `PetscSplitOwnership()`, `PetscSplitOwnershipEqual()`
25e5c89e4eSSatish Balay @*/
26d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSplitOwnershipBlock(MPI_Comm comm, PetscInt bs, PetscInt *n, PetscInt *N)
27d71ae5a4SJacob Faibussowitsch {
28e5c89e4eSSatish Balay   PetscMPIInt size, rank;
29e5c89e4eSSatish Balay 
30e5c89e4eSSatish Balay   PetscFunctionBegin;
31cc73adaaSBarry Smith   PetscCheck(*N != PETSC_DECIDE || *n != PETSC_DECIDE, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Both n and N cannot be PETSC_DECIDE");
32e5c89e4eSSatish Balay 
33e5c89e4eSSatish Balay   if (*N == PETSC_DECIDE) {
3408401ef6SPierre Jolivet     PetscCheck(*n % bs == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "local size %" PetscInt_FMT " not divisible by block size %" PetscInt_FMT, *n, bs);
351c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(n, N, 1, MPIU_INT, MPI_SUM, comm));
36e5c89e4eSSatish Balay   } else if (*n == PETSC_DECIDE) {
37e5c89e4eSSatish Balay     PetscInt Nbs = *N / bs;
389566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
399566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
40e5c89e4eSSatish Balay     *n = bs * (Nbs / size + ((Nbs % size) > rank));
41e5c89e4eSSatish Balay   }
423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43e5c89e4eSSatish Balay }
44e5c89e4eSSatish Balay 
45e30d2299SSatish Balay /*@
46e5c89e4eSSatish Balay   PetscSplitOwnership - Given a global (or local) length determines a local
47e5c89e4eSSatish Balay   (or global) length via a simple formula
48e5c89e4eSSatish Balay 
49*b3480c81SBarry Smith   Collective (if `n` or `N` is `PETSC_DECIDE` or `PETSC_DETERMINE`)
50e5c89e4eSSatish Balay 
51e5c89e4eSSatish Balay   Input Parameters:
52e5c89e4eSSatish Balay + comm - MPI communicator that shares the object being divided
53811af0c4SBarry Smith . n    - local length (or `PETSC_DECIDE` to have it set)
54*b3480c81SBarry Smith - N    - global length (or `PETSC_DETERMINE` to have it set)
55e5c89e4eSSatish Balay 
56e5c89e4eSSatish Balay   Level: developer
57e5c89e4eSSatish Balay 
58e5c89e4eSSatish Balay   Notes:
59*b3480c81SBarry Smith   `n` and `N` cannot be both `PETSC_DECIDE` and `PETSC_DETERMINE`
60e5c89e4eSSatish Balay 
61*b3480c81SBarry Smith   If one processor calls this with `n` of `PETSC_DECIDE` (or with `N` `PETSC_DETERMINE`) then all processors
620e9ea286SStefano Zampini   must. Otherwise, an error is thrown in debug mode while the program will hang
630e9ea286SStefano Zampini   in optimized (i.e. configured --with-debugging=0) mode.
64e5c89e4eSSatish Balay 
65*b3480c81SBarry Smith .seealso: `PetscSplitOwnershipBlock()`, `PetscSplitOwnershipEqual()`, `PETSC_DECIDE`, `PETSC_DETERMINE`
66e5c89e4eSSatish Balay @*/
67d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSplitOwnership(MPI_Comm comm, PetscInt *n, PetscInt *N)
68d71ae5a4SJacob Faibussowitsch {
69e5c89e4eSSatish Balay   PetscMPIInt size, rank;
70e5c89e4eSSatish Balay 
71e5c89e4eSSatish Balay   PetscFunctionBegin;
7200045ab3SPierre Jolivet   PetscCheck(*N != PETSC_DECIDE || *n != PETSC_DECIDE, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Both n and N cannot be PETSC_DECIDE, likely a call to VecSetSizes() or MatSetSizes() is wrong. See https://petsc.org/release/faq/#split-ownership");
7376bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
740e9ea286SStefano Zampini     PetscMPIInt l[2], g[2];
750e9ea286SStefano Zampini     l[0] = (*n == PETSC_DECIDE) ? 1 : 0;
760e9ea286SStefano Zampini     l[1] = (*N == PETSC_DECIDE) ? 1 : 0;
779566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
781c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(l, g, 2, MPI_INT, MPI_SUM, comm));
79cc73adaaSBarry Smith     PetscCheck(!g[0] || g[0] == size, comm, PETSC_ERR_ARG_INCOMP, "All processes must supply PETSC_DECIDE for local size");
80cc73adaaSBarry Smith     PetscCheck(!g[1] || g[1] == size, comm, PETSC_ERR_ARG_INCOMP, "All processes must supply PETSC_DECIDE for global size");
810e9ea286SStefano Zampini   }
82e5c89e4eSSatish Balay 
83e5c89e4eSSatish Balay   if (*N == PETSC_DECIDE) {
8481863419SJunchao Zhang     PetscInt64 m = *n, M;
851c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&m, &M, 1, MPIU_INT64, MPI_SUM, comm));
8608401ef6SPierre Jolivet     PetscCheck(M <= PETSC_MAX_INT, comm, PETSC_ERR_INT_OVERFLOW, "Global size overflow %" PetscInt64_FMT ". You may consider ./configure PETSc with --with-64-bit-indices for the case you are running", M);
87f7d195e4SLawrence Mitchell     *N = (PetscInt)M;
88e5c89e4eSSatish Balay   } else if (*n == PETSC_DECIDE) {
899566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
909566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
91e5c89e4eSSatish Balay     *n = *N / size + ((*N % size) > rank);
9276bd3646SJed Brown   } else if (PetscDefined(USE_DEBUG)) {
93e5c89e4eSSatish Balay     PetscInt tmp;
941c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(n, &tmp, 1, MPIU_INT, MPI_SUM, comm));
9500045ab3SPierre Jolivet     PetscCheck(tmp == *N, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Sum of local lengths %" PetscInt_FMT " does not equal global length %" PetscInt_FMT ", my local length %" PetscInt_FMT ", likely a call to VecSetSizes() or MatSetSizes() is wrong. See https://petsc.org/release/faq/#split-ownership", tmp, *N, *n);
96e5c89e4eSSatish Balay   }
973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98e5c89e4eSSatish Balay }
99e5c89e4eSSatish Balay 
100d24d4204SJose E. Roman /*@
101d24d4204SJose E. Roman   PetscSplitOwnershipEqual - Given a global (or local) length determines a local
102d24d4204SJose E. Roman   (or global) length via a simple formula, trying to have all local lengths equal
103d24d4204SJose E. Roman 
104667f096bSBarry Smith   Collective (if `n` or `N` is `PETSC_DECIDE`)
105d24d4204SJose E. Roman 
106d24d4204SJose E. Roman   Input Parameters:
107d24d4204SJose E. Roman + comm - MPI communicator that shares the object being divided
108811af0c4SBarry Smith . n    - local length (or `PETSC_DECIDE` to have it set)
109811af0c4SBarry Smith - N    - global length (or `PETSC_DECIDE`)
110d24d4204SJose E. Roman 
111d24d4204SJose E. Roman   Level: developer
112d24d4204SJose E. Roman 
113d24d4204SJose E. Roman   Notes:
114811af0c4SBarry Smith   This is intended to be used with `MATSCALAPACK`, where the local size must
115d24d4204SJose E. Roman   be equal in all processes (except possibly the last one). For instance,
116667f096bSBarry Smith   the local sizes when splitting `N`=50 with 6 processes are 9,9,9,9,9,5
117d24d4204SJose E. Roman 
118811af0c4SBarry Smith   n and N cannot be both `PETSC_DECIDE`
119d24d4204SJose E. Roman 
120667f096bSBarry Smith   If one processor calls this with `n` or `N` of `PETSC_DECIDE` then all processors
121d24d4204SJose E. Roman   must. Otherwise, an error is thrown in debug mode while the program will hang
122d24d4204SJose E. Roman   in optimized (i.e. configured --with-debugging=0) mode.
123d24d4204SJose E. Roman 
124db781477SPatrick Sanan .seealso: `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`
125d24d4204SJose E. Roman @*/
126d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSplitOwnershipEqual(MPI_Comm comm, PetscInt *n, PetscInt *N)
127d71ae5a4SJacob Faibussowitsch {
128d24d4204SJose E. Roman   PetscMPIInt size, rank;
129d24d4204SJose E. Roman 
130d24d4204SJose E. Roman   PetscFunctionBegin;
131cc73adaaSBarry Smith   PetscCheck(*N != PETSC_DECIDE || *n != PETSC_DECIDE, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Both n and N cannot be PETSC_DECIDE");
132d24d4204SJose E. Roman   if (PetscDefined(USE_DEBUG)) {
133d24d4204SJose E. Roman     PetscMPIInt l[2], g[2];
134d24d4204SJose E. Roman     l[0] = (*n == PETSC_DECIDE) ? 1 : 0;
135d24d4204SJose E. Roman     l[1] = (*N == PETSC_DECIDE) ? 1 : 0;
1369566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
1371c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(l, g, 2, MPI_INT, MPI_SUM, comm));
138cc73adaaSBarry Smith     PetscCheck(!g[0] || g[0] == size, comm, PETSC_ERR_ARG_INCOMP, "All processes must supply PETSC_DECIDE for local size");
139cc73adaaSBarry Smith     PetscCheck(!g[1] || g[1] == size, comm, PETSC_ERR_ARG_INCOMP, "All processes must supply PETSC_DECIDE for global size");
140d24d4204SJose E. Roman   }
141d24d4204SJose E. Roman 
142d24d4204SJose E. Roman   if (*N == PETSC_DECIDE) {
143d24d4204SJose E. Roman     PetscInt64 m = *n, M;
1441c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&m, &M, 1, MPIU_INT64, MPI_SUM, comm));
14508401ef6SPierre Jolivet     PetscCheck(M <= PETSC_MAX_INT, comm, PETSC_ERR_INT_OVERFLOW, "Global size overflow %" PetscInt64_FMT ". You may consider ./configure PETSc with --with-64-bit-indices for the case you are running", M);
146f7d195e4SLawrence Mitchell     *N = (PetscInt)M;
147d24d4204SJose E. Roman   } else if (*n == PETSC_DECIDE) {
1489566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
1499566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
150d24d4204SJose E. Roman     *n = *N / size;
151d24d4204SJose E. Roman     if (*N % size) {
152d24d4204SJose E. Roman       if ((rank + 1) * (*n + 1) <= *N) *n = *n + 1;
153d24d4204SJose E. Roman       else if (rank * (*n + 1) <= *N) *n = *N - rank * (*n + 1);
154d24d4204SJose E. Roman       else *n = 0;
155d24d4204SJose E. Roman     }
156d24d4204SJose E. Roman   } else if (PetscDefined(USE_DEBUG)) {
157d24d4204SJose E. Roman     PetscInt tmp;
1581c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(n, &tmp, 1, MPIU_INT, MPI_SUM, comm));
15908401ef6SPierre Jolivet     PetscCheck(tmp == *N, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Sum of local lengths %" PetscInt_FMT " does not equal global length %" PetscInt_FMT ", my local length %" PetscInt_FMT, tmp, *N, *n);
160d24d4204SJose E. Roman   }
1613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
162d24d4204SJose E. Roman }
163