views:

242

answers:

3

I have the following program

format compact; format short g; clear; clc;  
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;  
for i=1:500000  
omegan=1.+0.0001*i;

a(1,1) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(1,2) = 2; a(1,3) = 0; a(1,4) = 0;
a(2,1) = 1; a(2,2) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(2,3) = 1; a(2,4) = 0;
a(3,1) = 0; a(3,2) = 1; a(3,3) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(3,4) = 1;
a(4,1) = 0; a(4,2) = 0; a(4,3) = 2; a(4,4) = ((omegan^2)*(Jm/(G*J))*d^2)-2;

if(abs(det(a))<1E-10) sprintf('omegan= %8.3f det= %8.3f',omegan,det(a))
end          
end

Analytical solution of the above system, and the same program written in fortran gives out values of omegan equal to 16.3818 and 32.7636 (fortran values; analytical differ a little, but they're there somewhere).

So, now I'm wondering ... where am I going wrong with this ? Why is matlab not giving the expected results ?

(this is probably something terribly simple, but it's giving me headaches)

+2  A: 

New answer:

You can investigate this problem using symbolic equations, which gives me the correct answers:

>> clear all             %# Clear all existing variables
>> format long           %# Display more digits of precision
>> syms Jm d omegan G J  %# Your symbolic variables
>> a = ((Jm*(d*omegan)^2)/(G*J)-2).*eye(4)+...  %# Create the matrix a
       diag([2 1 1],1)+...
       diag([1 1 2],-1);
>> solns = solve(det(a),'omegan')  %# Solve for where the determinant is 0

solns =

                                0
                                0
            (G*J*Jm)^(1/2)/(Jm*d)
           -(G*J*Jm)^(1/2)/(Jm*d)
       -(2*(G*J*Jm)^(1/2))/(Jm*d)
        (2*(G*J*Jm)^(1/2))/(Jm*d)
  (3^(1/2)*(G*J*Jm)^(1/2))/(Jm*d)
 -(3^(1/2)*(G*J*Jm)^(1/2))/(Jm*d)

>> solns = subs(solns,{G,J,Jm,d},{8e7,77,10540,140/3})  %# Substitute values

solns =

                   0
                   0
  16.381862247021893
 -16.381862247021893
 -32.763724494043785
  32.763724494043785
  28.374217734436371
 -28.374217734436371

I think you either just weren't choosing values in your loop close enough to the solutions for omegan or your threshold for how close the determinant is to zero is too strict. When I plug in the given values to a, along with omegan = 16.3819 (which is the closest value to one solution your loop produces), I get this:

>> det(subs(a,{omegan,G,J,Jm,d},{16.3819,8e7,77,10540,140/3}))

ans =

    2.765476845475786e-005

Which is still larger in absolute amplitude than 1e-10.

gnovice
Hello gnovice, I was hoping you would stop by :) No, the "less then" sign is ok there (unless I'm missing something you're trying to imply). It is an eigenvalue problem in vibrations ... I need to find all omegans (natural frequencies) for which the determint is zero. There is an infinite number of them, but I'm only looking for the first few (two or three). However, what I cannot understand is why my fortran program "swallows" this without a problem, and the det() function does not. It doesn't seem to be a single/double
ldigas
precision problem either - fortran program does it in single, and by default in matlab everything is in double precision. So matlab should have the advantage there from start.
ldigas
The sprintf is superfluous really, it is here merely so people who will try to figure this out will not have to add it themselves. As I said, I already know the results in this case. I'm more interested in the reason for this error, since I don't know now if I can rely on matlab's mechanism, when solving a larger problem (to which I don't know the result).
ldigas
@Idigas: I gave an all new answer. Hope it helps.
gnovice
@gnovice - thanks! I haven't so far been trying the symbolic toolbox, since for assembling the coefficient matrix the routines are already done. Also, I probably won't be able to use it, since that matrix is usually a little more complicated than this (this was just a simple beam divided in 3 elements). But as I wrote just now to Jonas in the comments to the question, I don't understand. I have the same step for omegan, I have the same stopping criteria. Why is matlab which works in double precision not giving the appropriate results ?
ldigas
@Idigas: My guess is that there are discrepancies arising from the order of operations in your code or in the function `det`. If the order of arithmetic operations for doing certain computations is different between the two implementations, small differences in accuracy can result.
gnovice
+3  A: 

You're looking for too small of determinant values because Matlab is using a different determinant function (or some other reason like something to do with the floating point accuracy involved in the two different methods). I'll show you that Matlab is essentially giving you the correct values and a better way to approach this problem in general.

First, let's take your code and change it slightly.

format compact; format short g; clear; clc;
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;
vals = zeros(1,500000);
for i=1:500000
    omegan=1.+0.0001*i;

    a(1,1) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(1,2) = 2; a(1,3) = 0; a(1,4) = 0;
    a(2,1) = 1; a(2,2) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(2,3) = 1; a(2,4) = 0;
    a(3,1) = 0; a(3,2) = 1; a(3,3) = ((omegan^2)*(Jm/(G*J))*d^2)-2; a(3,4) = 1;
    a(4,1) = 0; a(4,2) = 0; a(4,3) = 2; a(4,4) = ((omegan^2)*(Jm/(G*J))*d^2)-2;
    vals(i) = abs(det(a));
    if(vals(i)<1E-10)
        sprintf('omegan= %8.3f det= %8.3f',omegan,det(a))
    end
