xref: /petsc/src/sys/utils/mpiu.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
1e5c89e4eSSatish Balay 
2c6db04a5SJed Brown #include <petscsys.h> /*I  "petscsys.h"  I*/
38ae1f613SSatish Balay #include <petsc/private/petscimpl.h>
4e5c89e4eSSatish Balay /*
5e5c89e4eSSatish Balay     Note that tag of 0 is ok because comm is a private communicator
6e5c89e4eSSatish Balay   generated below just for these routines.
7e5c89e4eSSatish Balay */
8e5c89e4eSSatish Balay 
99371c9d4SSatish Balay PETSC_INTERN PetscErrorCode PetscSequentialPhaseBegin_Private(MPI_Comm comm, int ng) {
10e5c89e4eSSatish Balay   PetscMPIInt rank, size, tag = 0;
11e5c89e4eSSatish Balay   MPI_Status  status;
12e5c89e4eSSatish Balay 
13e5c89e4eSSatish Balay   PetscFunctionBegin;
149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
15e5c89e4eSSatish Balay   if (size == 1) PetscFunctionReturn(0);
169566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
17*48a46eb9SPierre Jolivet   if (rank) PetscCallMPI(MPI_Recv(NULL, 0, MPI_INT, rank - 1, tag, comm, &status));
18e5c89e4eSSatish Balay   /* Send to the next process in the group unless we are the last process */
19*48a46eb9SPierre Jolivet   if ((rank % ng) < ng - 1 && rank != size - 1) PetscCallMPI(MPI_Send(NULL, 0, MPI_INT, rank + 1, tag, comm));
20e5c89e4eSSatish Balay   PetscFunctionReturn(0);
21e5c89e4eSSatish Balay }
22e5c89e4eSSatish Balay 
239371c9d4SSatish Balay PETSC_INTERN PetscErrorCode PetscSequentialPhaseEnd_Private(MPI_Comm comm, int ng) {
24e5c89e4eSSatish Balay   PetscMPIInt rank, size, tag = 0;
25e5c89e4eSSatish Balay   MPI_Status  status;
26e5c89e4eSSatish Balay 
27e5c89e4eSSatish Balay   PetscFunctionBegin;
289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
299566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
30e5c89e4eSSatish Balay   if (size == 1) PetscFunctionReturn(0);
31e5c89e4eSSatish Balay 
32e5c89e4eSSatish Balay   /* Send to the first process in the next group */
33*48a46eb9SPierre Jolivet   if ((rank % ng) == ng - 1 || rank == size - 1) PetscCallMPI(MPI_Send(NULL, 0, MPI_INT, (rank + 1) % size, tag, comm));
34*48a46eb9SPierre Jolivet   if (rank == 0) PetscCallMPI(MPI_Recv(NULL, 0, MPI_INT, size - 1, tag, comm, &status));
35e5c89e4eSSatish Balay   PetscFunctionReturn(0);
36e5c89e4eSSatish Balay }
37e5c89e4eSSatish Balay 
38e5c89e4eSSatish Balay /* ---------------------------------------------------------------------*/
39e5c89e4eSSatish Balay /*
40e5c89e4eSSatish Balay     The variable Petsc_Seq_keyval is used to indicate an MPI attribute that
41e5c89e4eSSatish Balay   is attached to a communicator that manages the sequential phase code below.
42e5c89e4eSSatish Balay */
432fe4ef4aSBarry Smith PetscMPIInt Petsc_Seq_keyval = MPI_KEYVAL_INVALID;
44e5c89e4eSSatish Balay 
45e30d2299SSatish Balay /*@
46e5c89e4eSSatish Balay    PetscSequentialPhaseBegin - Begins a sequential section of code.
47e5c89e4eSSatish Balay 
48d083f849SBarry Smith    Collective
49e5c89e4eSSatish Balay 
50e5c89e4eSSatish Balay    Input Parameters:
51e5c89e4eSSatish Balay +  comm - Communicator to sequentialize.
52e5c89e4eSSatish Balay -  ng   - Number in processor group.  This many processes are allowed to execute
53e5c89e4eSSatish Balay    at the same time (usually 1)
54e5c89e4eSSatish Balay 
55e5c89e4eSSatish Balay    Level: intermediate
56e5c89e4eSSatish Balay 
57e5c89e4eSSatish Balay    Notes:
58e5c89e4eSSatish Balay    PetscSequentialPhaseBegin() and PetscSequentialPhaseEnd() provide a
59e5c89e4eSSatish Balay    way to force a section of code to be executed by the processes in
60e5c89e4eSSatish Balay    rank order.  Typically, this is done with
61e5c89e4eSSatish Balay .vb
62e5c89e4eSSatish Balay       PetscSequentialPhaseBegin(comm, 1);
63e5c89e4eSSatish Balay       <code to be executed sequentially>
64e5c89e4eSSatish Balay       PetscSequentialPhaseEnd(comm, 1);
65e5c89e4eSSatish Balay .ve
66e5c89e4eSSatish Balay 
67e5c89e4eSSatish Balay    Often, the sequential code contains output statements (e.g., printf) to
68e5c89e4eSSatish Balay    be executed.  Note that you may need to flush the I/O buffers before
69e5c89e4eSSatish Balay    calling PetscSequentialPhaseEnd().  Also, note that some systems do
70e5c89e4eSSatish Balay    not propagate I/O in any order to the controling terminal (in other words,
71e5c89e4eSSatish Balay    even if you flush the output, you may not get the data in the order
72e5c89e4eSSatish Balay    that you want).
73e5c89e4eSSatish Balay 
74db781477SPatrick Sanan .seealso: `PetscSequentialPhaseEnd()`
75e5c89e4eSSatish Balay 
76e5c89e4eSSatish Balay @*/
779371c9d4SSatish Balay PetscErrorCode PetscSequentialPhaseBegin(MPI_Comm comm, int ng) {
78e5c89e4eSSatish Balay   PetscMPIInt size;
79e5c89e4eSSatish Balay   MPI_Comm    local_comm, *addr_local_comm;
80e5c89e4eSSatish Balay 
81e5c89e4eSSatish Balay   PetscFunctionBegin;
829566063dSJacob Faibussowitsch   PetscCall(PetscSysInitializePackage());
839566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
84e5c89e4eSSatish Balay   if (size == 1) PetscFunctionReturn(0);
85e5c89e4eSSatish Balay 
86e5c89e4eSSatish Balay   /* Get the private communicator for the sequential operations */
87*48a46eb9SPierre Jolivet   if (Petsc_Seq_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Seq_keyval, NULL));
88e5c89e4eSSatish Balay 
899566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_dup(comm, &local_comm));
909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &addr_local_comm));
91a297a907SKarl Rupp 
92e5c89e4eSSatish Balay   *addr_local_comm = local_comm;
93a297a907SKarl Rupp 
949566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Seq_keyval, (void *)addr_local_comm));
959566063dSJacob Faibussowitsch   PetscCall(PetscSequentialPhaseBegin_Private(local_comm, ng));
96e5c89e4eSSatish Balay   PetscFunctionReturn(0);
97e5c89e4eSSatish Balay }
98e5c89e4eSSatish Balay 
99e30d2299SSatish Balay /*@
100e5c89e4eSSatish Balay    PetscSequentialPhaseEnd - Ends a sequential section of code.
101e5c89e4eSSatish Balay 
102d083f849SBarry Smith    Collective
103e5c89e4eSSatish Balay 
104e5c89e4eSSatish Balay    Input Parameters:
105e5c89e4eSSatish Balay +  comm - Communicator to sequentialize.
106e5c89e4eSSatish Balay -  ng   - Number in processor group.  This many processes are allowed to execute
107e5c89e4eSSatish Balay    at the same time (usually 1)
108e5c89e4eSSatish Balay 
109e5c89e4eSSatish Balay    Level: intermediate
110e5c89e4eSSatish Balay 
111e5c89e4eSSatish Balay    Notes:
112e5c89e4eSSatish Balay    See PetscSequentialPhaseBegin() for more details.
113e5c89e4eSSatish Balay 
114db781477SPatrick Sanan .seealso: `PetscSequentialPhaseBegin()`
115e5c89e4eSSatish Balay 
116e5c89e4eSSatish Balay @*/
1179371c9d4SSatish Balay PetscErrorCode PetscSequentialPhaseEnd(MPI_Comm comm, int ng) {
118e5c89e4eSSatish Balay   PetscMPIInt size, flag;
119e5c89e4eSSatish Balay   MPI_Comm    local_comm, *addr_local_comm;
120e5c89e4eSSatish Balay 
121e5c89e4eSSatish Balay   PetscFunctionBegin;
1229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
123e5c89e4eSSatish Balay   if (size == 1) PetscFunctionReturn(0);
124e5c89e4eSSatish Balay 
1259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Seq_keyval, (void **)&addr_local_comm, &flag));
12628b400f6SJacob Faibussowitsch   PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Wrong MPI communicator; must pass in one used with PetscSequentialPhaseBegin()");
127e5c89e4eSSatish Balay   local_comm = *addr_local_comm;
128e5c89e4eSSatish Balay 
1299566063dSJacob Faibussowitsch   PetscCall(PetscSequentialPhaseEnd_Private(local_comm, ng));
130e5c89e4eSSatish Balay 
1319566063dSJacob Faibussowitsch   PetscCall(PetscFree(addr_local_comm));
1329566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_free(&local_comm));
1339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_delete_attr(comm, Petsc_Seq_keyval));
134e5c89e4eSSatish Balay   PetscFunctionReturn(0);
135e5c89e4eSSatish Balay }
1366ba4152bSMatthew G. Knepley 
1376ba4152bSMatthew G. Knepley /*@C
1386ba4152bSMatthew G. Knepley   PetscGlobalMinMaxInt - Get the global min/max from local min/max input
1396ba4152bSMatthew G. Knepley 
140d083f849SBarry Smith   Collective
1416ba4152bSMatthew G. Knepley 
1426ba4152bSMatthew G. Knepley   Input Parameter:
1436ba4152bSMatthew G. Knepley . minMaxVal - An array with the local min and max
1446ba4152bSMatthew G. Knepley 
1456ba4152bSMatthew G. Knepley   Output Parameter:
1466ba4152bSMatthew G. Knepley . minMaxValGlobal - An array with the global min and max
1476ba4152bSMatthew G. Knepley 
1486ba4152bSMatthew G. Knepley   Level: beginner
1496ba4152bSMatthew G. Knepley 
150db781477SPatrick Sanan .seealso: `PetscSplitOwnership()`
1516ba4152bSMatthew G. Knepley @*/
1529371c9d4SSatish Balay PetscErrorCode PetscGlobalMinMaxInt(MPI_Comm comm, const PetscInt minMaxVal[2], PetscInt minMaxValGlobal[2]) {
15358b5cd2aSSatish Balay   PetscInt sendbuf[3], recvbuf[3];
1546ba4152bSMatthew G. Knepley 
1556ba4152bSMatthew G. Knepley   PetscFunctionBegin;
15658b5cd2aSSatish Balay   sendbuf[0] = -minMaxVal[0]; /* Note that -PETSC_MIN_INT = PETSC_MIN_INT */
15758b5cd2aSSatish Balay   sendbuf[1] = minMaxVal[1];
15858b5cd2aSSatish Balay   sendbuf[2] = (minMaxVal[0] == PETSC_MIN_INT) ? 1 : 0; /* Are there PETSC_MIN_INT in minMaxVal[0]? */
1599566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(sendbuf, recvbuf, 3, MPIU_INT, MPI_MAX, comm));
16058b5cd2aSSatish Balay   minMaxValGlobal[0] = recvbuf[2] ? PETSC_MIN_INT : -recvbuf[0];
16158b5cd2aSSatish Balay   minMaxValGlobal[1] = recvbuf[1];
1626ba4152bSMatthew G. Knepley   PetscFunctionReturn(0);
1636ba4152bSMatthew G. Knepley }
1646ba4152bSMatthew G. Knepley 
1656ba4152bSMatthew G. Knepley /*@C
1666ba4152bSMatthew G. Knepley   PetscGlobalMinMaxReal - Get the global min/max from local min/max input
1676ba4152bSMatthew G. Knepley 
168d083f849SBarry Smith   Collective
1696ba4152bSMatthew G. Knepley 
1706ba4152bSMatthew G. Knepley   Input Parameter:
1716ba4152bSMatthew G. Knepley . minMaxVal - An array with the local min and max
1726ba4152bSMatthew G. Knepley 
1736ba4152bSMatthew G. Knepley   Output Parameter:
1746ba4152bSMatthew G. Knepley . minMaxValGlobal - An array with the global min and max
1756ba4152bSMatthew G. Knepley 
1766ba4152bSMatthew G. Knepley   Level: beginner
1776ba4152bSMatthew G. Knepley 
178db781477SPatrick Sanan .seealso: `PetscSplitOwnership()`
1796ba4152bSMatthew G. Knepley @*/
1809371c9d4SSatish Balay PetscErrorCode PetscGlobalMinMaxReal(MPI_Comm comm, const PetscReal minMaxVal[2], PetscReal minMaxValGlobal[2]) {
18158b5cd2aSSatish Balay   PetscReal sendbuf[2];
1826ba4152bSMatthew G. Knepley 
1836ba4152bSMatthew G. Knepley   PetscFunctionBegin;
18458b5cd2aSSatish Balay   sendbuf[0] = -minMaxVal[0];
18558b5cd2aSSatish Balay   sendbuf[1] = minMaxVal[1];
1861c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(sendbuf, minMaxValGlobal, 2, MPIU_REAL, MPIU_MAX, comm));
18758b5cd2aSSatish Balay   minMaxValGlobal[0] = -minMaxValGlobal[0];
1886ba4152bSMatthew G. Knepley   PetscFunctionReturn(0);
1896ba4152bSMatthew G. Knepley }
190