xref: /petsc/src/sys/classes/matlabengine/matlab.c (revision b698fc57f0bea7237255b29c1b77df0acc362ffd) !
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);CHKERRQ(ierr);
94   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
95   ierr = PetscMatlabEngineEvaluate(e,"MPI_Comm_rank = %d; MPI_Comm_size = %d;\n",rank,size);
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);CHKERRQ(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 
298 /*@C
299    PETSC_MATLAB_ENGINE_ - Creates a MATLAB engine on each process in a communicator.
300 
301    Not Collective
302 
303    Input Parameter:
304 .  comm - the MPI communicator to share the engine
305 
306    Options Database:
307 .  -matlab_engine_host - hostname
308 
309    Level: developer
310 
311    Notes:
312    Unlike almost all other PETSc routines, this does not return
313    an error code. Usually used in the form
314 $      PetscMatlabEngineYYY(XXX object,PETSC_MATLAB_ENGINE_(comm));
315 
316 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineGet(),
317           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
318           PetscMatlabEngineCreate(), PetscMatlabEnginePutArray(), PetscMatlabEngineGetArray(), PetscMatlabEngine,
319           PETSC_MATLAB_ENGINE_WORLD, PETSC_MATLAB_ENGINE_SELF
320 
321 @*/
322 PetscMatlabEngine  PETSC_MATLAB_ENGINE_(MPI_Comm comm)
323 {
324   PetscErrorCode    ierr;
325   PetscBool         flg;
326   PetscMatlabEngine mengine;
327 
328   PetscFunctionBegin;
329   if (Petsc_Matlab_Engine_keyval == MPI_KEYVAL_INVALID) {
330     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Matlab_Engine_keyval,0);
331     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
332   }
333   ierr = MPI_Comm_get_attr(comm,Petsc_Matlab_Engine_keyval,(void**)&mengine,(int*)&flg);
334   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
335   if (!flg) { /* viewer not yet created */
336     ierr = PetscMatlabEngineCreate(comm,NULL,&mengine);
337     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
338     ierr = PetscObjectRegisterDestroy((PetscObject)mengine);
339     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_REPEAT," ");PetscFunctionReturn(NULL);}
340     ierr = MPI_Comm_set_attr(comm,Petsc_Matlab_Engine_keyval,mengine);
341     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_MATLAB_ENGINE_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);}
342   }
343   PetscFunctionReturn(mengine);
344 }
345 
346 /*@C
347     PetscMatlabEnginePutArray - Puts an array into the MATLAB space, treating it as a Fortran style (column major ordering) array. For parallel objects,
348       each processors part is put in a separate  MATLAB process.
349 
350     Collective on PetscObject
351 
352     Input Parameters:
353 +    mengine - the MATLAB engine
354 .    m,n - the dimensions of the array
355 .    array - the array (represented in one dimension)
356 -    name - the name of the array
357 
358    Level: advanced
359 
360 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEngineCreate(), PetscMatlabEngineGet(),
361           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
362           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePut(), PetscMatlabEngineGetArray(), PetscMatlabEngine
363 @*/
364 PetscErrorCode  PetscMatlabEnginePutArray(PetscMatlabEngine mengine,int m,int n,const PetscScalar *array,const char name[])
365 {
366   PetscErrorCode ierr;
367   mxArray        *mat;
368 
369   PetscFunctionBegin;
370   if (!mengine) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
371   ierr = PetscInfo1(0,"Putting MATLAB array %s\n",name);CHKERRQ(ierr);
372 #if !defined(PETSC_USE_COMPLEX)
373   mat = mxCreateDoubleMatrix(m,n,mxREAL);
374 #else
375   mat = mxCreateDoubleMatrix(m,n,mxCOMPLEX);
376 #endif
377   ierr = PetscArraycpy(mxGetPr(mat),array,m*n);CHKERRQ(ierr);
378   engPutVariable(mengine->ep,name,mat);
379 
380   ierr = PetscInfo1(0,"Put MATLAB array %s\n",name);CHKERRQ(ierr);
381   PetscFunctionReturn(0);
382 }
383 
384 /*@C
385     PetscMatlabEngineGetArray - Gets a variable from MATLAB into an array
386 
387     Not Collective
388 
389     Input Parameters:
390 +    mengine - the MATLAB engine
391 .    m,n - the dimensions of the array
392 .    array - the array (represented in one dimension)
393 -    name - the name of the array
394 
395    Level: advanced
396 
397 .seealso: PetscMatlabEngineDestroy(), PetscMatlabEnginePut(), PetscMatlabEngineCreate(),
398           PetscMatlabEngineEvaluate(), PetscMatlabEngineGetOutput(), PetscMatlabEnginePrintOutput(),
399           PETSC_MATLAB_ENGINE_(), PetscMatlabEnginePutArray(), PetscMatlabEngineGet(), PetscMatlabEngine
400 @*/
401 PetscErrorCode  PetscMatlabEngineGetArray(PetscMatlabEngine mengine,int m,int n,PetscScalar *array,const char name[])
402 {
403   PetscErrorCode ierr;
404   mxArray        *mat;
405 
406   PetscFunctionBegin;
407   if (!mengine) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Null argument: probably PETSC_MATLAB_ENGINE_() failed");
408   ierr = PetscInfo1(0,"Getting MATLAB array %s\n",name);CHKERRQ(ierr);
409   mat  = engGetVariable(mengine->ep,name);
410   if (!mat) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Unable to get array %s from matlab",name);
411   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);
412   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);
413   ierr = PetscArraycpy(array,mxGetPr(mat),m*n);CHKERRQ(ierr);
414   ierr = PetscInfo1(0,"Got MATLAB array %s\n",name);CHKERRQ(ierr);
415   PetscFunctionReturn(0);
416 }
417 
418 
419 
420 
421 
422 
423