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