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