Actual source code: matlab.c
2: #include <engine.h> /* MATLAB include file */
3: #include <petscsys.h>
4: #include <petscmatlab.h>
5: #include <petsc/private/petscimpl.h>
7: struct _p_PetscMatlabEngine {
8: PETSCHEADER(int);
9: Engine *ep;
10: char buffer[1024];
11: };
13: PetscClassId MATLABENGINE_CLASSID = -1;
15: /*@C
16: PetscMatlabEngineCreate - Creates a MATLAB engine object
18: Not Collective
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)
24: Output Parameter:
25: . mengine - the resulting object
27: Options Database Keys:
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)
32: Notes:
33: If a host string is passed in, any MATLAB scripts that need to run in the
34: engine must be available via MATLABPATH on that machine.
36: One must `./configure` PETSc with `--with-matlab [-with-matlab-dir=matlab_root_directory]` to
37: use this capability
39: Level: advanced
41: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
42: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
43: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
44: @*/
45: PetscErrorCode PetscMatlabEngineCreate(MPI_Comm comm, const char host[], PetscMatlabEngine *mengine)
46: {
47: PetscMPIInt rank, size;
48: char buffer[256];
49: PetscMatlabEngine e;
50: PetscBool flg = PETSC_FALSE;
51: char lhost[64];
52: if (MATLABENGINE_CLASSID == -1) PetscClassIdRegister("MATLAB Engine", &MATLABENGINE_CLASSID);
53: PetscHeaderCreate(e, MATLABENGINE_CLASSID, "MatlabEngine", "MATLAB Engine", "Sys", comm, PetscMatlabEngineDestroy, NULL);
55: if (!host) {
56: PetscOptionsGetString(NULL, NULL, "-matlab_engine_host", lhost, sizeof(lhost), &flg);
57: if (flg) host = lhost;
58: }
59: flg = PETSC_FALSE;
60: PetscOptionsGetBool(NULL, NULL, "-matlab_engine_graphics", &flg, NULL);
62: if (host) {
63: PetscInfo(0, "Starting MATLAB engine on %s\n", host);
64: PetscStrcpy(buffer, "ssh ");
65: PetscStrcat(buffer, host);
66: PetscStrcat(buffer, " \"");
67: PetscStrlcat(buffer, PETSC_MATLAB_COMMAND, sizeof(buffer));
68: if (!flg) PetscStrlcat(buffer, " -nodisplay ", sizeof(buffer));
69: PetscStrlcat(buffer, " -nosplash ", sizeof(buffer));
70: PetscStrcat(buffer, "\"");
71: } else {
72: PetscStrncpy(buffer, PETSC_MATLAB_COMMAND, sizeof(buffer));
73: if (!flg) PetscStrlcat(buffer, " -nodisplay ", sizeof(buffer));
74: PetscStrlcat(buffer, " -nosplash ", sizeof(buffer));
75: }
76: PetscInfo(0, "Starting MATLAB engine with command %s\n", buffer);
77: e->ep = engOpen(buffer);
79: engOutputBuffer(e->ep, e->buffer, sizeof(e->buffer));
80: if (host) PetscInfo(0, "Started MATLAB engine on %s\n", host);
81: else PetscInfo(0, "Started MATLAB engine\n");
83: MPI_Comm_rank(comm, &rank);
84: MPI_Comm_size(comm, &size);
85: PetscMatlabEngineEvaluate(e, "MPI_Comm_rank = %d; MPI_Comm_size = %d;\n", rank, size);
86: /* work around bug in MATLAB R2021b https://www.mathworks.com/matlabcentral/answers/1566246-got-error-using-exit-in-nodesktop-mode */
87: PetscMatlabEngineEvaluate(e, "settings");
88: *mengine = e;
89: return 0;
90: }
92: /*@
93: PetscMatlabEngineDestroy - Shuts down a MATLAB engine.
95: Collective
97: Input Parameters:
98: . e - the engine
100: Level: advanced
102: .seealso: `PetscMatlabEngineCreate()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
103: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
104: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
105: @*/
106: PetscErrorCode PetscMatlabEngineDestroy(PetscMatlabEngine *v)
107: {
108: int err;
110: if (!*v) return 0;
112: if (--((PetscObject)(*v))->refct > 0) return 0;
113: PetscInfo(0, "Stopping MATLAB engine\n");
114: err = engClose((*v)->ep);
116: PetscInfo(0, "MATLAB engine stopped\n");
117: PetscHeaderDestroy(v);
118: return 0;
119: }
121: /*@C
122: PetscMatlabEngineEvaluate - Evaluates a string in MATLAB
124: Not Collective
126: Input Parameters:
127: + mengine - the MATLAB engine
128: - string - format as in a printf()
130: Notes:
131: Run the PETSc program with -info to always have printed back MATLAB's response to the string evaluation
133: If the string utilizes a MATLAB script that needs to run in the engine, the script must be available via MATLABPATH on that machine.
135: Level: advanced
137: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
138: `PetscMatlabEngineCreate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
139: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
140: @*/
141: PetscErrorCode PetscMatlabEngineEvaluate(PetscMatlabEngine mengine, const char string[], ...)
142: {
143: va_list Argp;
144: char buffer[1024];
145: size_t fullLength;
147: va_start(Argp, string);
148: PetscVSNPrintf(buffer, sizeof(buffer) - 9 - 5, string, &fullLength, Argp);
149: va_end(Argp);
151: PetscInfo(0, "Evaluating MATLAB string: %s\n", buffer);
152: engEvalString(mengine->ep, buffer);
153: PetscInfo(0, "Done evaluating MATLAB string: %s\n", buffer);
154: PetscInfo(0, " MATLAB output message: %s\n", mengine->buffer);
156: /*
157: Check for error in MATLAB: indicated by ? as first character in engine->buffer
158: */
160: return 0;
161: }
163: /*@C
164: PetscMatlabEngineGetOutput - Gets a string buffer where the MATLAB output is
165: printed
167: Not Collective
169: Input Parameter:
170: . mengine - the MATLAB engine
172: Output Parameter:
173: . string - buffer where MATLAB output is printed
175: Level: advanced
177: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
178: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineCreate()`, `PetscMatlabEnginePrintOutput()`,
179: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
180: @*/
181: PetscErrorCode PetscMatlabEngineGetOutput(PetscMatlabEngine mengine, char **string)
182: {
184: *string = mengine->buffer;
185: return 0;
186: }
188: /*@C
189: PetscMatlabEnginePrintOutput - prints the output from MATLAB to an ASCII file
191: Collective
193: Input Parameters:
194: + mengine - the MATLAB engine
195: - fd - the file
197: Level: advanced
199: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
200: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEngineCreate()`,
201: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
202: @*/
203: PetscErrorCode PetscMatlabEnginePrintOutput(PetscMatlabEngine mengine, FILE *fd)
204: {
205: PetscMPIInt rank;
208: MPI_Comm_rank(PetscObjectComm((PetscObject)mengine), &rank);
209: PetscSynchronizedFPrintf(PetscObjectComm((PetscObject)mengine), fd, "[%d]%s", rank, mengine->buffer);
210: PetscSynchronizedFlush(PetscObjectComm((PetscObject)mengine), fd);
211: return 0;
212: }
214: /*@
215: PetscMatlabEnginePut - Puts a Petsc object, such as a `Mat` or `Vec` into the MATLAB space. For parallel objects,
216: each processor's part is put in a separate MATLAB process.
218: Collective
220: Input Parameters:
221: + mengine - the MATLAB engine
222: - object - the PETSc object, for example Vec
224: Level: advanced
226: Note:
227: `Mat`s transferred between PETSc and MATLAB and vis versa are transposed in the other space
228: (this is because MATLAB uses compressed column format and PETSc uses compressed row format)
230: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`,
231: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
232: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
233: @*/
234: PetscErrorCode PetscMatlabEnginePut(PetscMatlabEngine mengine, PetscObject obj)
235: {
236: PetscErrorCode (*put)(PetscObject, void *);
239: PetscObjectQueryFunction(obj, "PetscMatlabEnginePut_C", &put);
241: PetscInfo(0, "Putting MATLAB object\n");
242: (*put)(obj, mengine->ep);
243: PetscInfo(0, "Put MATLAB object: %s\n", obj->name);
244: return 0;
245: }
247: /*@
248: PetscMatlabEngineGet - Gets a variable from MATLAB into a PETSc object.
250: Collective
252: Input Parameters:
253: + mengine - the MATLAB engine
254: - object - the PETSc object, for example a `Vec`
256: Level: advanced
258: Note:
259: `Mat`s transferred between PETSc and MATLAB and vis versa are transposed in the other space
260: (this is because MATLAB uses compressed column format and PETSc uses compressed row format)
262: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`,
263: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
264: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
265: @*/
266: PetscErrorCode PetscMatlabEngineGet(PetscMatlabEngine mengine, PetscObject obj)
267: {
268: PetscErrorCode (*get)(PetscObject, void *);
272: PetscObjectQueryFunction(obj, "PetscMatlabEngineGet_C", &get);
274: PetscInfo(0, "Getting MATLAB object\n");
275: (*get)(obj, mengine->ep);
276: PetscInfo(0, "Got MATLAB object: %s\n", obj->name);
277: return 0;
278: }
280: /*
281: The variable Petsc_Matlab_Engine_keyval is used to indicate an MPI attribute that
282: is attached to a communicator, in this case the attribute is a PetscMatlabEngine
283: */
284: static PetscMPIInt Petsc_Matlab_Engine_keyval = MPI_KEYVAL_INVALID;
286: /*@C
287: PETSC_MATLAB_ENGINE_ - Creates a MATLAB engine on each process in a communicator.
289: Not Collective
291: Input Parameter:
292: . comm - the MPI communicator to share the engine
294: Options Database Key:
295: . -matlab_engine_host - hostname on which to run MATLAB, one must be able to ssh to this host
297: Level: developer
299: Note:
300: Unlike almost all other PETSc routines, this does not return
301: an error code. Usually used in the form
302: $ PetscMatlabEngineYYY(XXX object,PETSC_MATLAB_ENGINE_(comm));
304: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
305: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
306: `PetscMatlabEngineCreate()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`,
307: `PETSC_MATLAB_ENGINE_WORLD`, `PETSC_MATLAB_ENGINE_SELF`
308: @*/
309: PetscMatlabEngine PETSC_MATLAB_ENGINE_(MPI_Comm comm)
310: {
311: PetscErrorCode ierr;
312: PetscBool flg;
313: PetscMatlabEngine mengine;
315: if (Petsc_Matlab_Engine_keyval == MPI_KEYVAL_INVALID) {
316: MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Matlab_Engine_keyval, 0);
317: if (ierr) {
318: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
319: return NULL;
320: }
321: }
322: MPI_Comm_get_attr(comm, Petsc_Matlab_Engine_keyval, (void **)&mengine, (int *)&flg);
323: if (ierr) {
324: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
325: return NULL;
326: }
327: if (!flg) { /* viewer not yet created */
328: PetscMatlabEngineCreate(comm, NULL, &mengine);
329: if (ierr) {
330: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
331: return NULL;
332: }
333: PetscObjectRegisterDestroy((PetscObject)mengine);
334: if (ierr) {
335: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
336: return NULL;
337: }
338: MPI_Comm_set_attr(comm, Petsc_Matlab_Engine_keyval, mengine);
339: if (ierr) {
340: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
341: return NULL;
342: }
343: }
344: return mengine;
345: }
347: /*@C
348: PetscMatlabEnginePutArray - Puts an array into the MATLAB space, treating it as a Fortran style (column major ordering) array. For parallel objects,
349: each processors part is put in a separate MATLAB process.
351: Collective
353: Input Parameters:
354: + mengine - the MATLAB engine
355: . m,n - the dimensions of the array
356: . array - the array (represented in one dimension)
357: - name - the name of the array
359: Level: advanced
361: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`,
362: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
363: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
364: @*/
365: PetscErrorCode PetscMatlabEnginePutArray(PetscMatlabEngine mengine, int m, int n, const PetscScalar *array, const char name[])
366: {
367: mxArray *mat;
370: PetscInfo(0, "Putting MATLAB array %s\n", name);
371: #if !defined(PETSC_USE_COMPLEX)
372: mat = mxCreateDoubleMatrix(m, n, mxREAL);
373: #else
374: mat = mxCreateDoubleMatrix(m, n, mxCOMPLEX);
375: #endif
376: PetscArraycpy(mxGetPr(mat), array, m * n);
377: engPutVariable(mengine->ep, name, mat);
379: PetscInfo(0, "Put MATLAB array %s\n", name);
380: return 0;
381: }
383: /*@C
384: PetscMatlabEngineGetArray - Gets a variable from MATLAB into an array
386: Not Collective
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
394: Level: advanced
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: mxArray *mat;
405: PetscInfo(0, "Getting MATLAB array %s\n", name);
406: mat = engGetVariable(mengine->ep, name);
410: PetscArraycpy(array, mxGetPr(mat), m * n);
411: PetscInfo(0, "Got MATLAB array %s\n", name);
412: return 0;
413: }