xref: /petsc/src/sys/classes/viewer/impls/matlab/vmatlab.c (revision 2d30e087755efd99e28fdfe792ffbeb2ee1ea928)
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        Note: Currently can only save PETSc vectors to .mat files, not matrices (use the `PETSCVIEWERBINARY` and
143              ${PETSC_DIR}/share/petsc/matlab/PetscBinaryRead.m to read matrices into MATLAB).
144 
145              For parallel vectors obtained with `DMCreateGlobalVector()` or `DMGetGlobalVector()` the vectors are saved to
146              the .mat file in natural ordering. You can use DMView() to save the `DMDA` information to the .mat file
147              the fields in the MATLAB loaded da variable give the array dimensions so you can reshape the `MATLAB`
148              vector to the same multidimensional shape as it had in PETSc for plotting etc. For example,
149 
150 $             In your PETSc C/C++ code (assuming a two dimensional DMDA with one degree of freedom per node)
151 $                PetscObjectSetName((PetscObject)x,"x");
152 $                VecView(x,PETSC_VIEWER_MATLAB_WORLD);
153 $                PetscObjectSetName((PetscObject)da,"da");
154 $                DMView(x,PETSC_VIEWER_MATLAB_WORLD);
155 $             Then from MATLAB
156 $                load('matlaboutput.mat')   % matlaboutput.mat is the default filename
157 $                xnew = zeros(da.n,da.m);
158 $                xnew(:) = x;    % reshape one dimensional vector back to two dimensions
159 
160               If you wish to put the same variable into the .mat file several times you need to give it a new
161               name before each call to view.
162 
163               Use `PetscViewerMatlabPutArray()` to just put an array of doubles into the .mat file
164 
165 .seealso: `PETSC_VIEWER_MATLAB_()`, `PETSC_VIEWER_MATLAB_SELF`, `PETSC_VIEWER_MATLAB_WORLD`, `PetscViewerCreate()`,
166           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERASCII`, `PETSCVIEWERDRAW`,
167           `PETSC_VIEWER_STDOUT_()`, `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscMatlabEngine`
168 M*/
169 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Matlab(PetscViewer viewer) {
170   PetscViewer_Matlab *e;
171 
172   PetscFunctionBegin;
173   PetscCall(PetscNewLog(viewer, &e));
174   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &e->rank));
175   e->btype     = FILE_MODE_UNDEFINED;
176   viewer->data = (void *)e;
177 
178   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_Matlab));
179   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_Matlab));
180 
181   viewer->ops->destroy = PetscViewerDestroy_Matlab;
182   PetscFunctionReturn(0);
183 }
184 
185 /*@C
186    PetscViewerMatlabOpen - Opens a Matlab .mat file for output
187 
188    Collective
189 
190    Input Parameters:
191 +  comm - MPI communicator
192 .  name - name of file
193 -  type - type of file
194 $    `FILE_MODE_WRITE` - create new file for MATLAB output
195 $    `FILE_MODE_READ` - open existing file for MATLAB input
196 $    ``FILE_MODE_WRITE - open existing file for MATLAB output
197 
198    Output Parameter:
199 .  binv - PetscViewer for MATLAB output to use with the specified file
200 
201    Level: beginner
202 
203    Notes:
204    This `PetscViewer` should be destroyed with `PetscViewerDestroy()`.
205 
206    For writing files it only opens the file on processor 0 in the communicator.
207 
208    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
209    instead of this routine.
210 
211 .seealso: `PETSCVIEWERMATLAB`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`
212           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`
213 @*/
214 PetscErrorCode PetscViewerMatlabOpen(MPI_Comm comm, const char name[], PetscFileMode type, PetscViewer *binv) {
215   PetscFunctionBegin;
216   PetscCall(PetscViewerCreate(comm, binv));
217   PetscCall(PetscViewerSetType(*binv, PETSCVIEWERMATLAB));
218   PetscCall(PetscViewerFileSetMode(*binv, type));
219   PetscCall(PetscViewerFileSetName(*binv, name));
220   PetscFunctionReturn(0);
221 }
222 
223 static PetscMPIInt Petsc_Viewer_Matlab_keyval = MPI_KEYVAL_INVALID;
224 
225 /*@C
226      PETSC_VIEWER_MATLAB_ - Creates a `PETSCVIEWERMATLAB` `PetscViewer` shared by all processors
227                      in a communicator.
228 
229      Collective
230 
231      Input Parameter:
232 .    comm - the MPI communicator to share the Matlab `PetscViewer`
233 
234    Options Database Key:
235 .    -viewer_matlab_filename <name> - name of the Matlab file
236 
237    Environmental variable:
238 .   `PETSC_VIEWER_MATLAB_FILENAME` - name of the Matlab file
239 
240      Level: intermediate
241 
242      Note:
243      Unlike almost all other PETSc routines, `PETSC_VIEWER_MATLAB_()` does not return
244      an error code.  The matlab PetscViewer is usually used in the form
245 $       XXXView(XXX object,PETSC_VIEWER_MATLAB_(comm));
246 
247      Use `PETSC_VIEWER_SOCKET_()` or `PetscViewerSocketOpen()` to communicator with an interactive MATLAB session.
248 
249 .seealso: `PETSC_VIEWER_MATLAB_WORLD`, `PETSC_VIEWER_MATLAB_SELF`, `PetscViewerMatlabOpen()`, `PetscViewerCreate()`,
250           `PetscViewerDestroy()`
251 @*/
252 PetscViewer PETSC_VIEWER_MATLAB_(MPI_Comm comm) {
253   PetscErrorCode ierr;
254   PetscBool      flg;
255   PetscViewer    viewer;
256   char           fname[PETSC_MAX_PATH_LEN];
257   MPI_Comm       ncomm;
258 
259   PetscFunctionBegin;
260   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
261   if (ierr) {
262     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
263     PetscFunctionReturn(0);
264   }
265   if (Petsc_Viewer_Matlab_keyval == MPI_KEYVAL_INVALID) {
266     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Matlab_keyval, 0);
267     if (ierr) {
268       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
269       PetscFunctionReturn(NULL);
270     }
271   }
272   ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void **)&viewer, (int *)&flg);
273   if (ierr) {
274     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
275     PetscFunctionReturn(NULL);
276   }
277   if (!flg) { /* PetscViewer not yet created */
278     ierr = PetscOptionsGetenv(ncomm, "PETSC_VIEWER_MATLAB_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg);
279     if (ierr) {
280       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
281       PetscFunctionReturn(NULL);
282     }
283     if (!flg) {
284       ierr = PetscStrcpy(fname, "matlaboutput.mat");
285       if (ierr) {
286         PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
287         PetscFunctionReturn(NULL);
288       }
289     }
290     ierr = PetscViewerMatlabOpen(ncomm, fname, FILE_MODE_WRITE, &viewer);
291     if (ierr) {
292       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
293       PetscFunctionReturn(NULL);
294     }
295     ierr = PetscObjectRegisterDestroy((PetscObject)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 = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Matlab_keyval, (void *)viewer);
301     if (ierr) {
302       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
303       PetscFunctionReturn(NULL);
304     }
305   }
306   ierr = PetscCommDestroy(&ncomm);
307   if (ierr) {
308     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_MATLAB_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
309     PetscFunctionReturn(NULL);
310   }
311   PetscFunctionReturn(viewer);
312 }
313