All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.velasolaris.plugin.controller.matlab.matconsolectl.MatlabPluginController Maven / Gradle / Ivy

The newest version!
package com.velasolaris.plugin.controller.matlab.matconsolectl;

import static com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.DEFAULT_TIMESTEP;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.velasolaris.plugin.controller.flowrate.FlowratePluginController;
import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration;
import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.ControlSignal;
import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.Log;
import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.Property;
import com.velasolaris.plugin.controller.spi.PluginControllerConfiguration.Sensor;
import com.velasolaris.plugin.controller.spi.PluginControllerException;
import com.velasolaris.plugin.controller.spi.PolysunSettings;

import com.velasolaris.plugin.painter.MatlabPluginControllerPainter;
import com.velasolaris.plugin.util.PluginUtils;
import matlabcontrol.MatlabConnectionException;
import matlabcontrol.MatlabInvocationException;
import matlabcontrol.MatlabProxy;
import matlabcontrol.MatlabProxyFactory;
import matlabcontrol.MatlabProxyFactoryOptions;

/**
 * Matlab plugin controller that delegates control() to a user-defined matlab function.
 *
 * The communication with Matlab is done with https://github.com/diffplug/matconsolectl.
 *
 * [plugin.dataPath] = plugins/com.velasolaris.plugin.controller.matlab.matconsolectl.MatlabPluginController
 * Basic configuration is read from [plugin.dataPath]/config.properties.
 * Basically all settings of MatConsoleCtl are configurable in config.properties.
 * The most important setting is the matlabStartingDirectory.
 * fixedTimestep = 0 means the default Polysun timesteps will be used.
 *
 * Matlab files are copied the first time to [plugin.dataPath].
 * The file control.m describes the Matlab function interface.
 *
 * The the user sets the matlab function name in the controller element GUI.
 * The function must either be in the path of Matlab or in the starting directory.
 *
 * The MatConsoleCtl demo can be run with
 * java -jar matconsolectl.jar.
 *
 * Performance:
 * A Java implementation is much faster. The time per function call is not measurable.
 * If performance is an important, the controller logic should directly implemented in Java,
 * see {@link FlowratePluginController}.
 *
 * Measured average time per function call for control_flowrate() in Python and controlFlowrate() in Matlab
 * and {@link FlowratePluginController} in Java 8 on a Intel Core i7-4500U CPU 1.80GHz (dual core) are about:
 *                                  JSON-RPC stream        JSON-RPC         XML-RPC            Java          Matlab
 * RPC type                                  custom        standard        standard          native         library
 * Communication protocol:               TCP socket            HTTP            HTTP          native             RMI
 * TCP connection per                  	 simulation        timestep        timestep             N/A      simulation
 * PyPy 5.4.1 and Polysun compiled:          0.06ms           0.3ms           0.6ms             0ms           0.6ms
 * Python 3.4 and Eclipse debug:             0.08ms           0.9ms           1.4ms             0ms           0.6ms
 *
 * Note: Since Matlab R2016b there is an official Matlab Enginge API for Java,
 * see https://ch.mathworks.com/help/matlab/matlab-engine-api-for-java.html
 *
 * @author rkurmann
 * @since Polysun 9.1
 *
 */
public class MatlabPluginController extends AbstractMatlabPluginController {

    /** Static instance of the Logger for this class */
    protected static Logger sLog = Logger.getLogger(MatlabPluginController.class.getName());

    /** Property name for the matlab function in the controller element GUI. */
    private static final String PROPERTY_MATLAB_FUNCTION = "Matlab function";
    /** Property name for the matlab starting path (read only) in the controller element GUI. */
    private static final String PROPERTY_MATLAB_STARTING_DIRECTORY = "Matlab starting directory";

    /**
     * Static MatConsoleCtl factory to create proxies.
     * This factory survies project reloads and avoids restarting Matlab.
     */
    private static MatlabProxyFactory staticFactory;
    /** MatConsoleCtl factory to create proxies. Stored in an instance. */
    private MatlabProxyFactory factory;
    /** MatConsoleCtl proxy to communicates with Matlab. */
    private MatlabProxy proxy;
    /**
     * Should we keep the same factory during a Polysun session?
     * I.e. Should we use the static MatConsoleCtl factory to create proxies?
     */
    private boolean keepFactory = true;

