xref: /petsc/src/sys/classes/viewer/impls/matlab/vmatlab.c (revision 5d7a6ebe9dde080aedbe86be0085708de8f97bb7)
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 static 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 static 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 static 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      Notes:
262      This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it
263 
264      Unlike almost all other PETSc routines, `PETSC_VIEWER_MATLAB_()` does not return
265      an error code.  The matlab PetscViewer is usually used in the form
266 $       XXXView(XXX object, PETSC_VIEWER_MATLAB_(comm));
267 
268      Use `PETSC_VIEWER_SOCKET_()` or `PetscViewerSocketOpen()` to communicator with an interactive MATLAB session.
269 
270 .seealso: `PETSC_VIEWER_MATLAB_WORLD`, `PETSC_VIEWER_MATLAB_SELF`, `PetscViewerMatlabOpen()`, `PetscViewerCreate()`,
271           `PetscViewerDestroy()`
272 @*/
273 PetscViewer PETSC_VIEWER_MATLAB_(MPI_Comm comm)
274 {
275   PetscErrorCode ierr;
276   PetscBool      flg;
277   PetscViewer    viewer;
278   char           fname[PETSC_MAX_PATH_LEN];
279   MPI_Comm       ncomm;
280 
281   PetscFunctionBegin;
282   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
283   if (ierr) {
284     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
285     PetscFunctionReturn(NULL);
286   }
287   if (Petsc_Viewer_Matlab_keyval == MPI_KEYVAL_INVALID) {
288     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Matlab_keyval, 0);
289     if (ierr) {
290       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
291       PetscFunctionReturn(NULL);
292     }
293   }
294   ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void **)&viewer, (int *)&flg);
295   if (ierr) {
296     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
297     PetscFunctionReturn(NULL);
298   }
299   if (!flg) { /* PetscViewer not yet created */
300     ierr = PetscOptionsGetenv(ncomm, "PETSC_VIEWER_MATLAB_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg);
301     if (ierr) {
302       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
303       PetscFunctionReturn(NULL);
304     }
305     if (!flg) {
306       ierr = PetscStrncpy(fname, "matlaboutput.mat", sizeof(fname));
307       if (ierr) {
308         PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
309         PetscFunctionReturn(NULL);
310       }
311     }
312     ierr                              = PetscViewerMatlabOpen(ncomm, fname, FILE_MODE_WRITE, &viewer);
313     ((PetscObject)viewer)->persistent = PETSC_TRUE;
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 = PetscObjectRegisterDestroy((PetscObject)viewer);
319     if (ierr) {
320       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
321       PetscFunctionReturn(NULL);
322     }
323     ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void *)viewer);
324     if (ierr) {
325       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
326       PetscFunctionReturn(NULL);
327     }
328   }
329   ierr = PetscCommDestroy(&ncomm);
330   if (ierr) {
331     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
332     PetscFunctionReturn(NULL);
333   }
334   PetscFunctionReturn(viewer);
335 }
336