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: 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 Notes: 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 PetscMatlabEngine 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 Level: advanced 129 130 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 131 `PetscMatlabEngineCreate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 132 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 133 @*/ 134 PetscErrorCode PetscMatlabEngineEvaluate(PetscMatlabEngine mengine, const char string[], ...) { 135 va_list Argp; 136 char buffer[1024]; 137 size_t fullLength; 138 139 PetscFunctionBegin; 140 va_start(Argp, string); 141 PetscCall(PetscVSNPrintf(buffer, sizeof(buffer) - 9 - 5, string, &fullLength, Argp)); 142 va_end(Argp); 143 144 PetscCall(PetscInfo(0, "Evaluating MATLAB string: %s\n", buffer)); 145 engEvalString(mengine->ep, buffer); 146 PetscCall(PetscInfo(0, "Done evaluating MATLAB string: %s\n", buffer)); 147 PetscCall(PetscInfo(0, " MATLAB output message: %s\n", mengine->buffer)); 148 149 /* 150 Check for error in MATLAB: indicated by ? as first character in engine->buffer 151 */ 152 PetscCheck(mengine->buffer[4] != '?', PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in evaluating MATLAB command:%s\n%s", string, mengine->buffer); 153 PetscFunctionReturn(0); 154 } 155 156 /*@C 157 PetscMatlabEngineGetOutput - Gets a string buffer where the MATLAB output is 158 printed 159 160 Not Collective 161 162 Input Parameter: 163 . mengine - the MATLAB engine 164 165 Output Parameter: 166 . string - buffer where MATLAB output is printed 167 168 Level: advanced 169 170 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 171 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineCreate()`, `PetscMatlabEnginePrintOutput()`, 172 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 173 @*/ 174 PetscErrorCode PetscMatlabEngineGetOutput(PetscMatlabEngine mengine, char **string) { 175 PetscFunctionBegin; 176 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 177 *string = mengine->buffer; 178 PetscFunctionReturn(0); 179 } 180 181 /*@C 182 PetscMatlabEnginePrintOutput - prints the output from MATLAB 183 184 Collective on PetscMatlabEngine 185 186 Input Parameters: 187 . mengine - the Matlab engine 188 189 Level: advanced 190 191 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 192 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEngineCreate()`, 193 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 194 @*/ 195 PetscErrorCode PetscMatlabEnginePrintOutput(PetscMatlabEngine mengine, FILE *fd) { 196 PetscMPIInt rank; 197 198 PetscFunctionBegin; 199 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 200 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mengine), &rank)); 201 PetscCall(PetscSynchronizedFPrintf(PetscObjectComm((PetscObject)mengine), fd, "[%d]%s", rank, mengine->buffer)); 202 PetscCall(PetscSynchronizedFlush(PetscObjectComm((PetscObject)mengine), fd)); 203 PetscFunctionReturn(0); 204 } 205 206 /*@ 207 PetscMatlabEnginePut - Puts a Petsc object into the MATLAB space. For parallel objects, 208 each processors part is put in a separate MATLAB process. 209 210 Collective on PetscObject 211 212 Input Parameters: 213 + mengine - the MATLAB engine 214 - object - the PETSc object, for example Vec 215 216 Level: advanced 217 218 Note: Mats transferred between PETSc and MATLAB and vis versa are transposed in the other space 219 (this is because MATLAB uses compressed column format and PETSc uses compressed row format) 220 221 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`, 222 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 223 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 224 @*/ 225 PetscErrorCode PetscMatlabEnginePut(PetscMatlabEngine mengine, PetscObject obj) { 226 PetscErrorCode (*put)(PetscObject, void *); 227 228 PetscFunctionBegin; 229 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 230 PetscCall(PetscObjectQueryFunction(obj, "PetscMatlabEnginePut_C", &put)); 231 PetscCheck(put, PETSC_COMM_SELF, PETSC_ERR_SUP, "Object %s cannot be put into MATLAB engine", obj->class_name); 232 PetscCall(PetscInfo(0, "Putting MATLAB object\n")); 233 PetscCall((*put)(obj, mengine->ep)); 234 PetscCall(PetscInfo(0, "Put MATLAB object: %s\n", obj->name)); 235 PetscFunctionReturn(0); 236 } 237 238 /*@ 239 PetscMatlabEngineGet - Gets a variable from MATLAB into a PETSc object. 240 241 Collective on PetscObject 242 243 Input Parameters: 244 + mengine - the MATLAB engine 245 - object - the PETSc object, for example Vec 246 247 Level: advanced 248 249 Note: Mats transferred between PETSc and MATLAB and vis versa are transposed in the other space 250 (this is because MATLAB uses compressed column format and PETSc uses compressed row format) 251 252 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`, 253 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 254 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 255 @*/ 256 PetscErrorCode PetscMatlabEngineGet(PetscMatlabEngine mengine, PetscObject obj) { 257 PetscErrorCode (*get)(PetscObject, void *); 258 259 PetscFunctionBegin; 260 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 261 PetscCheck(obj->name, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot get object that has no name"); 262 PetscCall(PetscObjectQueryFunction(obj, "PetscMatlabEngineGet_C", &get)); 263 PetscCheck(get, PETSC_COMM_SELF, PETSC_ERR_SUP, "Object %s cannot be gotten from MATLAB engine", obj->class_name); 264 PetscCall(PetscInfo(0, "Getting MATLAB object\n")); 265 PetscCall((*get)(obj, mengine->ep)); 266 PetscCall(PetscInfo(0, "Got MATLAB object: %s\n", obj->name)); 267 PetscFunctionReturn(0); 268 } 269 270 /* 271 The variable Petsc_Matlab_Engine_keyval is used to indicate an MPI attribute that 272 is attached to a communicator, in this case the attribute is a PetscMatlabEngine 273 */ 274 static PetscMPIInt Petsc_Matlab_Engine_keyval = MPI_KEYVAL_INVALID; 275 276 /*@C 277 PETSC_MATLAB_ENGINE_ - Creates a MATLAB engine on each process in a communicator. 278 279 Not Collective 280 281 Input Parameter: 282 . comm - the MPI communicator to share the engine 283 284 Options Database: 285 . -matlab_engine_host - hostname 286 287 Level: developer 288 289 Notes: 290 Unlike almost all other PETSc routines, this does not return 291 an error code. Usually used in the form 292 $ PetscMatlabEngineYYY(XXX object,PETSC_MATLAB_ENGINE_(comm)); 293 294 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 295 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 296 `PetscMatlabEngineCreate()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`, 297 `PETSC_MATLAB_ENGINE_WORLD`, `PETSC_MATLAB_ENGINE_SELF` 298 299 @*/ 300 PetscMatlabEngine PETSC_MATLAB_ENGINE_(MPI_Comm comm) { 301 PetscErrorCode ierr; 302 PetscBool flg; 303 PetscMatlabEngine mengine; 304 305 PetscFunctionBegin; 306 if (Petsc_Matlab_Engine_keyval == MPI_KEYVAL_INVALID) { 307 ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Matlab_Engine_keyval, 0); 308 if (ierr) { 309 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 310 PetscFunctionReturn(NULL); 311 } 312 } 313 ierr = MPI_Comm_get_attr(comm, Petsc_Matlab_Engine_keyval, (void **)&mengine, (int *)&flg); 314 if (ierr) { 315 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 316 PetscFunctionReturn(NULL); 317 } 318 if (!flg) { /* viewer not yet created */ 319 ierr = PetscMatlabEngineCreate(comm, NULL, &mengine); 320 if (ierr) { 321 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 322 PetscFunctionReturn(NULL); 323 } 324 ierr = PetscObjectRegisterDestroy((PetscObject)mengine); 325 if (ierr) { 326 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 327 PetscFunctionReturn(NULL); 328 } 329 ierr = MPI_Comm_set_attr(comm, Petsc_Matlab_Engine_keyval, mengine); 330 if (ierr) { 331 PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 332 PetscFunctionReturn(NULL); 333 } 334 } 335 PetscFunctionReturn(mengine); 336 } 337 338 /*@C 339 PetscMatlabEnginePutArray - Puts an array into the MATLAB space, treating it as a Fortran style (column major ordering) array. For parallel objects, 340 each processors part is put in a separate MATLAB process. 341 342 Collective on PetscObject 343 344 Input Parameters: 345 + mengine - the MATLAB engine 346 . m,n - the dimensions of the array 347 . array - the array (represented in one dimension) 348 - name - the name of the array 349 350 Level: advanced 351 352 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`, 353 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 354 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 355 @*/ 356 PetscErrorCode PetscMatlabEnginePutArray(PetscMatlabEngine mengine, int m, int n, const PetscScalar *array, const char name[]) { 357 mxArray *mat; 358 359 PetscFunctionBegin; 360 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 361 PetscCall(PetscInfo(0, "Putting MATLAB array %s\n", name)); 362 #if !defined(PETSC_USE_COMPLEX) 363 mat = mxCreateDoubleMatrix(m, n, mxREAL); 364 #else 365 mat = mxCreateDoubleMatrix(m, n, mxCOMPLEX); 366 #endif 367 PetscCall(PetscArraycpy(mxGetPr(mat), array, m * n)); 368 engPutVariable(mengine->ep, name, mat); 369 370 PetscCall(PetscInfo(0, "Put MATLAB array %s\n", name)); 371 PetscFunctionReturn(0); 372 } 373 374 /*@C 375 PetscMatlabEngineGetArray - Gets a variable from MATLAB into an array 376 377 Not Collective 378 379 Input Parameters: 380 + mengine - the MATLAB engine 381 . m,n - the dimensions of the array 382 . array - the array (represented in one dimension) 383 - name - the name of the array 384 385 Level: advanced 386 387 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`, 388 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 389 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGet()`, `PetscMatlabEngine` 390 @*/ 391 PetscErrorCode PetscMatlabEngineGetArray(PetscMatlabEngine mengine, int m, int n, PetscScalar *array, const char name[]) { 392 mxArray *mat; 393 394 PetscFunctionBegin; 395 PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 396 PetscCall(PetscInfo(0, "Getting MATLAB array %s\n", name)); 397 mat = engGetVariable(mengine->ep, name); 398 PetscCheck(mat, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to get array %s from matlab", name); 399 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); 400 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); 401 PetscCall(PetscArraycpy(array, mxGetPr(mat), m * n)); 402 PetscCall(PetscInfo(0, "Got MATLAB array %s\n", name)); 403 PetscFunctionReturn(0); 404 } 405