I have a program dealing with calculations for an engine. There are multiple limiters that need to be considered (pressure ratio, temperature, ect.). These are organized from users perspective in groups, with some parameters common to all groups and some not.
Because during the run time I need to work with these limiters depending on the requirements, potentially changing them during various calculation steps it would make sense to organize these in an array of polymorphic elements, depending on what each limiter group needs. In principle it works, but not quite how I want to.
I wrote a small program to test different method shown below:
Here is the module with derived types etc.
module ArrayTest
interface init_limiter
module procedure :: initGroup1, initGroup2
end interface
type :: base
contains
procedure, pass :: setup => idontwanttodothis
procedure, pass :: print_param
end type base
type, extends(base) :: Group1
real :: p1
contains
procedure, pass :: init => initGroup1
procedure, pass :: print_param => printGroup1
end type Group1
type, extends(base) :: Group2
integer :: p1
real :: rDummy
contains
procedure, pass :: init => initGroup2
procedure, pass :: print_param => printGroup2
end type Group2
type ArrElem
integer :: a, b, c
class(base), allocatable :: param
end type ArrElem
type(ArrElem), dimension(5) :: T1, T2
contains
subroutine idontwanttodothis(self, iDummy, rDummy)
class(base) :: self
integer, optional :: iDummy
real, optional :: rDummy
select type (self)
type is(group1); call self.init(rDummy)
type is(group2); call self.init(iDummy,rDummy)
end select
end subroutine idontwanttodothis
subroutine print_param(self)
class(base) :: self
select type(self)
type is(group1); call self.print_param()
type is(group2); call self.print_param()
class default; write(*,'(A)') 'Type:: Unknown'
end select
end subroutine print_param
pure subroutine initGroup1(self, x)
class(Group1), intent(inout) :: self
real, intent(in) :: x
self.p1 = x
end subroutine initGroup1
pure subroutine initGroup2(self, x, y)
class(Group2), intent(inout) :: self
integer, intent(in) :: x
real, intent(in) :: y
self.p1 = x
self.rDummy = y
end subroutine initGroup2
subroutine printGroup1(self)
class(Group1) :: self
write(*,'(A,F5.2)') 'Type:: Group1 ',self.p1
end subroutine printGroup1
subroutine printGroup2(self)
class(Group2) :: self
write(*,'(A,I2,F5.2)') 'Type:: Group2 ',self.p1, self.rDummy
end subroutine printGroup2
end module ArrayTest
And here is the main program:
program TestAlloc
use ArrayTest
call main()
contains
subroutine main
integer i
type(group1) :: g1Dummy
!Option 1
g1Dummy.p1 = 29
allocate(T1(1).param, source = g1Dummy)
!Option 2
allocate(Group2::T1(2).param)
select type(dummy => T1(2).param)
type is(Group2); call dummy.init(12,8.7)
end select
!Option 3
allocate(Group2::T1(3).param)
call T1(3).param.setup(3, 4.5)
!Option 4
allocate(Group1::T1(4).param)
call init_limiter(T1(4).param, 8.) !this does not work
call init_limiter(g1Dummy, 8.) !this works
T2 = T1
do i=1,5
if(allocated(T2(i).param)) call T2(i).param.print_param()
end do
return
end subroutine main
end program TestAlloc
Options 1, 2 and 3 work. Option 4 doesn't. Is there any way to make this work? i.e. overload a function call for an allocatable parameter?
p.s. Overriding inherited function through child will work, but that will require both parent and children to have the same interface, which I find inconvenient, might as well use option 3 then.