Last active
August 29, 2015 14:01
-
-
Save jckantor/b1678f34c8fd0347e77b to your computer and use it in GitHub Desktop.
A Matlab class for processing APMonitor models on a remote server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% APMONITOR A class for processing APMonitor models on a remote server. | |
% | |
% SYNOPSIS | |
% | |
% apmonitor(server) | |
% Initializes an APMonitor application on a remote server and | |
% returns an object with methods to upload, solve, and download | |
% application data. Results in an error if the server does not | |
% respond. | |
% | |
% server url string of the host server. | |
% | |
% USAGE | |
% | |
% a = apmonitor | |
% Creates an APMonitor application on the default server. | |
% | |
% a = apmonitor('http://xps.apmonitor.com') | |
% Creates an APMonitor application on the named server. | |
% | |
% METHODS | |
% | |
% response = a.apm(command) | |
% response = apm(a,command) | |
% Return the response to a command to APMonitor server. | |
% 'solve' : solve the loaded model | |
% 'clear all' : clear application and all files | |
% 'clear apm' : clear model file (.apm) | |
% 'clear csv' : clear data file (.csv) | |
% 'info {FV,MV,SV,CV} {name}' : create interface to variable | |
% 'ss.t0 {values}' : load ss.t0 restart file | |
% 'csva {contents}' : add contents to .csv data file | |
% 'csv {line}' : add one line to .csv data file | |
% 'apm {contents}' : add to apm file without c/r | |
% '{otherwise}' : add line to apm file | |
% 'option {name} = {value}' : set an option | |
% | |
% a.webroot | |
% webroot(a) | |
% Show all files on the server using the default browser. | |
% | |
% | |
% | |
% DEVELOPMENT NOTES | |
% | |
% * The constructor was kept simple because it is hard to predict the | |
% use cases for the class. The purpose of the constructor is to | |
% instantiate the apmonitor object, confirm that the APMonitor server | |
% is available, and initialize an application on the server. A | |
% destructor 'delete' executes a 'clear all' on the server when there is | |
% no longer any reference to the object. | |
% | |
% * The apmonitor object is a subclass of handle. This makes it | |
% possible for class methods to modify the class object. | |
% | |
% * Because an object has it's own name inside the Matlab workspace, | |
% the application name on the remote server appears redundant and | |
% potentially confusing to a new user. Therefore the design decision was | |
% to more or less hide the remote app name from the end user. | |
% | |
classdef apmonitor < handle | |
properties | |
server = 'http://byu.apmonitor.com' % default server | |
app = '' | |
results | |
vars | |
solver = 1 % 1:APOPT 2:BPOPT 3:IPOPT | |
imode = 3 % 3: | |
end | |
properties (Dependent = true) | |
% properties with getters | |
url_base | |
ip | |
appstatus | |
ctrlmode | |
cyclecount | |
iterations | |
objfcnval | |
solvestatus | |
solvetime | |
end | |
methods | |
% Class constructor, initializing server and app name | |
function obj = apmonitor(server) | |
if(nargin > 0) | |
obj.server = deblank(server); | |
else | |
% force a call to the setter function set.server | |
obj.server = obj.server; | |
end | |
obj.app = lower(deblank(['app' int2str(rand()*100000)])); | |
end | |
% Class destructor. Called automatically to clears APMonitor server | |
% when there are no longer any references to the object. | |
function delete(obj) | |
obj.apm('clear all'); | |
end | |
% setter function for server url | |
function set.server(obj,url) | |
oldurl = obj.server; | |
obj.server = url; | |
try | |
obj.apm('clear all'); | |
catch | |
obj.server = oldurl; | |
error(['Error reading ' url]); | |
end | |
end | |
% getter function for server url | |
function url = get.server(obj) | |
url = obj.server; | |
end | |
% getter function for obj.ip | |
function ip = get.ip(obj) | |
ip = deblank(urlread([obj.server '/ip.php'])); | |
end | |
% getter function for obj.url_base | |
function url = get.url_base(obj) | |
url = [obj.server '/online/apm_line.php']; | |
end | |
% getter function for obj.appstatus | |
function y = get.appstatus(obj) | |
y = obj.tag('nlc.appstatus'); | |
end | |
% getter function for obj.ctrlmode | |
function y = get.ctrlmode(obj) | |
y = obj.tag('nlc.ctrlmode'); | |
end | |
% getter function for obj.cyclecount | |
function y = get.cyclecount(obj) | |
y = obj.tag('nlc.cyclecount'); | |
end | |
% getter function for obj.iterations | |
function y = get.iterations(obj) | |
y = obj.tag('nlc.iterations'); | |
end | |
% getter function for obj.objfcnval | |
function y = get.objfcnval(obj) | |
y = obj.tag('nlc.objfcnval'); | |
end | |
% getter function for obj.solvestatus | |
function y = get.solvestatus(obj) | |
y = obj.tag('nlc.solvestatus'); | |
end | |
% getter function for obj.solvetime | |
function y = get.solvetime(obj) | |
y = obj.tag('nlc.solvetime'); | |
end | |
% APM: send command to server and return response filter for \r | |
function response = apm(obj,aline) | |
params = {'p',obj.app,'a',aline}; | |
response = strrep(urlread(obj.url_base,'get',params),'\r',''); | |
end | |
% APMLOAD: load .apm file to server | |
function response = apmload(obj,filename) | |
fid=fopen(filename,'r'); | |
if fid < 0 | |
error(['File ' filename ' not found.']); | |
end | |
tline = []; | |
while ~feof(fid) | |
tline = [tline fgets(fid)]; | |
end | |
fclose(fid); | |
len = size(tline,2); | |
blocksize = 2000; | |
j = 1; | |
while j <= len | |
k = min(j+blocksize,len); | |
obj.apm(['apm ' tline(j:k)]); | |
j = k + 1; | |
end | |
response = 'Successfully loaded APM file'; | |
end | |
% CSVLOAD: load .csv file to server | |
function response = csvload(obj,filename) | |
fid=fopen(filename,'r'); | |
if fid < 0 | |
error(['File ' filename ' not found.']); | |
end | |
tline = []; | |
while ~feof(fid) | |
% remove any double quote marks | |
tline = [tline strrep(fgets(fid),'"',' ')]; | |
end | |
fclose(fid); | |
len = size(tline,2); | |
blocksize = 2000; | |
j = 1; | |
k = min(j+blocksize,len); | |
while k < len | |
obj.apm(['csva ' tline(j:k)]); | |
j = k; | |
k = min(j+blockize,len); | |
end | |
obj.apm(['csv ' tline(j:end)]); | |
response = 'Successfully loaded CSV file'; | |
end | |
% OPTION: sends option specification to the APMonitor server | |
function response = option(obj,name,value) | |
response = apm(obj,['option ' deblank(char(name)) '=' num2str(value)]); | |
end | |
% SOL: retrieve solution to results file and load into object | |
function y = sol(obj) | |
url = [obj.server '/online/' obj.ip '_' obj.app '/results.csv']; | |
filename = ['solution_' obj.app '.csv']; | |
fid = fopen(filename,'w+'); | |
fwrite(fid,urlread(url)); | |
% load data from csv file with header on the right column | |
frewind(fid); | |
ctr = 0; | |
obj.results.names = {}; | |
obj.results.values = []; | |
while(~feof(fid)) | |
aline = fgetl(fid); | |
ctr = ctr + 1; | |
a = strsplit(aline,','); | |
obj.results.names(ctr) = a(1); | |
for j = 2:length(a) | |
obj.results.values(j-1,ctr) = str2num(a{j}); | |
end | |
% remove characters for MATLAB allowed in APM: "[],()." | |
var_name = regexprep(a(1),'[\[\],().]',''); | |
obj.vars.(var_name{1}) = obj.results.values(:,ctr); | |
end | |
fclose(fid); | |
end | |
% SOLVE: `` | |
function solve(obj,fname) | |
obj.apm('clear all'); | |
obj.apmload([fname '.apm']); | |
try | |
obj.csvload([fname '.csv']); | |
obj.imode = 7; | |
catch | |
obj.imode = 3; | |
end | |
obj.option('nlc.web',0); | |
obj.option('nlc.nodes',3); | |
obj.option('nlc.solver',obj.solver); | |
obj.option('nlc.sensitivity',0); | |
obj.option('nlc.imode',obj.imode); | |
solver_output = obj.apm('solve'); | |
if obj.appstatus == 1 | |
obj.sol | |
else | |
disp(solver_output); | |
end | |
end | |
% TAG: retrieve an option specification from the APMonitor server | |
function response = tag(obj,name) | |
url_base = [obj.server '/online/get_tag.php']; | |
params = {'p',obj.app,'n',name}; | |
response = str2num(urlread(url_base,'get',params)); | |
end | |
% WEBROOT: open default web browser showing files on server | |
function stat = webroot(obj) | |
url = [obj.server '/online/' obj.ip '_' obj.app '/']; | |
stat = web(url,'-browser'); | |
end | |
% WEB: open default browser showing application dashboard | |
function [stat] = web(obj) | |
iapp = [obj.ip '_' obj.app]; | |
url = [deblank(obj.server) '/online/' iapp '/' iapp '_dashboard.php']; | |
stat = web(url,'-browser'); | |
end | |
end | |
methods(Static = true) | |
function a = ss(fname) | |
a = apmonitor; | |
a.imode = 1; | |
a.solve(fname); | |
end | |
function a = rto(fname) | |
a = apmonitor; | |
a.imode = 3; | |
a.solve(fname); | |
end | |
function obj = sim(fname) | |
obj = apmonitor; | |
obj.imode = 6; | |
obj.apm('clear all'); | |
obj.apmload([fname '.apm']); | |
try | |
obj.csvload([fname '.csv']); | |
end | |
obj.option('nlc.web',0); | |
obj.option('nlc.nodes',3); | |
obj.option('nlc.solver',obj.solver); | |
obj.option('nlc.sensitivity',0); | |
obj.option('nlc.imode',obj.imode); | |
solver_output = obj.apm('solve'); | |
if obj.appstatus == 1 | |
obj.sol | |
else | |
disp(solver_output); | |
end | |
end | |
function demo() | |
% demo/demo | |
a = apmonitor.sim('demo/demo'); | |
t = a.vars.time; | |
x = a.vars.x; | |
y = a.vars.y; | |
plot(t,[x,y]); | |
xlabel('Time'); | |
legend({'x','y'},'location','nw'); | |
end | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment