I'm working on an aerodynamics code (source code here) using good old Fortran. Part of the initialization is reading in a file which contains information on a surface mesh, basically a set of triangular or quadrilateral panels making up the surface. I'd like to describe both quadrilateral and triangular panels using a single type panel. To do that, I've written two initialization functions panel_init_3 and panel_init_4 which will load the data into the type based on how many vertices the panel has. I'd like to bind these to my panel type and overload them based on the number of arguments (i.e. if it gets passed an integer and 3 vertex objects, then panel_init_3 gets called and similarly for 4 vertex objects.
Here is the source code for the type:
module panel_mod
use linked_list_mod
use vertex_mod
implicit none
type panel
! A panel with an arbitrary number of sides
integer :: N ! Number of sides/vertices
type(vertex_pointer),dimension(:),allocatable :: vertices
real,dimension(3) :: n_hat ! Normal vector
real :: A ! Surface area
contains
procedure :: init => panel_init_3, panel_init_4
procedure :: calc_area => panel_calc_area
procedure :: calc_normal => panel_calc_area
end type panel
contains
subroutine panel_init_3(this, v1, v2, v3)
! Initializes a 3-panel
implicit none
class(panel),intent(inout) :: this
type(vertex),intent(in),target :: v1, v2, v3
! Set number of sides
this%N = 3
! Allocate vertex array
allocate(this%vertices(this%N))
! Store info
this%vertices(1)%ptr => v1
this%vertices(2)%ptr => v2
this%vertices(3)%ptr => v3
! Calculate normal vec
! Calculate area
end subroutine panel_init_3
subroutine panel_init_4(this, v1, v2, v3, v4)
! Initializes a panel with 4 sides
implicit none
class(panel),intent(inout) :: this
type(vertex),intent(in),target :: v1, v2, v3, v4
! Set number of sides
this%N = 4
! Allocate vertex array
allocate(this%vertices(this%N))
! Store info
this%vertices(1)%ptr => v1
this%vertices(2)%ptr => v2
this%vertices(3)%ptr => v3
this%vertices(4)%ptr => v4
! Calculate normal vector
! Calculate area
end subroutine panel_init_4
subroutine panel_calc_area(this)
implicit none
class(panel),intent(inout) :: this
end subroutine panel_calc_area
subroutine panel_calc_normal(this)
implicit none
class(panel),intent(inout) :: this
end subroutine panel_calc_normal
end module panel_mod
This module compiles fine. But, when it gets used here
...
! Initialize triangular panel
if (N == 3) then
call panels(i)%init(vertices(i1+1), vertices(i2+1), vertices(i3+1)) ! Need +1 because VTK is 0-indexed
! Initialize quadrilateral panel
else
call panels(i)%init(vertices(i1+1), vertices(i2+1), vertices(i3+1), vertices(i4+1))
end if
...
I get the compiler message
70 | call panels(i)%init(vertices(i1+1), vertices(i2+1), vertices(i3+1), vertices(i4+1))
| 1
Error: More actual than formal arguments in procedure call at (1)
Am I reaching beyond the capabilities of Fortran, or is there a way to do this? I realize I could do this all without binding and overloading, but I like how clean it'd be. I am using gfortran 9.3.0.
It is possible, but you need to define
initas a generic procedure (binding) with those other two being the specific procedures (bindings)It is quite similar to what is normally done with normal procedures using named
interfaceblocks when you do