如何为假定形状数组使用可选属性
How to use optional attribute for assumed shape arrays
我在使用 Fortran 可选属性时遇到了以下情况
对于假定的形状数组并尝试找出最佳(在性能方面)解决方案。
如果有人能给我一个很好的提示,我会很高兴。
请注意,我对我能获得的每一个性能提升都很感兴趣,因为我的数组很大,循环的数量和它们的周期甚至更大。
我的情况是使用可选参数完成计算,或者如果它不存在,它会在其位置使用另一个数组。
subroutine compute(tmat,av,av2)
implicit none
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
complex,intent(in),optional :: av2(:)
if(present(av2)) then
tmat = av *av2
else
tmat = av *av
end if
end subroutine compute_transition_matrices_bosonic
在这个简单的例子中,上面的解决方案就可以了。尽管如此,我的真实代码要复杂得多。
这意味着例程的内部块可能非常大(数百行)并且最重要的是包含许多嵌套循环。
可以想象如下:
if(present(av2)) then
tmat = "function"(av,av2)
else
tmat = "function"(av,av)
end if
其中 "function" 代表很多操作和循环(因此是“”)。关键是对于这两种情况,这些都是相同的操作
if 语句,这样我需要写两次代码。另一种解决方案是检查 av2
是否出现在使用位置
会产生一些开销的代码,因为这种检查会非常(非常)频繁地进行。
我想知道是否有更聪明的方法来解决这样的问题。首先,人们可能会想到使用临时变量
complex, :: phi_tmp(:)
if(present(av2)) then
phi_tmp = av2
else
phi_tmp = av
end if
tmat = "function"(av,phi_tmp)
在使用可选参数时经常这样做。但这会复制数据,在我的例子中这是一个非常大的数组。
因此,我在考虑使用指针
complex,intent(in),target :: av(:)
complex,intent(in),optional,target :: av2(:)
complex,pointer :: phi_tmp(:)
if(present(av2)) then
phi_tmp => av2
else
phi_tmp => av
end if
tmat = "function"(av,phi_tmp)
但这需要 av
和 av2
的 TARGET
属性。在这里我不确定这是否会导致性能下降,因为编译器
不能再假设 av
和 av2
在其优化过程中没有别名,即使这里都有 INTENT(IN)
属性
这样就不会出现混叠问题。此外,如果调用例程时输入中的参数确实是什么意思
没有 TARGET
属性? (这编译和工作!)
有没有人对这些问题有一些经验?
有"standard"解决方案吗? (我找不到一个)
最终什么是最好的解决方案?
一种方法是对存在和不存在的情况使用不同的子程序。
subroutine compute1(tmat,av)
implicit none
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
call compute2(tmat, av, av) ! Ensure there is an explicit interface for compute2 here
end subroutine
subroutine compute2(tmat,av,av2)
implicit none
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
complex,intent(in) :: av2(:)
tmat = "function"(av,av2)
end subroutine
两者都没有可选参数。
这可以通过使 compute
成为这两者的通用来添加。
当然,这不会在所有情况下都有效,但是这里 av
上的 intent(in)
属性和 compute2
上的 av2
我们不必担心别名。
我建议的是你最后一个用指针的解决方案,如果实参没有目标属性就没有问题,指针在例程退出时会变成未定义的,但只要你不传递它回到无关紧要的调用过程。
您可以使用其他子例程(例如内部子例程)来执行实际计算,该例程不会知道它的参数是别名的,基本上,如果它们都具有 intent(in)
属性,这样就好了。所以不会有性能损失。
subroutine compute(tmat, av, av2)
implicit none
complex, intent(out) :: tmat(:)
complex,intent(in),target :: av(:)
complex,intent(in),optional,target :: av2(:)
complex,pointer :: phi_tmp(:)
if(present(av2)) then
phi_tmp => av2
else
phi_tmp => av
end if
call compute_internal(tmat, av, phi_tmp)
contains
subroutine compute_internal(tmat, av, av2)
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
complex,intent(in) :: av2(:)
.....
end subroutine
end subroutine
我在使用 Fortran 可选属性时遇到了以下情况 对于假定的形状数组并尝试找出最佳(在性能方面)解决方案。 如果有人能给我一个很好的提示,我会很高兴。 请注意,我对我能获得的每一个性能提升都很感兴趣,因为我的数组很大,循环的数量和它们的周期甚至更大。
我的情况是使用可选参数完成计算,或者如果它不存在,它会在其位置使用另一个数组。
subroutine compute(tmat,av,av2)
implicit none
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
complex,intent(in),optional :: av2(:)
if(present(av2)) then
tmat = av *av2
else
tmat = av *av
end if
end subroutine compute_transition_matrices_bosonic
在这个简单的例子中,上面的解决方案就可以了。尽管如此,我的真实代码要复杂得多。 这意味着例程的内部块可能非常大(数百行)并且最重要的是包含许多嵌套循环。 可以想象如下:
if(present(av2)) then
tmat = "function"(av,av2)
else
tmat = "function"(av,av)
end if
其中 "function" 代表很多操作和循环(因此是“”)。关键是对于这两种情况,这些都是相同的操作
if 语句,这样我需要写两次代码。另一种解决方案是检查 av2
是否出现在使用位置
会产生一些开销的代码,因为这种检查会非常(非常)频繁地进行。
我想知道是否有更聪明的方法来解决这样的问题。首先,人们可能会想到使用临时变量
complex, :: phi_tmp(:)
if(present(av2)) then
phi_tmp = av2
else
phi_tmp = av
end if
tmat = "function"(av,phi_tmp)
在使用可选参数时经常这样做。但这会复制数据,在我的例子中这是一个非常大的数组。 因此,我在考虑使用指针
complex,intent(in),target :: av(:)
complex,intent(in),optional,target :: av2(:)
complex,pointer :: phi_tmp(:)
if(present(av2)) then
phi_tmp => av2
else
phi_tmp => av
end if
tmat = "function"(av,phi_tmp)
但这需要 av
和 av2
的 TARGET
属性。在这里我不确定这是否会导致性能下降,因为编译器
不能再假设 av
和 av2
在其优化过程中没有别名,即使这里都有 INTENT(IN)
属性
这样就不会出现混叠问题。此外,如果调用例程时输入中的参数确实是什么意思
没有 TARGET
属性? (这编译和工作!)
有没有人对这些问题有一些经验? 有"standard"解决方案吗? (我找不到一个) 最终什么是最好的解决方案?
一种方法是对存在和不存在的情况使用不同的子程序。
subroutine compute1(tmat,av)
implicit none
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
call compute2(tmat, av, av) ! Ensure there is an explicit interface for compute2 here
end subroutine
subroutine compute2(tmat,av,av2)
implicit none
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
complex,intent(in) :: av2(:)
tmat = "function"(av,av2)
end subroutine
两者都没有可选参数。
这可以通过使 compute
成为这两者的通用来添加。
当然,这不会在所有情况下都有效,但是这里 av
上的 intent(in)
属性和 compute2
上的 av2
我们不必担心别名。
我建议的是你最后一个用指针的解决方案,如果实参没有目标属性就没有问题,指针在例程退出时会变成未定义的,但只要你不传递它回到无关紧要的调用过程。
您可以使用其他子例程(例如内部子例程)来执行实际计算,该例程不会知道它的参数是别名的,基本上,如果它们都具有 intent(in)
属性,这样就好了。所以不会有性能损失。
subroutine compute(tmat, av, av2)
implicit none
complex, intent(out) :: tmat(:)
complex,intent(in),target :: av(:)
complex,intent(in),optional,target :: av2(:)
complex,pointer :: phi_tmp(:)
if(present(av2)) then
phi_tmp => av2
else
phi_tmp => av
end if
call compute_internal(tmat, av, phi_tmp)
contains
subroutine compute_internal(tmat, av, av2)
complex,intent(out) :: tmat(:)
complex,intent(in) :: av(:)
complex,intent(in) :: av2(:)
.....
end subroutine
end subroutine