function retentostat_growth(V_B,Cs_chem, Cs_ret, Ysx_max, Ysp_max, ms_est, F_in, days, qp_func, qp_res) % By putting two percent-signs (%%), one can mark parts of the code. %% Looping over the volume of the mixing vessel (Vessel A) maxp = 20; % iterations over the volume of vessel A maxi = 20; % iterations over the maintenance coefficient. Fin_A = F_in; Cx_end = zeros(maxp,maxi); Cx_max = zeros(maxp,maxi); V_Ass = []; mu = []; % Vectors for the final analysis, storing ALL datapoints over time Cx_t = []; mu_t = []; Cs_t = []; Cp_t = []; for p = 1:maxp %% Process Parameters % Vessel A - Mixing Vessel % Fin_A = 0.035; % L/h V_A = 0 + p*0.1; %L Fout_A = Fin_A; % L/h % Vessel B - Fermenter Fin_B = Fout_A; Fout_B = Fin_B; %% Storage matrices % Because of the loops used in this function, certain values are % required to be stored in matrices. When an ode-solver is in a loop, % the output will usually be stored in the output matrix (c in this % function), but will be overwritten once the loop is run again with a % new value. This would mean a loss of data if the data wouldn't be % stored in a 'storage matrix'. this is necessary when the data needs % to be accessed later. Cx = []; % storage matrix for biomass concentrations in vessel B Cs = []; % storage matrix for substrate concentrations in vessel A Cp = []; % storage matrix for product concentrations in vessel B mss = []; % Storage matrix for the ms-values (for the plotting) tss= []; % storage vector for the time-points (for plotting) %% Time span of the ode-solver in h tini= 0 ; % h tend= 24*days; % h dt = 0.5; % the time steps that are used for the ode solver, [h] %% Initial concentrations for the ode-solver % In this model, these are the values that are obtained from the % chemostat phase. The time of 0 hours is when the chemostat is % switched to a retentostat. C_S0 = Cs_chem; % g/L Substrate in the inflow of vessel A %% Looping over ms % Herbert Pirt Equation Parameters for product formation A = qp_func; B = (Ysp_max+Ysx_max*A)/(Ysx_max*Ysp_max); G = qp_res/Ysp_max; for i = 1:maxi ms = (ms_est-maxi/2*0.0001) + i*0.0001 % maintenance coefficient % gs/gx/h C_X0 = ((Fin_B/V_B)*C_S0)/(((Fin_B/V_B)*B)+ms + G); C_P0 = (A*(Fin_B/V_B)+qp_res)*C_X0*V_B/Fout_B; c0 = [C_X0 C_S0 C_P0];% C_SB0]; %% ode solver opt = odeset('RelTol',1e-8, 'AbsTol',1e-8); [t,c] = ode45(@(t,c)dcdt(t,c,ms,Ysx_max,Ysp_max,Cs_ret,F_in,V_A,V_B, qp_res, B, A, G), tini:dt:tend, c0, opt); % there are several ode solvers available. ode45 is most common to % use for 'simple' problems % In order to keep the data available outside of the loop, the concentrations that are % yielded from the ode solver, they are stored in the % storage-matrices as defined above. Cx = [Cx c(:,1)]; Cx_t = [Cx_t c(:,1)]; Cs = [Cs c(:,2)]; Cs_t = [Cs_t c(:,2)]; Cp = [Cp c(:,3)]; Cp_t = [Cp_t c(:,3)]; Cs_B = 0; %% Plotting & Data Handling % Calculate mu, qp, qs, Ysp qs(mu) and qs(ms) are calculated from the Herbert-pirt equation. for k = 1:1:length(t) qs(k,i) = ((Fin_B/V_B)*(Cs(k,i)-Cs_B))/Cx(k,i); qs_t(k,i+(p-1)*maxi) = qs(k,i); mu(k,i) = (qs(k,i)-G-ms)/B; % based on substrate balance mu_t(k,i+(p-1)*maxi) = mu(k,i); qp(k,i) = A*mu(k,i)+qp_res; qp_t(k,i+(p-1)*maxi) = qp(k,i); Ysp(k,i) = qp(k,i)/qs(k,i); Ysp_t(k,i+(p-1)*maxi) = Ysp(k,i); qs_mu(k,i) = (mu(k,i)/Ysx_max)/qs(k,i); qs_mu_t(k,i+(p-1)*maxi) = qs_mu(k,i); qs_ms(k,i) = ms/qs(k,i); qs_ms_t(k,i+(p-1)*maxi) = qs_ms(k,i); end % as soon as the new loop starts, the data in matrices t and c and % the value for ms will be overwritten. Therefore, that data needs % to be stored in a nother matrix, that will contain all data of % all the loops. Cx_end(p,i) = c(end,1); Cx_max(p,i) = max(c(:,1)); mss = [mss;ms]; tss = [tss t]; end V_Ass = [V_Ass V_A]; %% Final data plotting figure(p*10) surf(mss,tss/24,Cx,'EdgeColor','none'); xlabel(' m_s (g_{glucose}.g_x^{-1}.h^{-1})', 'FontSize',14 ); ylabel('Time (d)', 'FontSize',14 ); zlabel('C_x (g.L^{-1})', 'FontSize',14 ); suptitle(['Volume_A = ' num2str(V_Ass(end)) ' L']) %when writing strings (of letters), an underscore (_) gives the next %letter as subscript OR whatever is between braces: {} end %close all %closes small plots before final data plotting %% Function Final Output % The function should give the required answers on maximal volume of vessel A for maximal ms % values as written output in the command window. to give written output, % the commands fprintf are used. The constraint on Volume of vessel A is % defined by the maximal volume for which the biomass specific growth rate % remains non-negative (= starvation). Cx_eval = Cx_max./Cx_end; % evaluate whether Cx max is at the end of the % retentostat mu_thres = ones(length(t),1)*1e-3; % This vector is created to have a % threshold line for the growth rate (has to be below 0.001 h-1 for p = 1:maxp; if Cx_eval(p,maxi) > 1 % It is easiest to have the output in an easily accessible format, % here a sentence. fprintf(['The maximal volume of mixing vessel A for ' ... 'which a robust set-up can be guaranteed \n based on this model, ' ... 'up to an ms of ' num2str(mss(maxi)) ' is a volume of '... num2str(V_Ass(p-1)) ' L. \n' ]) % It has to be p-1, because if p is used for the volume, the Cx_eval % is already > 1. % but a visual check of the conclusion is required as well. for a = 0:1 % plot for the first 'wrong' V_A and the last ' good' V_A. figure((p-a)*101);% suptitle(['Volume_A = ' num2str(V_Ass(p-a)) ' L']) Fontsize = 15; % Biomass concentration subplot(3,3,1) plot(t/24,Cx_t(:,1+((p-a)-1)*maxi),'r',t/24,Cx_t(:,(maxi+((p-a)-1)*maxi)),'k-', 'LineWidth', 1.5); hold on; xlabel(' Time (d)', 'FontSize',15 ); ylabel('C_x (g.L^{-1})', 'FontSize',15 ); title('a','FontSize',Fontsize); % Specific growth rate subplot(3,3,4) plot(t/24,mu_t(:,1+((p-a)-1)*maxi),'r',t/24,mu_t(:,maxi+((p-a)-1)*maxi),'k-', 'LineWidth', 1.5); hold on; xlabel(' Time (d)', 'FontSize',15 ); ylabel('\mu (h^{-1})', 'FontSize',15 ); title('d','FontSize',Fontsize); % Substrate inflow concentration subplot(3,3,2) plot(t/24,Cs_t(:,1+((p-a)-1)*maxi),'r',t/24,Cs_t(:,maxi+((p-a)-1)*maxi),... 'k-', 'LineWidth', 1.5); hold on; xlabel(' Time (d)', 'FontSize',15 ); ylabel('C_{s,}_{in} (g.L^{-1})', 'FontSize',15 ); title('b','FontSize',Fontsize); % Specific growth rate (logarithmic scale) subplot(3,3,7) semilogy(t/24,mu_t(:,1+((p-a)-1)*maxi),'r',t/24,mu_t(:,maxi+((p-a)-1)*maxi),... 'k-',t/24,mu_thres,'g', 'LineWidth', 1.5); hold on; xlabel(' Time (d)', 'FontSize',15 ); ylabel('\mu (h^{-1})', 'FontSize',15 ); title('g','FontSize',Fontsize); % specific product formation rate subplot(3,3,6) plot(t/24,qp_t(:,1+((p-a)-1)*maxi),'r',t/24,qp_t(:,maxi+((p-a)-1)*maxi),... 'k-', 'LineWidth', 1.5); hold on; xlabel(' Time (d)', 'FontSize',15 ); ylabel('q_p (g_{p}.g_{x}^{-1}.h^{-1})', 'FontSize',15 ); title('f','FontSize',Fontsize); % product concentration subplot(3,3,3) plot(t/24,Cp_t(:,1+((p-a)-1)*maxi),'r',t/24,Cp_t(:,maxi+((p-a)-1)*maxi),... 'k-', 'LineWidth', 1.5); hold on; xlabel(' Time (d)', 'FontSize',15 ); ylabel('C_p (g.L^{-1})', 'FontSize',15 ); title('c','FontSize',Fontsize); % specific substrate consumption rate subplot(3,3,5) plot(t/24,qs_t(:,1+((p-a)-1)*maxi),'r',t/24,qs_t(:,maxi+((p-a)-1)*maxi),... 'k-', 'LineWidth', 1.5); hold on; xlabel(' Time (d)', 'FontSize',15 ); ylabel('q_s (g_{s}.g_x^{-1}.h^{-1})', 'FontSize',15 ); title('e','FontSize',Fontsize); axis([0,1,0 , 0.07], 'auto x') subplot(3,3,8) plot(t/24,qs_mu_t(:,1+((p-a)-1)*maxi)*100,'r',t/24,qs_ms_t(:,1+((p-a)-1)*maxi)*100, 'k','LineWidth', 1.5); hold on plot(t/24,qs_mu_t(:,maxi+((p-a)-1)*maxi)*100,'g',t/24,qs_ms_t(:,maxi+((p-a)-1)*maxi)*100, 'b','LineWidth', 1.5); xlabel(' Time (d)', 'FontSize',Fontsize ); ylabel('Gluc. distr. (%)', 'FontSize',Fontsize ); title('h','FontSize',Fontsize ); % Product on substrate yield subplot(3,3,9) plot(t/24,Ysp_t(:,1+((p-a)-1)*maxi),'r',t/24,Ysp_t(:,maxi+((p-a)-1)*maxi),... 'k-', 'LineWidth', 1.5); hold on; xlabel(' Time (d)', 'FontSize',15 ); ylabel('Y_{sp} (g_p.g_s^{-1})', 'FontSize',15 ); title('i','FontSize',Fontsize); end break end end end function dc = dcdt(t,c,ms,Ysx_max,Ysp_max,Cs_ret,F_in,V_A,V_B, qp_res, B, A, G) % global Fin_A V_A Fout_A ms Ysx_max Ysp_max qp V_B %% Variables Cx_B = c(1); Cs_A = c(2); Cp_B = c(3); Cs_B = 0; %% Model Parameters % Vessel A - Mixing Vessel Cs_R = Cs_ret; % the concentration in the second medium vessel; eventually the concentration in vessel A. % Vessel B - Fermentor Fin_A = F_in; Fout_A = Fin_A; Fin_B = Fout_A; Fout_B = Fin_B; qs = ((Fin_B/V_B)*(Cs_A-Cs_B))/Cx_B; mu = (qs - G - ms)/B; qp = A * mu + qp_res; %% Equations dc(1) = mu*Cx_B; % Balance of Cx_B dc(2) = Fin_A/V_A*Cs_R - Fout_A/V_A*Cs_A; % % Balance of Cs_A dc(3) = qp*Cx_B-Fout_B*Cp_B; % Balance of Cp_B: Product formation dc = dc'; end