function ctmBATCH()
% CTMBATCH - equivalent of CTMGUI for batch mode, called from CTMSIM.
%
% Last modified: 03/18/2007.
%
% Alex Kurzhanskiy <akurzhan@eecs.berkeley.edu>
%
global g_ctmGUI;
%%% INITIALIZATION %%%
if ~isstruct(g_ctmGUI) | ~isfield(g_ctmGUI, 'configFile')
g_ctmGUI.configFile = 'ctm'; % default: 'ctm.mat'
end
g_ctmGUI.numColors = 1024;
g_ctmGUI.isStopped = 0;
g_ctmGUI.isSaved = 1;
load(g_ctmGUI.configFile);
g_ctmGUI.cellData = celldata; % MUST (!) be present in the config file
if ~exist('TS', 'var')
TS = 1;
end
minl = min(get_cell_lengths(g_ctmGUI.cellData));
maxv = max(get_ff_speeds(g_ctmGUI.cellData));
g_ctmGUI.TS = min([TS ((minl / maxv) - eps)]); % sampling period
if ~exist('plotTS', 'var')
plotTS = 1/60; % plote once a minute
end
g_ctmGUI.plotPeriod = max([round(plotTS/g_ctmGUI.TS) 1]);
if ~exist('dataFile', 'var')
dataFile = [g_ctmGUI.configFile '_data'];
end
g_ctmGUI.dataFile = dataFile;
if ~exist('taxislim', 'var')
taxislim = 100; % time axis limit
end
g_ctmGUI.taxislim = taxislim;
if ~exist('timeout', 'var')
timeout = 2; % in seconds
end
g_ctmGUI.timeout = timeout;
if ~exist('yoColorRatio', 'var')
yoColorRatio = [0.95 0.95];
end
g_ctmGUI.yoColorRatio = yoColorRatio;
if ~exist('densityCMF', 'var')
densityCMF = jet(g_ctmGUI.numColors);
end
g_ctmGUI.densityCMF = densityCMF;
if ~exist('flowCMF', 'var')
flowCMF = jet(g_ctmGUI.numColors);
end
g_ctmGUI.flowCMF = flowCMF;
if ~exist('orflowCMF', 'var')
orflowCMF = jet(g_ctmGUI.numColors);
end
g_ctmGUI.orflowCMF = orflowCMF;
if ~exist('orqueueCMF', 'var')
orqueueCMF = jet(g_ctmGUI.numColors);
end
g_ctmGUI.orqueueCMF = orqueueCMF;
if ~exist('frflowCMF', 'var')
frflowCMF = jet(g_ctmGUI.numColors);
end
g_ctmGUI.frflowCMF = frflowCMF;
if ~exist('frbetaCMF', 'var')
frbetaCMF = jet(g_ctmGUI.numColors);
end
g_ctmGUI.frbetaCMF = frbetaCMF;
if ~exist('speedCMF', 'var')
speedCMF = jet(g_ctmGUI.numColors);
end
g_ctmGUI.speedCMF = speedCMF;
if ~exist('vhtCMF', 'var')
vhtCMF = jet(g_ctmGUI.numColors);
end
g_ctmGUI.vhtCMF = vhtCMF;
if ~exist('vmtCMF', 'var')
vmtCMF = jet(g_ctmGUI.numColors);
end
g_ctmGUI.vmtCMF = vmtCMF;
if ~exist('initialDensities', 'var')
initialDensities = get_critical_densities(g_ctmGUI.cellData);
end
g_ctmGUI.densities = initialDensities;
if ~exist('inflow', 'var')
inflow = g_ctmGUI.cellData(1).FDfmax;
end
g_ctmGUI.inflow = inflow;
if ~exist('ifKnob', 'var')
ifKnob = 1;
end
g_ctmGUI.ifKnob = ifKnob;
if ~exist('outflow', 'var')
outflow = g_ctmGUI.cellData(end).FDfmax;
end
g_ctmGUI.outflow = outflow;
if ~exist('ofKnob', 'var')
ofKnob = 1;
end
g_ctmGUI.ofKnob = ofKnob;
if ~exist('demandProfile', 'var')
demandProfile = [];
end
g_ctmGUI.demandProfile = demandProfile;
if ~exist('demandTS', 'var')
demandTS = 1/12; % 5 minutes
end
g_ctmGUI.demandPeriod = round(demandTS/TS);
g_ctmGUI.demandIndex = 0;
g_ctmGUI.demandCount = 0;
if ~exist('betaProfile', 'var')
betaProfile = [];
end
g_ctmGUI.betaProfile = betaProfile;
if ~exist('betaTS', 'var')
betaTS = 1/12; % 5 minutes
end
g_ctmGUI.betaPeriod = round(betaTS/TS);
g_ctmGUI.betaIndex = 0;
g_ctmGUI.betaCount = 0;
if ~exist('frflowProfile', 'var')
frflowProfile = [];
end
g_ctmGUI.frflowProfile = frflowProfile;
if ~exist('frflowTS', 'var')
frflowTS = 1/12; % 5 minutes
end
g_ctmGUI.frflowPeriod = round(frflowTS/TS);
g_ctmGUI.frflowIndex = 0;
g_ctmGUI.frflowCount = 0;
if ~exist('maxSimStep', 'var')
maxSimStep = Inf;
end
g_ctmGUI.maxSimStep = maxSimStep;
if ~exist('maxSimTime', 'var')
maxSimTime = 24; % hours
end
g_ctmGUI.maxSimTime = maxSimTime;
g_ctmGUI.densityData = [];
g_ctmGUI.flowData = [];
g_ctmGUI.speedData = [];
g_ctmGUI.orflowData = [];
g_ctmGUI.orqueueData = [];
g_ctmGUI.frflowData = [];
g_ctmGUI.frbetaData = [];
g_ctmGUI.vhtData = [];
g_ctmGUI.vmtData = [];
g_ctmGUI.delayData = [];
g_ctmGUI.plossData = [];
g_ctmGUI.traveltimeData = [];
g_ctmGUI.tvhData = [];
g_ctmGUI.tvmData = [];
g_ctmGUI.cdelayData = [];
g_ctmGUI.cplossData = [];
g_ctmGUI.timeMinutes = []; % data needed for the TIME axis
g_ctmGUI.timeStep = 0;
g_ctmGUI.linIndex = 0;
g_ctmGUI.loutIndex = 1;
[g_ctmGUI.maxDensity, g_ctmGUI.maxFlow] = get_max_df(g_ctmGUI.cellData);
if exist('maxFlow', 'var')
g_ctmGUI.maxFlow = maxFlow;
end
if exist('maxDensity', 'var')
g_ctmGUI.maxDensity = maxDensity;
end
if exist('minFlow', 'var')
g_ctmGUI.minFlow = minFlow;
else
g_ctmGUI.minFlow = 0;
end
if exist('minDensity', 'var')
g_ctmGUI.minDensity = minDensity;
else
g_ctmGUI.minDensity = 0;
end
if ~exist('freeway', 'var')
freeway = 'Freeway XYZ';
end
g_ctmGUI.freeway = freeway;
g_ctmGUI.pmData = get_pm_data(g_ctmGUI.cellData);
g_ctmGUI.frbetas = get_fr_splitratios(g_ctmGUI.cellData)';
g_ctmGUI.orflows = get_or_flows(g_ctmGUI.cellData)';
xmin = g_ctmGUI.pmData(1);
xmax = g_ctmGUI.pmData(end);
if xmin > xmax
xlim = [xmax xmin];
else
xlim = [xmin xmax];
end
g_ctmGUI.xLims = xlim;
%%% SIMULATION %%%
NC = size(g_ctmGUI.cellData, 2); % number of cells
if isempty(g_ctmGUI.timeMinutes) % start new
densities = g_ctmGUI.densities;
orflows = get_or_fmax(g_ctmGUI.cellData);
orflows = orflows';
orqueues = zeros(NC, 1);
g_ctmGUI.controllerCounts = zeros(NC, 1);
g_ctmGUI.timeStep = -1;
flows = zeros(NC, 1);
frflows = zeros(NC, 1);
else % continue where we left off
densities = g_ctmGUI.densityData(1:NC, end);
flows = g_ctmGUI.flowData(1:NC, end);
orflows = g_ctmGUI.orflowData(1:NC, end);
orqueues = g_ctmGUI.orqueueData(1:NC, end);
frbetas = g_ctmGUI.frbetaData(1:NC, end);
frflows = g_ctmGUI.frflowData(1:NC, end);
speeds = g_ctmGUI.speedData(1:NC, end);
vht = g_ctmGUI.vhtData(1:NC, end);
vmt = g_ctmGUI.vmtData(1:NC, end);
delay = g_ctmGUI.delayData(1:NC, end);
ploss = g_ctmGUI.plossData(1:NC, end);
end
g_ctmGUI.controllerPeriods = get_controller_periods(g_ctmGUI.cellData, g_ctmGUI.TS);
g_ctmGUI.isStopped = 0;
orflows_prev = orflows;
onerow = ones(1, NC);
timeStep = g_ctmGUI.timeStep;
count = -1;
% main loop
while (timeStep <= g_ctmGUI.maxSimStep) & ...
(timeStep * g_ctmGUI.TS <= g_ctmGUI.maxSimTime) & ...
(g_ctmGUI.isStopped == 0)
if (count + 1) == g_ctmGUI.plotPeriod
count = -1;
end
count = count + 1;
% determine actual on-ramp demands, flows, queues
if ~isempty(g_ctmGUI.demandProfile)
if g_ctmGUI.demandCount == 0
g_ctmGUI.demandIndex = g_ctmGUI.demandIndex + 1;
if g_ctmGUI.demandIndex > size(g_ctmGUI.demandProfile, 1)
g_ctmGUI.demandIndex = 1;
g_ctmGUI.isStopped = 1;
end
end
if (g_ctmGUI.demandCount + 1) == g_ctmGUI.demandPeriod
g_ctmGUI.demandCount = -1;
end
g_ctmGUI.demandCount = g_ctmGUI.demandCount + 1;
demands = g_ctmGUI.demandProfile(g_ctmGUI.demandIndex, :);
g_ctmGUI.inflow = g_ctmGUI.ifKnob * demands(1);
g_ctmGUI.outflow = g_ctmGUI.ofKnob * demands(end);
demands = adjust_or_demands(demands(2:(NC+1))', g_ctmGUI.cellData);
if 1
[orflows, g_ctmGUI.controllerCounts] = ...
auto_control(densities, ...
[demands orflows orqueues], ...
g_ctmGUI.controllerCounts, ...
g_ctmGUI.controllerPeriods, ...
g_ctmGUI.cellData, ...
g_ctmGUI.TS, ...
1);
else
orflows = adjust_or_flow_limits(densities, g_ctmGUI.cellData, g_ctmGUI.TS);
end
else
demands = get_or_flows(g_ctmGUI.cellData);
demands = demands';
orflows = demands;
end
% make sure on-ramp flows do nor exceed allowed limits
orflows = adjust_or_flows(densities, orflows, g_ctmGUI.cellData, g_ctmGUI.TS);
% adjust on-ramp flow and queue values
[orflows, orqueues] = adjust_or_data(demands, ...
orflows, ...
orqueues, ...
g_ctmGUI.TS);
% update on-ramp flows in cell structures
g_ctmGUI.cellData = set_or_flows(g_ctmGUI.cellData, orflows);
if timeStep == -1
orflows_prev = orflows;
end
% determine off-ramp split ratio values
if ~isempty(g_ctmGUI.betaProfile)
if g_ctmGUI.betaCount == 0
g_ctmGUI.betaIndex = g_ctmGUI.betaIndex + 1;
if g_ctmGUI.betaIndex > size(g_ctmGUI.betaProfile, 1)
g_ctmGUI.betaIndex = 1;
g_ctmGUI.isStopped = 1;
end
end
if (g_ctmGUI.betaCount + 1) == g_ctmGUI.betaPeriod
g_ctmGUI.betaCount = -1;
end
g_ctmGUI.betaCount = g_ctmGUI.betaCount + 1;
frbetas = g_ctmGUI.betaProfile(g_ctmGUI.betaIndex, :);
frbetas = adjust_fr_split_ratios(frbetas', g_ctmGUI.cellData);
g_ctmGUI.cellData = set_fr_split_ratios(g_ctmGUI.cellData, frbetas);
end
if ~isempty(g_ctmGUI.frflowProfile)
if g_ctmGUI.frflowCount == 0
g_ctmGUI.frflowIndex = g_ctmGUI.frflowIndex + 1;
if g_ctmGUI.frflowIndex > size(g_ctmGUI.frflowProfile, 1)
g_ctmGUI.frflowIndex = 1;
g_ctmGUI.isStopped = 1;
end
end
if (g_ctmGUI.frflowCount + 1) == g_ctmGUI.frflowPeriod
g_ctmGUI.frflowCount = -1;
end
g_ctmGUI.frflowCount = g_ctmGUI.frflowCount + 1;
frflows = g_ctmGUI.frflowProfile(g_ctmGUI.frflowIndex, :);
frflows = adjust_fr_flows(densities, ...
frflows', ...
g_ctmGUI.cellData, ...
g_ctmGUI.TS);
[simdata, traveltime] = simulation_step_2(g_ctmGUI.cellData, ...
densities, ...
orflows_prev, ...
orqueues, ...
flows, ...
frflows, ...
g_ctmGUI.inflow, ...
g_ctmGUI.outflow, ...
g_ctmGUI.TS, ...
timeStep);
frbetas = simdata(:, 3);
% update beta values in the cell structures
g_ctmGUI.cellData = set_fr_split_ratios(g_ctmGUI.cellData, frbetas);
else
[simdata, traveltime] = simulation_step(g_ctmGUI.cellData, ...
densities, ...
orflows_prev, ...
orqueues, ...
flows, ...
frflows, ...
g_ctmGUI.inflow, ...
g_ctmGUI.outflow, ...
g_ctmGUI.TS, ...
timeStep);
frflows = simdata(:, 3);
% get off-ramp split ratios
frbetas = get_fr_splitratios(g_ctmGUI.cellData);
frbetas = frbetas';
end
densities = simdata(:, 1);
flows = simdata(:, 2);
speeds = simdata(:, 4);
orflows_prev = orflows;
% compute Vehicle Hours Traveled (VHT), Vehicle Miles Traveled (VMT)
% and Productivity Loss
if timeStep >= 0
vht = vht + simdata(:, 5);
vmt = vmt + simdata(:, 6);
ploss = ploss + simdata(:, 7);
else
vht = g_ctmGUI.plotPeriod * simdata(:, 5);
vmt = g_ctmGUI.plotPeriod * simdata(:, 6);
ploss = g_ctmGUI.plotPeriod * simdata(:, 7);
end
% compute total Productivity Loss
cploss = sum(ploss);
% compute new Total Vehicle Hours
tvh = sum(vht);
% compute new Total Vehicle Miles
tvm = sum(vmt);
% compute delay
delay = vht - (vmt ./ get_ff_speeds(g_ctmGUI.cellData));
delay = max([delay'; zeros(1, NC)])';
cdelay = sum(delay);
% next time step
timeStep = timeStep + 1;
if count > 0
continue;
end
% update data arrays
g_ctmGUI.timeStep = timeStep;
tm = g_ctmGUI.timeStep * g_ctmGUI.TS * 60;
g_ctmGUI.timeMinutes = [g_ctmGUI.timeMinutes tm];
g_ctmGUI.densityData = [g_ctmGUI.densityData [densities; densities(end, 1)]];
g_ctmGUI.flowData = [g_ctmGUI.flowData [flows; flows(end, 1)]];
g_ctmGUI.orflowData = [g_ctmGUI.orflowData [orflows; orflows(end, 1)]];
g_ctmGUI.orqueueData = [g_ctmGUI.orqueueData [orqueues; 200]];
g_ctmGUI.frflowData = [g_ctmGUI.frflowData [frflows; frflows(end, 1)]];
g_ctmGUI.frbetaData = [g_ctmGUI.frbetaData [frbetas; frbetas(end, 1)]];
g_ctmGUI.speedData = [g_ctmGUI.speedData [speeds; speeds(end, 1)]];
g_ctmGUI.vhtData = [g_ctmGUI.vhtData [vht; vht(end, 1)]];
g_ctmGUI.vmtData = [g_ctmGUI.vmtData [vmt; vmt(end, 1)]];
g_ctmGUI.delayData = [g_ctmGUI.delayData [delay; delay(end, 1)]];
g_ctmGUI.plossData = [g_ctmGUI.plossData [ploss; ploss(end, 1)]];
g_ctmGUI.traveltimeData = [g_ctmGUI.traveltimeData traveltime];
g_ctmGUI.tvhData = [g_ctmGUI.tvhData tvh];
g_ctmGUI.tvmData = [g_ctmGUI.tvmData tvm];
g_ctmGUI.cdelayData = [g_ctmGUI.cdelayData cdelay];
g_ctmGUI.cplossData = [g_ctmGUI.cplossData cploss];
vht = zeros(NC, 1);
vmt = zeros(NC, 1);
ploss = zeros(NC, 1);
end
l_save_simulation(g_ctmGUI);
return;
% save simulation
function l_save_simulation(ctmGUI_data)
if str2num(version('-release')) >= 14
feval(@save, '-v6', ctmGUI_data.dataFile, 'ctmGUI_data');
else
feval(@save, ctmGUI_data.dataFile, 'ctmGUI_data');
end
return;