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