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 10e5c89e4eSSatish Balay PetscFOpen - Has the first process in the communicator open a file; 11e5c89e4eSSatish Balay all others do nothing. 12e5c89e4eSSatish Balay 13d083f849SBarry Smith Logically Collective 14e5c89e4eSSatish Balay 15e5c89e4eSSatish Balay Input Parameters: 16e5c89e4eSSatish Balay + comm - the communicator 17e5c89e4eSSatish Balay . name - the filename 18e5c89e4eSSatish Balay - 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: 260298fd71SBarry Smith NULL (0), "stderr" or "stdout" may be passed in as the filename 27e5c89e4eSSatish Balay 28e5c89e4eSSatish Balay Fortran Note: 29e5c89e4eSSatish Balay This routine is not supported in Fortran. 30e5c89e4eSSatish Balay 31db781477SPatrick Sanan .seealso: `PetscFClose()`, `PetscSynchronizedFGets()`, `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, 32db781477SPatrick Sanan `PetscFPrintf()` 33e5c89e4eSSatish Balay @*/ 34*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFOpen(MPI_Comm comm, const char name[], const char mode[], FILE **fp) 35*d71ae5a4SJacob Faibussowitsch { 36e5c89e4eSSatish Balay PetscMPIInt rank; 37e5c89e4eSSatish Balay FILE *fd; 38e5c89e4eSSatish Balay char fname[PETSC_MAX_PATH_LEN], tname[PETSC_MAX_PATH_LEN]; 39e5c89e4eSSatish Balay 40e5c89e4eSSatish Balay PetscFunctionBegin; 419566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 42dd400576SPatrick Sanan if (rank == 0) { 43ace3abfcSBarry Smith PetscBool isstdout, isstderr; 449566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(name, "stdout", &isstdout)); 459566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(name, "stderr", &isstderr)); 46a297a907SKarl Rupp if (isstdout || !name) fd = PETSC_STDOUT; 47a297a907SKarl Rupp else if (isstderr) fd = PETSC_STDERR; 48a297a907SKarl Rupp else { 49b3f259d6SBarry Smith PetscBool devnull; 509566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(PETSC_COMM_SELF, name, tname, PETSC_MAX_PATH_LEN)); 519566063dSJacob Faibussowitsch PetscCall(PetscFixFilename(tname, fname)); 529566063dSJacob Faibussowitsch PetscCall(PetscStrbeginswith(fname, "/dev/null", &devnull)); 5348a46eb9SPierre Jolivet if (devnull) PetscCall(PetscStrcpy(fname, "/dev/null")); 549566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Opening file %s\n", fname)); 55e5c89e4eSSatish Balay fd = fopen(fname, mode); 5628b400f6SJacob Faibussowitsch PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file %s", fname); 57e5c89e4eSSatish Balay } 5802c9f0b5SLisandro Dalcin } else fd = NULL; 59e5c89e4eSSatish Balay *fp = fd; 60e5c89e4eSSatish Balay PetscFunctionReturn(0); 61e5c89e4eSSatish Balay } 62e5c89e4eSSatish Balay 63e8976759SBarry Smith /*@C 64e5c89e4eSSatish Balay PetscFClose - Has the first processor in the communicator close a 65e5c89e4eSSatish Balay file; all others do nothing. 66e5c89e4eSSatish Balay 67d083f849SBarry Smith Logically Collective 68e5c89e4eSSatish Balay 69e5c89e4eSSatish Balay Input Parameters: 70e5c89e4eSSatish Balay + comm - the communicator 71e5c89e4eSSatish Balay - fd - the file, opened with PetscFOpen() 72e5c89e4eSSatish Balay 73e5c89e4eSSatish Balay Level: developer 74e5c89e4eSSatish Balay 75e5c89e4eSSatish Balay Fortran Note: 76e5c89e4eSSatish Balay This routine is not supported in Fortran. 77e5c89e4eSSatish Balay 78db781477SPatrick Sanan .seealso: `PetscFOpen()` 79e5c89e4eSSatish Balay @*/ 80*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFClose(MPI_Comm comm, FILE *fd) 81*d71ae5a4SJacob Faibussowitsch { 82e5c89e4eSSatish Balay PetscMPIInt rank; 83ed9cf6e9SBarry Smith int err; 84e5c89e4eSSatish Balay 85e5c89e4eSSatish Balay PetscFunctionBegin; 869566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 87dd400576SPatrick Sanan if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) { 88ed9cf6e9SBarry Smith err = fclose(fd); 8928b400f6SJacob Faibussowitsch PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file"); 90ed9cf6e9SBarry Smith } 91e5c89e4eSSatish Balay PetscFunctionReturn(0); 92e5c89e4eSSatish Balay } 93e5c89e4eSSatish Balay 94e5c89e4eSSatish Balay #if defined(PETSC_HAVE_POPEN) 9574ba8654SBarry Smith static char PetscPOpenMachine[128] = ""; 96e5c89e4eSSatish Balay 97e5c89e4eSSatish Balay /*@C 98811af0c4SBarry Smith PetscPClose - Closes (ends) a program on processor zero run with `PetscPOpen()` 99e5c89e4eSSatish Balay 100d083f849SBarry Smith Collective, but only process 0 runs the command 101e5c89e4eSSatish Balay 102e5c89e4eSSatish Balay Input Parameters: 103e5c89e4eSSatish Balay + comm - MPI communicator, only processor zero runs the program 1040298fd71SBarry Smith - fp - the file pointer where program input or output may be read or NULL if don't care 105e5c89e4eSSatish Balay 106e5c89e4eSSatish Balay Level: intermediate 107e5c89e4eSSatish Balay 108811af0c4SBarry Smith Note: 109e5c89e4eSSatish Balay Does not work under Windows 110e5c89e4eSSatish Balay 111db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()` 112e5c89e4eSSatish Balay @*/ 113*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd) 114*d71ae5a4SJacob Faibussowitsch { 115e5c89e4eSSatish Balay PetscMPIInt rank; 116e5c89e4eSSatish Balay 117e5c89e4eSSatish Balay PetscFunctionBegin; 1189566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 119dd400576SPatrick Sanan if (rank == 0) { 120e5c89e4eSSatish Balay char buf[1024]; 1219371c9d4SSatish Balay while (fgets(buf, 1024, fd)) 1229371c9d4SSatish Balay ; /* wait till it prints everything */ 123016831caSBarry Smith (void)pclose(fd); 124e5c89e4eSSatish Balay } 125e5c89e4eSSatish Balay PetscFunctionReturn(0); 126e5c89e4eSSatish Balay } 127e5c89e4eSSatish Balay 128e5c89e4eSSatish Balay /*@C 129e5c89e4eSSatish Balay PetscPOpen - Runs a program on processor zero and sends either its input or output to 130e5c89e4eSSatish Balay a file. 131e5c89e4eSSatish Balay 132d083f849SBarry Smith Logically Collective, but only process 0 runs the command 133e5c89e4eSSatish Balay 134e5c89e4eSSatish Balay Input Parameters: 135e5c89e4eSSatish Balay + comm - MPI communicator, only processor zero runs the program 1360298fd71SBarry Smith . machine - machine to run command on or NULL, or string with 0 in first location 137e5c89e4eSSatish Balay . program - name of program to run 138e5c89e4eSSatish Balay - mode - either r or w 139e5c89e4eSSatish Balay 140e5c89e4eSSatish Balay Output Parameter: 1410298fd71SBarry Smith . fp - the file pointer where program input or output may be read or NULL if don't care 142e5c89e4eSSatish Balay 143e5c89e4eSSatish Balay Level: intermediate 144e5c89e4eSSatish Balay 145e5c89e4eSSatish Balay Notes: 146811af0c4SBarry Smith Use `PetscPClose()` to close the file pointer when you are finished with it 147811af0c4SBarry Smith 148e5c89e4eSSatish Balay Does not work under Windows 149e5c89e4eSSatish Balay 150811af0c4SBarry Smith If machine is not provided will use the value set with `PetsPOpenSetMachine()` if that was provided, otherwise 15174ba8654SBarry Smith will use the machine running node zero of the communicator 15274ba8654SBarry Smith 153e5c89e4eSSatish Balay The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these 154a5b23f4aSJose E. Roman will be replaced with relevant values. 155e5c89e4eSSatish Balay 156db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()` 157e5c89e4eSSatish Balay @*/ 158*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp) 159*d71ae5a4SJacob Faibussowitsch { 160e5c89e4eSSatish Balay PetscMPIInt rank; 161e5c89e4eSSatish Balay size_t i, len, cnt; 162e5c89e4eSSatish Balay char commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN]; 163e5c89e4eSSatish Balay FILE *fd; 164e5c89e4eSSatish Balay 165e5c89e4eSSatish Balay PetscFunctionBegin; 166e5c89e4eSSatish Balay /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */ 16774ba8654SBarry Smith if (PetscPOpenMachine[0] || (machine && machine[0])) { 1689566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(command, "ssh ")); 16974ba8654SBarry Smith if (PetscPOpenMachine[0]) { 1709566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, PetscPOpenMachine)); 17174ba8654SBarry Smith } else { 1729566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, machine)); 17374ba8654SBarry Smith } 1749566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, " \" export DISPLAY=${DISPLAY}; ")); 175e5c89e4eSSatish Balay /* 176e5c89e4eSSatish Balay Copy program into command but protect the " with a \ in front of it 177e5c89e4eSSatish Balay */ 1789566063dSJacob Faibussowitsch PetscCall(PetscStrlen(command, &cnt)); 1799566063dSJacob Faibussowitsch PetscCall(PetscStrlen(program, &len)); 180e5c89e4eSSatish Balay for (i = 0; i < len; i++) { 181a297a907SKarl Rupp if (program[i] == '\"') command[cnt++] = '\\'; 182e5c89e4eSSatish Balay command[cnt++] = program[i]; 183e5c89e4eSSatish Balay } 184e5c89e4eSSatish Balay command[cnt] = 0; 185a297a907SKarl Rupp 1869566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, "\"")); 187e5c89e4eSSatish Balay } else { 1889566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(command, program)); 189e5c89e4eSSatish Balay } 190e5c89e4eSSatish Balay 1919566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(comm, command, commandt, 1024)); 192e5c89e4eSSatish Balay 1939566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 194dd400576SPatrick Sanan if (rank == 0) { 1959566063dSJacob Faibussowitsch PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt)); 196cc73adaaSBarry Smith PetscCheck((fd = popen(commandt, mode)), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt); 197e5c89e4eSSatish Balay if (fp) *fp = fd; 198e5c89e4eSSatish Balay } 199e5c89e4eSSatish Balay PetscFunctionReturn(0); 200e5c89e4eSSatish Balay } 201e5c89e4eSSatish Balay 20274ba8654SBarry Smith /*@C 203811af0c4SBarry Smith PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on 20474ba8654SBarry Smith 205d083f849SBarry Smith Logically Collective, but only process 0 runs the command 20674ba8654SBarry Smith 20774ba8654SBarry Smith Input Parameter: 20810699b91SBarry Smith . machine - machine to run command on or NULL for the current machine 20974ba8654SBarry Smith 210811af0c4SBarry Smith Options Database Key: 21110699b91SBarry Smith . -popen_machine <machine> - run the process on this machine 21274ba8654SBarry Smith 21374ba8654SBarry Smith Level: intermediate 21474ba8654SBarry Smith 215db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()` 21674ba8654SBarry Smith @*/ 217*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpenSetMachine(const char machine[]) 218*d71ae5a4SJacob Faibussowitsch { 21974ba8654SBarry Smith PetscFunctionBegin; 22074ba8654SBarry Smith if (machine) { 2219566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(PetscPOpenMachine, machine)); 22274ba8654SBarry Smith } else { 22374ba8654SBarry Smith PetscPOpenMachine[0] = 0; 22474ba8654SBarry Smith } 22574ba8654SBarry Smith PetscFunctionReturn(0); 22674ba8654SBarry Smith } 22774ba8654SBarry Smith 228e5c89e4eSSatish Balay #endif 229