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 PetscCall(PetscStrcpy(buffer,"ssh ")); 61 PetscCall(PetscStrcat(buffer,host)); 62 PetscCall(PetscStrcat(buffer," \"")); 63 PetscCall(PetscStrlcat(buffer,PETSC_MATLAB_COMMAND,sizeof(buffer))); 64 if (!flg) PetscCall(PetscStrlcat(buffer," -nodisplay ",sizeof(buffer))); 65 PetscCall(PetscStrlcat(buffer," -nosplash ",sizeof(buffer))); 66 PetscCall(PetscStrcat(buffer,"\"")); 67 } else { 68 PetscCall(PetscStrncpy(buffer,PETSC_MATLAB_COMMAND,sizeof(buffer))); 69 if (!flg) PetscCall(PetscStrlcat(buffer," -nodisplay ",sizeof(buffer))); 70 PetscCall(PetscStrlcat(buffer," -nosplash ",sizeof(buffer))); 71 } 72 PetscCall(PetscInfo(0,"Starting MATLAB engine with command %s\n",buffer)); 73 e->ep = engOpen(buffer); 74 PetscCheck(e->ep,PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to start MATLAB engine with %s",buffer); 75 engOutputBuffer(e->ep,e->buffer,sizeof(e->buffer)); 76 if (host) PetscCall(PetscInfo(0,"Started MATLAB engine on %s\n",host)); 77 else PetscCall(PetscInfo(0,"Started MATLAB engine\n")); 78 79 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 80 PetscCallMPI(MPI_Comm_size(comm,&size)); 81 PetscCall(PetscMatlabEngineEvaluate(e,"MPI_Comm_rank = %d; MPI_Comm_size = %d;\n",rank,size)); 82 *mengine = e; 83 PetscFunctionReturn(0); 84 } 85 86 /*@ 87 PetscMatlabEngineDestroy - Shuts down a MATLAB engine. 88 89 Collective on PetscMatlabEngine 90 91 Input Parameters: 92 . e - the engine 93 94 Level: advanced 95 96 .seealso: `PetscMatlabEngineCreate()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 97 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 98 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 99 @*/ 100 PetscErrorCode PetscMatlabEngineDestroy(PetscMatlabEngine *v) 101 { 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 { 136 va_list Argp; 137 char buffer[1024]; 138 size_t fullLength; 139 140 PetscFunctionBegin; 141 va_start(Argp,string); 142 PetscCall(PetscVSNPrintf(buffer,sizeof(buffer)-9-5,string,&fullLength,Argp)); 143 va_end(Argp); 144 145 PetscCall(PetscInfo(0,"Evaluating MATLAB string: %s\n",buffer)); 146 engEvalString(mengine->ep, buffer); 147 PetscCall(PetscInfo(0,"Done evaluating MATLAB string: %s\n",buffer)); 148 PetscCall(PetscInfo(0," MATLAB output message: %s\n",mengine->buffer)); 149 150 /* 151 Check for error in MATLAB: indicated by ? as first character in engine->buffer 152 */ 153 PetscCheck(mengine->buffer[4] != '?',PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in evaluating MATLAB command:%s\n%s",string,mengine->buffer); 154 PetscFunctionReturn(0); 155 } 156 157 /*@C 158 PetscMatlabEngineGetOutput - Gets a string buffer where the MATLAB output is 159 printed 160 161 Not Collective 162 163 Input Parameter: 164 . mengine - the MATLAB engine 165 166 Output Parameter: 167 . string - buffer where MATLAB output is printed 168 169 Level: advanced 170 171 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 172 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineCreate()`, `PetscMatlabEnginePrintOutput()`, 173 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 174 @*/ 175 PetscErrorCode PetscMatlabEngineGetOutput(PetscMatlabEngine mengine,char **string) 176 { 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 185 186 Collective on PetscMatlabEngine 187 188 Input Parameters: 189 . mengine - the Matlab engine 190 191 Level: advanced 192 193 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`, 194 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEngineCreate()`, 195 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 196 @*/ 197 PetscErrorCode PetscMatlabEnginePrintOutput(PetscMatlabEngine mengine,FILE *fd) 198 { 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 into the MATLAB space. For parallel objects, 211 each processors part is put in a separate MATLAB process. 212 213 Collective on PetscObject 214 215 Input Parameters: 216 + mengine - the MATLAB engine 217 - object - the PETSc object, for example Vec 218 219 Level: advanced 220 221 Note: Mats transferred between PETSc and MATLAB and vis versa are transposed in the other space 222 (this is because MATLAB uses compressed column format and PETSc uses compressed row format) 223 224 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`, 225 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 226 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 227 @*/ 228 PetscErrorCode PetscMatlabEnginePut(PetscMatlabEngine mengine,PetscObject obj) 229 { 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 PetscObject 246 247 Input Parameters: 248 + mengine - the MATLAB engine 249 - object - the PETSc object, for example Vec 250 251 Level: advanced 252 253 Note: Mats transferred between PETSc and MATLAB and vis versa are transposed in the other space 254 (this is because MATLAB uses compressed column format and PETSc uses compressed row format) 255 256 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`, 257 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 258 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 259 @*/ 260 PetscErrorCode PetscMatlabEngineGet(PetscMatlabEngine mengine,PetscObject obj) 261 { 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: 290 . -matlab_engine_host - hostname 291 292 Level: developer 293 294 Notes: 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 @*/ 305 PetscMatlabEngine PETSC_MATLAB_ENGINE_(MPI_Comm comm) 306 { 307 PetscErrorCode ierr; 308 PetscBool flg; 309 PetscMatlabEngine mengine; 310 311 PetscFunctionBegin; 312 if (Petsc_Matlab_Engine_keyval == MPI_KEYVAL_INVALID) { 313 ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Matlab_Engine_keyval,0); 314 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 315 } 316 ierr = MPI_Comm_get_attr(comm,Petsc_Matlab_Engine_keyval,(void**)&mengine,(int*)&flg); 317 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 318 if (!flg) { /* viewer not yet created */ 319 ierr = PetscMatlabEngineCreate(comm,NULL,&mengine); 320 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);} 321 ierr = PetscObjectRegisterDestroy((PetscObject)mengine); 322 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);} 323 ierr = MPI_Comm_set_attr(comm,Petsc_Matlab_Engine_keyval,mengine); 324 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 325 } 326 PetscFunctionReturn(mengine); 327 } 328 329 /*@C 330 PetscMatlabEnginePutArray - Puts an array into the MATLAB space, treating it as a Fortran style (column major ordering) array. For parallel objects, 331 each processors part is put in a separate MATLAB process. 332 333 Collective on PetscObject 334 335 Input Parameters: 336 + mengine - the MATLAB engine 337 . m,n - the dimensions of the array 338 . array - the array (represented in one dimension) 339 - name - the name of the array 340 341 Level: advanced 342 343 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`, 344 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 345 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine` 346 @*/ 347 PetscErrorCode PetscMatlabEnginePutArray(PetscMatlabEngine mengine,int m,int n,const PetscScalar *array,const char name[]) 348 { 349 mxArray *mat; 350 351 PetscFunctionBegin; 352 PetscCheck(mengine,PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 353 PetscCall(PetscInfo(0,"Putting MATLAB array %s\n",name)); 354 #if !defined(PETSC_USE_COMPLEX) 355 mat = mxCreateDoubleMatrix(m,n,mxREAL); 356 #else 357 mat = mxCreateDoubleMatrix(m,n,mxCOMPLEX); 358 #endif 359 PetscCall(PetscArraycpy(mxGetPr(mat),array,m*n)); 360 engPutVariable(mengine->ep,name,mat); 361 362 PetscCall(PetscInfo(0,"Put MATLAB array %s\n",name)); 363 PetscFunctionReturn(0); 364 } 365 366 /*@C 367 PetscMatlabEngineGetArray - Gets a variable from MATLAB into an array 368 369 Not Collective 370 371 Input Parameters: 372 + mengine - the MATLAB engine 373 . m,n - the dimensions of the array 374 . array - the array (represented in one dimension) 375 - name - the name of the array 376 377 Level: advanced 378 379 .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`, 380 `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`, 381 `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGet()`, `PetscMatlabEngine` 382 @*/ 383 PetscErrorCode PetscMatlabEngineGetArray(PetscMatlabEngine mengine,int m,int n,PetscScalar *array,const char name[]) 384 { 385 mxArray *mat; 386 387 PetscFunctionBegin; 388 PetscCheck(mengine,PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed"); 389 PetscCall(PetscInfo(0,"Getting MATLAB array %s\n",name)); 390 mat = engGetVariable(mengine->ep,name); 391 PetscCheck(mat,PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to get array %s from matlab",name); 392 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); 393 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); 394 PetscCall(PetscArraycpy(array,mxGetPr(mat),m*n)); 395 PetscCall(PetscInfo(0,"Got MATLAB array %s\n",name)); 396 PetscFunctionReturn(0); 397 } 398