如何为假定的形状数组

时间:2015-09-15 09:50:24

标签: fortran optional

使用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)

但这需要TARGETav的{​​{1}}属性。在这里,我不确定这是否会导致自编译器以来性能下降 不能再假设av2av在其优化过程中没有别名,即使这两个都具有av2属性 这样就不会出现混叠问题。此外,如果在调用例程时输入中的参数有效,这意味着什么 没有INTENT(IN)属性? (这个编译并且有效!)

有没有人对这些问题有一些经验? 有“标准”解决方案吗? (我找不到一个) 什么是最好的解决方案?

2 个答案:

答案 0 :(得分:4)

一种方法是对当前和不存在的情况使用不同的子例程。

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成为这两者的通用。

当然,这并不适用于所有情况,但是intent(in) avav2中的compute2属性我们不必担心混叠。

答案 1 :(得分:2)

我建议使用指针的最后一个解决方案,如果实际参数没有target属性就没有问题,指针在例程的退出处将变为未定义,但只要你不将它传递给调用程序无关紧要。

您可以使用其他子例程(例如,内部例程)来执行实际计算,该例程不会知道其参数是别名的,并且基本上,如果它们都具有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