Actual source code: vmatlab.c

  1: #include <petsc/private/viewerimpl.h>
  2: #include <mat.h>                      /*I    "petscmat.h"      I*/

  4: typedef struct {
  5:   MATFile      *ep;
  6:   PetscMPIInt   rank;
  7:   PetscFileMode btype;
  8: } PetscViewer_Matlab;

 10: /*@
 11:   PetscViewerMatlabPutArray - Puts an array into the `PETSCVIEWERMATLAB` viewer.

 13:   Not Collective, only processor zero saves `array`

 15:   Input Parameters:
 16: + mfile - the viewer
 17: . m     - the first dimensions of `array`
 18: . n     - the second dimensions of `array`
 19: . array - the array (represented in one dimension)
 20: - name  - the MATLAB name of `array`

 22:   Level: advanced

 24:   Note:
 25:   Only writes `array` values on processor 0.

 27: .seealso: `PETSCVIEWERMATLAB`, `PetscViewerMatlabGetArray()`
 28: @*/
 29: PetscErrorCode PetscViewerMatlabPutArray(PetscViewer mfile, int m, int n, const PetscScalar *array, const char *name)
 30: {
 31:   PetscViewer_Matlab *ml;
 32:   mxArray            *mat;

 34:   PetscFunctionBegin;
 35:   PetscCheck(mfile, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_VIEWER_MATLAB_() failed");
 36:   ml = (PetscViewer_Matlab *)mfile->data;
 37:   if (!ml->rank) {
 38:     PetscCall(PetscInfo(mfile, "Putting MATLAB array %s\n", name));
 39: #if !defined(PETSC_USE_COMPLEX)
 40:     mat = mxCreateDoubleMatrix(m, n, mxREAL);
 41: #else
 42:     mat = mxCreateDoubleMatrix(m, n, mxCOMPLEX);
 43: #endif
 44:     PetscCall(PetscArraycpy(mxGetPr(mat), array, m * n));
 45:     matPutVariable(ml->ep, name, mat);

 47:     PetscCall(PetscInfo(mfile, "Put MATLAB array %s\n", name));
 48:   }
 49:   PetscFunctionReturn(PETSC_SUCCESS);
 50: }

 52: /*@C
 53:   PetscViewerMatlabPutVariable - Write a raw MATLAB `mxArray` variable into a `PETSCVIEWERMATLAB` file under a chosen name.

 55:   Not Collective; only processor zero writes the variable

 57:   Input Parameters:
 58: + viewer - the `PETSCVIEWERMATLAB` viewer
 59: . name   - the MATLAB variable name
 60: - mat    - the `mxArray *` variable to write (cast to `void *`)

 62:   Level: advanced

 64: .seealso: `PetscViewer`, `PETSCVIEWERMATLAB`, `PetscViewerMatlabPutArray()`, `PetscViewerMatlabGetArray()`, `PetscViewerMatlabOpen()`
 65: @*/
 66: PetscErrorCode PetscViewerMatlabPutVariable(PetscViewer viewer, const char *name, void *mat)
 67: {
 68:   PetscViewer_Matlab *ml = (PetscViewer_Matlab *)viewer->data;

 70:   PetscFunctionBegin;
 71:   matPutVariable(ml->ep, name, (mxArray *)mat);
 72:   PetscFunctionReturn(PETSC_SUCCESS);
 73: }

 75: /*@
 76:   PetscViewerMatlabGetArray - Gets a variable from a `PETSCVIEWERMATLAB` viewer into an array

 78:   Not Collective; only processor zero reads in the array

 80:   Input Parameters:
 81: + mfile - the MATLAB file viewer
 82: . m     - the first dimensions of `array`
 83: . n     - the second dimensions of `array`
 84: . array - the array (represented in one dimension), must of be length `m` * `n`
 85: - name  - the MATLAB name of `array`

 87:   Level: advanced

 89:   Note:
 90:   Only reads in `array` values on processor 0.

 92: .seealso: `PETSCVIEWERMATLAB`, `PetscViewerMatlabPutArray()`
 93: @*/
 94: PetscErrorCode PetscViewerMatlabGetArray(PetscViewer mfile, int m, int n, PetscScalar array[], const char *name)
 95: {
 96:   PetscViewer_Matlab *ml;
 97:   mxArray            *mat;

 99:   PetscFunctionBegin;
100:   PetscCheck(mfile, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_VIEWER_MATLAB_() failed");
101:   ml = (PetscViewer_Matlab *)mfile->data;
102:   if (!ml->rank) {
103:     PetscCall(PetscInfo(mfile, "Getting MATLAB array %s\n", name));
104:     mat = matGetVariable(ml->ep, name);
105:     PetscCheck(mat, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to get array %s from matlab", name);
106:     PetscCall(PetscArraycpy(array, mxGetPr(mat), m * n));
107:     PetscCall(PetscInfo(mfile, "Got MATLAB array %s\n", name));
108:   }
109:   PetscFunctionReturn(PETSC_SUCCESS);
110: }

112: static PetscErrorCode PetscViewerFileSetMode_Matlab(PetscViewer viewer, PetscFileMode type)
113: {
114:   PetscViewer_Matlab *vmatlab = (PetscViewer_Matlab *)viewer->data;

116:   PetscFunctionBegin;
117:   vmatlab->btype = type;
118:   PetscFunctionReturn(PETSC_SUCCESS);
119: }

121: /*
122:         Actually opens the file
123: */
124: static PetscErrorCode PetscViewerFileSetName_Matlab(PetscViewer viewer, const char name[])
125: {
126:   PetscViewer_Matlab *vmatlab = (PetscViewer_Matlab *)viewer->data;
127:   PetscFileMode       type    = vmatlab->btype;

129:   PetscFunctionBegin;
130:   PetscCheck(type != (PetscFileMode)-1, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
131:   if (vmatlab->ep) matClose(vmatlab->ep);

133:   /* only first processor opens file */
134:   if (!vmatlab->rank) {
135:     if (type == FILE_MODE_READ) vmatlab->ep = matOpen(name, "r");
136:     else if (type == FILE_MODE_WRITE) vmatlab->ep = matOpen(name, "w");
137:     else {
138:       PetscCheck(type != FILE_MODE_UNDEFINED, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
139:       SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[type]);
140:     }
141:   }
142:   PetscFunctionReturn(PETSC_SUCCESS);
143: }

145: static PetscErrorCode PetscViewerDestroy_Matlab(PetscViewer v)
146: {
147:   PetscViewer_Matlab *vf = (PetscViewer_Matlab *)v->data;

149:   PetscFunctionBegin;
150:   if (vf->ep) matClose(vf->ep);
151:   PetscCall(PetscFree(vf));
152:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetName_C", NULL));
153:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetMode_C", NULL));
154:   PetscFunctionReturn(PETSC_SUCCESS);
155: }

157: /*MC
158:    PETSCVIEWERMATLAB - A viewer that saves the variables into a MATLAB .mat file that may be read into MATLAB
159:        with load('filename').

161:    Level: intermediate

163:        Notes:
164:              Currently can only save PETSc vectors to .mat files, not matrices (use the `PETSCVIEWERBINARY` and
165:              ${PETSC_DIR}/share/petsc/matlab/PetscBinaryRead.m to read matrices into MATLAB).

167:              For parallel vectors obtained with `DMCreateGlobalVector()` or `DMGetGlobalVector()` the vectors are saved to
168:              the .mat file in natural ordering. You can use DMView() to save the `DMDA` information to the .mat file
169:              the fields in the MATLAB loaded da variable give the array dimensions so you can reshape the MATLAB
170:              vector to the same multidimensional shape as it had in PETSc for plotting etc. For example,

172:              In your PETSc C/C++ code (assuming a two dimensional `DMDA` with one degree of freedom per node)
173: .vb
174:                 PetscObjectSetName((PetscObject)x,"x");
175:                 VecView(x,PETSC_VIEWER_MATLAB_WORLD);
176:                 PetscObjectSetName((PetscObject)da,"da");
177:                 DMView(x,PETSC_VIEWER_MATLAB_WORLD);
178: .ve
179:              Then from MATLAB
180: .vb
181:                 load('matlaboutput.mat')   % matlaboutput.mat is the default filename
182:                 xnew = zeros(da.n,da.m);
183:                 xnew(:) = x;    % reshape one dimensional vector back to two dimensions
184: .ve

186:               If you wish to put the same variable into the .mat file several times you need to give it a new
187:               name before each call to view.

189:               Use `PetscViewerMatlabPutArray()` to just put an array of doubles into the .mat file

191: .seealso: `PETSC_VIEWER_MATLAB_()`, `PETSC_VIEWER_MATLAB_SELF`, `PETSC_VIEWER_MATLAB_WORLD`, `PetscViewerCreate()`,
192:           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERASCII`, `PETSCVIEWERDRAW`,
193:           `PETSC_VIEWER_STDOUT_()`, `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscMatlabEngine`
194: M*/
195: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Matlab(PetscViewer viewer)
196: {
197:   PetscViewer_Matlab *e;

199:   PetscFunctionBegin;
200:   PetscCall(PetscNew(&e));
201:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &e->rank));
202:   e->btype     = FILE_MODE_UNDEFINED;
203:   viewer->data = (void *)e;

205:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_Matlab));
206:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_Matlab));

