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