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

Derived type circualr dependency

Dharma
Beginner
1,832 Views
Hello,
I am trying to implement data structures for handling a mesh to be used in Finite Element methods. I am not abel to compile the folloing code. Can you pelase help me. I think it is illegal with respect to Fortran rules to have circular dependency in derived type definition. Can you suggest me a better alternative?

[fortran]module Test
 implicit none

 type Node
  integer :: id
  type(Element_ptr), allocatable :: Elm(:)
 end type Node

 type Node_ptr
  type(Node), pointer :: ptr
 end type Node_ptr

 type Element
  integer :: id
  type(Node_ptr), allocatable :: Nod(:)
 end type Element

 type Element_ptr
  type(Element),pointer :: ptr
 end type Element_ptr
 
end module Test[/fortran]

Thanks
Reddy
0 Kudos
6 Replies
Dharma
Beginner
1,832 Views
Hello,
Just figured out that this approach seems to work. Any other alternatives?

[bash]module Test
 implicit none

 type,abstract :: abs_node
 end type abs_node

 type,abstract :: abs_element
 end type abs_element

 type Node_ptr
  class(abs_node), pointer :: ptr
 end type Node_ptr

 type Element_ptr
  class(abs_element),pointer :: ptr
 end type Element_ptr


 type,extends(abs_node) :: Node
  integer :: id
  type(Element_ptr), allocatable :: Elm(:)
 end type Node

 type,extends(abs_element):: Element
  integer :: id
  type(Node_ptr), allocatable :: Nod(:)
 end type Element

end module Test

program TestMeshDS
 use Test
 implicit none
 type(node), target :: nod
 type(element), target :: elm

 nod%id=1
 allocate(nod%Elm(1))

 Elm%id=1
 allocate(Elm%nod(1))

 nod%Elm(1)%ptr => Elm

 Elm%nod(1)%ptr => nod

 print*,'Test Sucessful'

end program TestMeshDS[/bash]

Thanks
Reddy
0 Kudos
david_car
New Contributor I
1,832 Views
Um. Your type Node depends on type Element_ptr. With your latest approach, you've implemented something akin to forward declarations in Fortran using abstract types. But, you could have simply done this:
[fortran]module Test
 implicit none

 type Node_ptr
  type(Node), pointer :: ptr
 end type Node_ptr

 type Element
  integer :: id
  type(Node_ptr), allocatable :: Nod(:)
 end type Element

 type Element_ptr
  type(Element),pointer :: ptr
 end type Element_ptr

 type Node
  integer :: id
  type(Element_ptr), allocatable :: Elm(:)
 end type Node

end module Test
[/fortran]
This resolves the issue since everything that type Node depends on is declared. Cheers.
0 Kudos
Hirchert__Kurt_W
New Contributor II
1,832 Views
As a general rule, you need to define a type before you can declare objects or components of that type. In Fortran 90 and Fortran 95, the only exception to that rule was if the POINTER attribute was present, in which case the definition of the type could come later in the same scoping unit.

With the addition of allocatable components (first in a technical report and then in Fortran 2003), I believe that this exception was extended to also apply for the ALLOCATABLE attribute, but I haven't verified that in the standard.

Your ordering of the type definitions violated the Fortran 90/95 rule, although it should have been acceptable under the looser Fortran 2003 rule. David's reordering of your definitions conforms to Fortran 90/95 rule and is the obvious workaround for you to use.

The one question that remains is whether
a) this is a known limitation in ifort's implementation of F2003 and theTR,
b) this is an unintended limitation in ifort's implementation of F2003 and the TR (i.e., a bug), or
c) I am wrong about the POINTER exception having been extended to ALLOCATABLE (in which case, I should start lobbying now for such an extension being made in the next revision of the Fortran standard).

-Kurt
0 Kudos
Dharma
Beginner
1,832 Views
@David: Thanks. It works, when i change the code as you suggested. I was intially trying to use, pyF95++ to create a type such as class_Vector but i end up with circular module dependency if i use the approach suggested by you. That is why i tried the Abstract Data type approach and that resolves the circular modul dependence issue. But looks like, unless i use fortran intrinisc types, i need to overload operators (such as > and < ) for the derived types becuase of the mergesort algorithm in vector templete.

@Kurt: if i define a type with a component whose type is not defined yet but has an allocatable attribute, ifort gives an error[see the example code]. This, i think is consistent with R440 of the F2003 standard. It alos explains why the approach suggested by david works.

[fortran] module Test
  implicit none

  type Node_ptr
   type(Node), pointer :: ptr
  end type Node_ptr

  type Element_ptr
   type(Element),pointer :: ptr
  end type Element_ptr

  type Side_ptr
   type(Side),allocatable:: ptr
  end type Side_ptr

  type Element

   integer :: id
   type(Node_ptr), allocatable :: Nod(:)
   type(side_ptr), allocatable :: sid(:)
  end type Element

  type Node
   integer :: id
   type(Element_ptr), allocatable :: Elm(:)
   type(side_ptr), allocatable :: sid(:)
  end type Node

  type side
     integer :: id
   type(Element_ptr), allocatable :: Elm(:)
   type(node_ptr), allocatable :: sid(:)
  end type side
  end module Test
[/fortran]
Thanks
Reddy
0 Kudos
Hirchert__Kurt_W
New Contributor II
1,832 Views
@Kurt: if i define a type with a component whose type is not defined yet but has an allocatable attribute, ifort gives an error[see the example code]. This, i think is consistent with R440 of the F2003 standard. It alos explains why the approach suggested by david works.

Rather than cite R440 generally, I would cite C438 and C439 specifically (the constraints on R440 that address whether a type must be "previously defined" or not). It appears my option c) applies -- I was wrong in believing that the TR and F2003 extended the POINTER exception to ALLOCATABLE. However, I wasn't completely wrong -- the corresponding constraint in Fortran 2008 does extend the exception to ALLOCATABLE, so your original code will eventually be legal when compilers implement F2008.

The POINTER part of the exception goes all the way back to Fortran 90, so in sets of mutually recursive types where POINTER is used, it is wise to follow David's approach and make the only forward type references be in POINTER components. I welcome the F2008 ALLOCATABLE exception because I can imagine cases where one might wish to use ALLOCATABLE exclusively (to promote convenient automatic deallocation of complete trees or other structures involving such types).

-Kurt

0 Kudos
david_car
New Contributor I
1,832 Views
Reddy,
Correct about the templating using PyF95++. At the moment I'm working on the logic to have an extra template parameter like Sortable or something that you could set to remove that segment of code. This is definitely doable with the current framework as I have default template parameters, but it requires that you use an * for those when instantiating and choosing the defaults. If I add and extra template parameter with a default, this will break any codes using it now as it would require an additional * for the default. So, it would look like:
type (AList) :: int_list
I will have to add the capability of not specifying all the template parameters when instantiating a template. Something like:
type (AList) :: my_alist
type (AList) :: int_list
Something like that. For now, you simply need to create stub routines for the <, >, <=, >= operators for your type for it to build. No biggy really if you don't want to use the MergeSort. Or you can copy the AList template and remove the mergesort functions and rename all occurences of AList to NonSortAList or something like that. Then, all you have to do:
type (NonSortAList) :: my_alist
Thanks for giving it a try.
0 Kudos
Reply