Actual source code: matlab.c

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

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

     12: PetscClassId MATLABENGINE_CLASSID = -1;

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

     17:   Not Collective

     19:   Input Parameters:
     20: + comm - a separate MATLAB engine is started for each process in the communicator
     21: - host - name of machine where MATLAB engine is to be run (usually NULL)

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

     26:   Options Database Keys:
     27: + -matlab_engine_graphics - allow the MATLAB engine to display graphics
     28: . -matlab_engine_host     - hostname, machine to run the MATLAB engine on
     29: - -info                   - print out all requests to MATLAB and all if its responses (for debugging)

     31:   Level: advanced

     33:   Notes:
     34:   If a host string is passed in, any MATLAB scripts that need to run in the
     35:   engine must be available via MATLABPATH on that machine.

     37:   One must `./configure` PETSc with  `--with-matlab [-with-matlab-dir=matlab_root_directory]` to
     38:   use this capability

     40: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
     41:           `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
     42:           `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
     43: @*/
     44: PetscErrorCode PetscMatlabEngineCreate(MPI_Comm comm, const char host[], PetscMatlabEngine *mengine)
     45: {
     46:   PetscMPIInt       rank, size;
     47:   char              buffer[256];
     48:   PetscMatlabEngine e;
     49:   PetscBool         flg = PETSC_FALSE;
     50:   char              lhost[64];

     52:   PetscFunctionBegin;
     53:   PetscAssertPointer(mengine, 3);
     54:   if (MATLABENGINE_CLASSID == -1) PetscCall(PetscClassIdRegister("MATLAB Engine", &MATLABENGINE_CLASSID));

     56:   PetscCall(PetscHeaderCreate(e, MATLABENGINE_CLASSID, "MatlabEngine", "MATLAB Engine", "Sys", comm, PetscMatlabEngineDestroy, NULL));
     57:   if (!host) {
     58:     PetscCall(PetscOptionsGetString(NULL, NULL, "-matlab_engine_host", lhost, sizeof(lhost), &flg));
     59:     if (flg) host = lhost;
     60:   }
     61:   flg = PETSC_FALSE;
     62:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-matlab_engine_graphics", &flg, NULL));
     63:   if (host) {
     64:     PetscCall(PetscInfo(0, "Starting MATLAB engine on %s\n", host));
     65:     PetscCall(PetscStrncpy(buffer, "ssh ", sizeof(buffer)));
     66:     PetscCall(PetscStrlcat(buffer, host, sizeof(buffer)));
     67:     PetscCall(PetscStrlcat(buffer, " \"", sizeof(buffer)));
     68:     PetscCall(PetscStrlcat(buffer, PETSC_MATLAB_COMMAND, sizeof(buffer)));
     69:     if (!flg) PetscCall(PetscStrlcat(buffer, " -nodisplay ", sizeof(buffer)));
     70:     PetscCall(PetscStrlcat(buffer, " -nosplash ", sizeof(buffer)));
     71:     PetscCall(PetscStrlcat(buffer, "\"", sizeof(buffer)));
     72:   } else {
     73:     PetscCall(PetscStrncpy(buffer, PETSC_MATLAB_COMMAND, sizeof(buffer)));
     74:     if (!flg) PetscCall(PetscStrlcat(buffer, " -nodisplay ", sizeof(buffer)));
     75:     PetscCall(PetscStrlcat(buffer, " -nosplash ", sizeof(buffer)));
     76:   }
     77:   PetscCall(PetscInfo(0, "Starting MATLAB engine with command %s\n", buffer));
     78:   e->ep = engOpen(buffer);
     79:   PetscCheck(e->ep, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to start MATLAB engine with %s", buffer);
     80:   engOutputBuffer(e->ep, e->buffer, sizeof(e->buffer));
     81:   if (host) PetscCall(PetscInfo(0, "Started MATLAB engine on %s\n", host));
     82:   else PetscCall(PetscInfo(0, "Started MATLAB engine\n"));
     83:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
     84:   PetscCallMPI(MPI_Comm_size(comm, &size));
     85:   PetscCall(PetscMatlabEngineEvaluate(e, "MPI_Comm_rank = %d; MPI_Comm_size = %d;\n", rank, size));
     86:   /* work around bug in MATLAB R2021b https://www.mathworks.com/matlabcentral/answers/1566246-got-error-using-exit-in-nodesktop-mode */
     87:   PetscCall(PetscMatlabEngineEvaluate(e, "settings"));
     88:   *mengine = e;
     89:   PetscFunctionReturn(PETSC_SUCCESS);
     90: }

     92: /*@
     93:   PetscMatlabEngineDestroy - Shuts down a MATLAB engine.

     95:   Collective

     97:   Input Parameter:
     98: . v - the engine

    100:   Level: advanced

    102: .seealso: `PetscMatlabEngineCreate()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
    103:           `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
    104:           `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
    105: @*/
    106: PetscErrorCode PetscMatlabEngineDestroy(PetscMatlabEngine *v)
    107: {
    108:   int err;

    110:   PetscFunctionBegin;
    111:   if (!*v) PetscFunctionReturn(PETSC_SUCCESS);
    113:   if (--((PetscObject)*v)->refct > 0) PetscFunctionReturn(PETSC_SUCCESS);
    114:   PetscCall(PetscInfo(0, "Stopping MATLAB engine\n"));
    115:   err = engClose((*v)->ep);
    116:   PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error closing MATLAB engine");
    117:   PetscCall(PetscInfo(0, "MATLAB engine stopped\n"));
    118:   PetscCall(PetscHeaderDestroy(v));
    119:   PetscFunctionReturn(PETSC_SUCCESS);
    120: }

    122: /*@C
    123:   PetscMatlabEngineEvaluate - Evaluates a string in MATLAB

    125:   Not Collective

    127:   Input Parameters:
    128: + mengine - the MATLAB engine
    129: - string  - format as in a printf()

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

    134:   If the string utilizes a MATLAB script that needs to run in the engine, the script must be available via MATLABPATH on that machine.

    136:   Level: advanced

    138: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
    139:           `PetscMatlabEngineCreate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
    140:           `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
    141: @*/
    142: PetscErrorCode PetscMatlabEngineEvaluate(PetscMatlabEngine mengine, const char string[], ...)
    143: {
    144:   va_list Argp;
    145:   char    buffer[1024];
    146:   size_t  fullLength;

    148:   PetscFunctionBegin;
    149:   va_start(Argp, string);
    150:   PetscCall(PetscVSNPrintf(buffer, sizeof(buffer) - 9 - 5, string, &fullLength, Argp));
    151:   va_end(Argp);

    153:   PetscCall(PetscInfo(0, "Evaluating MATLAB string: %s\n", buffer));
    154:   engEvalString(mengine->ep, buffer);
    155:   PetscCall(PetscInfo(0, "Done evaluating MATLAB string: %s\n", buffer));
    156:   PetscCall(PetscInfo(0, "  MATLAB output message: %s\n", mengine->buffer));

    158:   /*
    159:      Check for error in MATLAB: indicated by ? as first character in engine->buffer
    160:   */
    161:   PetscCheck(mengine->buffer[4] != '?', PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in evaluating MATLAB command: %s %s", string, mengine->buffer);
    162:   PetscFunctionReturn(PETSC_SUCCESS);
    163: }

    165: /*@C
    166:   PetscMatlabEngineGetOutput - Gets a string buffer where the MATLAB output is
    167:   printed

    169:   Not Collective

    171:   Input Parameter:
    172: . mengine - the MATLAB engine

    174:   Output Parameter:
    175: . string - buffer where MATLAB output is printed

    177:   Level: advanced

    179: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
    180:           `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineCreate()`, `PetscMatlabEnginePrintOutput()`,
    181:           `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
    182: @*/
    183: PetscErrorCode PetscMatlabEngineGetOutput(PetscMatlabEngine mengine, const char *string[])
    184: {
    185:   PetscFunctionBegin;
    186:   PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed");
    187:   *string = mengine->buffer;
    188:   PetscFunctionReturn(PETSC_SUCCESS);
    189: }

    191: /*@C
    192:   PetscMatlabEnginePrintOutput - prints the output from MATLAB to an ASCII file

    194:   Collective

    196:   Input Parameters:
    197: + mengine - the MATLAB engine
    198: - fd      - the file

    200:   Level: advanced

    202: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
    203:           `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEngineCreate()`,
    204:           `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
    205: @*/
    206: PetscErrorCode PetscMatlabEnginePrintOutput(PetscMatlabEngine mengine, FILE *fd)
    207: {
    208:   PetscMPIInt rank;

    210:   PetscFunctionBegin;
    211:   PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed");
    212:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mengine), &rank));
    213:   PetscCall(PetscSynchronizedFPrintf(PetscObjectComm((PetscObject)mengine), fd, "[%d]%s", rank, mengine->buffer));
    214:   PetscCall(PetscSynchronizedFlush(PetscObjectComm((PetscObject)mengine), fd));
    215:   PetscFunctionReturn(PETSC_SUCCESS);
    216: }

    218: /*@
    219:   PetscMatlabEnginePut - Puts a PETSc object, such as a `Mat` or `Vec` into the MATLAB space. For parallel objects,
    220:   each processor's part is put in a separate  MATLAB process.

    222:   Collective

    224:   Input Parameters:
    225: + mengine - the MATLAB engine
    226: - obj     - the PETSc object, for example Vec

    228:   Level: advanced

    230:   Note:
    231:   `Mat`s transferred between PETSc and MATLAB and vis versa are transposed in the other space
    232:   (this is because MATLAB uses compressed column format and PETSc uses compressed row format)

    234: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`,
    235:           `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
    236:           `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
    237: @*/
    238: PetscErrorCode PetscMatlabEnginePut(PetscMatlabEngine mengine, PetscObject obj)
    239: {
    240:   PetscErrorCode (*put)(PetscObject, void *);

    242:   PetscFunctionBegin;
    243:   PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed");
    244:   PetscCall(PetscObjectQueryFunction(obj, "PetscMatlabEnginePut_C", &put));
    245:   PetscCheck(put, PETSC_COMM_SELF, PETSC_ERR_SUP, "Object %s cannot be put into MATLAB engine", obj->class_name);
    246:   PetscCall(PetscInfo(0, "Putting MATLAB object\n"));
    247:   PetscCall((*put)(obj, mengine->ep));
    248:   PetscCall(PetscInfo(0, "Put MATLAB object: %s\n", obj->name));
    249:   PetscFunctionReturn(PETSC_SUCCESS);
    250: }

    252: /*@
    253:   PetscMatlabEngineGet - Gets a variable from MATLAB into a PETSc object.

    255:   Collective

    257:   Input Parameters:
    258: + mengine - the MATLAB engine
    259: - obj     - the PETSc object, for example a `Vec`

    261:   Level: advanced

    263:   Note:
    264:   `Mat`s transferred between PETSc and MATLAB and vis versa are transposed in the other space
    265:   (this is because MATLAB uses compressed column format and PETSc uses compressed row format)

    267: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`,
    268:           `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
    269:           `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
    270: @*/
    271: PetscErrorCode PetscMatlabEngineGet(PetscMatlabEngine mengine, PetscObject obj)
    272: {
    273:   PetscErrorCode (*get)(PetscObject, void *);

    275:   PetscFunctionBegin;
    276:   PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed");
    277:   PetscCheck(obj->name, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot get object that has no name");
    278:   PetscCall(PetscObjectQueryFunction(obj, "PetscMatlabEngineGet_C", &get));
    279:   PetscCheck(get, PETSC_COMM_SELF, PETSC_ERR_SUP, "Object %s cannot be gotten from MATLAB engine", obj->class_name);
    280:   PetscCall(PetscInfo(0, "Getting MATLAB object\n"));
    281:   PetscCall((*get)(obj, mengine->ep));
    282:   PetscCall(PetscInfo(0, "Got MATLAB object: %s\n", obj->name));
    283:   PetscFunctionReturn(PETSC_SUCCESS);
    284: }

    286: /*
    287:     The variable Petsc_Matlab_Engine_keyval is used to indicate an MPI attribute that
    288:   is attached to a communicator, in this case the attribute is a PetscMatlabEngine
    289: */
    290: static PetscMPIInt Petsc_Matlab_Engine_keyval = MPI_KEYVAL_INVALID;

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

    295:    Not Collective

    297:    Input Parameter:
    298: .  comm - the MPI communicator to share the engine

    300:    Options Database Key:
    301: .  -matlab_engine_host - hostname on which to run MATLAB, one must be able to ssh to this host

    303:    Level: developer

    305:    Note:
    306:    Unlike almost all other PETSc routines, this does not return
    307:    an error code. Usually used in the form
    308: .vb
    309:   PetscMatlabEngineYYY(XXX object, PETSC_MATLAB_ENGINE_(comm));
    310: .ve

    312: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
    313:           `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
    314:           `PetscMatlabEngineCreate()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`,
    315:           `PETSC_MATLAB_ENGINE_WORLD`, `PETSC_MATLAB_ENGINE_SELF`
    316: @*/
    317: PetscMatlabEngine PETSC_MATLAB_ENGINE_(MPI_Comm comm)
    318: {
    319:   PetscErrorCode    ierr;
    320:   PetscMPIInt       iflg;
    321:   PetscMatlabEngine mengine;

    323:   PetscFunctionBegin;
    324:   if (Petsc_Matlab_Engine_keyval == MPI_KEYVAL_INVALID) {
    325:     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Matlab_Engine_keyval, 0);
    326:     if (ierr) {
    327:       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
    328:       PetscFunctionReturn(NULL);
    329:     }
    330:   }
    331:   ierr = MPI_Comm_get_attr(comm, Petsc_Matlab_Engine_keyval, (void **)&mengine, &iflg);
    332:   if (ierr) {
    333:     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
    334:     PetscFunctionReturn(NULL);
    335:   }
    336:   if (!iflg) { /* viewer not yet created */
    337:     ierr = PetscMatlabEngineCreate(comm, NULL, &mengine);
    338:     if (ierr) {
    339:       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
    340:       PetscFunctionReturn(NULL);
    341:     }
    342:     ierr = PetscObjectRegisterDestroy((PetscObject)mengine);
    343:     if (ierr) {
    344:       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
    345:       PetscFunctionReturn(NULL);
    346:     }
    347:     ierr = MPI_Comm_set_attr(comm, Petsc_Matlab_Engine_keyval, mengine);
    348:     if (ierr) {
    349:       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
    350:       PetscFunctionReturn(NULL);
    351:     }
    352:   }
    353:   PetscFunctionReturn(mengine);
    354: }

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

    360:   Collective

    362:   Input Parameters:
    363: + mengine - the MATLAB engine
    364: . m       - the x dimension of the array
    365: . n       - the y dimension of the array
    366: . array   - the array (represented in one dimension)
    367: - name    - the name of the array

    369:   Level: advanced

    371: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`,
    372:           `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
    373:           `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
    374: @*/
    375: PetscErrorCode PetscMatlabEnginePutArray(PetscMatlabEngine mengine, int m, int n, const PetscScalar array[], const char name[])
    376: {
    377:   mxArray *mat;

    379:   PetscFunctionBegin;
    380:   PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed");
    381:   PetscCall(PetscInfo(0, "Putting MATLAB array %s\n", name));
    382: #if !defined(PETSC_USE_COMPLEX)
    383:   mat = mxCreateDoubleMatrix(m, n, mxREAL);
    384: #else
    385:   mat = mxCreateDoubleMatrix(m, n, mxCOMPLEX);
    386: #endif
    387:   PetscCall(PetscArraycpy(mxGetPr(mat), array, m * n));
    388:   engPutVariable(mengine->ep, name, mat);

    390:   PetscCall(PetscInfo(0, "Put MATLAB array %s\n", name));
    391:   PetscFunctionReturn(PETSC_SUCCESS);
    392: }

    394: /*@
    395:   PetscMatlabEngineGetArray - Gets a variable from MATLAB into an array

    397:   Not Collective

    399:   Input Parameters:
    400: + mengine - the MATLAB engine
    401: . m       - the x dimension of the array
    402: . n       - the y dimension of the array
    403: . array   - the array (represented in one dimension), much be large enough to hold all the data
    404: - name    - the name of the array

    406:   Level: advanced

    408: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`,
    409:           `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
    410:           `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGet()`, `PetscMatlabEngine`
    411: @*/
    412: PetscErrorCode PetscMatlabEngineGetArray(PetscMatlabEngine mengine, int m, int n, PetscScalar array[], const char name[])
    413: {
    414:   mxArray *mat;

    416:   PetscFunctionBegin;
    417:   PetscCheck(mengine, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_MATLAB_ENGINE_() failed");
    418:   PetscCall(PetscInfo(0, "Getting MATLAB array %s\n", name));
    419:   mat = engGetVariable(mengine->ep, name);
    420:   PetscCheck(mat, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to get array %s from matlab", name);
    421:   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);
    422:   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);
    423:   PetscCall(PetscArraycpy(array, mxGetPr(mat), m * n));
    424:   PetscCall(PetscInfo(0, "Got MATLAB array %s\n", name));
    425:   PetscFunctionReturn(PETSC_SUCCESS);
    426: }