208:   viewer->ops->destroy = PetscViewerDestroy_Matlab;
209:   PetscFunctionReturn(PETSC_SUCCESS);
210: }

212: /*@
213:   PetscViewerMatlabOpen - Opens a MATLAB .mat file for output

215:   Collective

217:   Input Parameters:
218: + comm - MPI communicator
219: . name - name of file
220: - type - type of file
221: .vb
222:     FILE_MODE_WRITE - create new file for MATLAB output
223:     FILE_MODE_READ - open existing file for MATLAB input
224:     FILE_MODE_WRITE - open existing file for MATLAB output
225: .ve

227:   Output Parameter:
228: . binv - PetscViewer for MATLAB output to use with the specified file

230:   Level: beginner

232:   Notes:
233:   This `PetscViewer` should be destroyed with `PetscViewerDestroy()`.

235:   For writing files it only opens the file on processor 0 in the communicator.

237:   This only saves `Vec`s it cannot be used to save `Mat`s. We recommend using the `PETSCVIEWERBINARY` to save objects to be loaded into MATLAB
238:   instead of this routine.

240:   PETSc must be configured with the option `--with-matlab` for this functionality

242: .seealso: `PETSCVIEWERMATLAB`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`,
243:           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`
244: @*/
245: PetscErrorCode PetscViewerMatlabOpen(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *binv)
246: {
247:   PetscFunctionBegin;
248:   PetscCall(PetscViewerCreate(comm, binv));
249:   PetscCall(PetscViewerSetType(*binv, PETSCVIEWERMATLAB));
250:   PetscCall(PetscViewerFileSetMode(*binv, type));
251:   PetscCall(PetscViewerFileSetName(*binv, name));
252:   PetscFunctionReturn(PETSC_SUCCESS);
253: }

255: static PetscMPIInt Petsc_Viewer_Matlab_keyval = MPI_KEYVAL_INVALID;

257: /*@C
258:    PETSC_VIEWER_MATLAB_ - Creates a `PETSCVIEWERMATLAB` `PetscViewer` shared by all processors
259:    in a communicator.

261:    Collective

263:    Input Parameter:
264: .  comm - the MPI communicator to share the MATLAB `PetscViewer`

266:    Options Database Key:
267: .    -viewer_matlab_filename name - name of the MATLAB file

269:    Environmental variable:
270: .  `PETSC_VIEWER_MATLAB_FILENAME` - name of the MATLAB file

272:    Level: intermediate

274:    Notes:
275:    This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it

277:    Unlike almost all other PETSc routines, `PETSC_VIEWER_MATLAB_()` does not return
278:    an error code.  The MATLAB `PetscViewer` is usually used in the form `XXXView(XXX object, PETSC_VIEWER_MATLAB_(comm))`

280:    Use `PETSC_VIEWER_SOCKET_()` or `PetscViewerSocketOpen()` to communicator with an interactive MATLAB session.

282: .seealso: `PETSC_VIEWER_MATLAB_WORLD`, `PETSC_VIEWER_MATLAB_SELF`, `PetscViewerMatlabOpen()`, `PetscViewerCreate()`,
283:           `PetscViewerDestroy()`
284: @*/
285: PetscViewer PETSC_VIEWER_MATLAB_(MPI_Comm comm)
286: {
287:   PetscBool   flg;
288:   PetscMPIInt iflg;
289:   PetscViewer viewer;
290:   char        fname[PETSC_MAX_PATH_LEN];
291:   MPI_Comm    ncomm;

293:   PetscFunctionBegin;
294:   PetscCallNull(PetscCommDuplicate(comm, &ncomm, NULL));
295:   if (Petsc_Viewer_Matlab_keyval == MPI_KEYVAL_INVALID) PetscCallMPINull(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Matlab_keyval, 0));
296:   PetscCallMPINull(MPI_Comm_get_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void **)&viewer, &iflg));
297:   if (!iflg) { /* PetscViewer not yet created */
298:     PetscCallNull(PetscOptionsGetenv(ncomm, "PETSC_VIEWER_MATLAB_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg));
299:     if (!flg) PetscCallNull(PetscStrncpy(fname, "matlaboutput.mat", sizeof(fname)));
300:     PetscCallNull(PetscViewerMatlabOpen(ncomm, fname, FILE_MODE_WRITE, &viewer));
301:     PetscCallNull(PetscObjectRegisterDestroy((PetscObject)viewer));
302:     PetscCallMPINull(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void *)viewer));
303:   }
304:   PetscCallNull(PetscCommDestroy(&ncomm));
305:   PetscFunctionReturn(viewer);
306: }