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