xref: /petsc/src/sys/classes/viewer/impls/matlab/vmatlab.c (revision fbf9dbe564678ed6eff1806adbc4c4f01b9743f4)
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 - 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`
22 
23    Level: advanced
24 
25     Note:
26     Only writes `array` values on processor 0.
27 
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;
34 
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);
47 
48     PetscCall(PetscInfo(mfile, "Put MATLAB array %s\n", name));
49   }
50   PetscFunctionReturn(PETSC_SUCCESS);
51 }
52 
53 PetscErrorCode PetscViewerMatlabPutVariable(PetscViewer viewer, const char *name, void *mat)
54 {
55   PetscViewer_Matlab *ml = (PetscViewer_Matlab *)viewer->data;
56 
57   PetscFunctionBegin;
58   matPutVariable(ml->ep, name, (mxArray *)mat);
59   PetscFunctionReturn(PETSC_SUCCESS);
60 }
61 
62 /*@C
63     PetscViewerMatlabGetArray - Gets a variable from a `PETSCVIEWERMATLAB` viewer into an array
64 
65     Not Collective; only processor zero reads in the array
66 
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`
73 
74    Level: advanced
75 
76     Note:
77     Only reads in `array` values on processor 0.
78 
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;
85 
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 }
98 
99 PetscErrorCode PetscViewerFileSetMode_Matlab(PetscViewer viewer, PetscFileMode type)
100 {
101   PetscViewer_Matlab *vmatlab = (PetscViewer_Matlab *)viewer->data;
102 
103   PetscFunctionBegin;
104   vmatlab->btype = type;
105   PetscFunctionReturn(PETSC_SUCCESS);
106 }
107 
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;
115 
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);
119 
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 }
131 
132 PetscErrorCode PetscViewerDestroy_Matlab(PetscViewer v)
133 {
134   PetscViewer_Matlab *vf = (PetscViewer_Matlab *)v->data;
135 
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 }
143 
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').
147 
148    Level: intermediate
149 
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).
153 
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,
158 
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
172 
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.
175 
176               Use `PetscViewerMatlabPutArray()` to just put an array of doubles into the .mat file
177 
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;
185 
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;
191 
192   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_Matlab));
193   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_Matlab));
194 
195   viewer->ops->destroy = PetscViewerDestroy_Matlab;
196   PetscFunctionReturn(PETSC_SUCCESS);
197 }
198 
199 /*@C
200    PetscViewerMatlabOpen - Opens a Matlab .mat file for output
201 
202    Collective
203 
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
213 
214    Output Parameter:
215 .  binv - PetscViewer for MATLAB output to use with the specified file
216 
217    Level: beginner
218 
219    Notes:
220    This `PetscViewer` should be destroyed with `PetscViewerDestroy()`.
221 
222    For writing files it only opens the file on processor 0 in the communicator.
223 
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.
226 
227    PETSc must be configured with the option `--with-matlab` for this functionality
228 
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 }
241 
242 static PetscMPIInt Petsc_Viewer_Matlab_keyval = MPI_KEYVAL_INVALID;
243 
244 /*@C
245      PETSC_VIEWER_MATLAB_ - Creates a `PETSCVIEWERMATLAB` `PetscViewer` shared by all processors
246                      in a communicator.
247 
248      Collective
249 
250      Input Parameter:
251 .    comm - the MPI communicator to share the Matlab `PetscViewer`
252 
253    Options Database Key:
254 .    -viewer_matlab_filename <name> - name of the Matlab file
255 
256    Environmental variable:
257 .   `PETSC_VIEWER_MATLAB_FILENAME` - name of the Matlab file
258 
259      Level: intermediate
260 
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));
265 
266      Use `PETSC_VIEWER_SOCKET_()` or `PetscViewerSocketOpen()` to communicator with an interactive MATLAB session.
267 
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;
278 
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 }
333