1 2 #include <engine.h> /* MATLAB include file */ 3 #include <petscsys.h> 4 #include <petscmatlab.h> /*I "petscmatlab.h" I*/ 5 #include <petsc/private/petscimpl.h> 6 7 struct _p_PetscMatlabEngine { 8 PETSCHEADER(int); 9 Engine *ep; 10 char buffer[1024]; 11 }; 12 13 PetscClassId MATLABENGINE_CLASSID = -1; 14 15 /*@C 16 PetscMatlabEngineCreate - Creates a MATLAB engine object 17 18 Not Collective 19 20 Input Parameters: 21 + comm - a separate MATLAB engine is started for each process in the communicator 22 - host - name of machine where MATLAB engine is to be run (usually NULL) 23 24 Output Parameter: 25 . mengine - the resulting object 26 27 Options Database Keys: 28 + -matlab_engine_graphics - allow the MATLAB engine to display graphics 29 . -matlab_engine_host - hostname, machine to run the MATLAB engine on 30 - -info - print out all requests to MATLAB and all if its responses (for debugging) 31 32 Note: 33 If a host string is passed in, any MATLAB scripts that need to run in the 34 engine must be available via MATLABPATH on that machine. 35 36 Level: advanced 37 38 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 39 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 40 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 41 @*/ 42 PetscErrorCode PetscMatlabEngineCreate(MPI_Comm comm, const char host[], PetscMatlabEngine *mengine) { 43 PetscMPIInt rank, size; 44 char buffer[256]; 45 PetscMatlabEngine e; 46 PetscBool flg = PETSC_FALSE; 47 char lhost[64]; 48 PetscFunctionBegin; 49 if (MATLABENGINE_CLASSID == -1) PetscCall(PetscClassIdRegister("MATLAB Engine", &MATLABENGINE_CLASSID)); 50 PetscCall(PetscHeaderCreate(e, MATLABENGINE_CLASSID, "MatlabEngine", "MATLAB Engine", "Sys", comm, PetscMatlabEngineDestroy, NULL)); 51 52 if (!host) { 53 PetscCall(PetscOptionsGetString(NULL, NULL, "-matlab_engine_host", lhost, sizeof(lhost), &flg)); 54 if (flg) host = lhost; 55 } 56 flg = PETSC_FALSE; 57 PetscCall(PetscOptionsGetBool(NULL, NULL, "-matlab_engine_graphics", &flg, NULL)); 58 59 if (host) { 60 PetscCall(PetscInfo(0, "Starting MATLAB engine on %s\n", host)); 61 PetscCall(PetscStrcpy(buffer, "ssh ")); 62 PetscCall(PetscStrcat(buffer, host)); 63 PetscCall(PetscStrcat(buffer, " \"")); 64 PetscCall(PetscStrlcat(buffer, PETSC_MATLAB_COMMAND, sizeof(buffer))); 65 if (!flg) PetscCall(PetscStrlcat(buffer, " -nodisplay ", sizeof(buffer))); 66 PetscCall(PetscStrlcat(buffer, " -nosplash ", sizeof(buffer))); 67 PetscCall(PetscStrcat(buffer, "\"")); 68 } else { 69 PetscCall(PetscStrncpy(buffer, PETSC_MATLAB_COMMAND, sizeof(buffer))); 70 if (!flg) PetscCall(PetscStrlcat(buffer, " -nodisplay ", sizeof(buffer))); 71 PetscCall(PetscStrlcat(buffer, " -nosplash ", sizeof(buffer))); 72 } 73 PetscCall(PetscInfo(0, "Starting MATLAB engine with command %s\n", buffer)); 74 e->ep = engOpen(buffer); 75 PetscCheck(e->ep, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to start MATLAB engine with %s", buffer); 76 engOutputBuffer(e->ep, e->buffer, sizeof(e->buffer)); 77 if (host) PetscCall(PetscInfo(0, "Started MATLAB engine on %s\n", host)); 78 else PetscCall(PetscInfo(0, "Started MATLAB engine\n")); 79 80 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 81 PetscCallMPI(MPI_Comm_size(comm, &size)); 82 PetscCall(PetscMatlabEngineEvaluate(e, "MPI_Comm_rank = %d; MPI_Comm_size = %d;\n", rank, size)); 83 *mengine = e; 84 PetscFunctionReturn(0); 85 } 86 87 /*@ 88 PetscMatlabEngineDestroy - Shuts down a MATLAB engine. 89 90 Collective on v 91 92 Input Parameters: 93 . e - the engine 94 95 Level: advanced 96 97 .seealso: `PetscMatlabEngineCreate()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 98 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 99 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 100 @*/ 101 PetscErrorCode PetscMatlabEngineDestroy(PetscMatlabEngine *v) { 102 int err; 103 104 PetscFunctionBegin; 105 if (!*v) PetscFunctionReturn(0); 106 PetscValidHeaderSpecific(*v, MATLABENGINE_CLASSID, 1); 107 if (--((PetscObject)(*v))->refct > 0) PetscFunctionReturn(0); 108 PetscCall(PetscInfo(0, "Stopping MATLAB engine\n")); 109 err = engClose((*v)->ep); 110 PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing Matlab engine"); 111 PetscCall(PetscInfo(0, "MATLAB engine stopped\n")); 112 PetscCall(PetscHeaderDestroy(v)); 113 PetscFunctionReturn(0); 114 } 115 116 /*@C 117 PetscMatlabEngineEvaluate - Evaluates a string in MATLAB 118 119 Not Collective 120 121 Input Parameters: 122 + mengine - the MATLAB engine 123 - string - format as in a printf() 124 125 Notes: 126 Run the PETSc program with -info to always have printed back MATLAB's response to the string evaluation 127 128 If the string utilizes a MATLAB script that needs to run in the engine, the script must be available via MATLABPATH on that machine. 129 130 Level: advanced 131 132 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 133 `PetscMatlabEngineCreate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 134 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 135 @*/ 136 PetscErrorCode PetscMatlabEngineEvaluate(PetscMatlabEngine mengine, const char string[], ...) { 137 va_list Argp; 138 char buffer[1024]; 139 size_t fullLength; 140 141 PetscFunctionBegin; 142 va_start(Argp, string); 143 PetscCall(PetscVSNPrintf(buffer, sizeof(buffer) - 9 - 5, string, &fullLength, Argp)); 144 va_end(Argp); 145 146 PetscCall(PetscInfo(0, "Evaluating MATLAB string: %s\n", buffer)); 147 engEvalString(mengine->ep, buffer); 148 PetscCall(PetscInfo(0, "Done evaluating MATLAB string: %s\n", buffer)); 149 PetscCall(PetscInfo(0, " MATLAB output message: %s\n", mengine->buffer)); 150 151 /* 152 Check for error in MATLAB: indicated by ? as first character in engine->buffer 153 */ 154 PetscCheck(mengine->buffer[4] != '?', PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in evaluating MATLAB command:%s\n%s", string, mengine->buffer); 155 PetscFunctionReturn(0); 156 } 157 158 /*@C 159 PetscMatlabEngineGetOutput - Gets a string buffer where the MATLAB output is 160 printed 161 162 Not Collective 163 164 Input Parameter: 165 . mengine - the MATLAB engine 166 167 Output Parameter: 168 . string - buffer where MATLAB output is printed 169 170 Level: advanced 171 172 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 173 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineCreate()`, `PetscMatlabEnginePrintOutput()`, 174 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 175 @*/ 176 PetscErrorCode PetscMatlabEngineGetOutput(PetscMatlabEngine mengine, char **string) { 177 PetscFunctionBegin; 178 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 179 *string = mengine->buffer; 180 PetscFunctionReturn(0); 181 } 182 183 /*@C 184 PetscMatlabEnginePrintOutput - prints the output from MATLAB to an ASCII file 185 186 Collective on mengine 187 188 Input Parameters: 189 + mengine - the MATLAB engine 190 - fd - the file 191 192 Level: advanced 193 194 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 195 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEngineCreate()`, 196 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 197 @*/ 198 PetscErrorCode PetscMatlabEnginePrintOutput(PetscMatlabEngine mengine, FILE *fd) { 199 PetscMPIInt rank; 200 201 PetscFunctionBegin; 202 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 203 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mengine), &rank)); 204 PetscCall(PetscSynchronizedFPrintf(PetscObjectComm((PetscObject)mengine), fd, "[%d]%s", rank, mengine->buffer)); 205 PetscCall(PetscSynchronizedFlush(PetscObjectComm((PetscObject)mengine), fd)); 206 PetscFunctionReturn(0); 207 } 208 209 /*@ 210 PetscMatlabEnginePut - Puts a Petsc object, such as a `Mat` or `Vec` into the MATLAB space. For parallel objects, 211 each processor's part is put in a separate MATLAB process. 212 213 Collective on mengine 214 215 Input Parameters: 216 + mengine - the MATLAB engine 217 - object - the PETSc object, for example Vec 218 219 Level: advanced 220 221 Note: 222 `Mat`s transferred between PETSc and MATLAB and vis versa are transposed in the other space 223 (this is because MATLAB uses compressed column format and PETSc uses compressed row format) 224 225 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`, 226 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 227 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 228 @*/ 229 PetscErrorCode PetscMatlabEnginePut(PetscMatlabEngine mengine, PetscObject obj) { 230 PetscErrorCode (*put)(PetscObject, void *); 231 232 PetscFunctionBegin; 233 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 234 PetscCall(PetscObjectQueryFunction(obj, "PetscMatlabEnginePut_C", &put)); 235 PetscCheck(put, PETSC_COMM_SELF, PETSC_ERR_SUP, "Object %s cannot be put into MATLAB engine", obj->class_name); 236 PetscCall(PetscInfo(0, "Putting MATLAB object\n")); 237 PetscCall((*put)(obj, mengine->ep)); 238 PetscCall(PetscInfo(0, "Put MATLAB object: %s\n", obj->name)); 239 PetscFunctionReturn(0); 240 } 241 242 /*@ 243 PetscMatlabEngineGet - Gets a variable from MATLAB into a PETSc object. 244 245 Collective on mengine 246 247 Input Parameters: 248 + mengine - the MATLAB engine 249 - object - the PETSc object, for example a `Vec` 250 251 Level: advanced 252 253 Note: 254 `Mat`s transferred between PETSc and MATLAB and vis versa are transposed in the other space 255 (this is because MATLAB uses compressed column format and PETSc uses compressed row format) 256 257 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`, 258 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 259 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 260 @*/ 261 PetscErrorCode PetscMatlabEngineGet(PetscMatlabEngine mengine, PetscObject obj) { 262 PetscErrorCode (*get)(PetscObject, void *); 263 264 PetscFunctionBegin; 265 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 266 PetscCheck(obj->name, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot get object that has no name"); 267 PetscCall(PetscObjectQueryFunction(obj, "PetscMatlabEngineGet_C", &get)); 268 PetscCheck(get, PETSC_COMM_SELF, PETSC_ERR_SUP, "Object %s cannot be gotten from MATLAB engine", obj->class_name); 269 PetscCall(PetscInfo(0, "Getting MATLAB object\n")); 270 PetscCall((*get)(obj, mengine->ep)); 271 PetscCall(PetscInfo(0, "Got MATLAB object: %s\n", obj->name)); 272 PetscFunctionReturn(0); 273 } 274 275 /* 276 The variable Petsc_Matlab_Engine_keyval is used to indicate an MPI attribute that 277 is attached to a communicator, in this case the attribute is a PetscMatlabEngine 278 */ 279 static PetscMPIInt Petsc_Matlab_Engine_keyval = MPI_KEYVAL_INVALID; 280 281 /*@C 282 PETSC_MATLAB_ENGINE_ - Creates a MATLAB engine on each process in a communicator. 283 284 Not Collective 285 286 Input Parameter: 287 . comm - the MPI communicator to share the engine 288 289 Options Database Key: 290 . -matlab_engine_host - hostname on which to run MATLAB, one must be able to ssh to this host 291 292 Level: developer 293 294 Note: 295 Unlike almost all other PETSc routines, this does not return 296 an error code. Usually used in the form 297 $ PetscMatlabEngineYYY(XXX object,PETSC_MATLAB_ENGINE_(comm)); 298 299 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 300 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 301 `PetscMatlabEngineCreate()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`, 302 `PETSC_MATLAB_ENGINE_WORLD`, `PETSC_MATLAB_ENGINE_SELF` 303 @*/ 304 PetscMatlabEngine PETSC_MATLAB_ENGINE_(MPI_Comm comm) { 305 PetscErrorCode ierr; 306 PetscBool flg; 307 PetscMatlabEngine mengine; 308 309 PetscFunctionBegin; 310 if (Petsc_Matlab_Engine_keyval == MPI_KEYVAL_INVALID) { 311 ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Matlab_Engine_keyval, 0); 312 if (ierr) { 313 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 314 PetscFunctionReturn(NULL); 315 } 316 } 317 ierr = MPI_Comm_get_attr(comm, Petsc_Matlab_Engine_keyval, (void **)&mengine, (int *)&flg); 318 if (ierr) { 319 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 320 PetscFunctionReturn(NULL); 321 } 322 if (!flg) { /* viewer not yet created */ 323 ierr = PetscMatlabEngineCreate(comm, NULL, &mengine); 324 if (ierr) { 325 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 326 PetscFunctionReturn(NULL); 327 } 328 ierr = PetscObjectRegisterDestroy((PetscObject)mengine); 329 if (ierr) { 330 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 331 PetscFunctionReturn(NULL); 332 } 333 ierr = MPI_Comm_set_attr(comm, Petsc_Matlab_Engine_keyval, mengine); 334 if (ierr) { 335 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 336 PetscFunctionReturn(NULL); 337 } 338 } 339 PetscFunctionReturn(mengine); 340 } 341 342 /*@C 343 PetscMatlabEnginePutArray - Puts an array into the MATLAB space, treating it as a Fortran style (column major ordering) array. For parallel objects, 344 each processors part is put in a separate MATLAB process. 345 346 Collective on mengine 347 348 Input Parameters: 349 + mengine - the MATLAB engine 350 . m,n - the dimensions of the array 351 . array - the array (represented in one dimension) 352 - name - the name of the array 353 354 Level: advanced 355 356 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`, 357 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 358 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 359 @*/ 360 PetscErrorCode PetscMatlabEnginePutArray(PetscMatlabEngine mengine, int m, int n, const PetscScalar *array, const char name[]) { 361 mxArray *mat; 362 363 PetscFunctionBegin; 364 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 365 PetscCall(PetscInfo(0, "Putting MATLAB array %s\n", name)); 366 #if !defined(PETSC_USE_COMPLEX) 367 mat = mxCreateDoubleMatrix(m, n, mxREAL); 368 #else 369 mat = mxCreateDoubleMatrix(m, n, mxCOMPLEX); 370 #endif 371 PetscCall(PetscArraycpy(mxGetPr(mat), array, m * n)); 372 engPutVariable(mengine->ep, name, mat); 373 374 PetscCall(PetscInfo(0, "Put MATLAB array %s\n", name)); 375 PetscFunctionReturn(0); 376 } 377 378 /*@C 379 PetscMatlabEngineGetArray - Gets a variable from MATLAB into an array 380 381 Not Collective 382 383 Input Parameters: 384 + mengine - the MATLAB engine 385 . m,n - the dimensions of the array 386 . array - the array (represented in one dimension) 387 - name - the name of the array 388 389 Level: advanced 390 391 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`, 392 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 393 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGet()`, `PetscMatlabEngine` 394 @*/ 395 PetscErrorCode PetscMatlabEngineGetArray(PetscMatlabEngine mengine, int m, int n, PetscScalar *array, const char name[]) { 396 mxArray *mat; 397 398 PetscFunctionBegin; 399 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 400 PetscCall(PetscInfo(0, "Getting MATLAB array %s\n", name)); 401 mat = engGetVariable(mengine->ep, name); 402 PetscCheck(mat, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to get array %s from matlab", name); 403 PetscCheck(mxGetM(mat) == (size_t)m, PETSC_COMM_SELF, PETSC_ERR_LIB, "Array %s in MATLAB first dimension %d does not match requested size %d", name, (int)mxGetM(mat), m); 404 PetscCheck(mxGetN(mat) == (size_t)n, PETSC_COMM_SELF, PETSC_ERR_LIB, "Array %s in MATLAB second dimension %d does not match requested size %d", name, (int)mxGetN(mat), m); 405 PetscCall(PetscArraycpy(array, mxGetPr(mat), m * n)); 406 PetscCall(PetscInfo(0, "Got MATLAB array %s\n", name)); 407 PetscFunctionReturn(0); 408 } 409