Actual source code: matlab.c

petsc-master 2020-12-03
Report Typos and Errors

  2: #include <engine.h>   /* MATLAB include file */
  3: #include <petscsys.h>
  4: #include <petscmatlab.h>
  5: #include <petsc/private/petscimpl.h>

  7: struct  _p_PetscMatlabEngine {
  8:   PETSCHEADER(int);
  9:   Engine *ep;
 10:   char   buffer[1024];
 11: };

 13: PetscClassId MATLABENGINE_CLASSID = -1;

 15: /*@C
 16:     PetscMatlabEngineCreate - Creates a MATLAB engine object

 18:     Not Collective

 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)

 24:     Output Parameter:
 25: .   mengine - the resulting object

 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)

 32:    Level: advanced

 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:   PetscErrorCode    ierr;
 41:   PetscMPIInt       rank,size;
 42:   char              buffer[256];
 43:   PetscMatlabEngine e;
 44:   PetscBool         flg = PETSC_FALSE;

 47:   if (MATLABENGINE_CLASSID == -1) {
 48:     PetscClassIdRegister("MATLAB Engine",&MATLABENGINE_CLASSID);
 49:   }
 50:   PetscHeaderCreate(e,MATLABENGINE_CLASSID,"MatlabEngine","MATLAB Engine","Sys",comm,PetscMatlabEngineDestroy,NULL);

 52:   if (!host) {
 53:     char lhost[64];

 55:     PetscOptionsGetString(NULL,NULL,"-matlab_engine_host",lhost,sizeof(lhost),&flg);
 56:     if (flg) {host = lhost;}
 57:   }
 58:   flg = PETSC_FALSE;
 59:   PetscOptionsGetBool(NULL,NULL,"-matlab_engine_graphics",&flg,NULL);

 61:   if (host) {
 62:     PetscInfo1(0,"Starting MATLAB engine on %s\n",host);
 63:   } else {

 65:   }
 66:   if (host) {
 67:     PetscStrcpy(buffer,"ssh ");
 68:     PetscStrcat(buffer,host);
 69:     PetscStrcat(buffer," \"");
 70:     PetscStrlcat(buffer,PETSC_MATLAB_COMMAND,sizeof(buffer));
 71:     if (!flg) {
 72:       PetscStrlcat(buffer," -nodisplay ",sizeof(buffer));
 73:     }
 74:     PetscStrlcat(buffer," -nosplash ",sizeof(buffer));
 75:     PetscStrcat(buffer,"\"");
 76:   } else {
 77:     PetscStrncpy(buffer,PETSC_MATLAB_COMMAND,sizeof(buffer));
 78:     if (!flg) {
 79:       PetscStrlcat(buffer," -nodisplay ",sizeof(buffer));
 80:     }
 81:     PetscStrlcat(buffer," -nosplash ",sizeof(buffer));
 82:   }
 83:   PetscInfo1(0,"Starting MATLAB engine with command %s\n",buffer);
 84:   e->ep = engOpen(buffer);
 85:   if (!e->ep) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to start MATLAB engine with %s",buffer);
 86:   engOutputBuffer(e->ep,e->buffer,sizeof(e->buffer));
 87:   if (host) {
 88:     PetscInfo1(0,"Started MATLAB engine on %s\n",host);
 89:   } else {
 90:     PetscInfo(0,"Started MATLAB engine\n");
 91:   }

 93:   MPI_Comm_rank(comm,&rank);
 94:   MPI_Comm_size(comm,&size);
 95:   PetscMatlabEngineEvaluate(e,"MPI_Comm_rank = %d; MPI_Comm_size = %d;\n",rank,size);
 96:   *mengine = e;
 97:   return(0);
 98: }

100: /*@
101:    PetscMatlabEngineDestroy - Shuts down a MATLAB engine.

103:    Collective on PetscMatlabEngine

105:    Input Parameters:
106: .  e  - the engine

108:    Level: advanced

110: .seealso: PetscMatlabEngineCreate(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
111:           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
112:           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
113: @*/
114: PetscErrorCode  PetscMatlabEngineDestroy(PetscMatlabEngine *v)
115: {

119:   if (!*v) return(0);
121:   if (--((PetscObject)(*v))->refct > 0) return(0);
122:   PetscInfo(0,"Stopping MATLAB engine\n");
123:   engClose((*v)->ep);
124:   if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error closing Matlab engine");
125:   PetscInfo(0,"MATLAB engine stopped\n");
126:   PetscHeaderDestroy(v);
127:   return(0);
128: }

