3-Element Windkessel Model (Optimizing against flow (Q)): Why is my code so slow? It does not reach the optimizations.

15 views (last 30 days)
Hi, so I've wrote this code to optimize the parameters of a 3-element windkessel model. It was working when I was optimizing against the pressure (P), but when I switched it to flow (Q), it gets stuck calculating 'ppval' - it does not even reach the optimisation. Please advise. I have added the code and profiler results below. Is it the ODE function? I am suspecting that the ODE for Q is stiff, whereas for P it was not (even though it is the same equation)? How can I overcome this? Should I attempt the ODE solvers for stiff problems (e.g. ode15s) or for more accurate nonstiff problems (e.g. ode78)? Thanks!
The Windkessel model (P_out = 0):
%% Code to Optimize Parameters for Aorta 3-Element Windkessel Model
%%
clear all
close all
clc
%% Inputs
% For mmHg
% R1 * (0.000001/133.322);
% R2 * (0.000001/133.322);
% C * (133.322/0.000001);
R1 = 4.40e+06;
R2 = 1.05e+08;
C = 1.31e-08;
% Initial conditions for WK-3 parameters
IC = [C, R1, R2];
Q_peak = 5e-4; % Peak flow
t_s = 0.28; % Systolic Time
t_c = 0.84; % Cycle Time
dt=0.0001; % (CFD/FSI) Simulation Time Step
%% Importing flow and pressure data
RefQWK = readtable('Ref_P_Q_WK_No-Osc.csv');
RefPWK = readtable('Ref_P_Q_WK_No-Osc.csv');
P_ref=RefPWK.P; % multiply by 0.00750062 for mmHg
P0_ref=RefPWK.P(1); % multiply by 0.00750062 for mmHg
t_ref=RefPWK.t;
t=0:dt:t_ref(end);
P_smooth = smooth(interp1(t_ref, P_ref, t), 50);
P_spline = spline(t,P_smooth);
P_spline_dot = fnder(P_spline);
P=@(t) ppval(P_spline,t);
dPdt=@(t) ppval(P_spline_dot,t);
%Initial P condition
P0 = P(0);
%% Activate for flow data:
% Q_ref=RefQWK.Q; % multiply by e+6 for mL/s
% Q0_ref=RefQWK.Q(1);
% Q_smooth = smooth(interp1(t_ref, Q_ref, t), 50);
% Q_spline = spline(t,Q_smooth);
% Q_spline_dot = fnder(Q_spline);
%
% Q=@(t) ppval(Q_spline,t);
% dPdt=@(t) ppval(Q_spline_dot,t);
%
%Initial P condition
% Q0 = P(0);
%Activate for flow equation:
Q_eq = @(t)Q_peak*sin((pi*t)./t_s).^2.*(t>=0).*(t<=t_s);
Q = @(t)Q_eq(mod(t,t_c));
%Initial P condition
Q0 = Q(0);
%% Curve fitting using the method of least squares
LB = [1e-15 1 1]; UB = [1 1e10 1e10]; % Lower and Upper bounds
options = optimoptions('lsqcurvefit', 'Algorithm', 'levenberg-marquardt', 'MaxFunEvals',10000,'MaxIter',10000,'Display','iter');
f = @(x,t) fun_lsq(x, t, P, dPdt, Q0);
sol = lsqcurvefit(f, IC, t, Q(t), LB, UB, options);
C_optim_lsq = sol(1)
R1_optim_lsq = sol(2)
R2_optim_lsq = sol(3)
%% Curve fitting using the fminsearch
options = optimset('MaxFunEvals', 1e100, 'TolX', 1e-16, 'TolFun', 1e-16, 'Display','iter','PlotFcns',@optimplotfval);
f = @(x) fun_fmin(x, t, Q(t), P, dPdt, Q0);
sol = fminsearch(f,IC,options);
C_optim_fmin = sol(1)
R1_optim_fmin = sol(2)
R2_optim_fmin = sol(3)
%% Solving and Plotting ODE for Q
[t,Qsim_sterg] = integration(1.31e-8,4.4e+6,1.05e+8,t,P,dPdt,Q0);
[t,Qsim_lsq] = integration_data(C_optim_lsq,R1_optim_lsq,R2_optim_lsq,t,P,dPdt,Q0);
[t,Qsim_fmin] = integration_data(C_optim_fmin,R1_optim_fmin,R2_optim_fmin,t,P,dPdt,Q0);
[t,Qsim_fmin_manual] = integration_data(C,R1,R2,t,P,dPdt,Q0);
% PWK for FV
[t_FV_fmin, P_FV_fmin] = PWK_FV(C_optim_fmin, R1_optim_fmin, R2_optim_fmin, P0, Q(t), dt, t);
[t_FV_lsq, P_FV_lsq] = PWK_FV(C_optim_lsq, R1_optim_lsq, R2_optim_lsq, P0, Q(t), dt);
figure(1)
subplot(2,1,1)
plot(t,P(t),'DisplayName',strcat('Actual'))
plot(t_FV_lsq, P_FV_lsq, 'DisplayName',strcat('FlowVision lsq'))
plot(t_FV_fmin, P_FV_fmin, 'DisplayName',strcat('FlowVision fmin'))
title('PWK')
xlabel('Time (s)')
ylabel('Pressure (Pa)')
legend show
legend('Location', 'southeast', 'FontSize', 7)
subplot(2,1,2)
plot(t,Q(t), 'DisplayName',strcat('Actual'))
hold on
plot(t,Qsim_sterg,'DisplayName',strcat('Stergiopulos, C = 1.31E-8, R1 = 4.4E+6, R2 = 1.05E+8'))
plot(t,Qsim_lsq,'DisplayName',strcat('Sim LSQ, C =', num2str(C_optim_lsq, '%.3E'), ', R1 = ', num2str(R1_optim_lsq, '%.3E'), ', R2 = ', num2str(R2_optim_lsq, '%.3E')))
plot(t,Qsim_fmin,'DisplayName',strcat('Sim fmin, C =', num2str(C_optim_fmin, '%.3E'), ', R1 = ', num2str(R1_optim_fmin, '%.3E'), ', R2 = ', num2str(R2_optim_fmin, '%.3E')))
plot(t,Qsim_fmin_manual,'DisplayName',strcat('Sim manual, C =', num2str(C, '%.3E'), ', R1 = ', num2str(R1, '%.3E'), ', R2 = ', num2str(R2, '%.3E')))
hold off
title('QWK')
xlabel('Time (s)')
ylabel('Flow (m^{3}/s)')
legend show
legend('Location', 'southeast', 'FontSize', 7)
%% Function for lsq optimisation
function f = fun_lsq(x, time, P, dPdt, Q0)
%Renaming the constants
C = x(1); R1 = x(2); R2 = x(3);
[~,y] = integration(C,R1,R2,time,P,dPdt,Q0);
Q = y(:,1);
f = Q;
end
%% Function for fminsearch optimisation
function f = fun_fmin(x, time, Q_in, P, dPdt, Q0)
%Renaming the constants
C = x(1); R1 = x(2); R2 = x(3);
[~,y] = integration(C,R1,R2,time,P,dPdt,Q0);
Q = y(:,1);
f = sum((Q-Q_in).^2);
end
%% Function for ODE Integration using equation
function [t,y] = integration(C,R1,R2,time,P,dPdt,Q0)
ode_fun = @(t,y)((P(t)/(C*R1*R2)) + (dPdt(t)/R1) - (y(1)*(1/C*R1 + 1/C*R2)));
[t,y] = ode45(ode_fun, time, Q0);
end
%% Function for FV PWK
function [t_FV,P_FV] = PWK_FV(C_FV, R1_FV, R2_FV, P_FV_i, Q_FV, timestep, total_time)
t_FV=0:timestep:total_time(end);
P_FV=zeros(numel(t_FV):1);
P_FV(1) = P_FV_i;
for i=2:width(t_FV)
Beta = timestep / (C_FV*R2_FV);
Num1 = Q_FV(i)*( (Beta*R2_FV) + (Beta*R1_FV) + R1_FV );
Num2 = R1_FV*Q_FV(i-1);
Num3 = P_FV(i-1);
Num = Num1 - Num2 + Num3;
Den = 1 + Beta;
P_FV(i) = Num / Den;
end
end
I even tried to get rid of the equation for pressure and use tabular data (and reduced the data to 1 cycle), reduced the dt (timestep) to 0.01, as below, but it still gets stuck in the ODE function. Should I try another ode solver than ode45, maybe ode78?
%% Code to Optimize Parameters for Aorta 3-Element Windkessel Model
%%
clear all
close all
clc
%% Inputs
% For mmHg
% R1 * (0.000001/133.322);
% R2 * (0.000001/133.322);
% C * (133.322/0.000001);
R1 = 4.40e+06;
R2 = 1.05e+08;
C = 1.31e-08;
% Initial conditions for WK-3 parameters
IC = [C, R1, R2];
Q_peak = 5e-4; % Peak flow
t_s = 0.28; % Systolic Time
t_c = 0.84; % Cycle Time
dt=0.01; % (CFD/FSI) Simulation Time Step
%% Importing flow and pressure data
RefQWK = readtable('Ref_P_Q_WK_No-Osc_1-Cycle.csv');
RefPWK = readtable('Ref_P_Q_WK_No-Osc_1-Cycle.csv');
P_ref=RefPWK.P; % multiply by 0.00750062 for mmHg
P0_ref=RefPWK.P(1); % multiply by 0.00750062 for mmHg
t_ref=RefPWK.t;
t=0:dt:t_ref(end);
P0=P0_ref; %Initial P condition
P = smooth(interp1(t_ref, P_ref, t), 50);
dPdt = diff(P)./dt;
dPdt(end+1) = dPdt(end);
P0=P(1);
% P_smooth = smooth(interp1(t_ref, P_ref, t), 50);
% P_spline = spline(t,P_smooth);
% P_spline_dot = fnder(P_spline);
% P=@(t) ppval(P_spline,t);
% dPdt=@(t) ppval(P_spline_dot,t);
%Initial P condition for P equation
% P0 = P(0);
%% Activate for flow data:
% Q_ref=RefQWK.Q; % multiply by e+6 for mL/s
% Q0_ref=RefQWK.Q(1);
% Q_smooth = smooth(interp1(t_ref, Q_ref, t), 50);
% Q_spline = spline(t,Q_smooth);
% Q_spline_dot = fnder(Q_spline);
%
% Q=@(t) ppval(Q_spline,t);
% dQdt=@(t) ppval(Q_spline_dot,t);
%
%Initial Q condition
% Q0 = Q(0);
%Activate for flow equation:
Q_eq = @(t)Q_peak*sin((pi*t)./t_s).^2.*(t>=0).*(t<=t_s);
Q = @(t)Q_eq(mod(t,t_c));
%Initial P condition
Q0 = Q(0);
%% Curve fitting using the method of least squares
LB = [1e-15 1 1]; UB = [1 1e10 1e10]; % Lower and Upper bounds
options = optimoptions('lsqcurvefit', 'Algorithm', 'levenberg-marquardt', 'MaxFunEvals',10000,'MaxIter',10000,'Display','iter');
f = @(x,t) fun_lsq(x, t, P, dPdt, Q0);
sol = lsqcurvefit(f, IC, t_ref, Q(t), LB, UB, options);
C_optim_lsq = sol(1)
R1_optim_lsq = sol(2)
R2_optim_lsq = sol(3)
%% Curve fitting using the fminsearch
% options = optimset('MaxFunEvals', 1e100, 'TolX', 1e-16, 'TolFun', 1e-16, 'Display','iter','PlotFcns',@optimplotfval);
options = optimset('MaxFunEvals',10000,'MaxIter',10000, 'Display','iter','PlotFcns',@optimplotfval);
f = @(x) fun_fmin(x, t, Q(t), P, dPdt, Q0);
sol = fminsearch(f,IC,options);
C_optim_fmin = sol(1)
R1_optim_fmin = sol(2)
R2_optim_fmin = sol(3)
%% Solving and Plotting ODE for Q
[t,Qsim_sterg] = integration(1.31e-8,4.4e+6,1.05e+8,t,P,dPdt,Q0);
[t,Qsim_lsq] = integration_data(C_optim_lsq,R1_optim_lsq,R2_optim_lsq,t,P,dPdt,Q0);
[t,Qsim_fmin] = integration_data(C_optim_fmin,R1_optim_fmin,R2_optim_fmin,t,P,dPdt,Q0);
[t,Qsim_fmin_manual] = integration_data(C,R1,R2,t,P,dPdt,Q0);
% PWK for FV
[t_FV_fmin, P_FV_fmin] = PWK_FV(C_optim_fmin, R1_optim_fmin, R2_optim_fmin, P0, Q(t), dt, t);
[t_FV_lsq, P_FV_lsq] = PWK_FV(C_optim_lsq, R1_optim_lsq, R2_optim_lsq, P0, Q(t), dt);
figure(1)
subplot(2,1,1)
plot(t,P(t),'DisplayName',strcat('Actual'))
plot(t_FV_lsq, P_FV_lsq, 'DisplayName',strcat('FlowVision lsq'))
plot(t_FV_fmin, P_FV_fmin, 'DisplayName',strcat('FlowVision fmin'))
title('PWK')
xlabel('Time (s)')
ylabel('Pressure (Pa)')
legend show
legend('Location', 'southeast', 'FontSize', 7)
subplot(2,1,2)
plot(t,Q(t), 'DisplayName',strcat('Actual'))
hold on
plot(t,Qsim_sterg,'DisplayName',strcat('Stergiopulos, C = 1.31E-8, R1 = 4.4E+6, R2 = 1.05E+8'))
% plot(t,Qsim_lsq,'DisplayName',strcat('Sim LSQ, C =', num2str(C_optim_lsq, '%.3E'), ', R1 = ', num2str(R1_optim_lsq, '%.3E'), ', R2 = ', num2str(R2_optim_lsq, '%.3E')))
plot(t,Qsim_fmin,'DisplayName',strcat('Sim fmin, C =', num2str(C_optim_fmin, '%.3E'), ', R1 = ', num2str(R1_optim_fmin, '%.3E'), ', R2 = ', num2str(R2_optim_fmin, '%.3E')))
plot(t,Qsim_fmin_manual,'DisplayName',strcat('Sim manual, C =', num2str(C, '%.3E'), ', R1 = ', num2str(R1, '%.3E'), ', R2 = ', num2str(R2, '%.3E')))
hold off
title('QWK')
xlabel('Time (s)')
ylabel('Flow (m^{3}/s)')
legend show
legend('Location', 'southeast', 'FontSize', 7)
%% Function for lsq optimisation
function f = fun_lsq(x, time, P, dPdt, Q0)
%Renaming the constants
C = x(1); R1 = x(2); R2 = x(3);
[~,y] = integration(C,R1,R2,time,P,dPdt,Q0);
Q = y(:,1);
f = Q;
end
%% Function for fminsearch optimisation
function f = fun_fmin(x, time, Q_in, P, dPdt, Q0)
%Renaming the constants
C = x(1); R1 = x(2); R2 = x(3);
[~,y] = integration(C,R1,R2,time,P,dPdt,Q0);
Q = y(:,1);
f = sum((Q-Q_in).^2);
end
%% Function for ODE Integration using equation
function [t,y] = integration(C,R1,R2,time,P,dPdt,Q0)
% For P data
ode_fun = @(t,y) Q_odefcn(t, y, C, R1, R2, time, P, dPdt);
% For P equation:
% ode_fun = @(t,y)((P(t)/(C*R1*R2)) + (dPdt(t)/R1) - ((y(1)*(1 + R1/R2))/C*R1));
[t,y] = ode45(ode_fun, time, Q0);
end
%% Function for ODE using flow tabular data
function dQdt = Q_odefcn(t, y, C, R1, R2, time, P_in, dPdt_in)
% dQdt = zeros(1,1); %Initializing the output vector
% Determine the closest point to the current time
% [d, closestIndex]=min(abs(time-t));
% P = interp1(time,P_in,t);
% for i = 1:numel(time)
% if time(i+1) >= t
% dPdt = (P_in(i+1)-P_in(i))/(time(i+1)-time(i));
% break
% end
% end
%dQ = dQ_in(closestIndex);
dQdt = zeros(1,1); %Initializing the output vector
%Determine the closest point to the current time
[~, closestIndex]=min(abs(time-t));
P = P_in(closestIndex);
dPdt = dPdt_in(closestIndex);
dQdt(1) = P/(C*R1*R2) + (dPdt/R1) - y(1)*(1/C*R1 + 1/C*R2);
end
%% Function for FV PWK
function [t_FV,P_FV] = PWK_FV(C_FV, R1_FV, R2_FV, P_FV_i, Q_FV, timestep, total_time)
t_FV=0:timestep:total_time(end);
P_FV=zeros(numel(t_FV):1);
P_FV(1) = P_FV_i;
for i=2:width(t_FV)
Beta = timestep / (C_FV*R2_FV);
Num1 = Q_FV(i)*( (Beta*R2_FV) + (Beta*R1_FV) + R1_FV );
Num2 = R1_FV*Q_FV(i-1);
Num3 = P_FV(i-1);
Num = Num1 - Num2 + Num3;
Den = 1 + Beta;
P_FV(i) = Num / Den;
end
end
  15 Comments
