Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28602 Discussions

optional parameter and openmp exception

Jauch
Beginner
460 Views
Hi,

I have a really weird problem with openmp...
We were able to use openmp and fortran for a long time now, in a very complex software.

I'm trying to change ONE routine, and the results, with different "compilation options", are as this:

Using DEBUG, no optimizations: works fine.
No DEBUG, Optimizations for speed: works fine.
No DEBUG, Optimizations for speed, OpenMP: doesn't work.
No DEBUG, no optimizations, OpenMP, works fine.

Like you can see, only when I set (in Visual Studio) Fortran->Optimization->Optimization = No Optimization is that the OpenMP works...

The code that I made looks like this:

subroutine a (param_a, param_b)

real, dimension(:,:), pointer :: param_a
real, dimension(:,:), pointer, optional :: param_b

real :: x
integer :: i, j

if (present(param_b)) then
write(*,*) 'param_b present'
else
write(*,*) 'param_b not present'
endif


x = 0.0

do j = 1, 10
do i = 1, 10
if (present(param_b)) then
x = x + param_b(i, j)
endif

enddo
enddo

end subroutine a

The only place where param_b is used, is inside the if block where I verify if it is present.
In my test case, it is never present and I'm surprized that I get an error at all.
If I comment the line where it is used, or if I comment only the "+ param_b(i, j)", the code then works fine. This is very weird, because param_b is never present (I verified it through the "param_b not present").

I made a simple program test and no error raised at all.
Maybe I have something wrong with my code, of course (and I'm still looking for it), but why only when OpenMP and Optimized for Speed is ON is that I get an error?

If I run the program with a project that pass a value for param_b, than all configurations work without problem.

Any ideas?

Thanks!
0 Kudos
8 Replies
Steven_L_Intel1
Employee
460 Views
I can think of lots of possibilities, but without seeing a complete example, not a portion of what the code "looks like", it's hard to be definitive. All I can say right now is that yoiu have not shown that an explicit interface to subroutine A is visible to the caller, and that is required when you have an OPTIONAL argument.

Please show us a complete program that demonstrates the problen. You can attach a ZIP to a reply here.
0 Kudos
Jauch
Beginner
460 Views
Hi Steve :)

First, thanks for the fast answer.
I think I'm unable to send the code because including all the sources and the external libs are +100MB to run the project that shows the problem...
But I'll send a zip with the code of the module that shows the problem.

But you ask about the explicit interface.

Because the subroutines that presents the problem is inside a module and the subroutine that calls it is in the same module, the two are only declared at the top.

Here are the code (I'll put only the code wich involves the problem):

[fortran]ModuleBasin

use ModuleAtmosphere     only : GetAtmosphereProperty

implicit none

private

private ::      AtmosphereProcesses
private ::          DividePrecipitation

subroutine AtmosphereProcesses
  integer                                     :: STAT_CALL
  real, dimension(:, :), pointer              :: PrecipitationFlux
  real, dimension(:, :), pointer              :: IrrigationFlux
  logical                                     :: IrrigationExists = .false.

  call GetAtmosphereProperty  (Me%ObjAtmosphere, PrecipitationFlux, ID = Precipitation_, STAT = STAT_CALL)
  if (STAT_CALL /= SUCCESS_) stop 'AtmosphereProcesses - ModuleBasin - ERR020'

  call GetAtmosphereProperty  (Me%ObjAtmosphere, IrrigationFlux, ID = Irrigation_, STAT = STAT_CALL, ShowWarning = .false.)
  if (STAT_CALL == SUCCESS_) then
    IrrigationExists = .true.
  elseif (STAT_CALL == NOT_FOUND_ERR_) then
    IrrigationExists = .false.
  else
    stop 'AtmosphereProcesses - ModuleBasin - ERR030'
  endif

  if (IrrigationExists) then
    call DividePrecipitation(PrecipitationFlux, IrrigationFlux)
  else
    call DividePrecipitation(PrecipitationFlux)
  endif
end subroutine AtmosphereProcesses

subroutine DividePrecipitation (PrecipitationFlux, IrrigationFlux)
  real, dimension(:, :), pointer                       :: PrecipitationFlux
  real, dimension(:, :), pointer, optional, intent(IN) :: IrrigationFlux

  integer                                     :: i, j, STAT_CALL
  logical                                     :: IsPresent = .false.
       
  if (present(IrrigationFlux)) then
    IsPresent = .true.
  endif

  do j = Me%WorkSize%JLB, Me%WorkSize%JUB
  do i = Me%WorkSize%ILB, Me%WorkSize%IUB
    if(Me%ExtVar%BasinPoints (i,j) == BasinPoint) then
      CurrentFlux = PrecipitationFlux(i, j)
      if (IsPresent) then                  
        CurrentFlux = CurrentFlux + IrrigationFlux(i, j)
      endif                        
    endif
  enddo
  enddo
end subroutine DividePrecipitation[/fortran]
This code above will cause an error, even if IsPresent is false (I checked it), when OpenMP and Speed Optimizations are ON.
If I comment the "+ IrrigationFlux(i, j)" part of the code, then it runs ok. And this is really weird, because on the study case, IsPresent is always False.
I checked it putting a write instruction right before the if, but if the "+ IrrigationFlux(i, j)" is there, the code blows before reaching the point. Again, if I comment the "+ IrrigationFlux(i, j)" part, a write instruction right before the "if (IsPresent) then" will show that the IsPresent variable is False.

And all the problems happens only with OpenMP and Optimizations on.

But, if I change a litle the code to something like the code below, the error is gone:

[fortran]subroutine DividePrecipitation (PrecipitationFlux, IrrigationFlux)
  real, dimension(:, :), pointer                       :: PrecipitationFlux
  real, dimension(:, :), pointer, optional, intent(IN) :: IrrigationFlux

  integer                                     :: i, j, STAT_CALL
  logical                                     :: IsPresent = .false.
real, dimension(:, :), pointer,                        :: Irri => Null()
       
  if (present(IrrigationFlux)) then
    IsPresent = .true.
    Irri => IrrigationFlux
  endif

  do j = Me%WorkSize%JLB, Me%WorkSize%JUB
  do i = Me%WorkSize%ILB, Me%WorkSize%IUB
    if(Me%ExtVar%BasinPoints (i,j) == BasinPoint) then
      CurrentFlux = PrecipitationFlux(i, j)
      if (IsPresent) then                  
        CurrentFlux = CurrentFlux + Irri(i, j)
      endif                        
    endif
  enddo
  enddo
end subroutine DividePrecipitation
[/fortran]

With this code, no more errors happens.
If IrrigationFlux is present, than no errors at all, in any configuration, shows up.
0 Kudos
jimdempseyatthecove
Honored Contributor III
460 Views
Check to make sure that the pointer "PercipitationFlux" is valid.
By this I mean it points to a valid array. The test if(associated(PercipitationFlux)) only indicate if the pointer is .not. NULLIFIED as opposed to pointing at a valid array (or contains some random address). What you will need to do is to test the location of the first cell (obtained where you allocated or associated the pointer)and possibly test the contents for a signature (that you placed into the cell).

Jim Dempsey
0 Kudos
Jauch
Beginner
460 Views
Hello Jim :)

