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