【问题标题】:Compile-time defined storage order in Fortran using C++ preprocessor使用 C++ 预处理器在 Fortran 中编译时定义的存储顺序
【发布时间】:2012-07-04 10:28:41
【问题描述】:

我想在 Fortran 90 中获得一个灵活的(编译时间定义的)存储顺序。为此,我尝试使用 C++ 预处理器,包括一些 boost pp 头文件。

因此,例如,不要像这样访问 3D 数组:

myArray(k,i,j)

我想要这个:

myArray(POINT3D(i,j,k))

并在编译时确定访问顺序。

现在我已经尝试过:

#include "boost_pp_cat.hpp"
#include "boost_pp_comma.hpp"

! ------ Define storage orders here --------- !
!Forward lookup {i,j,k} <- {1,2,3}
#define KIJ_ORDER_ARG1 k
#define KIJ_ORDER_ARG2 i
#define KIJ_ORDER_ARG3 j

! ------ Switch between storage orders ------ !
#define CURR_ORDER KIJ_ORDER

! ------ Generate all required macros ------- !
#define STOR_ORDER_ARG(storOrder, argNum) BOOST_PP_CAT(BOOST_PP_CAT(storOrder, _ARG), argNum)

#define CHOOSE_PARAM(storOrder, argNum) BOOST_PP_CAT(STOR_ORDER_ARG(storOrder, argNum), Param)

#define POINT3D(iParam, jParam, kParam) POINT3D_WITH_STORORDER(CURR_ORDER, iParam, jParam, kParam)

#define POINT3D_WITH_STORORDER(storOrder, iParam, jParam, kParam)     POINT3D_WITH_STORORDER_PRE(storOrder) 
#define POINT3D_WITH_STORORDER_PRE(storOrder) CHOOSE_PARAM(storOrder, 1), CHOOSE_PARAM(storOrder, 2), CHOOSE_PARAM(storOrder, 3)

这将扩大

myArray(POINT3D(i,j,k))

myArray(kParam, iParam, jParam)

.

快到了!现在我的问题:

  1. 是否可以使用 C 预处理器做我想做的事?
  2. 如果不是 - 您会使用什么技术? (我正在考虑制作自己的专用“预处理器”python 脚本,但您还有其他建议吗?)

【问题讨论】:

    标签: boost fortran c-preprocessor


    【解决方案1】:

    1:我不知道,但我个人不会依赖预处理器来进行这种操作。

    2:我会按照这些思路编写一个 Fortran 定义的类型

       type odd_storage_order_real_array
            integer, dimension(3) :: permutation
            real, dimension(:,:,:), allocatable :: elements
          contains
            procedure :: get_element_at
        end type odd_storage_order_real_array
    

    然后您可以编写诸如

    之类的语句
    type(odd_storage_order_real_array) :: an_array
    .
    .
    .
    an_array%get_element_at(1,2,3)
    

    获取指定位置的元素。您会注意到我没有为您编写 get_element_at 函数,但您的问题向我表明您自己编写它不会有任何问题。当然,它会使用permutation 组件根据需要重新排序索引。您可能需要一个对应的 set_element_at 函数,以及用于在内置数组之间进行“类型转换”的函数。

    如果您想为任何等级的数组提供单一类型,请将它们展平,如下所示:

    type odd_storage_order_real_array
        integer, dimension(:), allocatable :: permutation
        real, dimension(:), allocatable :: elements
      contains
        procedure :: element_at
    end type odd_storage_order_real_array
    

    编辑

    回应 OP 的评论。我仍然不会使用预处理器。

    我认为在这种情况下我要做的是编写一个函数来将数组从其“自然”顺序转置(推广到尽可能多的维度)到所需的顺序,并编写该函数的逆.在初始化时应用函数,在完成时应用反函数;执行成本不应该很大。我不知道这是否适合您的应用程序模式。

    我真正要做的是尝试一些变体,看看哪一个给我带来了最佳的性能比:可编程性;换句话说,我将在搜索速度时制作 HPC 代码的不可读性(和不可维护性等)是有限度的。

    【讨论】:

    • 感谢您的回答。有一点我还没有提到:这应该是针对 HPC 任务的。如果编译器可以内联访问器并将其扩展为常量,则您的答案可能适用,否则会严重损害性能。那我得测试一下。
    【解决方案2】:

    如果有人读到这个:我选择了下面的解决方案。没有那么优雅、可扩展或可重用,但它完成了工作,让我可以使用没有扩展的“标准”fortran 预处理器(当您必须调试代码时,这是一个很大的优势,因为可以显示原始文件的行号)。

    ! ------ Define storage orders here --------- !
    #define IJK_ORDER 1
    #define KIJ_ORDER 2
    #define IKJ_ORDER 3
    ! ------ Switch between storage orders ------ !
    #ifdef GPU
      #define CURR_ORDER IJK_ORDER
    #else
      #define CURR_ORDER KIJ_ORDER
    #endif
    
    ! ------ Order dependent macros ------------- !
    #if (CURR_ORDER == KIJ_ORDER)
      #define AT(iParam, jParam, kParam) kParam, iParam, jParam
    #elif (CURR_ORDER == IKJ_ORDER)
      #define AT(iParam, jParam, kParam) iParam, kParam, jParam
    #else
      #define AT(iParam, jParam, kParam) iParam, jParam, kParam
    #endif
    
    ! ------ general macros --------------------- !
    !note: this is just a rename. Same syntax can be used for domain definition and array access
    !-> give it two seperate names to make the intention of the code clearer
    #define DOM(iParam, jParam, kParam) AT(iParam, jParam, kParam)
    

    【讨论】:

      猜你喜欢
      • 2011-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多