Date: 2022-03-04T17:37:04+00:00

Actual source code: matlab.c

      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;

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

    300:    Not Collective

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

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

    308:    Level: developer

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

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

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

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

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

    349:     Collective on PetscObject

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

    357:    Level: advanced

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

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

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

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

    386:     Not Collective

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

    394:    Level: advanced

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

    406:   if (!mengine) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
    407:   PetscInfo1(0,"Getting MATLAB array %s\n",name);
    408:   mat  = engGetVariable(mengine->ep,name);
    409:   if (!mat) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to get array %s from matlab",name);
    410:   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);
    411:   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);
    412:   PetscArraycpy(array,mxGetPr(mat),m*n);
    413:   PetscInfo1(0,"Got MATLAB array %s\n",name);
    414:   return(0);
    415: }