130: /*@C
131:     PetscMatlabEngineEvaluate - Evaluates a string in MATLAB

133:     Not Collective

135:     Input Parameters:
136: +   mengine - the MATLAB engine
137: -   string - format as in a printf()

139:    Notes:
140:      Run the PETSc program with -info to always have printed back MATLAB's response to the string evaluation

142:    Level: advanced

144: .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
145:           PetscMatlabEngineCreate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
146:           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
147: @*/
148: PetscErrorCode  PetscMatlabEngineEvaluate(PetscMatlabEngine mengine,const char string[],...)
149: {
150:   va_list        Argp;
151:   char           buffer[1024];
153:   size_t         fullLength;

156:   va_start(Argp,string);
157:   PetscVSNPrintf(buffer,sizeof(buffer)-9-5,string,&fullLength,Argp);
158:   va_end(Argp);

160:   PetscInfo1(0,"Evaluating MATLAB string: %s\n",buffer);
161:   engEvalString(mengine->ep, buffer);
162:   PetscInfo1(0,"Done evaluating MATLAB string: %s\n",buffer);
163:   PetscInfo1(0,"  MATLAB output message: %s\n",mengine->buffer);

165:   /*
166:      Check for error in MATLAB: indicated by ? as first character in engine->buffer
167:   */
168:   if (mengine->buffer[4] == '?') SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in evaluating MATLAB command:%s\n%s",string,mengine->buffer);
169:   return(0);
170: }

172: /*@C
173:     PetscMatlabEngineGetOutput - Gets a string buffer where the MATLAB output is
174:           printed

176:     Not Collective

178:     Input Parameter:
179: .   mengine - the MATLAB engine

181:     Output Parameter:
182: .   string - buffer where MATLAB output is printed

184:    Level: advanced

186: .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
187:           PetscMatlabEngineEvaluate(), PetscMatlabEngineCreate(), PetscMatlabEnginePrintOutput(),
188:           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
189: @*/
190: PetscErrorCode  PetscMatlabEngineGetOutput(PetscMatlabEngine mengine,char **string)
191: {
193:   if (!mengine) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
194:   *string = mengine->buffer;
195:   return(0);
196: }

198: /*@C
199:     PetscMatlabEnginePrintOutput - prints the output from MATLAB

201:     Collective on PetscMatlabEngine

203:     Input Parameters:
204: .    mengine - the Matlab engine

206:    Level: advanced

208: .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
209:           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEngineCreate(),
210:           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
211: @*/
212: PetscErrorCode  PetscMatlabEnginePrintOutput(PetscMatlabEngine mengine,FILE *fd)
213: {
215:   PetscMPIInt    rank;

218:   if (!mengine) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
219:   MPI_Comm_rank(PetscObjectComm((PetscObject)mengine),&rank);
220:   PetscSynchronizedFPrintf(PetscObjectComm((PetscObject)mengine),fd,"[%d]%s",rank,mengine->buffer);
221:   PetscSynchronizedFlush(PetscObjectComm((PetscObject)mengine),fd);
222:   return(0);
223: }

225: /*@
226:     PetscMatlabEnginePut - Puts a Petsc object into the MATLAB space. For parallel objects,
227:       each processors part is put in a separate  MATLAB process.

229:     Collective on PetscObject

231:     Input Parameters:
232: +    mengine - the MATLAB engine
233: -    object - the PETSc object, for example Vec

235:    Level: advanced

237:    Note: Mats transferred between PETSc and MATLAB and vis versa are transposed in the other space
238:          (this is because MATLAB uses compressed column format and PETSc uses compressed row format)

240: .seealso: PetscMatlabEngineDestroy(), PetscMatlabEngineCreate(), PetscMatlabEngineGet(),
241:           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
242:           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
243: @*/
244: PetscErrorCode  PetscMatlabEnginePut(PetscMatlabEngine mengine,PetscObject obj)
245: {
246:   PetscErrorCode ierr,(*put)(PetscObject,void*);

249:   if (!mengine) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
250:   PetscObjectQueryFunction(obj,"PetscMatlabEnginePut_C",&put);
251:   if (!put) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Object %s cannot be put into MATLAB engine",obj->class_name);
252:   PetscInfo(0,"Putting MATLAB object\n");
253:   (*put)(obj,mengine->ep);
254:   PetscInfo1(0,"Put MATLAB object: %s\n",obj->name);
255:   return(0);
256: }

258: /*@
259:     PetscMatlabEngineGet - Gets a variable from MATLAB into a PETSc object.

261:     Collective on PetscObject

263:     Input Parameters:
264: +    mengine - the MATLAB engine
265: -    object - the PETSc object, for example Vec

267:    Level: advanced

269:    Note: Mats transferred between PETSc and MATLAB and vis versa are transposed in the other space
270:          (this is because MATLAB uses compressed column format and PETSc uses compressed row format)

272: .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineCreate(),
273:           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
274:           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
275: @*/
276: PetscErrorCode  PetscMatlabEngineGet(PetscMatlabEngine mengine,PetscObject obj)
277: {
278:   PetscErrorCode ierr,(*get)(PetscObject,void*);

281:   if (!mengine) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
282:   if (!obj->name) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Cannot get object that has no name");
283:   PetscObjectQueryFunction(obj,"PetscMatlabEngineGet_C",&get);
284:   if (!get) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Object %s cannot be gotten from MATLAB engine",obj->class_name);
285:   PetscInfo(0,"Getting MATLAB object\n");
286:   (*get)(obj,mengine->ep);
287:   PetscInfo1(0,"Got MATLAB object: %s\n",obj->name);
288:   return(0);
289: }

