#include /*I "petscsys.h" I*/ #include /* Note that tag of 0 is ok because comm is a private communicator generated below just for these routines. */ PETSC_INTERN PetscErrorCode PetscSequentialPhaseBegin_Private(MPI_Comm comm, int ng) { PetscMPIInt rank, size, tag = 0; MPI_Status status; PetscFunctionBegin; PetscCallMPI(MPI_Comm_size(comm, &size)); if (size == 1) PetscFunctionReturn(PETSC_SUCCESS); PetscCallMPI(MPI_Comm_rank(comm, &rank)); if (rank) PetscCallMPI(MPI_Recv(NULL, 0, MPI_INT, rank - 1, tag, comm, &status)); /* Send to the next process in the group unless we are the last process */ if ((rank % ng) < ng - 1 && rank != size - 1) PetscCallMPI(MPI_Send(NULL, 0, MPI_INT, rank + 1, tag, comm)); PetscFunctionReturn(PETSC_SUCCESS); } PETSC_INTERN PetscErrorCode PetscSequentialPhaseEnd_Private(MPI_Comm comm, int ng) { PetscMPIInt rank, size, tag = 0; MPI_Status status; PetscFunctionBegin; PetscCallMPI(MPI_Comm_rank(comm, &rank)); PetscCallMPI(MPI_Comm_size(comm, &size)); if (size == 1) PetscFunctionReturn(PETSC_SUCCESS); /* Send to the first process in the next group */ if ((rank % ng) == ng - 1 || rank == size - 1) PetscCallMPI(MPI_Send(NULL, 0, MPI_INT, (rank + 1) % size, tag, comm)); if (rank == 0) PetscCallMPI(MPI_Recv(NULL, 0, MPI_INT, size - 1, tag, comm, &status)); PetscFunctionReturn(PETSC_SUCCESS); } /* The variable Petsc_Seq_keyval is used to indicate an MPI attribute that is attached to a communicator that manages the sequential phase code below. */ PetscMPIInt Petsc_Seq_keyval = MPI_KEYVAL_INVALID; /*@ PetscSequentialPhaseBegin - Begins a sequential section of code. Collective Input Parameters: + comm - Communicator to sequentialize over - ng - Number in processor group. This many processes are allowed to execute at the same time (usually 1) Level: intermediate Notes: `PetscSequentialPhaseBegin()` and `PetscSequentialPhaseEnd()` provide a way to force a section of code to be executed by the processes in rank order. Typically, this is done with .vb PetscSequentialPhaseBegin(comm, 1); PetscSequentialPhaseEnd(comm, 1); .ve You should use `PetscSynchronizedPrintf()` to ensure output between MPI ranks is properly order and not these routines. .seealso: `PetscSequentialPhaseEnd()`, `PetscSynchronizedPrintf()` @*/ PetscErrorCode PetscSequentialPhaseBegin(MPI_Comm comm, int ng) { PetscMPIInt size; MPI_Comm local_comm, *addr_local_comm; PetscFunctionBegin; PetscCall(PetscSysInitializePackage()); PetscCallMPI(MPI_Comm_size(comm, &size)); if (size == 1) PetscFunctionReturn(PETSC_SUCCESS); /* Get the private communicator for the sequential operations */ 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)); PetscCallMPI(MPI_Comm_dup(comm, &local_comm)); PetscCall(PetscMalloc1(1, &addr_local_comm)); *addr_local_comm = local_comm; PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Seq_keyval, (void *)addr_local_comm)); PetscCall(PetscSequentialPhaseBegin_Private(local_comm, ng)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ PetscSequentialPhaseEnd - Ends a sequential section of code. Collective Input Parameters: + comm - Communicator to sequentialize. - ng - Number in processor group. This many processes are allowed to execute at the same time (usually 1) Level: intermediate Note: See `PetscSequentialPhaseBegin()` for more details. .seealso: `PetscSequentialPhaseBegin()` @*/ PetscErrorCode PetscSequentialPhaseEnd(MPI_Comm comm, int ng) { PetscMPIInt size, iflg; MPI_Comm local_comm, *addr_local_comm; PetscFunctionBegin; PetscCallMPI(MPI_Comm_size(comm, &size)); if (size == 1) PetscFunctionReturn(PETSC_SUCCESS); PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Seq_keyval, (void **)&addr_local_comm, &iflg)); PetscCheck(iflg, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Wrong MPI communicator; must pass in one used with PetscSequentialPhaseBegin()"); local_comm = *addr_local_comm; PetscCall(PetscSequentialPhaseEnd_Private(local_comm, ng)); PetscCall(PetscFree(addr_local_comm)); PetscCallMPI(MPI_Comm_free(&local_comm)); PetscCallMPI(MPI_Comm_delete_attr(comm, Petsc_Seq_keyval)); PetscFunctionReturn(PETSC_SUCCESS); } /*@ PetscGlobalMinMaxInt - Get the global min/max from local min/max input Collective Input Parameters: + comm - The MPI communicator to reduce with - minMaxVal - An array with the local min and max Output Parameter: . minMaxValGlobal - An array with the global min and max Level: beginner .seealso: `PetscSplitOwnership()`, `PetscGlobalMinMaxReal()` @*/ PetscErrorCode PetscGlobalMinMaxInt(MPI_Comm comm, const PetscInt minMaxVal[2], PetscInt minMaxValGlobal[2]) { PetscInt sendbuf[3], recvbuf[3]; PetscBool hasminint = (PetscBool)(minMaxVal[0] == PETSC_MIN_INT); PetscFunctionBegin; sendbuf[0] = hasminint ? PETSC_MIN_INT : -minMaxVal[0]; /* Note that -PETSC_INT_MIN = PETSC_INT_MIN: ternary to suppress sanitizer warnings */ sendbuf[1] = minMaxVal[1]; sendbuf[2] = hasminint ? 1 : 0; /* Are there PETSC_INT_MIN in minMaxVal[0]? */ PetscCallMPI(MPIU_Allreduce(sendbuf, recvbuf, 3, MPIU_INT, MPI_MAX, comm)); minMaxValGlobal[0] = recvbuf[2] ? PETSC_INT_MIN : -recvbuf[0]; minMaxValGlobal[1] = recvbuf[1]; PetscFunctionReturn(PETSC_SUCCESS); } /*@ PetscGlobalMinMaxReal - Get the global min/max from local min/max input Collective Input Parameters: + comm - The MPI communicator to reduce with - minMaxVal - An array with the local min and max Output Parameter: . minMaxValGlobal - An array with the global min and max Level: beginner .seealso: `PetscSplitOwnership()`, `PetscGlobalMinMaxInt()` @*/ PetscErrorCode PetscGlobalMinMaxReal(MPI_Comm comm, const PetscReal minMaxVal[2], PetscReal minMaxValGlobal[2]) { PetscReal sendbuf[2]; PetscFunctionBegin; sendbuf[0] = -minMaxVal[0]; sendbuf[1] = minMaxVal[1]; PetscCallMPI(MPIU_Allreduce(sendbuf, minMaxValGlobal, 2, MPIU_REAL, MPIU_MAX, comm)); minMaxValGlobal[0] = -minMaxValGlobal[0]; PetscFunctionReturn(PETSC_SUCCESS); }