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