xref: /petsc/src/sys/classes/viewer/impls/matlab/vmatlab.c (revision c8c5c547f526914c69472d8cade615559dc64129)
1 
2 #include <petsc/private/viewerimpl.h>
3 #include <mat.h>
4 
5 typedef struct {
6   MATFile      *ep;
7   PetscMPIInt   rank;
8   PetscFileMode btype;
9 } PetscViewer_Matlab;
10 
11 /*@C
12     PetscViewerMatlabPutArray - Puts an array into the `PETSCVIEWERMATLAB` viewer.
13 
14       Not collective: only processor zero saves `array`
15 
16     Input Parameters:
17 +    mfile - the viewer
18 .    m,n - the dimensions of `array`
19 .    array - the array (represented in one dimension)
20 -    name - the MATLAB name of `array`
21 
22    Level: advanced
23 
24     Note:
25     Only writes `array` values on processor 0.
26 
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;
33 
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);
46 
47     PetscCall(PetscInfo(mfile, "Put MATLAB array %s\n", name));
48   }
49   PetscFunctionReturn(PETSC_SUCCESS);
50 }
51 
52 PetscErrorCode PetscViewerMatlabPutVariable(PetscViewer viewer, const char *name, void *mat)
53 {
54   PetscViewer_Matlab *ml = (PetscViewer_Matlab *)viewer->data;
55 
56   PetscFunctionBegin;
57   matPutVariable(ml->ep, name, (mxArray *)mat);
58   PetscFunctionReturn(PETSC_SUCCESS);
59 }
60 
61 /*@C
62     PetscViewerMatlabGetArray - Gets a variable from a `PETSCVIEWERMATLAB` viewer into an array
63 
64     Not Collective; only processor zero reads in the array
65 
66     Input Parameters:
67 +    mfile - the MATLAB file viewer
68 .    m,n - the dimensions of `array`
69 .    array - the array (represented in one dimension)
70 -    name - the MATLAB name of `array`
71 
72    Level: advanced
73 
74     Note:
75     Only reads in `array` values on processor 0.
76 
77 .seealso: `PETSCVIEWERMATLAB`, `PetscViewerMatlabPutArray()`
78 @*/
79 PetscErrorCode PetscViewerMatlabGetArray(PetscViewer mfile, int m, int n, PetscScalar *array, const char *name)
80 {
81   PetscViewer_Matlab *ml;
82   mxArray            *mat;
83 
84   PetscFunctionBegin;
85   PetscCheck(mfile, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Null argument: probably PETSC_VIEWER_MATLAB_() failed");
86   ml = (PetscViewer_Matlab *)mfile->data;
87   if (!ml->rank) {
88     PetscCall(PetscInfo(mfile, "Getting MATLAB array %s\n", name));
89     mat = matGetVariable(ml->ep, name);
90     PetscCheck(mat, PETSC_COMM_SELF, PETSC_ERR_LIB, "Unable to get array %s from matlab", name);
91     PetscCall(PetscArraycpy(array, mxGetPr(mat), m * n));
92     PetscCall(PetscInfo(mfile, "Got MATLAB array %s\n", name));
93   }
94   PetscFunctionReturn(PETSC_SUCCESS);
95 }
96 
97 PetscErrorCode PetscViewerFileSetMode_Matlab(PetscViewer viewer, PetscFileMode type)
98 {
99   PetscViewer_Matlab *vmatlab = (PetscViewer_Matlab *)viewer->data;
100 
101   PetscFunctionBegin;
102   vmatlab->btype = type;
103   PetscFunctionReturn(PETSC_SUCCESS);
104 }
105 
106 /*
107         Actually opens the file
108 */
109 PetscErrorCode PetscViewerFileSetName_Matlab(PetscViewer viewer, const char name[])
110 {
111   PetscViewer_Matlab *vmatlab = (PetscViewer_Matlab *)viewer->data;
112   PetscFileMode       type    = vmatlab->btype;
113 
114   PetscFunctionBegin;
115   PetscCheck(type != (PetscFileMode)-1, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
116   if (vmatlab->ep) matClose(vmatlab->ep);
117 
118   /* only first processor opens file */
119   if (!vmatlab->rank) {
120     if (type == FILE_MODE_READ) vmatlab->ep = matOpen(name, "r");
121     else if (type == FILE_MODE_WRITE) vmatlab->ep = matOpen(name, "w");
122     else {
123       PetscCheck(type != FILE_MODE_UNDEFINED, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerFileSetName()");
124       SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[type]);
125     }
126   }
127   PetscFunctionReturn(PETSC_SUCCESS);
128 }
129 
130 PetscErrorCode PetscViewerDestroy_Matlab(PetscViewer v)
131 {
132   PetscViewer_Matlab *vf = (PetscViewer_Matlab *)v->data;
133 
134   PetscFunctionBegin;
135   if (vf->ep) matClose(vf->ep);
136   PetscCall(PetscFree(vf));
137   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetName_C", NULL));
138   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetMode_C", NULL));
139   PetscFunctionReturn(PETSC_SUCCESS);
140 }
141 
142 /*MC
143    PETSCVIEWERMATLAB - A viewer that saves the variables into a MATLAB .mat file that may be read into MATLAB
144        with load('filename').
145 
146    Level: intermediate
147 
148        Notes:
149              Currently can only save PETSc vectors to .mat files, not matrices (use the `PETSCVIEWERBINARY` and
150              ${PETSC_DIR}/share/petsc/matlab/PetscBinaryRead.m to read matrices into MATLAB).
151 
152              For parallel vectors obtained with `DMCreateGlobalVector()` or `DMGetGlobalVector()` the vectors are saved to
153              the .mat file in natural ordering. You can use DMView() to save the `DMDA` information to the .mat file
154              the fields in the MATLAB loaded da variable give the array dimensions so you can reshape the MATLAB
155              vector to the same multidimensional shape as it had in PETSc for plotting etc. For example,
156 
157              In your PETSc C/C++ code (assuming a two dimensional `DMDA` with one degree of freedom per node)
158 .vb
159                 PetscObjectSetName((PetscObject)x,"x");
160                 VecView(x,PETSC_VIEWER_MATLAB_WORLD);
161                 PetscObjectSetName((PetscObject)da,"da");
162                 DMView(x,PETSC_VIEWER_MATLAB_WORLD);
163 .ve
164              Then from MATLAB
165 .vb
166                 load('matlaboutput.mat')   % matlaboutput.mat is the default filename
167                 xnew = zeros(da.n,da.m);
168                 xnew(:) = x;    % reshape one dimensional vector back to two dimensions
169 .ve
170 
171               If you wish to put the same variable into the .mat file several times you need to give it a new
172               name before each call to view.
173 
174               Use `PetscViewerMatlabPutArray()` to just put an array of doubles into the .mat file
175 
176 .seealso: `PETSC_VIEWER_MATLAB_()`, `PETSC_VIEWER_MATLAB_SELF`, `PETSC_VIEWER_MATLAB_WORLD`, `PetscViewerCreate()`,
177           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERASCII`, `PETSCVIEWERDRAW`,
178           `PETSC_VIEWER_STDOUT_()`, `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscMatlabEngine`
179 M*/
180 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Matlab(PetscViewer viewer)
181 {
182   PetscViewer_Matlab *e;
183 
184   PetscFunctionBegin;
185   PetscCall(PetscNew(&e));
186   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &e->rank));
187   e->btype     = FILE_MODE_UNDEFINED;
188   viewer->data = (void *)e;
189 
190   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_Matlab));
191   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_Matlab));
192 
193   viewer->ops->destroy = PetscViewerDestroy_Matlab;
194   PetscFunctionReturn(PETSC_SUCCESS);
195 }
196 
197 /*@C
198    PetscViewerMatlabOpen - Opens a Matlab .mat file for output
199 
200    Collective
201 
202    Input Parameters:
203 +  comm - MPI communicator
204 .  name - name of file
205 -  type - type of file
206 .vb
207     FILE_MODE_WRITE - create new file for MATLAB output
208     FILE_MODE_READ - open existing file for MATLAB input
209     FILE_MODE_WRITE - open existing file for MATLAB output
210 .ve
211 
212    Output Parameter:
213 .  binv - PetscViewer for MATLAB output to use with the specified file
214 
215    Level: beginner
216 
217    Notes:
218    This `PetscViewer` should be destroyed with `PetscViewerDestroy()`.
219 
220    For writing files it only opens the file on processor 0 in the communicator.
221 
222    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
223    instead of this routine.
224 
225    PETSc must be configured with the option `--with-matlab` for this functionality
226 
227 .seealso: `PETSCVIEWERMATLAB`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`
228           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`
229 @*/
230 PetscErrorCode PetscViewerMatlabOpen(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *binv)
231 {
232   PetscFunctionBegin;
233   PetscCall(PetscViewerCreate(comm, binv));
234   PetscCall(PetscViewerSetType(*binv, PETSCVIEWERMATLAB));
235   PetscCall(PetscViewerFileSetMode(*binv, type));
236   PetscCall(PetscViewerFileSetName(*binv, name));
237   PetscFunctionReturn(PETSC_SUCCESS);
238 }
239 
240 static PetscMPIInt Petsc_Viewer_Matlab_keyval = MPI_KEYVAL_INVALID;
241 
242 /*@C
243      PETSC_VIEWER_MATLAB_ - Creates a `PETSCVIEWERMATLAB` `PetscViewer` shared by all processors
244                      in a communicator.
245 
246      Collective
247 
248      Input Parameter:
249 .    comm - the MPI communicator to share the Matlab `PetscViewer`
250 
251    Options Database Key:
252 .    -viewer_matlab_filename <name> - name of the Matlab file
253 
254    Environmental variable:
255 .   `PETSC_VIEWER_MATLAB_FILENAME` - name of the Matlab file
256 
257      Level: intermediate
258 
259      Note:
260      Unlike almost all other PETSc routines, `PETSC_VIEWER_MATLAB_()` does not return
261      an error code.  The matlab PetscViewer is usually used in the form
262 $       XXXView(XXX object,PETSC_VIEWER_MATLAB_(comm));
263 
264      Use `PETSC_VIEWER_SOCKET_()` or `PetscViewerSocketOpen()` to communicator with an interactive MATLAB session.
265 
266 .seealso: `PETSC_VIEWER_MATLAB_WORLD`, `PETSC_VIEWER_MATLAB_SELF`, `PetscViewerMatlabOpen()`, `PetscViewerCreate()`,
267           `PetscViewerDestroy()`
268 @*/
269 PetscViewer PETSC_VIEWER_MATLAB_(MPI_Comm comm)
270 {
271   PetscErrorCode ierr;
272   PetscBool      flg;
273   PetscViewer    viewer;
274   char           fname[PETSC_MAX_PATH_LEN];
275   MPI_Comm       ncomm;
276 
277   PetscFunctionBegin;
278   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
279   if (ierr) {
280     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
281     PetscFunctionReturn(PETSC_SUCCESS);
282   }
283   if (Petsc_Viewer_Matlab_keyval == MPI_KEYVAL_INVALID) {
284     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Matlab_keyval, 0);
285     if (ierr) {
286       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
287       PetscFunctionReturn(NULL);
288     }
289   }
290   ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void **)&viewer, (int *)&flg);
291   if (ierr) {
292     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
293     PetscFunctionReturn(NULL);
294   }
295   if (!flg) { /* PetscViewer not yet created */
296     ierr = PetscOptionsGetenv(ncomm, "PETSC_VIEWER_MATLAB_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg);
297     if (ierr) {
298       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
299       PetscFunctionReturn(NULL);
300     }
301     if (!flg) {
302       ierr = PetscStrcpy(fname, "matlaboutput.mat");
303       if (ierr) {
304         PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
305         PetscFunctionReturn(NULL);
306       }
307     }
308     ierr = PetscViewerMatlabOpen(ncomm, fname, FILE_MODE_WRITE, &viewer);
309     if (ierr) {
310       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
311       PetscFunctionReturn(NULL);
312     }
313     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
314     if (ierr) {
315       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
316       PetscFunctionReturn(NULL);
317     }
318     ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void *)viewer);
319     if (ierr) {
320       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
321       PetscFunctionReturn(NULL);
322     }
323   }
324   ierr = PetscCommDestroy(&ncomm);
325   if (ierr) {
326     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
327     PetscFunctionReturn(NULL);
328   }
329   PetscFunctionReturn(viewer);
330 }
331