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