% optimal_design_CSTR.m
% This program optimizes the design of a CSTR
% that produces C from A and B through the network:
% A + B --> C   r_R1 = k1*cA*cB
% A --> S1  r_R2 = k2*cA
% C --> S2  r_R3 = k3*cC
% The design is optimized to maximize the production
% of C from A.
% Kenneth Beers.
% MIT Department of Chemical Engineering
% May 29, 2005

function iflag_main = optimal_design_CSTR();
iflag_main = 0;
disp(' '); disp('Running optimal design_CSTR ...');

% ask user for choice of design goal
imode = input(...
    'Enter 1 for max. C production, 2 for max. economic benefit : ');
prices = zeros(5,1);
if(imode == 2)
    prices(1) = input('Enter $ per mol. for A : ');
    prices(2) = input('Enter $ per mol. for B : ');
    prices(3) = input('Enter $ per mol. for C : ');
    prices(4) = input('Enter $ per mol. to dispose S1 : ');
    prices(5) = input('Enter $ per mol. to dispose S2 : ');
    disp(' ');
end

% ask user for initial guesses of parameters
volFlow_g = input('Enter guess of volFlow (L per hr) : ');
cA_0_g = input('Enter guess of cA_0 (M) : ');
cB_0_g = input('Enter guess of cB_0 (M) : ');
T_g = input('Enter guess of T (K) : ');
theta_g = [volFlow_g; cA_0_g; cB_0_g; T_g];

% compute initial cost function value
F_g = CSTR_cost_fcn(theta_g, imode, prices);
disp(' '); disp(['  initial cost fcn = ', num2str(F_g)]);

% perform constrained optimization
% lower and upper bounds
LB = [1e-4; 1e-4; 1e-4; 298];  % lower bounds
UB = [360; 2; 2; 360];  % upper bounds
% linear inequality constraint, cA_0 + cB_0 <= 2
A = [0 1 1 0];  b = 2;
% set options and call fmincon
Options = optimset('LargeScale','off','Display','iter');
[theta,F,exitflag,output] = fmincon(@CSTR_cost_fcn, ...
    theta_g, A, b, [], [], LB, UB, [], Options, imode, prices);
% extract and report results
disp(' '); exitflag, output,
disp('Optimized design : '); F,
volFlow = theta(1),  cA_0 = theta(2),
cB_0 = theta(3), T = theta(4),
% compute final state and report results
[F,x] = CSTR_cost_fcn(theta,imode,prices);
disp(' ');
cA = x(1),  cB = x(2),  cC = x(3),  cS1 = x(4),  cS2 = x(5),

iflag_main = 1;
return;


% --------------------
% This routine computes the cost function for the
% reactor by computing the stable steady-state
% reactor concentrations through dynamic integration.
% As a second argument, the routine returns the final
% state vector at steady state.
function [F,x] = CSTR_cost_fcn(theta, imode, prices);

% extract the design parameters
volFlow = theta(1);  cA_0 = theta(2);
cB_0 = theta(3);  T = theta(4);

% perform a dynamic integration
x0 = [cA_0; cB_0; 0; 0; 0];  % initial state
% integrate in multiples of the reactor residence time
% until the time derivatives are less than a tolerance value
V_R = 1;  res_time = V_R/volFlow;
for iter=1:1000
    [t_traj,x_traj] = ode23s(@CSTR_xdot,[0 2*res_time],x0,[],...
        volFlow, cA_0, cB_0, T, V_R);
    % extract final state
    num_traj = length(t_traj);  x = x_traj(num_traj,:)';
    % check if we have approached steady-state
    xdot = CSTR_xdot(t_traj(num_traj),x,volFlow,cA_0,cB_0,T,V_R);
    xdot_norm = norm(xdot,inf);
    if(xdot_norm <= 1e-6)
        break;
    else
        x0 = x;
    end
end
% extract final values of state variables
cA = x(1);  cB = x(2);  cC = x(3);  cS1 = x(4);  cS2 = x(5);

% if maximizing production of C
if(imode == 1)
    F = -volFlow*cC;
else  % maximize net economic benefit
    F = -volFlow*(-prices(1)*(cA_0-cA) - prices(2)*(cB_0-cB) ...
        + prices(3)*cC - prices(4)*cS1 - prices(5)*cS2);
end

return;

% ----------
% This routine returns the time derivatives for the CSTR.
function xdot = CSTR_xdot(t,x,volFlow,cA_0,cB_0,T,V_R);
xdot = zeros(5,1);
cA = x(1);  cB = x(2);  cC = x(3);  cS1 = x(4);  cS2 = x(5);

var1 = volFlow/V_R;  % inverse residence time
% compute reaction rates
k1 = 2.3*exp(15.4*(1-298/T));  r_R1 = k1*cA*cB;
k2 = 0.2*exp(17.9*(1-298/T));  r_R2 = k2*cA;
k3 = 0.1*exp(22.3*(1-298/T));  r_R3 = k3*cC;

% compute time derivatives
xdot(1) = var1*(cA_0 - cA) - r_R1 - r_R2;  % A balance
xdot(2) = var1*(cB_0 - cB) - r_R1;  % B balance
xdot(3) = -var1*cC + r_R1 - r_R3;  % C balance
xdot(4) = -var1*cS1 + r_R2;  % S1 balance
xdot(5) = -var1*cS2 + r_R3;  % S2 balance

return;

