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