291: /*
292:     The variable Petsc_Matlab_Engine_keyval is used to indicate an MPI attribute that
293:   is attached to a communicator, in this case the attribute is a PetscMatlabEngine
294: */
295: static PetscMPIInt Petsc_Matlab_Engine_keyval = MPI_KEYVAL_INVALID;


298: /*@C
299:    PETSC_MATLAB_ENGINE_ - Creates a MATLAB engine on each process in a communicator.

301:    Not Collective

303:    Input Parameter:
304: .  comm - the MPI communicator to share the engine

306:    Options Database:
307: .  -matlab_engine_host - hostname

309:    Level: developer

311:    Notes:
312:    Unlike almost all other PETSc routines, this does not return
313:    an error code. Usually used in the form
314: $      PetscMatlabEngineYYY(XXX object,PETSC_MATLAB_ENGINE_(comm));

316: .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
317:           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
318:           PetscMatlabEngineCreate(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine,
319:           PETSC_MATLAB_ENGINE_WORLD, PETSC_MATLAB_ENGINE_SELF

321: @*/
322: PetscMatlabEngine  PETSC_MATLAB_ENGINE_(MPI_Comm comm)
323: {
324:   PetscErrorCode    ierr;
325:   PetscBool         flg;
326:   PetscMatlabEngine mengine;

329:   if (Petsc_Matlab_Engine_keyval == MPI_KEYVAL_INVALID) {
330:     MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Matlab_Engine_keyval,0);
331:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
332:   }
333:   MPI_Comm_get_attr(comm,Petsc_Matlab_Engine_keyval,(void**)&mengine,(int*)&flg);
334:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
335:   if (!flg) { /* viewer not yet created */
336:     PetscMatlabEngineCreate(comm,NULL,&mengine);
337:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
338:     PetscObjectRegisterDestroy((PetscObject)mengine);
339:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
340:     MPI_Comm_set_attr(comm,Petsc_Matlab_Engine_keyval,mengine);
341:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
342:   }
343:   PetscFunctionReturn(mengine);
344: }

346: /*@C
347:     PetscMatlabEnginePutArray - Puts an array into the MATLAB space, treating it as a Fortran style (column major ordering) array. For parallel objects,
348:       each processors part is put in a separate  MATLAB process.

350:     Collective on PetscObject

352:     Input Parameters:
353: +    mengine - the MATLAB engine
354: .    m,n - the dimensions of the array
355: .    array - the array (represented in one dimension)
356: -    name - the name of the array

358:    Level: advanced

360: .seealso: PetscMatlabEngineDestroy(), PetscMatlabEngineCreate(), PetscMatlabEngineGet(),
361:           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
362:           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePut(), PetscMatlabEngineGetArray(), PetscMatlabEngine
363: @*/
364: PetscErrorCode  PetscMatlabEnginePutArray(PetscMatlabEngine mengine,int m,int n,const PetscScalar *array,const char name[])
365: {
367:   mxArray        *mat;

370:   if (!mengine) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
371:   PetscInfo1(0,"Putting MATLAB array %s\n",name);
372: #if !defined(PETSC_USE_COMPLEX)
373:   mat = mxCreateDoubleMatrix(m,n,mxREAL);
374: #else
375:   mat = mxCreateDoubleMatrix(m,n,mxCOMPLEX);
376: #endif
377:   PetscArraycpy(mxGetPr(mat),array,m*n);
378:   engPutVariable(mengine->ep,name,mat);

380:   PetscInfo1(0,"Put MATLAB array %s\n",name);
381:   return(0);
382: }

384: /*@C
385:     PetscMatlabEngineGetArray - Gets a variable from MATLAB into an array

387:     Not Collective

389:     Input Parameters:
390: +    mengine - the MATLAB engine
391: .    m,n - the dimensions of the array
392: .    array - the array (represented in one dimension)
393: -    name - the name of the array

395:    Level: advanced

397: .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineCreate(),
398:           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
399:           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGet(), PetscMatlabEngine
400: @*/
401: PetscErrorCode  PetscMatlabEngineGetArray(PetscMatlabEngine mengine,int m,int n,PetscScalar *array,const char name[])
402: {
404:   mxArray        *mat;

407:   if (!mengine) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
408:   PetscInfo1(0,"Getting MATLAB array %s\n",name);
409:   mat  = engGetVariable(mengine->ep,name);
410:   if (!mat) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to get array %s from matlab",name);
411:   if (mxGetM(mat) != (size_t) m) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_LIB,"Array %s in MATLAB first dimension %d does not match requested size %d",name,(int)mxGetM(mat),m);
412:   if (mxGetN(mat) != (size_t) n) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_LIB,"Array %s in MATLAB second dimension %d does not match requested size %d",name,(int)mxGetN(mat),m);
413:   PetscArraycpy(array,mxGetPr(mat),m*n);
414:   PetscInfo1(0,"Got MATLAB array %s\n",name);
415:   return(0);
416: }