Search code examples
scilab

Embedding an fsolve into an ODE as opposed to using DAE solver in Scilab


I am trying to embed a Fsolve to solve this non-linear system in Scilab.

I have solved the problem with the DAE, so I know what to expect, but I am struggling with embedding the Fsolve.

Here is the full copy of the code, DAE included.

I'm not sure where to embed the fsolve function.

//dassl approach
//given data
p=[20.086, 8100, 20.086, 20.086, 4050, 1E-17, 1E-11, 1E-17] //mol/kgh
ynames = ['y1' 'y2' 'y3' 'y4' 'y5' 'y6' 'y7' 'y8' 'y9' 'y10']
y0=[1.5776, 0.32, 0, 0, 0, 0.0131, 4.0E-06, 4.0E-06, 0, 0]'//initial conditions 
t0=0
t=linspace(0,1,1000)

dy0 = [0 0 0 0 0 0 0 0 0 0]'
function [f,r]=BatchRXorDassl(t,y,dy)
    f(1)=-p(3)*y(2)*y(8)-dy(1)
    f(2)=-p(1)*y(2)*y(6)+p(2)*y(10)-p(3)*y(2)*y(8)-dy(2)
    f(3)=p(3)*y(2)*y(8)+p(4)*y(4)*y(6)-p(5)*y(9)-dy(3)
    f(4)=-p(4)*y(4)*y(6)+p(5)*y(9)-dy(4)
    f(5)=p(1)*y(2)*y(6)-p(2)*y(10)-dy(5)
    f(6)=-p(1)*y(2)*y(6)-p(4)*y(4)*y(6)+p(2)*y(10)+p(5)*y(9)-dy(6)
    f(7)=-0.0131+y(6)+y(8)+y(9)+y(10)-y(7)
    f(8)=p(7)*y(1)-y(8)*(p(7)+y(7))
    f(9)=p(8)*y(3)-y(9)*(p(8)+y(7))
    f(10)=p(6)*y(5)-y(10)*(p(6)+y(7))
    r=0
endfunction

y=dassl([y0,dy0],t0,t,BatchRXorDassl)
y=y'
tplot = y(:,1)
yplot = y(:,2:11)

clf(11), scf(11)
plot(tplot,yplot)
xlabel('t (s)')
ylabel('C')
legend(ynames,-4)
xtitle('Batch Reactor Concentration Profiles')

////embedded fsolve approach
////given data
//p=[20.086, 8100, 20.086, 20.086, 4050, 1E-17, 1E-11, 1E-17] //mol/kgh
//ynames = ['y1' 'y2' 'y3' 'y4' 'y5' 'y6' 'y7' 'y8' 'y9' 'y10']
//y0=[1.5776, 0.32, 0, 0, 0, 0.0131, 4.0E-06, 4.0E-06, 0, 0]'//initial conditions 
//t0=0
//t=linspace(0,1,1000)
//function ff=fsolvve(y)
//    y1 = y(1)
//    y2 = y(2)
//    y3 = y(3)
//    y4 = y(4)
//    y5 = y(5)
//    y6 = y(6)
//    y7 = y(7)
//    y8 = y(8)
//    y9 = y(9)
//    y10 = y(10)
//    ff(1) = -0.0131+y(6)+y(8)+y(9)+y(10)-y(7)
//    ff(2) = p(7)*y(1)-y(8)*(p(7)+y(7))
//    ff(3) = p(8)*y(3)-y(9)*(p(8)+y(7))
//    ff(4) = p(6)*y(5)-y(10)*(p(6)+y(7))
//    ff(5) = -p(3)*y(2)*y(8)
//    ff(6) = -p(1)*y(2)*y(6)+p(2)*y(10)-p(3)*y(2)*y(8)
//    ff(7) = p(3)*y(2)*y(8)+p(4)*y(4)*y(6)-p(5)*y(9)
//    ff(8) = -p(4)*y(4)*y(6)+p(5)*y(9)
//    ff(9) = p(1)*y(2)*y(6)-p(2)*y(10)
//    ff(10) = -p(1)*y(2)*y(6)-p(4)*y(4)*y(6)+p(2)*y(10)+p(5)*y(9)
//endfunction
//yfsolve0 = [0 0 0 0 0 0 0 0 0 0]'
//yfsolve = fsolve(yfsolve0,fsolvve)

Solution

  • The following code does what you want if you considerably relax the default RTOL and ATOL of ode:

    p = [20.086, 8100, 20.086, 20.086, 4050, 1E-17, 1E-11, 1E-17] //mol/kgh
    ynames = ['y1' 'y2' 'y3' 'y4' 'y5' 'y6' 'y7' 'y8' 'y9' 'y10']
    y0 = [1.5776, 0.32, 0, 0, 0, 0.0131, 4.0E-06, 4.0E-06, 0, 0]'//initial condition 
    t0 = 0
    t = linspace(0,1,1000)
    
    function dy = rhs(t,y1)
        y2 = fsolve([1;1;1;1],list(cstr,y1));
        y = [y1;y2];
        dy = [-p(3)*y(2)*y(8)
               p(1)*y(2)*y(6)+p(2)*y(10)-p(3)*y(2)*y(8)
               p(3)*y(2)*y(8)+p(4)*y(4)*y(6)-p(5)*y(9)
              -p(4)*y(4)*y(6)+p(5)*y(9)
               p(1)*y(2)*y(6)-p(2)*y(10)
              -p(1)*y(2)*y(6)-p(4)*y(4)*y(6)+p(2)*y(10)+p(5)*y(9)];
    endfunction
    
    function g = cstr(y2,y1)
        g = [-0.0131+y1(6)+y2(2)+y2(3)+y2(4)-y2(1)
             p(7)*y1(1)-y2(2)*(p(7)+y2(1))
             p(8)*y1(3)-y2(3)*(p(8)+y2(1))
             p(6)*y1(5)-y2(4)*(p(6)+y2(1))];
    endfunction
    
    y1 = ode(y0(1:6),t0,t,1e-3,1e-3,rhs)
    

    Having to do that show that it is nonsense to proceed that way. Please realize that fsolve uses an iterative algorithm and that with this approach you even cannot even take an adequate initial vector for it. If you absolutely want to use ode I can propose a much better approach using implicit differentiation.