Handling underflow errors in fortran 90

  • Context: Fortran 
  • Thread starter Thread starter meteo student
  • Start date Start date
  • Tags Tags
    Errors Fortran
Click For Summary

Discussion Overview

The discussion revolves around handling underflow errors in Fortran 90 while solving an elliptic partial differential equation, specifically Poisson's equation. Participants explore coding techniques, debugging strategies, and the implications of underflow in numerical computations.

Discussion Character

  • Technical explanation
  • Debate/contested
  • Mathematical reasoning

Main Points Raised

  • One participant describes encountering an underflow error in their Fortran code and expresses uncertainty about their attempts to refactor the code to handle this issue.
  • Another participant points out potential issues in the original code, such as missing variable declarations and the absence of a PROGRAM section, suggesting that these could hinder functionality.
  • A participant mentions using a debugger (gdb) but faced challenges due to large array sizes, which complicated the debugging process.
  • There is a suggestion to flush very small values (e.g., -1.0E-45) to zero to avoid underflow errors, although this approach is debated.
  • Concerns are raised about dividing by zero in the context of the code, highlighting potential logical errors in the calculations.
  • Suggestions for improving code readability are made, including formatting and naming conventions.

Areas of Agreement / Disagreement

Participants do not reach a consensus on the best approach to handle underflow errors, with differing opinions on whether flushing small values to zero is reasonable and how to address the underlying coding issues.

Contextual Notes

Limitations include missing variable initializations, potential logical errors in the code, and unresolved mathematical steps related to handling underflow conditions.

meteo student
Messages
72
Reaction score
0
I am using fortran 90 to solve a elliptic partial differential equation numerically(Poisson's equation) and I have encountered a underflow error. All the arrays involved are stored as real data types. The original expression is highlighted in the comments and the my attempt at refactoring into simpler expressions is shown as expr0, expr1, expr2,expr3. I am not sure about my attempt to handle the underflow error because while the FPE problem goes away the solution does not converge and I get all zero values.

Any suggestions to improve my coding attempts ?
Fortran:
    use,intrinsic :: ieee_arithmetic
     use, intrinsic :: iso_fortran_env, only: compiler_version, compiler_options
     implicit none
     logical :: underflow_support, underflow
  
    do k=1,nz-1
         do i=1,nx-1
           do j=1,ny-1
           expr0 = omega*(-dxyz*rhoref(2*k)*pv(i,j,k)+a(i,j,k)*&
                (psi(i+1,j,k)+psi(i-1,j,k)))
           expr1 = b(i,j,k)*psi(i,j+1,k)+b(i,j-1,k)&
                *psi(i,j-1,k)+c(i,j,k)*&
                psi(i,j,k+1)+c(i,j,k-1)&
                *psi(i,j,k-1)
           expr1 = expr0 + expr1
           expr2 = (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k-1)+c(i,j,k))

           call ieee_get_flag(ieee_underflow,underflow)
           if (underflow) then
           end if
           if (expr1 == 0.0) then
              expr3 = expr1/expr2
              expr3 = expr3 + (1.-omega)*psi(i,j,k)
              psi(i,j,k) = expr3
           end if
         
!
           !             psi(i,j,k)=omega*(-dxyz*rhoref(2*k)*pv(i,j,k)+a(i,j,k)*
           !   >              (psi(i+1,j,k)+psi(i-1,j,k))
           !   >              +b(i,j,k)*psi(i,j+1,k)+b(i,j-1,k)
           !   >              *psi(i,j-1,k)+c(i,j,k)*
           !   >              psi(i,j,k+1)+c(i,j,k-1)
           !   >              *psi(i,j,k-1))/
           !   >              (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)
           !   >              +c(i,j,k-1)+
           !   >              c(i,j,k))
           !                 +(1.-omega)*psi(i,j,k)
         
        enddo
     enddo
  enddo
 
Last edited:
Technology news on Phys.org
Please use code tags, as they preserve your indentation, which helps make your code more readable. I have added them to your code. For more info, see https://www.physicsforums.com/threads/read-this-before-posting-code-geshi-syntax-highlighter.773407/ at the top of this forum section.
meteo student said:
I am using fortran 90 to solve a elliptic partial differential equation numerically(Poisson's equation) and I have encountered a underflow error. All the arrays involved are stored as real data types. The original expression is highlighted in the comments and the my attempt at refactoring into simpler expressions is shown as expr0, expr1, expr2,expr3. I am not sure about my attempt to handle the underflow error because while the FPE problem goes away the solution does not converge and I get all zero values.

Any suggestions to improve my coding attempts ?
I don't see how this could possibly work.
1. There is no PROGRAM section. Possibly you just copied a short section of your code.
2. Your three DO loop run from 1 to, respectively, nz-1, nx-1, and ny-1. None of the nx, ny, nz variables has been initialized, at least in the section of code that you posted.
3. I don't see any declarations for any variables, including omega and dxyz, or for any of the arrays.
When I see obvious errors like these, I stop looking.

Since you asked how you might improve your coding attempts, here are some suggestions.
  • Add spaces in your code. The compiler doesn't care, but jamming everything together makes it harder for humans to read and understand what you're trying to do. Here is one of your assignment statements, written on one line:
    Fortran:
    expr0 = omega*(-dxyz*rhoref(2*k)*pv(i,j,k)+a(i,j,k)*(psi(i+1,j,k)+psi(i-1,j,k)))
    Granted, you wrote it on two lines, using &, but it's almost unreadable with everything jammed together.
  • Use more informative names -- rhoref means what? And what is dxyz?
    Single-letter names are OK for loop control variables (i, j, and k in your code), but you really should have better names than nx, ny, nz.
  • Where's the rest of the code? The only declarations I see are for underflow_support and underflow, neither of which has been initialized.
  • If your code isn't working correctly, use a debugger, and insert a breakpoint to inspect the values of the variables being manipulated. If you don't know how to use a debugger, invest some time in doing this. Any time you spend will be amply rewarded. In the meantime, use the tried and true method of inserting write statements to print the values of variables. When your code is working as expected, you can delete or comment out the extra write statements.

meteo student said:
Following is my code
Fortran:
    use,intrinsic :: ieee_arithmetic
     use, intrinsic :: iso_fortran_env, only: compiler_version, compiler_options
     implicit none
     logical :: underflow_support, underflow
  
    do k=1,nz-1
         do i=1,nx-1
           do j=1,ny-1
           expr0 = omega*(-dxyz*rhoref(2*k)*pv(i,j,k)+a(i,j,k)*&
                (psi(i+1,j,k)+psi(i-1,j,k)))
           expr1 = b(i,j,k)*psi(i,j+1,k)+b(i,j-1,k)&
                *psi(i,j-1,k)+c(i,j,k)*&
                psi(i,j,k+1)+c(i,j,k-1)&
                *psi(i,j,k-1)
           expr1 = expr0 + expr1
           expr2 = (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)+c(i,j,k-1)+c(i,j,k))

           call ieee_get_flag(ieee_underflow,underflow)
           if (underflow) then
           end if
           if (expr1 == 0.0) then
              expr3 = expr1/expr2
              expr3 = expr3 + (1.-omega)*psi(i,j,k)
              psi(i,j,k) = expr3
           end if
         
!
           !             psi(i,j,k)=omega*(-dxyz*rhoref(2*k)*pv(i,j,k)+a(i,j,k)*
           !   >              (psi(i+1,j,k)+psi(i-1,j,k))
           !   >              +b(i,j,k)*psi(i,j+1,k)+b(i,j-1,k)
           !   >              *psi(i,j-1,k)+c(i,j,k)*
           !   >              psi(i,j,k+1)+c(i,j,k-1)
           !   >              *psi(i,j,k-1))/
           !   >              (2.*a(i,j,k)+b(i,j,k)+b(i,j-1,k)
           !   >              +c(i,j,k-1)+
           !   >              c(i,j,k))
           !                 +(1.-omega)*psi(i,j,k)
         
        enddo
     enddo
  enddo
 
