Introduction
This document describes the process of calling Matlab computations within MML models. This is one of several ways to connect JSim and Matlab. For an overview of possible JSim/Matlab connection strategies, see Connecting JSim and Matlab.
Prerequisites:
- Connecting JSim and Matlab
- Using Functions and Procedures in MML
- Familiarity with Matlab
- Familiarity with either the Java or C programming languages, preferably both
Contents
- Getting Started
- Calling Matlab via the command line
- Example: Determinant calculated via Java function and Matlab
- Example: Matrix inverse calculated via Java procedure and Matlab
- Example: 4 solute reaction network, steady state calculated via Java procedure and Matlab
- Comments or Questions?
- Calling Matlab via an API
- Future Plans
Getting Started
Although, in the future, model writers will be able to write Matlab commands directly in MML, for the present, you must connect to Matlab via Java or C (follow links for details on each language). Using either language you may call Matlab via the command line or an available Matlab API. Calling Matlab via the command line is simple and robust, but the overhead of loading Matlab for each function or procedure call may result in inadequate performance, depending upon the nature of the problem at hand. Calling Matlab via a Java or C API requires more technical expertise, but is potentially much higher performance, again depending upon the problem.
Calling Matlab via the command line
In this scenario, an MML function or procedure creates or modifies one or more Matlab .m files, launches Matlab to run the .m file command which writes an appropriate output file, then reads the output file back, and returns the results to the JSim model. Since there is significant overhead in starting Matlab, this approach is only well suited to problems in which the number of Matlab calls is limited or the computation time for each Matlab call in large in comparison to the Matlab load time.
Example: Determinant calculated via Java Function and Matlab
In this example model, a Java function runs the Matlab application to calculate the determinant v of a random square matrix u.
source real function determinant(u@x@y) { language="java"; maincode={{ RegularGridData gx = (RegularGridData) u.grid(0); RegularGridData gy = (RegularGridData) u.grid(1); int N = gx.ct(); try { java.io.File f = new java.io.File("jdet.m"); java.io.PrintWriter wrt = new java.io.PrintWriter( new java.io.FileWriter(f)); wrt.print("A=[" + Util.pretty(u.samples()) + "];"); wrt.print("A=reshape(A," + N + "," + N + ");"); wrt.println("B=det(A');"); wrt.println("save 'mdet.txt' B -ASCII"); wrt.println("exit"); wrt.close(); Process proc = Runtime.getRuntime().exec( "matlab -nodesktop -nosplash -r jdet"); proc.waitFor(); String txt = UtilIO.readText( new java.io.File("mdet.txt")); return Util.toDouble(txt); } catch (Exception e) { throw Xcept.wrap(e); } }}; } math main { int N=2; realDomain x, y; x.min=1; x.max=N; x.delta=1; y.min=1; y.max=N; y.delta=1; real u(x,y) = random(); real v = determinant(u@x@y); }
Example: Matrix inversion calculated via Java Procedure and Matlab
In this example model, a Java procedure runs the Matlab application to calculate the inverse v of a random square matrix u.
source procedure inverse(u@x@y; v@x@y) { language="java"; maincode={{ RegularGridData gx = (RegularGridData) u.grid(0); RegularGridData gy = (RegularGridData) u.grid(1); int N = gx.ct(); try { java.io.File f = new java.io.File("jinv.m"); java.io.PrintWriter wrt = new java.io.PrintWriter( new java.io.FileWriter(f)); wrt.print("A=[" + Util.pretty(u.samples()) + "];"); wrt.print("A=reshape(A," + N + "," + N + ");"); wrt.println("B=inv(A);"); wrt.println("save 'mdet.txt' B -ASCII"); wrt.println("exit"); wrt.close(); Process proc = Runtime.getRuntime().exec( "matlab -nodesktop -nosplash -r jinv"); proc.waitFor(); String txt = UtilIO.readText( new java.io.File("mdet.txt")); java.util.StringTokenizer stok = new java.util.StringTokenizer(txt); for (int i=0; i<N*N; i++) v.set(i, Util.toDouble(stok.nextToken())); } catch (Exception e) { throw Xcept.wrap(e); } }}; } math main { int N=2; realDomain x, y; x.min=1; x.max=N; x.delta=1; y.min=1; y.max=N; y.delta=1; real u(x,y) = random(); real v(x,y); inverse(u@x@y, v@x@y); }
Example: 4 solute reaction network, steady state calculated via Java procedure Matlab
In this example, 4 solutes (A,B,C,D) react in a mixing chamber. JSim calculates the time-series solution via standard ODEs. JSim also passes the stoichiometry matrix to Matlab, for calculation of the steady-state solution(Af, Bf, Cf, Df).
JSim model with matlab:
JSim model without matlab (for comparison):
Calling Matlab via an API
Using an API to control to Matlab allow the model writer to start the Matlab engine only once, rather than multiple times. Depending upon the problem, this approach can save a significant amount of computation time, usually at the cost of more complex control code.
Matlab provides a variety of APIs for connecting to external software. A complete description of Matlab's APIs is beyond the scope of this document, but see, for example: "Mastering Matlab 7" by Hanselman and Littlefield, chapter 34. In addition, various third parties have provided Matlab connectivity products. Again, a complete review of such products is beyond the scope of this document. This document will demonstrate one possible API for controlling Matlab from JSim: the Matlab Engine C API.
The Matlab Engine C API
This API is supported by Mathworks, and so should be fairly stable. Connecting via C poses the standard portability problems mentioned in Calling C Code From MML, including the inability to run in applets and the difficulties of distributing such models to non-expert users.
Example of calling Matlab Engine C API from MML
This example is under construction.
Future plans
In the future, JSim will support writing Matlab commands directly within MML functions and procedures. When this feature is available, it will make the process of calling Matlab efficiently from MML considerably simpler that it is currently. The text below is a mockup of what Matlab F&P might look like. In this example, the Matlab procedure reverse() reverses the elements in the provided 1-dimensional array.
source procedure reverse(u@t; v@t) { language = "matlab"; maincode={{ % u and t automatically generated N = length(u) v = u( N:(-1):1 ) }}; } math main { realDomain t; t.min=0; t.max=4; t.delta=1; real u(t) = t^2; real v(t); reverse(u@t, v@t); }
Comments or Questions?
Model development and archiving support at https://www.imagwiki.nibib.nih.gov/physiome provided by the following grants: NIH U01HL122199 Analyzing the Cardiac Power Grid, 09/15/2015 - 05/31/2020, NIH/NIBIB BE08407 Software Integration, JSim and SBW 6/1/09-5/31/13; NIH/NHLBI T15 HL88516-01 Modeling for Heart, Lung and Blood: From Cell to Organ, 4/1/07-3/31/11; NSF BES-0506477 Adaptive Multi-Scale Model Simulation, 8/15/05-7/31/08; NIH/NHLBI R01 HL073598 Core 3: 3D Imaging and Computer Modeling of the Respiratory Tract, 9/1/04-8/31/09; as well as prior support from NIH/NCRR P41 RR01243 Simulation Resource in Circulatory Mass Transport and Exchange, 12/1/1980-11/30/01 and NIH/NIBIB R01 EB001973 JSim: A Simulation Analysis Platform, 3/1/02-2/28/07.