xref: /petsc/src/sys/classes/viewer/impls/matlab/vmatlab.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
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 the array
15 
16     Input Parameters:
17 +    mfile - the viewer
18 .    m,n - the dimensions of the array
19 .    array - the array (represented in one dimension)
20 -    name - the name of the 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(0);
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(0);
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 the array
69 .    array - the array (represented in one dimension)
70 -    name - the name of the 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(0);
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(0);
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(0);
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(0);
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(0);
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 $    `FILE_MODE_WRITE` - create new file for MATLAB output
207 $    `FILE_MODE_READ` - open existing file for MATLAB input
208 $    `FILE_MODE_WRITE` - open existing file for MATLAB output
209 
210    Output Parameter:
211 .  binv - PetscViewer for MATLAB output to use with the specified file
212 
213    Level: beginner
214 
215    Notes:
216    This `PetscViewer` should be destroyed with `PetscViewerDestroy()`.
217 
218    For writing files it only opens the file on processor 0 in the communicator.
219 
220    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
221    instead of this routine.
222 
223    PETSc must be configured with the option -with-matlab for this functionality
224 
225 .seealso: `PETSCVIEWERMATLAB`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`
226           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`
227 @*/
228 PetscErrorCode PetscViewerMatlabOpen(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *binv)
229 {
230   PetscFunctionBegin;
231   PetscCall(PetscViewerCreate(comm, binv));
232   PetscCall(PetscViewerSetType(*binv, PETSCVIEWERMATLAB));
233   PetscCall(PetscViewerFileSetMode(*binv, type));
234   PetscCall(PetscViewerFileSetName(*binv, name));
235   PetscFunctionReturn(0);
236 }
237 
238 static PetscMPIInt Petsc_Viewer_Matlab_keyval = MPI_KEYVAL_INVALID;
239 
240 /*@C
241      PETSC_VIEWER_MATLAB_ - Creates a `PETSCVIEWERMATLAB` `PetscViewer` shared by all processors
242                      in a communicator.
243 
244      Collective
245 
246      Input Parameter:
247 .    comm - the MPI communicator to share the Matlab `PetscViewer`
248 
249    Options Database Key:
250 .    -viewer_matlab_filename <name> - name of the Matlab file
251 
252    Environmental variable:
253 .   `PETSC_VIEWER_MATLAB_FILENAME` - name of the Matlab file
254 
255      Level: intermediate
256 
257      Note:
258      Unlike almost all other PETSc routines, `PETSC_VIEWER_MATLAB_()` does not return
259      an error code.  The matlab PetscViewer is usually used in the form
260 $       XXXView(XXX object,PETSC_VIEWER_MATLAB_(comm));
261 
262      Use `PETSC_VIEWER_SOCKET_()` or `PetscViewerSocketOpen()` to communicator with an interactive MATLAB session.
263 
264 .seealso: `PETSC_VIEWER_MATLAB_WORLD`, `PETSC_VIEWER_MATLAB_SELF`, `PetscViewerMatlabOpen()`, `PetscViewerCreate()`,
265           `PetscViewerDestroy()`
266 @*/
267 PetscViewer PETSC_VIEWER_MATLAB_(MPI_Comm comm)
268 {
269   PetscErrorCode ierr;
270   PetscBool      flg;
271   PetscViewer    viewer;
272   char           fname[PETSC_MAX_PATH_LEN];
273   MPI_Comm       ncomm;
274 
275   PetscFunctionBegin;
276   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
277   if (ierr) {
278     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
279     PetscFunctionReturn(0);
280   }
281   if (Petsc_Viewer_Matlab_keyval == MPI_KEYVAL_INVALID) {
282     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Matlab_keyval, 0);
283     if (ierr) {
284       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
285       PetscFunctionReturn(NULL);
286     }
287   }
288   ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void **)&viewer, (int *)&flg);
289   if (ierr) {
290     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
291     PetscFunctionReturn(NULL);
292   }
293   if (!flg) { /* PetscViewer not yet created */
294     ierr = PetscOptionsGetenv(ncomm, "PETSC_VIEWER_MATLAB_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg);
295     if (ierr) {
296       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
297       PetscFunctionReturn(NULL);
298     }
299     if (!flg) {
300       ierr = PetscStrcpy(fname, "matlaboutput.mat");
301       if (ierr) {
302         PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
303         PetscFunctionReturn(NULL);
304       }
305     }
306     ierr = PetscViewerMatlabOpen(ncomm, fname, FILE_MODE_WRITE, &viewer);
307     if (ierr) {
308       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
309       PetscFunctionReturn(NULL);
310     }
311     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
312     if (ierr) {
313       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
314       PetscFunctionReturn(NULL);
315     }
316     ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void *)viewer);
317     if (ierr) {
318       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
319       PetscFunctionReturn(NULL);
320     }
321   }
322   ierr = PetscCommDestroy(&ncomm);
323   if (ierr) {
324     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
325     PetscFunctionReturn(NULL);
326   }
327   PetscFunctionReturn(viewer);
328 }
329