Thank you Mark for the response. I apologize for not adding the code tag. I added the tag now.
Thanks also for the suggestions on the readability.
Yes I already used a debugger (gdb) and could not make much progress with it.I am using gfortran and I added the breakpoint on the offending line. As the values for the arrays are very large gdb outputs these statements -
<error reading variable: value requires 250000 bytes, which is more than max-value-size>.
So I set max-value unlimited. After that I tried to run gdb it hangs without doing anything.
Then I removed following lines during compilation fpe=overflow,underflow,zero,denormal and then ran it and got an IEEE underflow error. I tried printing the values and there were some very small values - 1.E-45 etc.

I could post the full code but I wanted to avoid it as I had a specific question i.e. how to handle a underflow. Is there a way to flush the really low values to zero and then move on ?
 
Last edited:
Fortran:
if (expr1 == 0.0) then
              expr3 = expr1/expr2
Here you are trying to divide Zero by something. Even with pencil and paper this does not work well.
 
Tom.G said:
Fortran:
if (expr1 == 0.0) then
              expr3 = expr1/expr2
Here you are trying to divide Zero by something. Even with pencil and paper this does not work well.
Tom - I agree. If you can read my response to Mark I have summarized my efforts so far. My question was how to handle an underflow error and move on.

So if expr1 is a really low value such as -1.0E-45 is it reasonable to flush it to zero and move on ? That is the question I am asking here.
 
As a minor nit, I'd reformat this piece of code to make it even more readable:

Fortran:
           expr0 = omega * ( (-dxyz) * rhoref(2*k) * pv(i, j, k) + a(i, j, k) * ( psi(i+1, j, k) + psi(i-1, j, k) ) )
       
           expr1 =    b(i, j, k)    * psi(i, j+1, k)    &
                    + b(i ,j-1, k)  * psi(i, j-1, k)    &
                    + c(i, j, k)    * psi(i, j, k+1)    &
                    + c(i, j, k-1)  * psi(i, j, k-1)

or

Fortran:
           expr0 = omega * ( (-dxyz) * rhoref(2*k) * pv(i, j, k)
                   + a(i, j, k) * ( psi(i+1, j, k) + psi(i-1, j, k) ) )
        
           expr1 = b(i, j, k)    * psi(i, j+1, k)    &
                   + b(i ,j-1, k)  * psi(i, j-1, k)    &
                     + c(i, j, k)    * psi(i, j, k+1)    &
                       + c(i, j, k-1)  * psi(i, j, k-1)

If you spend some time now reformatting it then you'll simplify your debugging effort later on especially if you have to revisit it 6 months later to fix something.
 
Tom.G said:
Fortran:
if (expr1 == 0.0) then
              expr3 = expr1/expr2
Here you are trying to divide Zero by something. Even with pencil and paper this does not work well.
Sure it does. There's no problem dividing 0.0 by a nonzero value -- you get 0.0 as the answer. The problem comes when you divide by zero.
 
meteo student said:
Yes I already used a debugger (gdb) and could not make much progress with it.I am using gfortran and I added the breakpoint on the offending line. As the values for the arrays are very large gdb outputs these statements -
<error reading variable: value requires 250000 bytes, which is more than max-value-size>.
So I set max-value unlimited. After that I tried to run gdb it hangs without doing anything.
250KB isn't all that big. Can you show the line of code that is causing this problem? Be sure to include declarations for all variables, and their values before that line is hit.

gdb shouldn't hang. Once you hit a breakpoint, the program will stop, and you can single-step through succeeding lines of code.
meteo student said:
Then I removed following lines during compilation fpe=overflow,underflow,zero,denormal and then ran it and got an IEEE underflow error. I tried printing the values and there were some very small values - 1.E-45 etc.

meteo student said:
So if expr1 is a really low value such as -1.0E-45 is it reasonable to flush it to zero and move on ? That is the question I am asking here.
Seems reasonable to me.
 

Similar threads

  • · Replies 4 ·
Replies
4
Views
3K
  • · Replies 22 ·
Replies
22
Views
5K
  • · Replies 4 ·
Replies
4
Views
8K
Replies
6
Views
4K
  • · Replies 4 ·
Replies
4
Views
2K
  • · Replies 2 ·
Replies
2
Views
6K
  • · Replies 2 ·
Replies
2
Views
3K
  • · Replies 6 ·
Replies
6
Views
5K
  • · Replies 8 ·
Replies
8
Views
6K
  • · Replies 1 ·
Replies
1
Views
3K