Domanda

I'm running a set of ODEs with ode45 in MATLAB and I need to save one of the variables (that's not the derivative) for later use. I'm using the function 'assignin' to assign a temporary variable in the base workspace and updating it at each step. This seems to work, however, the size of the array does not match the size of the solution vector acquired from ode45. For example, I have the following nested function:

function [Z,Y] = droplet_momentum(theta,K,G,P,zspan,Y0)

options = odeset('RelTol',1e-7,'AbsTol',1e-7);
[Z,Y] = ode45(@momentum,zspan,Y0,options);

function DY = momentum(z,y)

    DY = zeros(4,1);

    %Entrained Total Velocity
    Ve = sin(theta)*(y(4));

    %Total Relative Velocity
    Urs = sqrt((y(1) - y(4))^2 + (y(2) - Ve*cos(theta))^2 + (y(3))^2);

    %Coefficients
    PSI = K*Urs/y(1);
    PHI = P*Urs/y(1);

    %Liquid Axial Velocity
    DY(1) = PSI*sign(y(1) - y(4))*(1 + (1/6)*(abs(y(1) - y(4))*G)^(2/3));

    %Liquid Radial Velocity
    DY(2) = PSI*sign(y(2) - Ve*cos(theta))*(1 + (1/6)*(abs(y(2) - ...
        Ve*cos(theta))*G)^(2/3));

    %Liquid Tangential Velocity
    DY(3) = PSI*sign(y(3))*(1 + (1/6)*(abs(y(3))*G)^(2/3));

    %Gaseous Axial Velocity
    DY(4) = (1/z/y(4))*((PHI/z)*sign(y(1) - y(4))*(1 + ...
        (1/6)*(abs(y(1) - y(4))*G)^(2/3)) + Ve*Ve - y(4)*y(4));

    assignin('base','Ve_step',Ve);
    evalin('base','Ve_out(end+1) = Ve_step');
end

end

In the above code, theta (radians), K (negative value), P, & G are constants and for the sake of this example can be taken as any value. Zspan is just the integration time step for the ODE solver and Y0 is the initial conditions vector (4x1). Again, for the sake of this example these can take any reasonable value. Now in the main file, the function is called with the following:

Ve_out = 0;
[Z,Y] = droplet_momentum(theta,K,G,P,zspan,Y0);
Ve_out = Ve_out(2:end);

This method works without complaint from MATLAB, but the problem is that the size of Ve_out is not the same as the size of Z or Y. The reason for this is because MATLAB calls the ODE function multiple times for its algorithm, so the solution is going to be slightly smaller than Ve_out. As am304 suggested, I could just simply calculated DY by giving the ode function a Z and Y vector such as DY = momentum(Z,Y), however, I need to get this working with 'assignin' (or similar method) because another version of this problem has an implicit dependence between DY and Ve and it would be too computationally expensive to calculate DY at every iteration (I will be running this problem for many iterations).

È stato utile?

Soluzione

Ok, so let's start off with a quick example of an SSCCE:

function [Z,Y] = khan

options = odeset('RelTol',1e-7,'AbsTol',1e-7);
[Z,Y] = ode45(@momentum,[0 12],[0 0],options);
end

function Dy = momentum(z,y)
Dy = [0 0]';

Dy(1) = 3*y(1) + 2* y(2) - 2;
Dy(2) = y(1) - y(2);

Ve = Dy(1)+ y(2);

    assignin('base','Ve_step',Ve);
    evalin('base','Ve_out(end+1) = Ve_step;');

    assignin('base','T_step',z);
    evalin('base','T_out(end+1) = T_step;');
end

By running [Z,Y] = khan as the command line, I get a complete functional code that demonstrates your problem, without all the headaches associated. My patience for this has been exhausted: live and learn.

This seems to work, however, the size of the array does not match the size of the solution vector acquired from ode45

Note that I added two lines to your code which extracts time variable. From the command prompt, one simply has to run the following to understand what's going on:

Ve_out = [];
T_out = [];
[Z,Y] = khan;
size (Z)
size (T_out)
size (Ve_out)
plot (diff(T_out))

ans =
   109     1

ans =   
     1   163

ans =
     1   163

enter image description here

Basically ode45 is an iterative algorithm, which means it will regularly course correct (that's why you regularly see diff(T) = 0). You can't force the algorithm to do what you want, you have to live with it.

So your options are
1. Use a fixed step algorithm
2. Have a function call that reproduces what you want after the ode45 algorithm has done its dirty work. (am304's solution)
3. Collects the data with the time function, then have an algorithm parse through everything to removes the extra data.

Altri suggerimenti

Can you not do something like that? Obviously check the sizes of the matrices/vectors are correct and amend the code accordingly.

[Z,Y] = droplet_momentum2(theta,K,G,P,zspan,Y0);
DY = momentum(Z,Y);
Ve = sin(theta)*(0.5*z*DY(4) + y(4));

i.e. once the ODE is solved, computed the derivative DY as a function of Z and Y (which have just been solved by the ODE) and finally Ve.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top