    /** Name of the Matlab function to call. Comes from the controller element GUI. */
    private String matlabFunction;
    /** MatConsoleCtl matlabStartingDirectory factory setting. */
    private String matlabStartingDirectory = null;
    /** MatConsoleCtl usePreviouslyControlledSession factory setting. */
    private boolean usePreviouslyControlledSession = true;
    /** MatConsoleCtl port factory setting. */
    private int port = 2100;
    /** MatConsoleCtl matlabLocation factory setting. */
    private String matlabLocation = null;
    /** MatConsoleCtl proxyTimeout [ms] factory setting. */
    private long proxyTimeout = 180000l;
    /** MatConsoleCtl hidden factory setting. */
    private boolean hidden = false;
    /** MatConsoleCtl osgiClassloaderFriendly factory setting. */
    private boolean osgiClassloaderFriendly = true;
    /** MatConsoleCtl logFile factory setting. */
    private String logFile = null;
    /** MatConsoleCtl javaDebugPort factory setting. */
    private Integer javaDebugPort = null;
    /** MatConsoleCtl licenseFile factory setting. */
    private String licenseFile = null;
    /** MatConsoleCtl useSingleCompThread factory setting. */
    private boolean useSingleCompThread = false;

    /** Has the invalid number of control signals message already be shown? Avoid repeating output. */
    private boolean invalidControlSignalsMsgShown;
    /** Has the invalid number of logs already be shown? Avoid repeating output. */
    private boolean invalidLogsMsgShown;

    /**
     * Default constructor.
     */
    public MatlabPluginController() {
    }

    @Override
    public String getName() {
        return "Matlab";
    }

