Actual source code: vmatlab.c


  2: #include <petsc/private/viewerimpl.h>
  3: #include <mat.h>

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

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

 14:       Not Collective: only processor zero saves `array`

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

 23:    Level: advanced

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

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

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

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

 53: PetscErrorCode PetscViewerMatlabPutVariable(PetscViewer viewer, const char *name, void *mat)
 54: {
 55:   PetscViewer_Matlab *ml = (PetscViewer_Matlab *)viewer->data;

 57:   PetscFunctionBegin;
 58:   matPutVariable(ml->ep, name, (mxArray *)mat);
 59:   PetscFunctionReturn(PETSC_SUCCESS);
 60: }

 62: /*@C
 63:     PetscViewerMatlabGetArray - Gets a variable from a `PETSCVIEWERMATLAB` viewer into an array

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

 67:     Input Parameters:
 68: +    mfile - the MATLAB file viewer
 69: .    m - the first dimensions of `array`
 70: .    n - the second dimensions of `array`
 71: .    array - the array (represented in one dimension)
 72: -    name - the MATLAB name of `array`

 74:    Level: advanced

 76:     Note:
 77:     Only reads in `array` values on processor 0.

 79: .seealso: `PETSCVIEWERMATLAB`, `PetscViewerMatlabPutArray()`
 80: @*/
 81: PetscErrorCode PetscViewerMatlabGetArray(PetscViewer mfile, int m, int n, PetscScalar *array, const char *name)
 82: {
 83:   PetscViewer_Matlab *ml;
 84:   mxArray            *mat;

 86:   PetscFunctionBegin;
 87:   PetscCheck(mfile, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_VIEWER_MATLAB_() failed");
 88:   ml = (PetscViewer_Matlab *)mfile->data;
 89:   if (!ml->rank) {
 90:     PetscCall(PetscInfo(mfile, "Getting MATLAB array %s\n", name));
 91:     mat = matGetVariable(ml->ep, name);
 92:     PetscCheck(mat, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to get array %s from matlab", name);
 93:     PetscCall(PetscArraycpy(array, mxGetPr(mat), m * n));
 94:     PetscCall(PetscInfo(mfile, "Got MATLAB array %s\n", name));
 95:   }
 96:   PetscFunctionReturn(PETSC_SUCCESS);
 97: }

 99: PetscErrorCode PetscViewerFileSetMode_Matlab(PetscViewer viewer, PetscFileMode type)
100: {
101:   PetscViewer_Matlab *vmatlab = (PetscViewer_Matlab *)viewer->data;

103:   PetscFunctionBegin;
104:   vmatlab->btype = type;
105:   PetscFunctionReturn(PETSC_SUCCESS);
106: }

108: /*
109:         Actually opens the file
110: */
111: PetscErrorCode PetscViewerFileSetName_Matlab(PetscViewer viewer, const char name[])
112: {
113:   PetscViewer_Matlab *vmatlab = (PetscViewer_Matlab *)viewer->data;
114:   PetscFileMode       type    = vmatlab->btype;

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

120:   /* only first processor opens file */
121:   if (!vmatlab->rank) {
122:     if (type == FILE_MODE_READ) vmatlab->ep = matOpen(name, "r");
123:     else if (type == FILE_MODE_WRITE) vmatlab->ep = matOpen(name, "w");
124:     else {
125:       PetscCheck(type != FILE_MODE_UNDEFINED, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
126:       SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[type]);
127:     }
128:   }
129:   PetscFunctionReturn(PETSC_SUCCESS);
130: }

132: PetscErrorCode PetscViewerDestroy_Matlab(PetscViewer v)
133: {
134:   PetscViewer_Matlab *vf = (PetscViewer_Matlab *)v->data;

136:   PetscFunctionBegin;
137:   if (vf->ep) matClose(vf->ep);
138:   PetscCall(PetscFree(vf));
139:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetName_C", NULL));
140:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetMode_C", NULL));
141:   PetscFunctionReturn(PETSC_SUCCESS);
142: }

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

148:    Level: intermediate

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

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

159:              In your PETSc C/C++ code (assuming a two dimensional `DMDA` with one degree of freedom per node)
160: .vb
161:                 PetscObjectSetName((PetscObject)x,"x");
162:                 VecView(x,PETSC_VIEWER_MATLAB_WORLD);
163:                 PetscObjectSetName((PetscObject)da,"da");
164:                 DMView(x,PETSC_VIEWER_MATLAB_WORLD);
165: .ve
166:              Then from MATLAB
167: .vb
168:                 load('matlaboutput.mat')   % matlaboutput.mat is the default filename
169:                 xnew = zeros(da.n,da.m);
170:                 xnew(:) = x;    % reshape one dimensional vector back to two dimensions
171: .ve

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

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

178: .seealso: `PETSC_VIEWER_MATLAB_()`, `PETSC_VIEWER_MATLAB_SELF`, `PETSC_VIEWER_MATLAB_WORLD`, `PetscViewerCreate()`,
179:           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERASCII`, `PETSCVIEWERDRAW`,
180:           `PETSC_VIEWER_STDOUT_()`, `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscMatlabEngine`
181: M*/
182: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Matlab(PetscViewer viewer)
183: {
184:   PetscViewer_Matlab *e;

186:   PetscFunctionBegin;
187:   PetscCall(PetscNew(&e));
188:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &e->rank));
189:   e->btype     = FILE_MODE_UNDEFINED;
190:   viewer->data = (void *)e;

192:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_Matlab));
193:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_Matlab));

195:   viewer->ops->destroy = PetscViewerDestroy_Matlab;
196:   PetscFunctionReturn(PETSC_SUCCESS);
197: }

199: /*@C
200:    PetscViewerMatlabOpen - Opens a Matlab .mat file for output

202:    Collective

204:    Input Parameters:
205: +  comm - MPI communicator
206: .  name - name of file
207: -  type - type of file
208: .vb
209:     FILE_MODE_WRITE - create new file for MATLAB output
210:     FILE_MODE_READ - open existing file for MATLAB input
211:     FILE_MODE_WRITE - open existing file for MATLAB output
212: .ve

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

217:    Level: beginner

219:    Notes:
220:    This `PetscViewer` should be destroyed with `PetscViewerDestroy()`.

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

224:    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
225:    instead of this routine.

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

229: .seealso: `PETSCVIEWERMATLAB`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`
230:           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`
231: @*/
232: PetscErrorCode PetscViewerMatlabOpen(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *binv)
233: {
234:   PetscFunctionBegin;
235:   PetscCall(PetscViewerCreate(comm, binv));
236:   PetscCall(PetscViewerSetType(*binv, PETSCVIEWERMATLAB));
237:   PetscCall(PetscViewerFileSetMode(*binv, type));
238:   PetscCall(PetscViewerFileSetName(*binv, name));
239:   PetscFunctionReturn(PETSC_SUCCESS);
240: }

242: static PetscMPIInt Petsc_Viewer_Matlab_keyval = MPI_KEYVAL_INVALID;

244: /*@C
245:      PETSC_VIEWER_MATLAB_ - Creates a `PETSCVIEWERMATLAB` `PetscViewer` shared by all processors
246:                      in a communicator.

248:      Collective

250:      Input Parameter:
251: .    comm - the MPI communicator to share the Matlab `PetscViewer`

253:    Options Database Key:
254: .    -viewer_matlab_filename <name> - name of the Matlab file

256:    Environmental variable:
257: .   `PETSC_VIEWER_MATLAB_FILENAME` - name of the Matlab file

259:      Level: intermediate

261:      Note:
262:      Unlike almost all other PETSc routines, `PETSC_VIEWER_MATLAB_()` does not return
263:      an error code.  The matlab PetscViewer is usually used in the form
264: $       XXXView(XXX object, PETSC_VIEWER_MATLAB_(comm));

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

268: .seealso: `PETSC_VIEWER_MATLAB_WORLD`, `PETSC_VIEWER_MATLAB_SELF`, `PetscViewerMatlabOpen()`, `PetscViewerCreate()`,
269:           `PetscViewerDestroy()`
270: @*/
271: PetscViewer PETSC_VIEWER_MATLAB_(MPI_Comm comm)
272: {
273:   PetscErrorCode ierr;
274:   PetscBool      flg;
275:   PetscViewer    viewer;
276:   char           fname[PETSC_MAX_PATH_LEN];
277:   MPI_Comm       ncomm;

279:   PetscFunctionBegin;
280:   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
281:   if (ierr) {
282:     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
283:     PetscFunctionReturn(NULL);
284:   }
285:   if (Petsc_Viewer_Matlab_keyval == MPI_KEYVAL_INVALID) {
286:     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Matlab_keyval, 0);
287:     if (ierr) {
288:       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
289:       PetscFunctionReturn(NULL);
290:     }
291:   }
292:   ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void **)&viewer, (int *)&flg);
293:   if (ierr) {
294:     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
295:     PetscFunctionReturn(NULL);
296:   }
297:   if (!flg) { /* PetscViewer not yet created */
298:     ierr = PetscOptionsGetenv(ncomm, "PETSC_VIEWER_MATLAB_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg);
299:     if (ierr) {
300:       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
301:       PetscFunctionReturn(NULL);
302:     }
303:     if (!flg) {
304:       ierr = PetscStrncpy(fname, "matlaboutput.mat", sizeof(fname));
305:       if (ierr) {
306:         PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
307:         PetscFunctionReturn(NULL);
308:       }
309:     }
310:     ierr = PetscViewerMatlabOpen(ncomm, fname, FILE_MODE_WRITE, &viewer);
311:     if (ierr) {
312:       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
313:       PetscFunctionReturn(NULL);
314:     }
315:     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
316:     if (ierr) {
317:       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
318:       PetscFunctionReturn(NULL);
319:     }
320:     ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void *)viewer);
321:     if (ierr) {
322:       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
323:       PetscFunctionReturn(NULL);
324:     }
325:   }
326:   ierr = PetscCommDestroy(&ncomm);
327:   if (ierr) {
328:     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
329:     PetscFunctionReturn(NULL);
330:   }
331:   PetscFunctionReturn(viewer);
332: }