Calling Java Code From MML

Introduction

This document describes the process of defining and using Java procedural code within MML models.

Prerequisites:

Java code can be called from MML via either class or java source F&P. Class F&P access pre-compiled Java classes and is recommended only for JSim internal developers. This document will address java source F&P in which Java source code is embedded within MML and compiled at model build time. This mechanism guarantees maximum compatibility with future JSim releases.

Note: Variables and realDomain variables that are labeled 'private' are not available to Java functions and procedures when run as a Java applet over the web from a remote server (By default all variables and domains are public). The JSim compiler will complain that the variable is 'unknown'. The same code will compile and run fine when run locally.

The remainder of this document shows several examples of calling Java code from MML. For the complete Application Programmer Interface (API), see The JSim Public API . Examples are:

  • Example 1 - a scalar function;
  • Example 2 - a non-scalar function;
  • Example 3 - a procedure.
  • Example 4 - a procedure used within an electrophysiology model to detect peaks.
  • Comments or Questions?

Give feedback

Example 1

In the following example, a java source function "gmean" is defined that accepts two scalar arguments and returns their geometric mean. The main program defines a variable v(t) as the geometric mean of t and t^3, which should thus be equal to t^2:

// geometric mean via java function
source real function gmean(a, b) {
  language="java";
  maincode={{
    double aval = a.realVal();
    double bval = b.realVal();
    return Math.sqrt(aval*bval);
  }};
}

math main {
  realDomain t;
  t.min=0; t.max=5; t.delta=1;
  real v(t) = gmean(t, t^3);
}

The first paragraph comprises the gmean function declaration. The keyword "real" indicates that the function returns a real number. (Currently, real is the only supported function data type. Other data types may be supported in the future.) The keyword "source" indicates that the function will be defined in terms on source code within MML. The name "gmean" follows the keyword "function", giving a unique name to this function. Function names must follow standard MML naming conventions. The argument list following the function name indicates this function takes exactly two scalar arguments. (Non-scalar arguments use the @ directive, described later in this document).

The "language" clause inside the function declaration indicates the procedural code will follow the JSim Java Model API . The "maincode" clause contains the java procedural code. Conventions for this code are fully described in The JSim Java API . In brief, the modeler specified maincode block is copied into a double returning dynamic Java method, whose calling arguments are RealNData objects named a and b. RealNData has a method realVal() returning the value of a scalar variable. The return statement is required for a real function. It's omission will cause a compiler error.

� The second paragraph comprises the main line of the MML model. In this case, gmean will be called once for each t. Although only a single equation using gmean is present in this example, multiple uses of gmean, including nested uses, are supported. It should be noted that incautious use of static methods within maincode can break this nesting ability.

Example 2

The first example is trivial because the desired functionality could more easily be obtained simply using MML. This is the case for most situations involving scalar arguments. Function and procedures become more useful when passing multi-dimensional arguments because the looping constructs within Java are more general than those available in MML.

In the following example, one-dimensional integration is implemented as a java source function:

// calculating integral via java function
source real function jintegral(u@t) {
  language="java";
  maincode={{
    RegularGridData t = (RegularGridData) u.grid(0);
    int[] inx = new int[1];
    double tot = 0;
    for (int i=0; i<t.ct(); i++) {
      int mult = 2;
      if (i==0 || i==t.ct()-1) mult = 1;
      inx[0] = i;
      tot += mult*u.realVal(inx);
    }
    tot *= (t.max() - t.min()) / (2*(t.ct() - 1));
    return tot;   
  }};
}

math main {
  realDomain t;
  t.min=0; t.max=5; t.delta=1;
  real u(t) = t*t;
  real v = jintegral(u@t);
} 

The MML @ construct is used here twice. In the function declaration, u@t indicates that the single function argument must be one-dimensional. When the function is called u@t, which should be read "u for all t", indicates that u values for all t should be passed to integral. If a function's declared argument dimensions do not match the arguments passed at call time, MML will alert the modeler at compile time.

RealNData have a method grid(int i), which provides access to the associated data grid(s) of a multidimensional variable. Since the function argument is not scalar, realVal(int[]) replaces realVal() as the method used to access argument values at various grid points. Again, see the JSim Public API for further information.

Multiple @ constructs can be used for higher dimensional function arguments.

Example 3

In the following example a procedure, rather than a function is demonstrated. The procedure "reverse" takes a one-dimensional input argument, reverses the order of the data, and places the result in a one-dimensional output argument:

// array reversal via java procedure
source procedure reverse(u@t; v@t) {
  language="java";
  maincode={{
    RegularGridData t = (RegularGridData) u.grid(0);
    for (int i=0; i<t.ct(); i++) {
      double uval = u.realVal(i);
      int inx = t.ct()-i-1;
      v.set(inx, uval);
    }
  }};
}

math main {
  realDomain t;
  t.min=0; t.max=6; t.delta=2;
  real u(t) = t*t;
  real v(t);
  reverse(u@t, v@t); 
}

The keywords "java" and "procedure" indicate that the embedded code block(s) will follow the JSim Java Model API for procedures. Most comments above regarding functions apply equally to procedures, with a few differences noted below.

The procedure argument list separates input arguments from output arguments with a semi-colon, with inputs listed first. This example has one input and one output argument.

The maincode block returns no value as is appropriate for a procedure. The RealNData method set(int, double) provides a means to set the value of output arguments. Again, see the JSim Public API for further information.

Comments or Questions?

Give feedback

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.