0

I'm developing a Fortran program for scientific computing. I want to use procedure pointers to assign the boundary conditions in the problem, shown in the following main program

program main
use boundary
implicit none

  bc1 => boundaryA
  bc2 => boundaryB
  bc3 => boundaryC

  call comp_boundary

end program

I define all the boundary operations "boundaryA/B/C" in a "boundary" module

module boundary
implicit none

procedure(boundary_type), pointer :: bc1,bc2,bc3

abstract interface
  subroutine boundary_type(i)
    integer :: i
  end subroutine
end interface

contains

subroutine boundaryA(i)
integer :: i
  print*, 'Boundary A at ',i
end subroutine

subroutine boundaryB(i)
integer :: i
  print*, 'Boundary B at ',i
end subroutine

subroutine boundaryC(i)
integer :: i
  print*, 'Boundary C at',i
end subroutine

subroutine comp_boundary
  call bc1(1)
  call bc2(2)
  call bc3(3)
end subroutine

end module

This works well.

But my question is that if, say, boundaryC has not one input argument, but two, then my definition for the abstract interface boundary_type doesn't work now.

Is that possible to use the procedure pointer to deal with this case? Or any other way around?

zljt3216
  • 53
  • 1
  • 5
  • 2
    How will the code that calls bcN know that it needs to supply two arguments? – IanH Jan 17 '18 at 08:29
  • I suggest you to use some indentation. It makes a huge difference in readability of your code. You also don't have to repeat `implicit none` in every module subroutine. Once in the module is enough. – Vladimir F Героям слава Jan 17 '18 at 09:39
  • I guess that's also my question. Is that possible to use some generic interface here? @IanH – zljt3216 Jan 17 '18 at 12:08
  • 1
    Supposing it was possible to write a generic interface to procedures which take either one or two arguments, that just pushes the decision of which procedure (or interface) to call somewhere else in the code path. Perhaps you could rewrite the two-argument procedure to one-argument form, and have it make a call to get its other argument. Whatever option you go for, you have to design your program accordingly. Personally I don't see the interface as the right place for the decision – High Performance Mark Jan 17 '18 at 12:23
  • @HighPerformanceMark, yes, rewriting the two-argument procedure could be one solution for now. I'll also do some research to be familiar with generic coding in Fortran and maybe resign the program. – zljt3216 Jan 17 '18 at 14:05
  • A generic interface lets you call different procedures that happen to have the same name depending on the type and kind of the arguments provided. I don't think that is relevant here - you know the specific procedure to call - you have a pointer pointing at it. What you need to describe to us is the nature of the information flow to the procedure. Maybe the solution is for the call to provide the maximum information (multiple arguments) regardless of what gets called, perhaps information needs to be bound with the procedure in an object. – IanH Jan 18 '18 at 09:56

1 Answers1

0

You could achieve this with an OPTIONAL argument. This is more an academic solution as there is always conservation of misery. As the comment of High Performance Mark states, your decision to use one or two arguments will need to be made somewhere.

Nonetheless, the OPTIONAL argument would require to add this too all subroutines and could therefore be not really the solution you request as all subroutines are essentially changed. It is essentially the same solution you gave, with just different set of procedure arguments.

MODULE boundary
  IMPLICIT NONE

  PROCEDURE(boundary_type), POINTER :: bc1,bc2

  ABSTRACT INTERFACE
     SUBROUTINE boundary_type(i,j)
       INTEGER           :: i
       INTEGER, OPTIONAL :: j
     END SUBROUTINE boundary_type
  END INTERFACE

CONTAINS

  SUBROUTINE boundaryA(i,j)
    INTEGER           :: i
    INTEGER, OPTIONAL :: j
    PRINT *, 'Boundary A at ',i
  END SUBROUTINE boundaryA

  SUBROUTINE boundaryB(i,j)
    INTEGER           :: i
    INTEGER, OPTIONAL :: j
    PRINT *, 'Boundary B at ',i,j
  END SUBROUTINE boundaryB

  SUBROUTINE comp_boundary
    CALL bc1(1)
    CALL bc2(2,3)
  END SUBROUTINE comp_boundary

END MODULE boundary

Note: the subroutine boundaryB must always be called with both arguments as no check is done for the availability of j (using PRESENT)

kvantour
  • 25,269
  • 4
  • 47
  • 72