0

Fortran 90 で柔軟な (コンパイル時に定義された) ストレージ順序を取得したいと考えています。このために、いくつかのブースト pp ヘッダーを含む C++ プリプロセッサを使用しようとしています。

したがって、たとえば、次のように 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 に答える