xref: /petsc/src/sys/classes/matlabengine/matlab.c (revision 356ed81403a8ddb9cbcae868d64486ea275d004c)
1 
2 #include <engine.h>   /* MATLAB include file */
3 #include <petscsys.h>
4 #include <petscmatlab.h>               /*I   "petscmatlab.h"  I*/
5 #include <petsc/private/petscimpl.h>
6 
7 struct  _p_PetscMatlabEngine {
8   PETSCHEADER(int);
9   Engine *ep;
10   char   buffer[1024];
11 };
12 
13 PetscClassId MATLABENGINE_CLASSID = -1;
14 
15 /*@C
16     PetscMatlabEngineCreate - Creates a MATLAB engine object
17 
18     Not Collective
19 
20     Input Parameters:
21 +   comm - a separate MATLAB engine is started for each process in the communicator
22 -   host - name of machine where MATLAB engine is to be run (usually NULL)
23 
24     Output Parameter:
25 .   mengine - the resulting object
26 
27    Options Database:
28 +    -matlab_engine_graphics - allow the MATLAB engine to display graphics
29 .    -matlab_engine_host - hostname, machine to run the MATLAB engine on
30 -    -info - print out all requests to MATLAB and all if its responses (for debugging)
31 
32    Level: advanced
33 
34 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
35           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
36           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
37 @*/
38 PetscErrorCode  PetscMatlabEngineCreate(MPI_Comm comm,const char host[],PetscMatlabEngine *mengine)
39 {
40   PetscMPIInt       rank,size;
41   char              buffer[256];
42   PetscMatlabEngine e;
43   PetscBool         flg = PETSC_FALSE;
44 
45   PetscFunctionBegin;
46   if (MATLABENGINE_CLASSID == -1) PetscCall(PetscClassIdRegister("MATLAB Engine",&MATLABENGINE_CLASSID));
47   PetscCall(PetscHeaderCreate(e,MATLABENGINE_CLASSID,"MatlabEngine","MATLAB Engine","Sys",comm,PetscMatlabEngineDestroy,NULL));
48 
49   if (!host) {
50     char lhost[64];
51 
52     PetscCall(PetscOptionsGetString(NULL,NULL,"-matlab_engine_host",lhost,sizeof(lhost),&flg));
53     if (flg) {host = lhost;}
54   }
55   flg = PETSC_FALSE;
56   PetscCall(PetscOptionsGetBool(NULL,NULL,"-matlab_engine_graphics",&flg,NULL));
57 
58   if (host) {
59     PetscCall(PetscInfo(0,"Starting MATLAB engine on %s\n",host));
60   } else {
61 
62   }
63   if (host) {
64     PetscCall(PetscStrcpy(buffer,"ssh "));
65     PetscCall(PetscStrcat(buffer,host));
66     PetscCall(PetscStrcat(buffer," \""));
67     PetscCall(PetscStrlcat(buffer,PETSC_MATLAB_COMMAND,sizeof(buffer)));
68     if (!flg) {
69       PetscCall(PetscStrlcat(buffer," -nodisplay ",sizeof(buffer)));
70     }
71     PetscCall(PetscStrlcat(buffer," -nosplash ",sizeof(buffer)));
72     PetscCall(PetscStrcat(buffer,"\""));
73   } else {
74     PetscCall(PetscStrncpy(buffer,PETSC_MATLAB_COMMAND,sizeof(buffer)));
75     if (!flg) {
76       PetscCall(PetscStrlcat(buffer," -nodisplay ",sizeof(buffer)));
77     }
78     PetscCall(PetscStrlcat(buffer," -nosplash ",sizeof(buffer)));
79   }
80   PetscCall(PetscInfo(0,"Starting MATLAB engine with command %s\n",buffer));
81   e->ep = engOpen(buffer);
82   PetscCheck(e->ep,PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to start MATLAB engine with %s",buffer);
83   engOutputBuffer(e->ep,e->buffer,sizeof(e->buffer));
84   if (host) {
85     PetscCall(PetscInfo(0,"Started MATLAB engine on %s\n",host));
86   } else {
87     PetscCall(PetscInfo(0,"Started MATLAB engine\n"));
88   }
89 
90   PetscCallMPI(MPI_Comm_rank(comm,&rank));
91   PetscCallMPI(MPI_Comm_size(comm,&size));
92   PetscCall(PetscMatlabEngineEvaluate(e,"MPI_Comm_rank = %d; MPI_Comm_size = %d;\n",rank,size));
93   *mengine = e;
94   PetscFunctionReturn(0);
95 }
96 
97 /*@
98    PetscMatlabEngineDestroy - Shuts down a MATLAB engine.
99 
100    Collective on PetscMatlabEngine
101 
102    Input Parameters:
103 .  e  - the engine
104 
105    Level: advanced
106 
107 .seealso: PetscMatlabEngineCreate(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
108           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
109           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
110 @*/
111 PetscErrorCode  PetscMatlabEngineDestroy(PetscMatlabEngine *v)
112 {
113   PetscErrorCode ierr;
114 
115   PetscFunctionBegin;
116   if (!*v) PetscFunctionReturn(0);
117   PetscValidHeaderSpecific(*v,MATLABENGINE_CLASSID,1);
118   if (--((PetscObject)(*v))->refct > 0) PetscFunctionReturn(0);
119   PetscCall(PetscInfo(0,"Stopping MATLAB engine\n"));
120   ierr = engClose((*v)->ep);
121   PetscCheck(!ierr,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error closing Matlab engine");
122   PetscCall(PetscInfo(0,"MATLAB engine stopped\n"));
123   PetscCall(PetscHeaderDestroy(v));
124   PetscFunctionReturn(0);
125 }
126 
127 /*@C
128     PetscMatlabEngineEvaluate - Evaluates a string in MATLAB
129 
130     Not Collective
131 
132     Input Parameters:
133 +   mengine - the MATLAB engine
134 -   string - format as in a printf()
135 
136    Notes:
137      Run the PETSc program with -info to always have printed back MATLAB's response to the string evaluation
138 
139    Level: advanced
140 
141 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
142           PetscMatlabEngineCreate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
143           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
144 @*/
145 PetscErrorCode  PetscMatlabEngineEvaluate(PetscMatlabEngine mengine,const char string[],...)
146 {
147   va_list        Argp;
148   char           buffer[1024];
149   size_t         fullLength;
150 
151   PetscFunctionBegin;
152   va_start(Argp,string);
153   PetscCall(PetscVSNPrintf(buffer,sizeof(buffer)-9-5,string,&fullLength,Argp));
154   va_end(Argp);
155 
156   PetscCall(PetscInfo(0,"Evaluating MATLAB string: %s\n",buffer));
157   engEvalString(mengine->ep, buffer);
158   PetscCall(PetscInfo(0,"Done evaluating MATLAB string: %s\n",buffer));
159   PetscCall(PetscInfo(0,"  MATLAB output message: %s\n",mengine->buffer));
160 
161   /*
162      Check for error in MATLAB: indicated by ? as first character in engine->buffer
163   */
164   PetscCheckFalse(mengine->buffer[4] == '?',PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in evaluating MATLAB command:%s\n%s",string,mengine->buffer);
165   PetscFunctionReturn(0);
166 }
167 
168 /*@C
169     PetscMatlabEngineGetOutput - Gets a string buffer where the MATLAB output is
170           printed
171 
172     Not Collective
173 
174     Input Parameter:
175 .   mengine - the MATLAB engine
176 
177     Output Parameter:
178 .   string - buffer where MATLAB output is printed
179 
180    Level: advanced
181 
182 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
183           PetscMatlabEngineEvaluate(), PetscMatlabEngineCreate(), PetscMatlabEnginePrintOutput(),
184           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
185 @*/
186 PetscErrorCode  PetscMatlabEngineGetOutput(PetscMatlabEngine mengine,char **string)
187 {
188   PetscFunctionBegin;
189   PetscCheck(mengine,PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
190   *string = mengine->buffer;
191   PetscFunctionReturn(0);
192 }
193 
194 /*@C
195     PetscMatlabEnginePrintOutput - prints the output from MATLAB
196 
197     Collective on PetscMatlabEngine
198 
199     Input Parameters:
200 .    mengine - the Matlab engine
201 
202    Level: advanced
203 
204 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
205           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEngineCreate(),
206           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
207 @*/
208 PetscErrorCode  PetscMatlabEnginePrintOutput(PetscMatlabEngine mengine,FILE *fd)
209 {
210   PetscMPIInt    rank;
211 
212   PetscFunctionBegin;
213   PetscCheck(mengine,PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
214   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mengine),&rank));
215   PetscCall(PetscSynchronizedFPrintf(PetscObjectComm((PetscObject)mengine),fd,"[%d]%s",rank,mengine->buffer));
216   PetscCall(PetscSynchronizedFlush(PetscObjectComm((PetscObject)mengine),fd));
217   PetscFunctionReturn(0);
218 }
219 
220 /*@
221     PetscMatlabEnginePut - Puts a Petsc object into the MATLAB space. For parallel objects,
222       each processors part is put in a separate  MATLAB process.
223 
224     Collective on PetscObject
225 
226     Input Parameters:
227 +    mengine - the MATLAB engine
228 -    object - the PETSc object, for example Vec
229 
230    Level: advanced
231 
232    Note: Mats transferred between PETSc and MATLAB and vis versa are transposed in the other space
233          (this is because MATLAB uses compressed column format and PETSc uses compressed row format)
234 
235 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEngineCreate(), PetscMatlabEngineGet(),
236           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
237           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
238 @*/
239 PetscErrorCode  PetscMatlabEnginePut(PetscMatlabEngine mengine,PetscObject obj)
240 {
241   PetscErrorCode (*put)(PetscObject,void*);
242 
243   PetscFunctionBegin;
244   PetscCheck(mengine,PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
245   PetscCall(PetscObjectQueryFunction(obj,"PetscMatlabEnginePut_C",&put));
246   PetscCheck(put,PETSC_COMM_SELF,PETSC_ERR_SUP,"Object %s cannot be put into MATLAB engine",obj->class_name);
247   PetscCall(PetscInfo(0,"Putting MATLAB object\n"));
248   PetscCall((*put)(obj,mengine->ep));
249   PetscCall(PetscInfo(0,"Put MATLAB object: %s\n",obj->name));
250   PetscFunctionReturn(0);
251 }
252 
253 /*@
254     PetscMatlabEngineGet - Gets a variable from MATLAB into a PETSc object.
255 
256     Collective on PetscObject
257 
258     Input Parameters:
259 +    mengine - the MATLAB engine
260 -    object - the PETSc object, for example Vec
261 
262    Level: advanced
263 
264    Note: Mats transferred between PETSc and MATLAB and vis versa are transposed in the other space
265          (this is because MATLAB uses compressed column format and PETSc uses compressed row format)
266 
267 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineCreate(),
268           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
269           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine
270 @*/
271 PetscErrorCode  PetscMatlabEngineGet(PetscMatlabEngine mengine,PetscObject obj)
272 {
273   PetscErrorCode (*get)(PetscObject,void*);
274 
275   PetscFunctionBegin;
276   PetscCheck(mengine,PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
277   PetscCheck(obj->name,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Cannot get object that has no name");
278   PetscCall(PetscObjectQueryFunction(obj,"PetscMatlabEngineGet_C",&get));
279   PetscCheck(get,PETSC_COMM_SELF,PETSC_ERR_SUP,"Object %s cannot be gotten from MATLAB engine",obj->class_name);
280   PetscCall(PetscInfo(0,"Getting MATLAB object\n"));
281   PetscCall((*get)(obj,mengine->ep));
282   PetscCall(PetscInfo(0,"Got MATLAB object: %s\n",obj->name));
283   PetscFunctionReturn(0);
284 }
285 
286 /*
287     The variable Petsc_Matlab_Engine_keyval is used to indicate an MPI attribute that
288   is attached to a communicator, in this case the attribute is a PetscMatlabEngine
289 */
290 static PetscMPIInt Petsc_Matlab_Engine_keyval = MPI_KEYVAL_INVALID;
291 
292 /*@C
293    PETSC_MATLAB_ENGINE_ - Creates a MATLAB engine on each process in a communicator.
294 
295    Not Collective
296 
297    Input Parameter:
298 .  comm - the MPI communicator to share the engine
299 
300    Options Database:
301 .  -matlab_engine_host - hostname
302 
303    Level: developer
304 
305    Notes:
306    Unlike almost all other PETSc routines, this does not return
307    an error code. Usually used in the form
308 $      PetscMatlabEngineYYY(XXX object,PETSC_MATLAB_ENGINE_(comm));
309 
310 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
311           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
312           PetscMatlabEngineCreate(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine,
313           PETSC_MATLAB_ENGINE_WORLD, PETSC_MATLAB_ENGINE_SELF
314 
315 @*/
316 PetscMatlabEngine  PETSC_MATLAB_ENGINE_(MPI_Comm comm)
317 {
318   PetscErrorCode    ierr;
319   PetscBool         flg;
320   PetscMatlabEngine mengine;
321 
322   PetscFunctionBegin;
323   if (Petsc_Matlab_Engine_keyval == MPI_KEYVAL_INVALID) {
324     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Matlab_Engine_keyval,0);
325     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
326   }
327   ierr = MPI_Comm_get_attr(comm,Petsc_Matlab_Engine_keyval,(void**)&mengine,(int*)&flg);
328   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
329   if (!flg) { /* viewer not yet created */
330     ierr = PetscMatlabEngineCreate(comm,NULL,&mengine);
331     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
332     ierr = PetscObjectRegisterDestroy((PetscObject)mengine);
333     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
334     ierr = MPI_Comm_set_attr(comm,Petsc_Matlab_Engine_keyval,mengine);
335     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
336   }
337   PetscFunctionReturn(mengine);
338 }
339 
340 /*@C
341     PetscMatlabEnginePutArray - Puts an array into the MATLAB space, treating it as a Fortran style (column major ordering) array. For parallel objects,
342       each processors part is put in a separate  MATLAB process.
343 
344     Collective on PetscObject
345 
346     Input Parameters:
347 +    mengine - the MATLAB engine
348 .    m,n - the dimensions of the array
349 .    array - the array (represented in one dimension)
350 -    name - the name of the array
351 
352    Level: advanced
353 
354 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEngineCreate(), PetscMatlabEngineGet(),
355           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
356           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePut(), PetscMatlabEngineGetArray(), PetscMatlabEngine
357 @*/
358 PetscErrorCode  PetscMatlabEnginePutArray(PetscMatlabEngine mengine,int m,int n,const PetscScalar *array,const char name[])
359 {
360   mxArray *mat;
361 
362   PetscFunctionBegin;
363   PetscCheck(mengine,PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
364   PetscCall(PetscInfo(0,"Putting MATLAB array %s\n",name));
365 #if !defined(PETSC_USE_COMPLEX)
366   mat = mxCreateDoubleMatrix(m,n,mxREAL);
367 #else
368   mat = mxCreateDoubleMatrix(m,n,mxCOMPLEX);
369 #endif
370   PetscCall(PetscArraycpy(mxGetPr(mat),array,m*n));
371   engPutVariable(mengine->ep,name,mat);
372 
373   PetscCall(PetscInfo(0,"Put MATLAB array %s\n",name));
374   PetscFunctionReturn(0);
375 }
376 
377 /*@C
378     PetscMatlabEngineGetArray - Gets a variable from MATLAB into an array
379 
380     Not Collective
381 
382     Input Parameters:
383 +    mengine - the MATLAB engine
384 .    m,n - the dimensions of the array
385 .    array - the array (represented in one dimension)
386 -    name - the name of the array
387 
388    Level: advanced
389 
390 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineCreate(),
391           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
392           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGet(), PetscMatlabEngine
393 @*/
394 PetscErrorCode  PetscMatlabEngineGetArray(PetscMatlabEngine mengine,int m,int n,PetscScalar *array,const char name[])
395 {
396   mxArray        *mat;
397 
398   PetscFunctionBegin;
399   PetscCheck(mengine,PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
400   PetscCall(PetscInfo(0,"Getting MATLAB array %s\n",name));
401   mat  = engGetVariable(mengine->ep,name);
402   PetscCheck(mat,PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to get array %s from matlab",name);
403   PetscCheck(mxGetM(mat) == (size_t) m,PETSC_COMM_SELF,PETSC_ERR_LIB,"Array %s in MATLAB first dimension %d does not match requested size %d",name,(int)mxGetM(mat),m);
404   PetscCheck(mxGetN(mat) == (size_t) n,PETSC_COMM_SELF,PETSC_ERR_LIB,"Array %s in MATLAB second dimension %d does not match requested size %d",name,(int)mxGetN(mat),m);
405   PetscCall(PetscArraycpy(array,mxGetPr(mat),m*n));
406   PetscCall(PetscInfo(0,"Got MATLAB array %s\n",name));
407   PetscFunctionReturn(0);
408 }
409