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

Strange result with polymorphic variables

Arjen_Markus
Honored Contributor I
216 Views
Hello,

the program below gives the following output:

Two-dimensional walk:

-1.0295 -0.9157

-0.9369 -0.8480

-0.9698 -0.7649

-0.9106 -0.6984

-0.9416 -0.6242

-1.0236 -0.5465

-0.9835 -0.4996

-1.0234 -0.5896

-0.9418 -0.6701

-1.0337 -0.7531

Three-dimensional walk:

0.2000 0.7713 -0.8487

0.2705 0.6955 -0.8487

0.3261 0.5994 -0.8487

0.4251 0.6502 -0.8487

0.4569 0.6580 -0.8487

0.5248 0.5630 -0.8487

0.5419 0.6165 -0.8487

0.5838 0.6754 -0.8487

0.5256 0.7216 -0.8487

0.5700 0.6639 -0.8487

Where I expect the third column to vary just as the other two, it remains constant.
I may be missing something, but the output is more to what I expect if I use gfortran
(this has a different problem though).

Can anyone shed some light on this issue?

For your information: I use Intel Fortran 12.0.3 on Linux.

Regards,

Arjen

----------

! random_walk.f90 --

! Simulate a random walk in two and three dimensions

!

module points2d3d

implicit none

type point2d

real :: x, y

contains

procedure :: print => print_2d

procedure :: random_vector => random_vector_2d

procedure :: add_vector => add_vector_2d

procedure, pass(vector) :: scale_by_factor => scale_by_factor_2d

procedure :: assign => assign_2d

generic :: operator(+) => add_vector

generic :: operator(*) => scale_by_factor

generic :: assignment(=) => assign

end type point2d

type, extends(point2d) :: point3d

real :: z

contains

procedure :: print => print_3d

procedure :: random_vector => random_vector_3d

procedure :: add_vector => add_vector_3d

procedure, pass(vector) :: scale_by_factor => scale_by_factor_3d

procedure :: assign => assign_3d

end type point3d

contains

!

! Auxiliary routine to convert from class to point

!

subroutine assign_2d( point1, point2 )

class(point2d), intent(inout) :: point1

class(point2d), intent(in) :: point2

point1%x = point2%x

point1%y = point2%y

end subroutine assign_2d

subroutine assign_3d( point1, point2 )

class(point3d), intent(inout) :: point1

class(point2d), intent(in) :: point2

point1%x = point2%x

point1%y = point2%y

point1%z = 0.0

select type (point2)

class is (point3d)

point1%z = point2%z

end select

end subroutine assign_3d

subroutine print_2d( point )

class(point2d) :: point

write(*,'(2f10.4)') point%x, point%y

end subroutine print_2d

subroutine print_3d( point )

class(point3d) :: point

write(*,'(3f10.4)') point%x, point%y, point%z

end subroutine print_3d

subroutine random_vector_2d( point )

class(point2d) :: point

call random_number( point%x )

call random_number( point%y )

point%x = 2.0 * (point%x - 0.5)

point%y = 2.0 * (point%y - 0.5)

end subroutine random_vector_2d

subroutine random_vector_3d( point )

class(point3d) :: point

call point%point2d%random_vector

call random_number( point%z )

point%z = 2.0 * (point%z - 0.5)

end subroutine random_vector_3d

function add_vector_2d( point, vector )

class(point2d), intent(in) :: point, vector

class(point2d), allocatable :: add_vector_2d

allocate( add_vector_2d )

add_vector_2d%x = point%x + vector%x

add_vector_2d%y = point%y + vector%y

end function add_vector_2d

function add_vector_3d( point, vector )

class(point3d), intent(in) :: point

class(point2d), intent(in) :: vector

class(point2d), allocatable :: add_vector_3d

class(point3d), allocatable :: add_result

allocate( add_result )

select type (vector)

class is (point3d)

!add_result%point2d = point%point2d + vector%point2d

add_result%point2d = point%point2d%add_vector( vector%point2d )

add_result%z = point%z + vector%z

class default

add_result%point2d = point%point2d + vector

add_result%z = 0.0

end select

call move_alloc( add_result, add_vector_3d )

end function add_vector_3d

function scale_by_factor_2d( factor, vector )

real, intent(in) :: factor

class(point2d), intent(in) :: vector

class(point2d), allocatable :: scale_by_factor_2d

allocate( scale_by_factor_2d )

scale_by_factor_2d%x = factor * vector%x

scale_by_factor_2d%y = factor * vector%y

end function scale_by_factor_2d

function scale_by_factor_3d( factor, vector )

real, intent(in) :: factor

class(point3d), intent(in) :: vector

class(point2d), allocatable :: scale_by_factor_3d

class(point3d), allocatable :: scale_result

allocate( scale_result )

scale_result%point2d = factor * vector%point2d

scale_result%z = factor * vector%z

call move_alloc( scale_result, scale_by_factor_3d )

end function scale_by_factor_3d

end module points2d3d

program random_walk

use points2d3d ! Both 2D and 3D points available

type(point2d), target :: point_2d

type(point3d), target :: point_3d

type(point2d), target :: vector_2d

type(point3d), target :: vector_3d

!

! A variable of class point2d can point to point_2d but

! also to point_3d

!

class(point2d), pointer :: point

class(point2d), pointer :: vector

integer :: nsteps = 10

integer :: i

integer :: trial

real :: deltt = 0.1

do trial = 1,2

! Select what type of point ...

if ( trial == 1 ) then

point => point_2d

vector => vector_2d

write(*,*) 'Two-dimensional walk:'

else

point => point_3d

vector => vector_3d

write(*,*) 'Three-dimensional walk:'

endif

call point%random_vector

do i = 1,nsteps

call vector%random_vector

point = point + deltt * vector

call point%print

enddo

enddo

end program random_walk

0 Kudos
2 Replies
reinhold-bader
New Contributor II
216 Views
Hello,

my impression is that ifort gets the dispatch for the generic wrong. It should, for example, invoke the 3D vector add, and from there the 2D vector add. However, it directly invokes the 3D vector add from the main program even though the dynamic type of "point" is point3d. This error persists through more recent releases of the compiler.

Regards
Reinhold
0 Kudos
Steven_L_Intel1
Employee
216 Views
This problem sounds vaguely familiar - I am looking at it now.
0 Kudos
Reply