Torsten
Torsten on 30 Mar 2024
Edited: Torsten on 30 Mar 2024
I thought you try to reproduce the pressure or flow curves you supply in the .csv files. Here, pressure converges asymptotically not against 0, but against atmospheric pressure, and that's what your model equations should reflect. Or is there an iterative procedure between MATLAB and CFD ?
In CFD calculations, you often solve the equations for pressure above atmospheric pressure p'. The "real" pressure is then p = p' + p_atmospheric. Maybe you set p' = p_atmospheric when the solver diverges, thus an overpressure of 1.013 bar. But it's only speculation.
Hussam
Hussam on 30 Mar 2024
Edited: Hussam on 30 Mar 2024
So, I'm trying to target to output pressure to be the same as the one provided to the matlab code, but I am unaware of the flow. So I am assuming a certain flow (with the flow equation) for the code and optimize the WK parameters for that. Then I run the FSI simulation with WK at the outlet boundary condition and I end up with a different flow curve. I then take that flow curve and input it to the code, and iterate. However, since they are aortic valve FSI simulations, they take quite a long time, so I am trying to figure out a faster way to converge to the right parameters that I want. Any change in the WK parameters change my flow and cardiac output (so far the peak flow ranges from 5e-4 to 1e-3 m^3/s). Ideally, I would like to target the flow equation with a peak value of 5e-4 m^3/s.
In the FSI simulation, when I set p_out to the diastolic pressure (same as in the code), the pressure diverges upwards, keeps on increasing to infinity. It works well when I set p_out = 0. I understand that it should not be 0 (atmospheric), but it should not be diastolic pressure either (at least physiologically), possibly some small value. I have seen a lot of people in the community/literature use it as zero.
I hope this shows my thinking more. Please correct me if I am wrong. What do you think?

Sign in to comment.

Answers (0)

Categories

Find more on Quadratic Programming and Cone Programming in Help Center and File Exchange

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!