    @Override
    public PluginControllerConfiguration getConfiguration(Map parameters) throws PluginControllerException {
        setConfiguration(parameters);
        Properties config = new Properties();
        int defaultNumGenericSensors = 3;
        int defaultNumGenericControlSignals = 3;
        int defaultNumGenericProperties = 5;
        int defaultNumLogValues = 1;
        int defaultFixedTimestep = DEFAULT_TIMESTEP;
        String defaultMatlabFunction = "control";
        Integer defaultVerboseLevel = 1;
        List printMessage = new ArrayList<>();
        File configFile = new File(pluginDataPath + File.separator + "config.properties");
        matlabStartingDirectory = "[pluginDataPath]";
        try {
            if (configFile.exists()) {
                try(FileReader fileReader = new FileReader(configFile);
                        BufferedReader reader = new BufferedReader(fileReader);) {
                    config.load(reader);
                    Object obj;
                    defaultNumGenericProperties = (obj = config.get("defaultNumGenericProperties")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultNumGenericProperties;
                    defaultNumGenericSensors = (obj = config.get("defaultNumGenericSensors")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultNumGenericSensors;
                    defaultNumGenericControlSignals = (obj = config.get("defaultNumGenericControlSignals")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultNumGenericControlSignals;
                    defaultFixedTimestep = (obj = config.get("defaultFixedTimestep")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultFixedTimestep;
                    defaultNumLogValues = (obj = config.get("defaultNumLogValues")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultNumLogValues;
                    defaultMatlabFunction = (obj = config.get("defaultMatlabFunction")) != null && !"".equals(obj) ? obj.toString() : defaultMatlabFunction;
                    defaultVerboseLevel = (obj = config.get("defaultVerboseLevel")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : defaultVerboseLevel;
                    port = (obj = config.get("matctl.port")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : port;
                    javaDebugPort = (obj = config.get("matctl.javaDebugPort")) != null && !"".equals(obj) ? Integer.parseInt(obj.toString()) : null;
                    proxyTimeout = (obj = config.get("matctl.proxyTimeout")) != null && !"".equals(obj) ? Long.parseLong(obj.toString()) : proxyTimeout;
                    keepFactory = (obj = config.get("keepFactory")) != null && !"".equals(obj) ? Boolean.parseBoolean(obj.toString()) : keepFactory;
                    usePreviouslyControlledSession = (obj = config.get("matctl.usePreviouslyControlledSession")) != null && !"".equals(obj) ? Boolean.parseBoolean(obj.toString()) : usePreviouslyControlledSession;
                    hidden = (obj = config.get("matctl.hidden")) != null && !"".equals(obj) ? Boolean.parseBoolean(obj.toString()) : hidden;
                    osgiClassloaderFriendly = (obj = config.get("matctl.osgiClassloaderFriendly")) != null && !"".equals(obj) ? Boolean.parseBoolean(obj.toString()) : osgiClassloaderFriendly;
                    useSingleCompThread = (obj = config.get("matctl.useSingleCompThread")) != null && !"".equals(obj) ? Boolean.parseBoolean(obj.toString()) : useSingleCompThread;
                    matlabLocation = (obj = config.get("matctl.matlabLocation")) != null && !"".equals(obj) ? obj.toString() : null;
                    logFile = (obj = config.get("matctl.logFile")) != null && !"".equals(obj) ? obj.toString() : null;
                    licenseFile = (obj = config.get("matctl.licenseFile")) != null && !"".equals(obj) ? obj.toString() : null;
                    matlabStartingDirectory = (obj = config.get("matctl.matlabStartingDirectory")) != null && !"".equals(obj) ? obj.toString() : matlabStartingDirectory;
                    sLog.info("Config.properties read: " + configFile);
                } catch (IOException e) {
                    sLog.warning(PluginUtils.getRootCauseStackTrace(e));
                }
            } else {
                new File(pluginDataPath).mkdirs();
                try (FileWriter fileWriter = new FileWriter(configFile);
                        BufferedWriter writer = new BufferedWriter(fileWriter)) {
                    config.put("defaultNumGenericProperties", "" + defaultNumGenericProperties);
                    config.put("defaultNumGenericSensors", "" + defaultNumGenericSensors);
                    config.put("defaultNumGenericControlSignals", "" + defaultNumGenericControlSignals);
                    config.put("defaultNumLogValues", "" + defaultNumLogValues);
                    config.put("defaultFixedTimestep", "" + defaultFixedTimestep);
                    config.put("keepFactory", "" + keepFactory);
                    config.put("defaultMatlabFunction", "" + defaultMatlabFunction);
                    config.put("defaultVerboseLevel", "" + defaultVerboseLevel);
                    config.put("matctl.matlabStartingDirectory", matlabStartingDirectory != null ? matlabStartingDirectory : "");
                    config.put("matctl.matlabLocation", matlabLocation != null ? matlabLocation : "");
                    config.put("matctl.port", "" + port);
                    config.put("matctl.proxyTimeout", "" + proxyTimeout);
                    config.put("matctl.usePreviouslyControlledSession", "" + usePreviouslyControlledSession);
                    config.put("matctl.logFile", logFile != null ? logFile : "");
                    config.put("matctl.javaDebugPort", javaDebugPort != null ? "" + javaDebugPort : "");
                    config.put("matctl.useSingleCompThread", "" + useSingleCompThread);
                    config.put("matctl.osgiClassloaderFriendly", "" + osgiClassloaderFriendly);
                    config.put("matctl.hidden", "" + hidden);

                    config.store(writer, "Properties of the Polysun MatlabPluginController + [" + getId() + "]");
                    sLog.info("Config file written: " + configFile);
                    exportResource("/com/velasolaris/plugin/controller/matlab/control.m", pluginDataPath, true);
                    exportResource("/com/velasolaris/plugin/controller/matlab/controlFlowrate.m", pluginDataPath, true);
                    exportResource("/com/velasolaris/plugin/controller/matlab/controlCoSimSimulink.m", pluginDataPath, true);
                    new File(pluginDataPath + "/simulink").mkdirs();
                    exportResource("/com/velasolaris/plugin/controller/matlab/simulink/pauseCallback.m", pluginDataPath + "/simulink", true);
                    exportResource("/com/velasolaris/plugin/controller/matlab/simulink/SFunCoSim_ReadSensors.m", pluginDataPath + "/simulink", true);
                    exportResource("/com/velasolaris/plugin/controller/matlab/simulink/SFunCoSim_WriteCtrlSig.m", pluginDataPath + "/simulink", true);
                    exportResource("/com/velasolaris/plugin/controller/matlab/simulink/SimulinkBreak.m", pluginDataPath + "/simulink", true);
                    exportResource("/com/velasolaris/plugin/controller/matlab/simulink/SimulinkModel.slx", pluginDataPath + "/simulink", true);
                    printMessage.add("Configuration file and .m files written to " + pluginDataPath);
                } catch(IOException e) {
                    sLog.warning(PluginUtils.getRootCauseStackTrace(e));
                }
            }
        } catch (Exception e) {
            sLog.warning(PluginUtils.getRootCauseStackTrace(e));
        }
        List properties = new ArrayList<>();
        properties.add(new Property(PROPERTY_MATLAB_FUNCTION, defaultMatlabFunction));
        properties.add(new Property(PROPERTY_MATLAB_STARTING_DIRECTORY, matlabStartingDirectory));
        properties.add(new Property(PROPERTY_FIXED_TIMESTEP, defaultFixedTimestep, 0f, 900, "s"));
        properties.add(new Property(PROPERTY_NUM_GENERIC_SENSORS, defaultNumGenericSensors, 0, 100));
        properties.add(new Property(PROPERTY_NUM_GENERIC_CONTROL_SIGNALS, defaultNumGenericControlSignals, 0, 100));
        properties.add(new Property(PROPERTY_NUM_GENERIC_LOGS, defaultNumLogValues, 0, 100));
        //		properties.add(new Property(PROPERTY_NUM_GENERIC_PROPERTIES, defaultNumGenericProperties, 0, 100));
        properties.add(new Property(PROPERTY_VERBOSE_LEVEL, new String[] { "Standard", "Verbose", "Debug" }, defaultVerboseLevel));

        numInternProperties = properties.size();

        List sensors = new ArrayList<>();

        List controlSignals = new ArrayList<>();

        List logs = new ArrayList<>();

        parameters.put("Plugin.PrintMessage", printMessage);

        PluginControllerConfiguration.Builder builder = new PluginControllerConfiguration.Builder();
        builder.setProperties(properties);
        builder.setSensors(sensors);
        builder.setControlSignals(controlSignals);
        builder.setLogs(logs);
        builder.setNumGenericProperties(defaultNumGenericProperties);
        builder.setNumGenericSensors(defaultNumGenericSensors);
        builder.setNumGenericControlSignals(defaultNumGenericControlSignals);
        builder.setPropertyNameNumGenericSensors(PROPERTY_NUM_GENERIC_SENSORS);
        builder.setPropertyNameNumGenericControlSignals(PROPERTY_NUM_GENERIC_CONTROL_SIGNALS);
        builder.setPropertyNameNumGenericLogs(PROPERTY_NUM_GENERIC_LOGS);
        builder.setImagePainter(new MatlabPluginControllerPainter());
        return builder.build();
    }

    @Override
    public void initialiseSimulation(Map parameters) throws PluginControllerException {
        super.initialiseSimulation(parameters);
        invalidControlSignalsMsgShown = false;
        invalidLogsMsgShown = false;
        try {
            if (verboseLevel > VERBOSE_LEVEL_STANDARD) {
                writeMsgToMatlab("Polysun simulation started");
            }
            File matlabStartingDir = getMatlabStartingDir(parameters);
            if (matlabStartingDir != null && matlabStartingDir.exists()) {
                getProxy().eval("cd('" + matlabStartingDir.getPath() + "')");
                writeMsgToMatlab("Changed directory to " + matlabStartingDir.getPath());
                getProxy().eval("disp(['The current directory is ', pwd])");
                //				Object[] obj = getProxy().returningEval("pwd", 1);
                //				if (obj != null && obj.length != 0) {
                //					String path = (String) obj[0];
                //					writeMsgToMatlab("The current directory is " + path);
                //				}
            }

            // function [ controlSignals, logValues, timepoints ] = control( simulationTime, status, sensors, sensorsUsed, properties, propertiesStr, preRun, controlSignalsUsed, numLogValues, stage, fixedTimestep, verboseLevel, parameters)
            getProxy().returningFeval(matlabFunction, 3, 0, false, new float[sensorsUsed.length], sensorsUsed, matlabPropertiesFloat, matlabPropertiesString, true, controlSignalsUsed, 0, FUNCTION_STAGE_INIT, fixedTimestep, verboseLevel, null);
        } catch (MatlabInvocationException | MatlabConnectionException e) {
            sLog.severe(PluginUtils.getRootCauseStackTrace(e));
            disconnectProxy();
            throw new PluginControllerException(e);
        }
    }

    /**
     * Returns the Matlab starting directory.
     * [pluginDataPath], [userHome], [projectDir] are replaced.
     *
     * @param parameters Generic parameters
     * @return the plugin data path or null if matlabStartingDirectory is null or empty
     * @see MatlabPluginController#replacePathPlaceholders(String, Map)
     */
    private File getMatlabStartingDir(Map parameters) {
        if (matlabStartingDirectory != null && !"".equals(matlabStartingDirectory)) {
            return new File(replacePathPlaceholders(matlabStartingDirectory, parameters));
        }
        return null;
    }

    @Override
    public void build(PolysunSettings polysunSettings, Map parameters) throws PluginControllerException {
        super.build(polysunSettings, parameters);

        matlabStartingDirectory = getProperty(PROPERTY_MATLAB_STARTING_DIRECTORY).getString();
        matlabFunction = getProperty(PROPERTY_MATLAB_FUNCTION).getString();
        try {
            setupMatlabCtl(parameters);
        } catch (MatlabConnectionException | MatlabInvocationException e) {
            sLog.warning(PluginUtils.getRootCauseStackTrace(e));
            disconnectProxy();
            throw new PluginControllerException(e);
        }
    }

    @Override
    public int[] control(int simulationTime, boolean status, float[] sensors, float[] controlSignals, float[] logValues,
            boolean preRun, Map parameters) throws PluginControllerException {
        try {
            // function [ controlSignals, logValues, timepoints ] = control( simulationTime, status, sensors, sensorsUsed, properties, propertiesStr, preRun, controlSignalsUsed, numLogValues, stage, fixedTimestep, verboseLevel, parameters )
            startMeasureFunctionCall();
            Object[] result = getProxy().returningFeval(matlabFunction, 3, simulationTime, status, sensors, sensorsUsed, matlabPropertiesFloat, matlabPropertiesString, preRun, controlSignalsUsed, logValues.length, FUNCTION_STAGE_SIMULATION, fixedTimestep, verboseLevel, parameters);
            double[] matlabControlSignals = (double[]) result[0];
            double[] matlabLogs = (double[]) result[1];
            double[] matlabTimepoints = (double[]) result[2];
            stopMeasureFunctionCall();
            if (matlabControlSignals.length != controlSignals.length && verboseLevel > VERBOSE_LEVEL_STANDARD && !invalidControlSignalsMsgShown) {
                writeMsgToMatlab("Wrong number of control signals. Using smaller value. Expected: " + controlSignals.length + ", actual: " + matlabControlSignals.length);
                invalidControlSignalsMsgShown = true;
            }
            if (matlabLogs.length != logValues.length && verboseLevel > VERBOSE_LEVEL_STANDARD && !invalidLogsMsgShown) {
                writeMsgToMatlab("Wrong number of log values. Using smaller value. Expected: " + logValues.length + ", actual: " + matlabLogs.length);
                invalidLogsMsgShown = true;
            }
            for (int i = 0; i < Math.min(controlSignals.length, matlabControlSignals.length); i++) {
                controlSignals[i] = (float) matlabControlSignals[i];
            }
            for (int i = 0; i < Math.min(logValues.length, matlabLogs.length); i++) {
                logValues[i] = (float) matlabLogs[i];
            }
            int[] timepoints = new int[matlabTimepoints.length];
            for (int i = 0; i < timepoints.length; i++) {
                timepoints[i] = (int) matlabTimepoints[i];
            }
            return timepoints;
        } catch (MatlabInvocationException | MatlabConnectionException e) {
            sLog.severe(PluginUtils.getRootCauseStackTrace(e));
            disconnectProxy();
            throw new PluginControllerException(e);
        }
    }

    @Override
    public void terminateSimulation(Map parameters) {
        super.terminateSimulation(parameters);
        try {
            if (verboseLevel > VERBOSE_LEVEL_STANDARD) {
                writeMsgToMatlab("Polysun simulation terminated");
                logPerfMeasure("Overall: ", parameters);
            }
            // function [ controlSignals, logValues, timepoints ] = control( simulationTime, status, sensors, sensorsUsed, properties, propertiesStr, preRun, controlSignalsUsed, numLogValues, stage, fixedTimestep, verboseLevel, parameters)
            getProxy().returningFeval(matlabFunction, 3, 0, false, new float[0], sensorsUsed, matlabPropertiesFloat, matlabPropertiesString, true, controlSignalsUsed, 0, FUNCTION_STAGE_TERMINATE, fixedTimestep, verboseLevel, null);
            writeMsgToMatlab("Disconnect");
            getProxy().disconnect();
        } catch (Throwable e) {
            sLog.warning(PluginUtils.getRootCauseStackTrace(e));
            // ignore
            disconnectProxy();
        }
    }

    /**
     * Sets up the MatConsoleCtl factory with settings from config.properties.
     * @param parameters Generic parameters
     * @throws MatlabConnectionException for any Matlab connection problems
     * @throws MatlabInvocationException for any Matlab function or command invocation problems
     */
    protected void setupMatlabCtl(Map parameters) throws MatlabConnectionException, MatlabInvocationException {
        if (factory == null) {
            if (keepFactory && staticFactory != null) {
                factory = staticFactory;
            } else {
                sLog.info("Start connecting to Matlab...");
                MatlabProxyFactoryOptions.Builder builder = new MatlabProxyFactoryOptions.Builder()
                    .setUsePreviouslyControlledSession(usePreviouslyControlledSession)
                    .setPort(port)
                    .setOSGiClassloaderFriendly(osgiClassloaderFriendly)
                    .setProxyTimeout(proxyTimeout)
                    .setHidden(hidden)
                    .setUseSingleComputationalThread(useSingleCompThread)
                    ;
                File matlabStartingDir = getMatlabStartingDir(parameters);
                if (matlabStartingDir != null && matlabStartingDir.exists()) {
                    builder.setMatlabStartingDirectory(matlabStartingDir);
                }
                if (matlabLocation != null && !"".equals(matlabLocation)) {
                    builder.setMatlabLocation(matlabLocation);
                }
                if (logFile != null && !"".equals(logFile)) {
                    builder.setLogFile(logFile);
                }
                if (licenseFile != null && !"".equals(licenseFile)) {
                    builder.setLicenseFile(licenseFile);
                }
                if (javaDebugPort != null && javaDebugPort != 0) {
                    builder.setJavaDebugger(javaDebugPort);
                }
                sLog.info("Create MatlabProxyFactory");
                factory = new MatlabProxyFactory(builder.build());
                if (staticFactory == null) {
                    staticFactory = factory;
                }
            }
            writeMsgToMatlab("Polysun connected to Matlab.");
            sLog.info("Connected to Matlab");
            parameters.put("Plugin.PrintMessage", "Connected to Matlab");
            getProxy().eval("format compact;");
            getProxy().disconnect();
        }
    }

    /**
     * Returns a proxy to communicate with Matlab.
     *
     * @return the proxy
     * @throws MatlabConnectionException for any Matlab connection problems
     */
    protected MatlabProxy getProxy() throws MatlabConnectionException {
        if (proxy == null || !proxy.isConnected()) {
            if (verboseLevel >= VERBOSE_LEVEL_DEBUG) {
                sLog.fine("Create Matlab proxy");
            }
            proxy = factory.getProxy();
        }
        return proxy;
    }

    /**
     * Writes a message to the Matlab console.
     * @param msg message to print in Matlab console
     * @throws MatlabConnectionException for any Matlab connection problems
     * @throws MatlabInvocationException for any Matlab function or command invocation problems
     */
    protected void writeMsgToMatlab(String msg) throws MatlabInvocationException, MatlabConnectionException {
        if (verboseLevel >= VERBOSE_LEVEL_DEBUG) {
            sLog.fine("Write Message to Matlab: " + msg);
        }
        getProxy().eval("disp('" + msg + "')");
    }

    @Override
    public String getDescription() {
        return "Matlab plugin controller that delegates the controller call to a user-defined matlab function.";
    }

    @Override
    public String getDocumentation() {
        return "Matlab plugin controller that delegates control() to a user-defined matlab function." +
            "
" + "
[plugin.dataPath] = plugins/com.velasolaris.plugin.controller.matlab.matconsolectl.MatlabPluginController" + "
Basic configuration is read from [plugin.dataPath]/config.properties." + "
Basically all settings of MatConsoleCtl are configurable in config.properties." + "
" + "
Matlab files are copied the first time to [plugin.dataPath]." + "
The file control.m describes the Matlab function interface." + "
" + "
The the user sets the matlab function name in the controller element GUI." + "
The function must either be in the path of Matlab or in the starting directory." + "
" + "
The communication with Matlab is done with https://github.com/diffplug/matconsolectl." ; } /** * Disconnects the Matlab proxy. * It is important that the proxy is disconnected at the end since a * Matlab instance can be only connected to one Proxy at a time. * If project is closed, but proxies remain open, a new Matlab instance * will be started. */ protected void disconnectProxy() { if (proxy != null) { if (sLog.isLoggable(Level.INFO)) sLog.info("Disconnect proxy, isConnected=" + proxy.isConnected()); proxy.disconnect(); } } @Override public void closeResources() { disconnectProxy(); } @Override protected void finalize() throws Throwable { super.finalize(); disconnectProxy(); } // /** Test call. */ // public static void main(String... args) throws MatlabConnectionException, MatlabInvocationException, PluginControllerException { // MatlabPluginController controller = new MatlabPluginController(); // System.out.println("Start"); // controller.setupMatlabCtl(); // controller.initialiseSimulation(null); // controller.control(0, true, new float[1], new float[1], new float[1], false, null); // controller.control(0, true, new float[1], new float[1], new float[1], false, null); // controller.terminateSimulation(null); // System.out.println("End"); // System.exit(0); // } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy