Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
794 views
in Technique[技术] by (71.8m points)

fortran - Making SUM function work with derived types

I have a user type which contains two or more arrays of different sizes.

type state    
    real(real64) :: pos(3), ori(4), vee(3), omg(3)
end type

and I have defined the (*) and (+) operators in order to be able to do algebra

interface operator (+)
    procedure st_add
end interface
interface operator (*)
    procedure st_scale1, st_scale2
end interface

contains

elemental function st_add(a,b) result(c)
type(state), intent(in) :: a,b
type(state) :: c
    c = state( &
        a%pos + b%pos, &
        a%ori + b%ori, &
        a%vee + b%vee, &
        a%omg + b%omg)
    
end function

elemental function st_scale1(a,b) result(c)
real(real64), intent(in) :: a
type(state), intent(in) :: b
type(state) :: c

    c = state( &
        a * b%pos, &
        a * b%ori, &
        a * b%vee, &
        a * b%omg)
    
end function

elemental function st_scale2(b,a) result(c)
real(real64), intent(in) :: a
type(state), intent(in) :: b
type(state) :: c

    c = state( &
        a * b%pos, &
        a * b%ori, &
        a * b%vee, &
        a * b%omg)
    
end function

now I am using the above in a linear algebra operation such as

    real(real64), parameter :: c(4) = [1/6d0, 2/6d0, 2/6d0, 1/6d0]        
    type(state) :: k(4),k_step

    k_step = c(1)*k(1)+c(2)*k(2)+c(3)*k(3)+c(4)*k(4)

but what I want for brevity and code flexibility to use the following

    k_step = sum( c(:)*k(:) )    ! error

which results in the following error error #6362: The data types of the argument(s) are invalid. [SUM].

So what are my options? Do I need an generic interface for sum calling st_add? Or do I need some other definition?

I am using Intel? Fortran Compiler Classic 2021.1.2 (part of oneAPI HPC).


Solution

The solution that worked best is to add the following

interface sum
    procedure st_sum
end interface

contains

pure function st_sum(a) result (s)
type(state), intent(in) :: a(:)
type(state) :: s
integer :: i, n
    n = size(a)        
    s = a(1)
    do i=2, n
        s = s + a(i)
    end do
end function

and usage

k_step = sum(c(:)*k(:))
st = this + h*k_step

Well, I actually I combined the two statements above into one

st = this + sum( (h*c(:))*k(:) )

Overall I get the same results, but with a slight performance penalty (about 10%). It must be all that array copying values for function results. IDK.

question from:https://stackoverflow.com/questions/66065400/making-sum-function-work-with-derived-types

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Do I need an generic interface for sum calling st_add?

You do need to add a specific function to the sum generic interface. It does not matter that much what exactly that function calls internally. It must be a function that works for the state type arrays, that is important.

interface sum
  procedure your_function
end interface


function your_function(a)
   type(state) :: your_function
   type(state), intent(in) :: a(:)
   ...
end function

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...