Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
Welcome to the Intel Community. If you get an answer you like, please mark it as an Accepted Solution to help others. Thank you!
26758 Discussions

allocate array of abstract class objects

S__MPay
Beginner
404 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
404 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.

S__MPay
Beginner
404 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)

 

 

FortranFan
Honored Contributor II
404 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) )

 

Lee__Ho
Beginner
404 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
 

Reply