end
plot(1.+0.0001*(1:500000),log(vals))

All that I've done really is logged the values of the determinant for all values of omegan and plotted the log of those determinant values as a function of omegan. Here is the plot:

alt text

You notice three major dips in the graph. Two coincide with your results of 16.3818 and 32.7636, but there is also an additional one which you were missing (probably because your condition of the determinant being less than 1e-10 was too low even for your Fortran code to pick it up). Therefore, Matlab is also telling you that those are the values of omegan that you were looking for, but because of the determinant was determined in a different manner in Matlab, the values weren't the same - not surprising when dealing with badly conditioned matrices. Also, it probably has to do with Fortran using single precision floats as someone else said. I'm not going to look into why they aren't because I don't want to waste my time on that. Instead, let's look at what you are trying to do and try a different approach.

You, as I'm sure you are aware, are trying to find the eigenvalues of the matrix

a = [[-2 2 0 0]; [1 -2 1 0]; [0 1 -2 1]; [0 0 2 -2]];

, set them equal to

-omegan^2*(Jm/(G*J)*d^2)

and solve for omegan. This is how I went about it:

format compact; format short g; clear; clc;
L = 140; J = 77; Jm = 10540; G = 0.8*10^8; d = L/3;
C1 = (Jm/(G*J)*d^2);
a = [[-2 2 0 0]; [1 -2 1 0]; [0 1 -2 1]; [0,0,2,-2]];
myeigs = eig(a);
myeigs(abs(myeigs) < eps) = 0.0;
for i=1:4
    sprintf('omegan= %8.3f', sqrt(-myeigs(i)/C1))
end

This gives you all four solutions - not just the two that you had found with your Fortran code (though one of them, zero, was outside of your testing range for omegan ). If you want to go about solving this by checking the determinant in Matlab, as you've been trying to do, then you'll have to play with the value that you're checking the absolute value of the determinant to be less than. I got it to work for a value of 1e-4 (it gave 3 solutions: 16.382, 28.374, and 32.764).

Sorry for such a long solution, but hopefully it helps.

Update:

In my first block of code above, I replaced

vals(i) = abs(det(a));

with

[L,U] = lu(a);
s = det(L);
vals(i) = abs(s*prod(diag(U)));

which is the algorithm that det is supposedly using according to the Matlab docs. Now, I am able to use 1E-10 as the condition and it works. So maybe Matlab isn't calculating the determinant exactly as the docs say? This is kind of disturbing.

Justin Peel
That could be the problem (matlab using different determinant function). Do you know where one could find out what algorithm matlab is using for that ?Btw, I appreciate the effort you putted into solving this system, but unfortunatellyI'm not able to use it in my work. The coefficient matrices I use, are assembledusing the already written functions, and are always more complicated (and larger)then this one (which was for a simple beam divided into 3 elements/4 nodes).
ldigas
I didn't miss the third (or the second, depends how you look at it) omegan. Fortranprogram gave that one as well.It's just that, that wasn't one of the solutions,although it was numerically correct. The freqs. have to be in certain rations oneto another. I apologize if I caused you some confusion with that; I should have mentioned it in the question.
ldigas
I find this terribly annoying btw. I expected that if matlab works in double precision, and if I write my fortran programs in such; I would be able to get the same results without much rewriting (mostly ** operators to ^ :). I didn't expect matlab's functions to cause problems.
ldigas
@Idigas: How do you know that Fortran is 'right'? :)
Jonas
@Jonas - analytical solutions are the same (on my calculator and using dp in fortran, up to seventh or eight sig. decimal. Single precision doesn't differ from those values, so that tells me there isn't any rounding/adding errors, that make a significant difference).
ldigas
Matlab uses an LU decomposition to compute the determinant as described in the algorithm section of help.
Justin Peel
@ldigas: The real problem is that you're trying to use the characteristic polynomial to find eigenvalues, which is numerically problematic; in addition, you're using a very inefficient root finder. Finding eigenvalues is a numerically tricky subject; I would strongly recommend that you use an existing routine, such as MATLAB's eig() routine. You say that you can't use this approach for your existing matrices -- but why?
Martin B
@Justin: Yes, this is somewhat disturbing. I think we may want to call TMW support about that.
Jonas
@Martin B - well, to tell the truth, I'm not sure what I actually can use matlab for. I've always been a fortran user, but recently I've started using matlab more and more, for prototyping and simple analysis of less refined models. I like it because it is very simple to develop. Then I re-refine the mesh by a factor of 200 and put it in my fortran solvers. I'm still having trouble adjusting to matlab's quircks in some views, though; therefore this (and probably more will follow) questions.
ldigas
@Justin - that is a little scary !
ldigas
+1  A: 

I put this as an answer because I cannot paste this into a comment: Here's how Matlab calculates the determinant. I assume the rounding errors come from calculating the product of multiple diagonal elements in U.

Algorithm

The determinant is computed from the triangular factors obtained by Gaussian elimination

[L,U] = lu(A) s =  det(L)        
%# This is always +1 or -1  
det(A) = s*prod(diag(U))
Jonas

related questions