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

allocate array of abstract class objects

S__MPay
Beginner
1,463 Views

I want to allocate an allocatable array of abstract class objects in a subroutine.

Subroutine adds a new object to the existing array of abstract objects by resizing the array:

      subroutine apmArrayAddNewMember(array, member)
          use class_absMaterial !! abstract class
          use class_mat02       !! child class
          implicit none

          ! class mat02 extends abstract class absMaterial
          class(absMaterial), allocatable, dimension(:), &
                   intent(inout)  :: array                       !! existing array
          type(mat02), target, intent(in) :: member              !! new object
          class(absMaterial), allocatable, dimension(:) :: temp
          integer intSize
          type(mat02), pointer, dimension(:) :: molder
          
          if (allocated(array)) then 
              intSize = size(array)
              allocate(molder(intSize+1))
              allocate(temp, mold=molder)
              deallocate(molder)
              temp(1:intSize) = array
              temp(intSize+1) = member
              deallocate(array)
              call move_alloc(temp, array)
          else 
              allocate(molder(1))
              allocate(array(1), mold=molder)
              deallocate(molder)
              array(1) = member
          end if
      end subroutine apmArrayAddNewMember

I am not sure if this works correctly. As you can see I have to allocate molder so that I can specify 'mold ='

I could not find any other way, also I don't know what if all the objects are not mat02 class and be another objects that extends absMaterial.

Will this code steel works if the other objects need same or less memory as mat02?

0 Kudos
4 Replies
Andrew_Smith
New Contributor III
1,463 Views

Arrays in Fortran are all contiguous with all elements the same size. Therefore you can only have one concrete type for the whole array.

The usual way around this is to create a concrete type like this:

type MaterialHolder
    class(absMaterial), allocatable :: item
end type

type(MaterialHolder), allocatable :: array(:)

Now you can allocate the array without using a mold, then allocate each item to any non-abstract child class of absMaterial:

allocate(mat02::array(1)%item)
allocate(mat03::array(2)%item)

While you are re-sizing you can use move_alloc on each item.

0 Kudos
S__MPay
Beginner
1,463 Views

Andrew Smith wrote:

Arrays in Fortran are all contiguous with all elements the same size. Therefore you can only have one concrete type for the whole array.

The usual way around this is to create a concrete type like this:

type MaterialHolder
    class(absMaterial), allocatable :: item
end type

type(MaterialHolder), allocatable :: array(:)

Now you can allocate the array without using a mold, then allocate each item to any non-abstract child class of absMaterial:

allocate(mat02::array(1)%item)
allocate(mat03::array(2)%item)

While you are re-sizing you can use move_alloc on each item.

Dear Andrew, Thank for your reply.

I wish it was possible to use dimension() statement inside allocate!

allocate(type(mat02), dimension(intSize) :: array)

 

 

0 Kudos
FortranFan
Honored Contributor II
1,463 Views

S. MPay wrote:

..

I wish it was possible to use dimension() statement inside allocate!

allocate(type(mat02), dimension(intSize) :: array)

 

@S. MPay,

Note you can do

allocate( mat02 :: array(intSize) )

 

0 Kudos
Lee__Ho
Beginner
1,463 Views

Question: As I execute this Program will give a compilation error such as BoundaryConditionLTu is allocated before. Iknow the problem but I don't know how to fix it. Please let me know how to use Dynamic class in this simple program.

Thank you

 

 

    :
    :
    ! ClassBoundaryCond is an abstract class
    class(ClassBoundaryCond),allocatable,Dimension(:) :: BoundaryConditionLTU
    subroutine initiateBoundaryCondition()
    implicit none

    integer :: i
    ! Date : 06/24/2019
    ! Arguments
    ! Body
    do i=1,6
        if (leftBC(i) == 0) then
            allocate(ClassDirichlet_BC::BoundaryConditionLTU(i))
        else if (leftBC(i) == 1) then
            allocate(ClassNeumann_BC::BoundaryConditionLTU(i))
        else if (leftBC(i) == 2) then
            allocate(ClassMix_BC::BoundaryConditionLTU(i))
        end if
    end do
    end subroutine initiateBoundaryCondition
 

0 Kudos
Reply