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: Note:
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: Level: advanced
38: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
39: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
40: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
41: @*/
42: PetscErrorCode PetscMatlabEngineCreate(MPI_Comm comm, const char host[], PetscMatlabEngine *mengine)
43: {
44: PetscMPIInt rank, size;
45: char buffer[256];
46: PetscMatlabEngine e;
47: PetscBool flg = PETSC_FALSE;
48: char lhost[64];
49: if (MATLABENGINE_CLASSID == -1) PetscClassIdRegister("MATLAB Engine", &MATLABENGINE_CLASSID);
50: PetscHeaderCreate(e, MATLABENGINE_CLASSID, "MatlabEngine", "MATLAB Engine", "Sys", comm, PetscMatlabEngineDestroy, NULL);
52: if (!host) {
53: PetscOptionsGetString(NULL, NULL, "-matlab_engine_host", lhost, sizeof(lhost), &flg);
54: if (flg) host = lhost;
55: }
56: flg = PETSC_FALSE;
57: PetscOptionsGetBool(NULL, NULL, "-matlab_engine_graphics", &flg, NULL);
59: if (host) {
60: PetscInfo(0, "Starting MATLAB engine on %s\n", host);
61: PetscStrcpy(buffer, "ssh ");
62: PetscStrcat(buffer, host);
63: PetscStrcat(buffer, " \"");
64: PetscStrlcat(buffer, PETSC_MATLAB_COMMAND, sizeof(buffer));
65: if (!flg) PetscStrlcat(buffer, " -nodisplay ", sizeof(buffer));
66: PetscStrlcat(buffer, " -nosplash ", sizeof(buffer));
67: PetscStrcat(buffer, "\"");
68: } else {
69: PetscStrncpy(buffer, PETSC_MATLAB_COMMAND, sizeof(buffer));
70: if (!flg) PetscStrlcat(buffer, " -nodisplay ", sizeof(buffer));
71: PetscStrlcat(buffer, " -nosplash ", sizeof(buffer));
72: }
73: PetscInfo(0, "Starting MATLAB engine with command %s\n", buffer);
74: e->ep = engOpen(buffer);
76: engOutputBuffer(e->ep, e->buffer, sizeof(e->buffer));
77: if (host) PetscInfo(0, "Started MATLAB engine on %s\n", host);
78: else PetscInfo(0, "Started MATLAB engine\n");
80: MPI_Comm_rank(comm, &rank);
81: MPI_Comm_size(comm, &size);
82: PetscMatlabEngineEvaluate(e, "MPI_Comm_rank = %d; MPI_Comm_size = %d;\n", rank, size);
83: /* work around bug in MATLAB R2021b https://www.mathworks.com/matlabcentral/answers/1566246-got-error-using-exit-in-nodesktop-mode */
84: PetscMatlabEngineEvaluate(e, "settings");
85: *mengine = e;
86: return 0;
87: }
89: /*@
90: PetscMatlabEngineDestroy - Shuts down a MATLAB engine.
92: Collective on v
94: Input Parameters:
95: . e - the engine
97: Level: advanced
99: .seealso: `PetscMatlabEngineCreate()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
100: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
101: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
102: @*/
103: PetscErrorCode PetscMatlabEngineDestroy(PetscMatlabEngine *v)
104: {
105: int err;
107: if (!*v) return 0;
109: if (--((PetscObject)(*v))->refct > 0) return 0;
110: PetscInfo(0, "Stopping MATLAB engine\n");
111: err = engClose((*v)->ep);
113: PetscInfo(0, "MATLAB engine stopped\n");
114: PetscHeaderDestroy(v);
115: return 0;
116: }
118: /*@C
119: PetscMatlabEngineEvaluate - Evaluates a string in MATLAB
121: Not Collective
123: Input Parameters:
124: + mengine - the MATLAB engine
125: - string - format as in a printf()
127: Notes:
128: Run the PETSc program with -info to always have printed back MATLAB's response to the string evaluation
130: If the string utilizes a MATLAB script that needs to run in the engine, the script must be available via MATLABPATH on that machine.
132: Level: advanced
134: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
135: `PetscMatlabEngineCreate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
136: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
137: @*/
138: PetscErrorCode PetscMatlabEngineEvaluate(PetscMatlabEngine mengine, const char string[], ...)
139: {
140: va_list Argp;
141: char buffer[1024];
142: size_t fullLength;
144: va_start(Argp, string);
145: PetscVSNPrintf(buffer, sizeof(buffer) - 9 - 5, string, &fullLength, Argp);
146: va_end(Argp);
148: PetscInfo(0, "Evaluating MATLAB string: %s\n", buffer);
149: engEvalString(mengine->ep, buffer);
150: PetscInfo(0, "Done evaluating MATLAB string: %s\n", buffer);
151: PetscInfo(0, " MATLAB output message: %s\n", mengine->buffer);
153: /*
154: Check for error in MATLAB: indicated by ? as first character in engine->buffer
155: */
157: return 0;
158: }
160: /*@C
161: PetscMatlabEngineGetOutput - Gets a string buffer where the MATLAB output is
162: printed
164: Not Collective
166: Input Parameter:
167: . mengine - the MATLAB engine
169: Output Parameter:
170: . string - buffer where MATLAB output is printed
172: Level: advanced
174: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
175: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineCreate()`, `PetscMatlabEnginePrintOutput()`,
176: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
177: @*/
178: PetscErrorCode PetscMatlabEngineGetOutput(PetscMatlabEngine mengine, char **string)
179: {
181: *string = mengine->buffer;
182: return 0;
183: }
185: /*@C
186: PetscMatlabEnginePrintOutput - prints the output from MATLAB to an ASCII file
188: Collective on mengine
190: Input Parameters:
191: + mengine - the MATLAB engine
192: - fd - the file
194: Level: advanced
196: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
197: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEngineCreate()`,
198: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
199: @*/
200: PetscErrorCode PetscMatlabEnginePrintOutput(PetscMatlabEngine mengine, FILE *fd)
201: {
202: PetscMPIInt rank;
205: MPI_Comm_rank(PetscObjectComm((PetscObject)mengine), &rank);
206: PetscSynchronizedFPrintf(PetscObjectComm((PetscObject)mengine), fd, "[%d]%s", rank, mengine->buffer);
207: PetscSynchronizedFlush(PetscObjectComm((PetscObject)mengine), fd);
208: return 0;
209: }
211: /*@
212: PetscMatlabEnginePut - Puts a Petsc object, such as a `Mat` or `Vec` into the MATLAB space. For parallel objects,
213: each processor's part is put in a separate MATLAB process.
215: Collective on mengine
217: Input Parameters:
218: + mengine - the MATLAB engine
219: - object - the PETSc object, for example Vec
221: Level: advanced
223: Note:
224: `Mat`s transferred between PETSc and MATLAB and vis versa are transposed in the other space
225: (this is because MATLAB uses compressed column format and PETSc uses compressed row format)
227: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`,
228: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
229: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
230: @*/
231: PetscErrorCode PetscMatlabEnginePut(PetscMatlabEngine mengine, PetscObject obj)
232: {
233: PetscErrorCode (*put)(PetscObject, void *);
236: PetscObjectQueryFunction(obj, "PetscMatlabEnginePut_C", &put);
238: PetscInfo(0, "Putting MATLAB object\n");
239: (*put)(obj, mengine->ep);
240: PetscInfo(0, "Put MATLAB object: %s\n", obj->name);
241: return 0;
242: }
244: /*@
245: PetscMatlabEngineGet - Gets a variable from MATLAB into a PETSc object.
247: Collective on mengine
249: Input Parameters:
250: + mengine - the MATLAB engine
251: - object - the PETSc object, for example a `Vec`
253: Level: advanced
255: Note:
256: `Mat`s transferred between PETSc and MATLAB and vis versa are transposed in the other space
257: (this is because MATLAB uses compressed column format and PETSc uses compressed row format)
259: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`,
260: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
261: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
262: @*/
263: PetscErrorCode PetscMatlabEngineGet(PetscMatlabEngine mengine, PetscObject obj)
264: {
265: PetscErrorCode (*get)(PetscObject, void *);
269: PetscObjectQueryFunction(obj, "PetscMatlabEngineGet_C", &get);
271: PetscInfo(0, "Getting MATLAB object\n");
272: (*get)(obj, mengine->ep);
273: PetscInfo(0, "Got MATLAB object: %s\n", obj->name);
274: return 0;
275: }
277: /*
278: The variable Petsc_Matlab_Engine_keyval is used to indicate an MPI attribute that
279: is attached to a communicator, in this case the attribute is a PetscMatlabEngine
280: */
281: static PetscMPIInt Petsc_Matlab_Engine_keyval = MPI_KEYVAL_INVALID;
283: /*@C
284: PETSC_MATLAB_ENGINE_ - Creates a MATLAB engine on each process in a communicator.
286: Not Collective
288: Input Parameter:
289: . comm - the MPI communicator to share the engine
291: Options Database Key:
292: . -matlab_engine_host - hostname on which to run MATLAB, one must be able to ssh to this host
294: Level: developer
296: Note:
297: Unlike almost all other PETSc routines, this does not return
298: an error code. Usually used in the form
299: $ PetscMatlabEngineYYY(XXX object,PETSC_MATLAB_ENGINE_(comm));
301: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGet()`,
302: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
303: `PetscMatlabEngineCreate()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`,
304: `PETSC_MATLAB_ENGINE_WORLD`, `PETSC_MATLAB_ENGINE_SELF`
305: @*/
306: PetscMatlabEngine PETSC_MATLAB_ENGINE_(MPI_Comm comm)
307: {
308: PetscErrorCode ierr;
309: PetscBool flg;
310: PetscMatlabEngine mengine;
312: if (Petsc_Matlab_Engine_keyval == MPI_KEYVAL_INVALID) {
313: MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Matlab_Engine_keyval, 0);
314: if (ierr) {
315: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
316: return NULL;
317: }
318: }
319: MPI_Comm_get_attr(comm, Petsc_Matlab_Engine_keyval, (void **)&mengine, (int *)&flg);
320: if (ierr) {
321: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
322: return NULL;
323: }
324: if (!flg) { /* viewer not yet created */
325: PetscMatlabEngineCreate(comm, NULL, &mengine);
326: if (ierr) {
327: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
328: return NULL;
329: }
330: PetscObjectRegisterDestroy((PetscObject)mengine);
331: if (ierr) {
332: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
333: return NULL;
334: }
335: MPI_Comm_set_attr(comm, Petsc_Matlab_Engine_keyval, mengine);
336: if (ierr) {
337: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_MATLAB_ENGINE_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
338: return NULL;
339: }
340: }
341: return mengine;
342: }
344: /*@C
345: PetscMatlabEnginePutArray - Puts an array into the MATLAB space, treating it as a Fortran style (column major ordering) array. For parallel objects,
346: each processors part is put in a separate MATLAB process.
348: Collective on mengine
350: Input Parameters:
351: + mengine - the MATLAB engine
352: . m,n - the dimensions of the array
353: . array - the array (represented in one dimension)
354: - name - the name of the array
356: Level: advanced
358: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEngineCreate()`, `PetscMatlabEngineGet()`,
359: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
360: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineGetArray()`, `PetscMatlabEngine`
361: @*/
362: PetscErrorCode PetscMatlabEnginePutArray(PetscMatlabEngine mengine, int m, int n, const PetscScalar *array, const char name[])
363: {
364: mxArray *mat;
367: PetscInfo(0, "Putting MATLAB array %s\n", name);
368: #if !defined(PETSC_USE_COMPLEX)
369: mat = mxCreateDoubleMatrix(m, n, mxREAL);
370: #else
371: mat = mxCreateDoubleMatrix(m, n, mxCOMPLEX);
372: #endif
373: PetscArraycpy(mxGetPr(mat), array, m * n);
374: engPutVariable(mengine->ep, name, mat);
376: PetscInfo(0, "Put MATLAB array %s\n", name);
377: return 0;
378: }
380: /*@C
381: PetscMatlabEngineGetArray - Gets a variable from MATLAB into an array
383: Not Collective
385: Input Parameters:
386: + mengine - the MATLAB engine
387: . m,n - the dimensions of the array
388: . array - the array (represented in one dimension)
389: - name - the name of the array
391: Level: advanced
393: .seealso: `PetscMatlabEngineDestroy()`, `PetscMatlabEnginePut()`, `PetscMatlabEngineCreate()`,
394: `PetscMatlabEngineEvaluate()`, `PetscMatlabEngineGetOutput()`, `PetscMatlabEnginePrintOutput()`,
395: `PETSC_MATLAB_ENGINE_()`, `PetscMatlabEnginePutArray()`, `PetscMatlabEngineGet()`, `PetscMatlabEngine`
396: @*/
397: PetscErrorCode PetscMatlabEngineGetArray(PetscMatlabEngine mengine, int m, int n, PetscScalar *array, const char name[])
398: {
399: mxArray *mat;
402: PetscInfo(0, "Getting MATLAB array %s\n", name);
403: mat = engGetVariable(mengine->ep, name);
407: PetscArraycpy(array, mxGetPr(mat), m * n);
408: PetscInfo(0, "Got MATLAB array %s\n", name);
409: return 0;
410: }