10039db0dSBarry Smith #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for popen() */ 2e5c89e4eSSatish Balay /* 34c500f23SPierre Jolivet Some PETSc utility routines to add simple parallel IO capabilities 4e5c89e4eSSatish Balay */ 5c6db04a5SJed Brown #include <petscsys.h> 6e94e781bSJacob Faibussowitsch #include <petsc/private/logimpl.h> 7d0286d30SJed Brown #include <errno.h> 8d0286d30SJed Brown 9e5c89e4eSSatish Balay /*@C 10*21532e8aSBarry Smith PetscFOpen - Has the first process in the MPI communicator open a file; 11e5c89e4eSSatish Balay all others do nothing. 12e5c89e4eSSatish Balay 13cf53795eSBarry Smith Logically Collective; No Fortran Support 14e5c89e4eSSatish Balay 15e5c89e4eSSatish Balay Input Parameters: 16*21532e8aSBarry Smith + comm - the MPI communicator 17e5c89e4eSSatish Balay . name - the filename 18bfbbc7b7SBarry Smith - mode - the mode for `fopen()`, usually "w" 19e5c89e4eSSatish Balay 20e5c89e4eSSatish Balay Output Parameter: 21e5c89e4eSSatish Balay . fp - the file pointer 22e5c89e4eSSatish Balay 23e5c89e4eSSatish Balay Level: developer 24e5c89e4eSSatish Balay 25811af0c4SBarry Smith Note: 26bfbbc7b7SBarry Smith `NULL`, "stderr" or "stdout" may be passed in as the filename 27e5c89e4eSSatish Balay 28db781477SPatrick Sanan .seealso: `PetscFClose()`, `PetscSynchronizedFGets()`, `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, 29db781477SPatrick Sanan `PetscFPrintf()` 30e5c89e4eSSatish Balay @*/ 31d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFOpen(MPI_Comm comm, const char name[], const char mode[], FILE **fp) 32d71ae5a4SJacob Faibussowitsch { 33e5c89e4eSSatish Balay PetscMPIInt rank; 34e5c89e4eSSatish Balay FILE *fd; 35e5c89e4eSSatish Balay char fname[PETSC_MAX_PATH_LEN], tname[PETSC_MAX_PATH_LEN]; 36e5c89e4eSSatish Balay 37e5c89e4eSSatish Balay PetscFunctionBegin; 389566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 39dd400576SPatrick Sanan if (rank == 0) { 40ace3abfcSBarry Smith PetscBool isstdout, isstderr; 419566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(name, "stdout", &isstdout)); 429566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(name, "stderr", &isstderr)); 43a297a907SKarl Rupp if (isstdout || !name) fd = PETSC_STDOUT; 44a297a907SKarl Rupp else if (isstderr) fd = PETSC_STDERR; 45a297a907SKarl Rupp else { 46bbcf679cSJacob Faibussowitsch PetscBool devnull = PETSC_FALSE; 479566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(PETSC_COMM_SELF, name, tname, PETSC_MAX_PATH_LEN)); 489566063dSJacob Faibussowitsch PetscCall(PetscFixFilename(tname, fname)); 499566063dSJacob Faibussowitsch PetscCall(PetscStrbeginswith(fname, "/dev/null", &devnull)); 50c6a7a370SJeremy L Thompson if (devnull) PetscCall(PetscStrncpy(fname, "/dev/null", sizeof(fname))); 519566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Opening file %s\n", fname)); 52e5c89e4eSSatish Balay fd = fopen(fname, mode); 5328b400f6SJacob Faibussowitsch PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file %s", fname); 54e5c89e4eSSatish Balay } 5502c9f0b5SLisandro Dalcin } else fd = NULL; 56e5c89e4eSSatish Balay *fp = fd; 573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58e5c89e4eSSatish Balay } 59e5c89e4eSSatish Balay 60e8976759SBarry Smith /*@C 61*21532e8aSBarry Smith PetscFClose - Has MPI rank 0 in the communicator close a 62*21532e8aSBarry Smith file (usually obtained with `PetscFOpen()`; all others do nothing. 63e5c89e4eSSatish Balay 64cf53795eSBarry Smith Logically Collective; No Fortran Support 65e5c89e4eSSatish Balay 66e5c89e4eSSatish Balay Input Parameters: 67*21532e8aSBarry Smith + comm - the MPI communicator 68*21532e8aSBarry Smith - fd - the file, opened with `PetscFOpen()` 69e5c89e4eSSatish Balay 70e5c89e4eSSatish Balay Level: developer 71e5c89e4eSSatish Balay 72db781477SPatrick Sanan .seealso: `PetscFOpen()` 73e5c89e4eSSatish Balay @*/ 74d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFClose(MPI_Comm comm, FILE *fd) 75d71ae5a4SJacob Faibussowitsch { 76e5c89e4eSSatish Balay PetscMPIInt rank; 77ed9cf6e9SBarry Smith int err; 78e5c89e4eSSatish Balay 79e5c89e4eSSatish Balay PetscFunctionBegin; 809566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 81dd400576SPatrick Sanan if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) { 82ed9cf6e9SBarry Smith err = fclose(fd); 8328b400f6SJacob Faibussowitsch PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file"); 84ed9cf6e9SBarry Smith } 853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 86e5c89e4eSSatish Balay } 87e5c89e4eSSatish Balay 88e5c89e4eSSatish Balay #if defined(PETSC_HAVE_POPEN) 8974ba8654SBarry Smith static char PetscPOpenMachine[128] = ""; 90e5c89e4eSSatish Balay 91e5c89e4eSSatish Balay /*@C 92*21532e8aSBarry Smith PetscPClose - Closes (ends) a program on MPI rank 0 run with `PetscPOpen()` 93e5c89e4eSSatish Balay 94*21532e8aSBarry Smith Collective, but only MPI rank 0 does anything 95e5c89e4eSSatish Balay 96e5c89e4eSSatish Balay Input Parameters: 97*21532e8aSBarry Smith + comm - MPI communicator, only rank 0 performs the close 98*21532e8aSBarry Smith - fd - the file pointer where program input or output may be read or `NULL` if don't care 99e5c89e4eSSatish Balay 100e5c89e4eSSatish Balay Level: intermediate 101e5c89e4eSSatish Balay 102811af0c4SBarry Smith Note: 103bfbbc7b7SBarry Smith Does not work under Microsoft Windows 104e5c89e4eSSatish Balay 105db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()` 106e5c89e4eSSatish Balay @*/ 107d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd) 108d71ae5a4SJacob Faibussowitsch { 109e5c89e4eSSatish Balay PetscMPIInt rank; 110e5c89e4eSSatish Balay 111e5c89e4eSSatish Balay PetscFunctionBegin; 1129566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 113dd400576SPatrick Sanan if (rank == 0) { 114e5c89e4eSSatish Balay char buf[1024]; 1159371c9d4SSatish Balay while (fgets(buf, 1024, fd)) 1169371c9d4SSatish Balay ; /* wait till it prints everything */ 117016831caSBarry Smith (void)pclose(fd); 118e5c89e4eSSatish Balay } 1193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 120e5c89e4eSSatish Balay } 121e5c89e4eSSatish Balay 122e5c89e4eSSatish Balay /*@C 123*21532e8aSBarry Smith PetscPOpen - Runs a program on MPI rank 0 and sends either its input or output to 124e5c89e4eSSatish Balay a file. 125e5c89e4eSSatish Balay 126bfbbc7b7SBarry Smith Logically Collective, but only MPI rank 0 runs the command 127e5c89e4eSSatish Balay 128e5c89e4eSSatish Balay Input Parameters: 129e5c89e4eSSatish Balay + comm - MPI communicator, only processor zero runs the program 130*21532e8aSBarry Smith . machine - machine to run command on or `NULL`, or a string with 0 in first location 131e5c89e4eSSatish Balay . program - name of program to run 132bfbbc7b7SBarry Smith - mode - either "r" or "w" 133e5c89e4eSSatish Balay 134e5c89e4eSSatish Balay Output Parameter: 135*21532e8aSBarry Smith . fp - the file pointer where program input or output may be read or `NULL` if results are not needed 136e5c89e4eSSatish Balay 137e5c89e4eSSatish Balay Level: intermediate 138e5c89e4eSSatish Balay 139e5c89e4eSSatish Balay Notes: 140811af0c4SBarry Smith Use `PetscPClose()` to close the file pointer when you are finished with it 141811af0c4SBarry Smith 142bfbbc7b7SBarry Smith Does not work under Microsoft Windows 143e5c89e4eSSatish Balay 144811af0c4SBarry Smith If machine is not provided will use the value set with `PetsPOpenSetMachine()` if that was provided, otherwise 145*21532e8aSBarry Smith will use the machine running MPI rank 0 of the communicator 14674ba8654SBarry Smith 147e5c89e4eSSatish Balay The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these 148a5b23f4aSJose E. Roman will be replaced with relevant values. 149e5c89e4eSSatish Balay 150db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()` 151e5c89e4eSSatish Balay @*/ 152d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp) 153d71ae5a4SJacob Faibussowitsch { 154e5c89e4eSSatish Balay PetscMPIInt rank; 155e5c89e4eSSatish Balay size_t i, len, cnt; 156e5c89e4eSSatish Balay char commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN]; 157e5c89e4eSSatish Balay FILE *fd; 158e5c89e4eSSatish Balay 159e5c89e4eSSatish Balay PetscFunctionBegin; 160e5c89e4eSSatish Balay /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */ 16174ba8654SBarry Smith if (PetscPOpenMachine[0] || (machine && machine[0])) { 162c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(command, "ssh ", sizeof(command))); 16374ba8654SBarry Smith if (PetscPOpenMachine[0]) { 164c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, PetscPOpenMachine, sizeof(command))); 16574ba8654SBarry Smith } else { 166c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, machine, sizeof(command))); 16774ba8654SBarry Smith } 168c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, " \" export DISPLAY=${DISPLAY}; ", sizeof(command))); 169e5c89e4eSSatish Balay /* 170e5c89e4eSSatish Balay Copy program into command but protect the " with a \ in front of it 171e5c89e4eSSatish Balay */ 1729566063dSJacob Faibussowitsch PetscCall(PetscStrlen(command, &cnt)); 1739566063dSJacob Faibussowitsch PetscCall(PetscStrlen(program, &len)); 174e5c89e4eSSatish Balay for (i = 0; i < len; i++) { 175a297a907SKarl Rupp if (program[i] == '\"') command[cnt++] = '\\'; 176e5c89e4eSSatish Balay command[cnt++] = program[i]; 177e5c89e4eSSatish Balay } 178e5c89e4eSSatish Balay command[cnt] = 0; 179a297a907SKarl Rupp 180c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, "\"", sizeof(command))); 181e5c89e4eSSatish Balay } else { 182c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(command, program, sizeof(command))); 183e5c89e4eSSatish Balay } 184e5c89e4eSSatish Balay 1859566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(comm, command, commandt, 1024)); 186e5c89e4eSSatish Balay 1879566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 188dd400576SPatrick Sanan if (rank == 0) { 1899566063dSJacob Faibussowitsch PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt)); 190cc73adaaSBarry Smith PetscCheck((fd = popen(commandt, mode)), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt); 191e5c89e4eSSatish Balay if (fp) *fp = fd; 192e5c89e4eSSatish Balay } 1933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 194e5c89e4eSSatish Balay } 195e5c89e4eSSatish Balay 19674ba8654SBarry Smith /*@C 197811af0c4SBarry Smith PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on 19874ba8654SBarry Smith 199bfbbc7b7SBarry Smith Logically Collective, but only MPI rank 0 runs the command 20074ba8654SBarry Smith 20174ba8654SBarry Smith Input Parameter: 202bfbbc7b7SBarry Smith . machine - machine to run command on or `NULL` for the current machine 20374ba8654SBarry Smith 204811af0c4SBarry Smith Options Database Key: 20510699b91SBarry Smith . -popen_machine <machine> - run the process on this machine 20674ba8654SBarry Smith 20774ba8654SBarry Smith Level: intermediate 20874ba8654SBarry Smith 209db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()` 21074ba8654SBarry Smith @*/ 211d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpenSetMachine(const char machine[]) 212d71ae5a4SJacob Faibussowitsch { 21374ba8654SBarry Smith PetscFunctionBegin; 21474ba8654SBarry Smith if (machine) { 215c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(PetscPOpenMachine, machine, sizeof(PetscPOpenMachine))); 21674ba8654SBarry Smith } else { 21774ba8654SBarry Smith PetscPOpenMachine[0] = 0; 21874ba8654SBarry Smith } 2193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22074ba8654SBarry Smith } 22174ba8654SBarry Smith 222e5c89e4eSSatish Balay #endif 223