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