PrecipitationFlux, as IrrigationFlux (if present) are always valid.
They ara 2D arrays that are created in another module ModuleAtmosphere and we get a pointer to them using the subroutine GetAtmosphereProperty (see code).
In fact, this module reads a file that contains information to create both matrices. Only that PrecipitationFlux is mandatory and IrrigationFlux isn't.

When I use both PrecipitationFlux and IrrigationFlux, both matrices have valid values (I checked both) at the point they enter the subroutine DividePrecipitation.

In fact, as I said before, the problem shows up only when I do not use IrrigationFlux and yet, only when I compile the code WITH OpenMP and WITH Speed Optimizations. If I shutdown OpenMP OR SpeedOptimizations, everything works fine. AND this problem only occours if I use, in the code, the IrrigationFlux directly. If I change the code to use a pointer to the parameter IrrigationFlux if it's present, then everything works even with OpenMP and SpeedOptimizations ON.

Steve have mentioned that a subroutine that uses optional arguments needs an explicit interface.
But seems (to me) that if the subroutine that calls it is on the same module, this should not be necessary...?
If yet this is necessary, how to code this?

I solved (I think) using a pointer to the parameter instead using the parameter directly, but I would like to discover why I have to do this...
0 Kudos
Steven_L_Intel1
Employee
460 Views
Since this is in a module, you have the explicit interface. But I think I have an idea.

Remove the initialization of IsPresent from the declaration and explicitly assign .false. to it on entry to the subroutine. The problem is that when you give a local variable an initialization, that implicitly makes it SAVE and therefore it retains its value across calls. If it ever gets set to .true., it will stay that way forever.

Also, the implicit SAVE means it is statically allocated and shared among threads. This is probably not what you want.
0 Kudos
Jauch
Beginner
460 Views
Hi again, Steve :)

This seems to be good advice.
Indeed, I don't wanna to have an implicit "SAVE" for any variable here.

But I think this is not the problem. I'll explain.

When we run the software the uses this piece of code, we must tell, in a configuration file, if we want to use the "IrrigationFlux" or not. If not, it will not be used for the entire run, no matter what happens. If we say we wanna to use it, it will always be present.

So, if we use it, we use it all the time and it will always be present (and no errors happens).
If we do not use for the beginning, it will never be present.

My tests seuggests that in the scenario case where the run fails, the "IsPresent" have the correct value (.False.), and thus, the fact that we get an exception because of the presence of the "+ IrrigationFlux" inside a "if" block that will never be executed is very weird...

But I'll try what you said and see what happens

Anyway, you gave me an idea to improve some areas of the code using the "save" attribute.
I'll take a look at it :)
0 Kudos
Steven_L_Intel1
Employee
460 Views
Which exact compiler version are you using? I have a vague recollection of a compiler bug where it would move a use of an OPTIONAL variable outside a test. Or I could be imagining things. If you are using the latest version (12.0.5) then please try to come up with a reproducible test case for us to look at.
0 Kudos
Jauch
Beginner
460 Views
Hum...

No. I'm using version 11.1, I think (I'm not at the office right now), on Windows XP.
I'm finishing a new machine with Windows 7 and probably will use a 64 bit version of Intel, but don't know exactly the version of it...

I'll have to talk to people back at office on monday to see this.
0 Kudos
Reply