0

我想在 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 脚本,但您还有其他建议吗?)
4

2 回答 2

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 代码的不可读性(和不可维护性等)是有限度的。

于 2012-07-04T12:35:54.660 回答
0

如果有人读到这个:我选择了下面的解决方案。没有那么优雅、可扩展或可重用,但它完成了工作,让我可以使用没有扩展的“标准”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)
于 2012-07-07T12:37:07.193 回答