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