Cactusを使った,オリジナルな数値計算コードの作成手順
2002/10/31 update
2002/10/29 update
Cactusコードには,(全部英文だが)100ページ以上に及ぶマニュアルが添付されている. ここでは,それを翻訳する気はないが,初心者の視点から,コメントを補足しておく.
Cactusコードの紹介(ダウンロード方法・テストコンパイルと実行方法)は,別のページを参考のこと.
Contentsとりあえずここまで.
- まず知っておくこと
- 必要最小限なthornは何か
- make newthornとcclファイル
- プログラミングの実際(0)異なるthorn間のaccess level
- プログラミングの実際(1)CCTK_ARGUMENTS
- プログラミングの実際(2)グリッドを支配する量
- プログラミングの実際(3)他のthornのsubroutineをcallする
- プログラミングの実際(4)他のthornのmoduleを使う
- まず知っておくこと
- Cactusディレクトリで,make UsersGuideとすると,マニュアルが自動生成 される(LaTeX, dvipsなどがインストールされていることが必要).make helpとすると, makeの他のoptionが表示される.
- Cactusでは,プログラムのグループをthornと呼び, さらにそのグループをarrangementと呼ぶ. 例えば Cactus/arrangements の下には,CactusBaseというarrangementがあり,その下にはCartGrid3Dというthornがある. 実際のプログラムは,例えば,CartGrid3D/srcの下にある. thornやarrangementsを超えて,相互にプログラムをcallして使うことが可能である.
- Cactusコードは,自らがサポートする機能をCCTK (Cactus Code Toolkit)と呼ぶ.
- プログラム全体を流れる3次元行列 A(i,j,k) のことを,GridFunctionと呼ぶ. Cactusの定義に従って,GridFunctionを定義しておけば,それらは並列プログラミングに おいて,syncronizeやdata共有が,CCTK_Functionsを用いて簡単に可能となる.データの 取り出しにもMPIを意識する必要がない.
- 各自のプログラムはCで書いてもFortranで書いても良い.混在していても良い. srcディレクトリの中のmake.code.defnの ファイルに,プログラムをxxx.cあるいはxxx.fあるいはxxx.F90と登録するだけで,コンパイルは自動 に行われる.以下の説明は,Fortran90を例に挙げているが,Cの場合,argumentsの呼び方が若干 異なるので注意.
- 必要最小限なthornは何か
CVSでダウンロードすると, Cactus/arrangementsの中にいろいろ存在するが,本当に 残しておかなければならない便利なthornは,次のもの.
# arrangement/thorn # implements (inherits) [friend] {shares} # CactusBase/Boundary # boundary (grid) [ ] { } CactusBase/CartGrid3D # grid ( ) [ ] {driver} CactusBase/IOASCII # IOASCII (IO,hyperslab) [ ] {IO} CactusBase/IOBasic # IOBasic (IO) [ ] {IO} CactusBase/IOUtil # IO ( ) [ ] { } CactusBase/Time # time ( ) [ ] { } CactusPUGH/PUGH # driver (Cactus) [ ] {cactus} CactusPUGH/PUGHReduce # reduce (driver) [ ] { } CactusPUGH/PUGHSlab # Hyperslab (Driver) [ ] { }これらは,座標を張るGridFunctionを定義したり,時間発展に必要な基本量を定義していたりする.
- make newthornとcclファイル
- 新しいプログラムを作ろうとするときの第一歩は,Cactusディレクトリの下で
make newthornとすることである.thornの名前を何にするか,どこのarrangementに所属するthornにするかを 聞かれる.この名前は自由である. arrangementsを超えて,相互にプログラムを使うことが可能であるので,自分で解りやすいものに しておけばよい.ここでは,arrangements名 = GR thorn名 = GRmainとしておこう.- make newthornで,自動的に作られるファイルが,いくつかある.まず重要なのは次の3つ.
GR/GRmain/interface.ccl GR/GRmain/param.ccl GR/GRmain/schedule.cclである.CCLとは,Cactus Configulation Languageの頭文字だそうだ. これらのファイルの役割を簡単に説明しておく.
- interface.ccl
このファイルの役割は次の3つ.このthornが,必ず必要とするthornをinheritsとして登録しておくと, これらがコンパイル時に欠けているとコンパイルエラーとして警告することが可能になる. GridFunctionは,ここで定義しても,actibate(storage/allocate)させない限り, それらはsize (1,1,1)として 登録されているだけなので,メモリを無駄に消費することはない. ここで定義されたGridFunctionは,inherits/friendsで定義された他のthornのGridFunctionと共に, 後に各プログラムで,自動的にsubroutine間の 引き渡し変数(CCTK_ARUGUMENTS)として定義されることになる.
- thornを代表させる名前(implements: xxx)の登録.この名前が将来にわたって, GridFunctionのsynchronizationや,パラメータファイルでの記述に関わってくる.thornの名前と 同じでも良いし,違っても良い.
- 他のどのthornと共通にgrid functionを共有するかの登録 (inherits: boundary Grid xxx , friend: xxx) これらのアクセスレベルに関しては,下記に補足あり.
- 利用する GridFunction xxx(i,j,k)の定義.
- param.ccl
このthornで使うパラメータを定義する.新たに定義しても良いし,他のthornで定義されたパラメータを 拡張定義してもよい.ここで定義されたパラメータは,後に各プログラムで,自動的にCCTK_PARAMETERS として(moduleとして) 定義されることになる.- schedule.ccl
grid functionをいつactibate(storage/allocate)させるか,の定義を行う.これらは,パラメータで on/off してもよいし,どのsubroutineを呼ぶときにon/offするか,として設定しても良い. また,このファイルには, GR/GRmain/src/内の個々のsubroutineを,実行時にいつ呼び出すかを記入する. 「いつ」かは,Cactus内ですでに決められていて,CCTK_STARTUP CCTK_PARAMCHECK CCTK_BASEGRID CCTK_INITIAL CCTK_PRESTEP CCTK_EVOL CCTK_POSTSTEP CCTK_ANALYSISなどの「時刻」があらかじめ設定されている.かならずしもすべてのsubroutineについて,この 設定をする必要はなく,あるsubroutineが他をcallすれば,それで済む.Cactusの思想としては, 一つのthornは,上記の「時刻」の「どこかひとつ」に属すること,というのが原則である. この原則を守れば,引き渡し変数(arguments)の不一致でbus errorが発生することが防げるが, 必ずしもこの原則を守る必要もない.- make newthornで自動的に作られるディレクトリは,
GR/GRmain/src GR/GRmain/par GR/GRmain/doc GR/GRmain/testの4つである.srcの下にはプログラムを収納,parはパラメータファイルのサンプルを作って 入れて置くところ.docは,マニュアルを入れておく所, testは,計算結果のサンプルデータを入れるところ.testにデータを入れておくと, 後にdebugするときに,以前と同じ結果を完全に再現するかどうかのcheckを簡単に行うことが できるが,必ずしも必要ではない.
- プログラミングの実際(0)異なるthorn間のaccess level
thorn間で,変数(GridFunctions)やパラメータを共有する場合には,次のaccess levelの違いが ある.
thorn A 内の interface.ccl で定義された,次のレベルのGridFunctionについて説明する.
public: CCTK_REAL geometry type=gf { gxx gxy gxz gyy gyz gzz } "metric" protected: CCTK_REAL energy type=gf { energy momentumx } "energy term" private: CCTK_REAL stock type=gf { stock1 stock2 stock3 } "temporal stock"public登録されたものは,他のthorn Bで,thorn A がinherit指定されていれば,自動的にそのthorn B内でも 共通にデータを持ったまま利用できる.
protected登録されたものは,他のthorn Cで,thorn A がfriend指定されていれば,thorn C内でも有効である. 他のthorn Dでもfriend指定されていれば,thorn D内でも有効である.
private登録されたものは,他のthornでは,利用できない.同様,thorn A 内の param.ccl で定義された,次のレベルのパラメータについて説明する.
Global: Restricted: Private:Global登録されたものは,すべてのthornで有効になる.Restricted登録されたものは,他のthorn Bのparam.cclで shares: thornA とthorn Aを指定した後にそのパラメータが再宣言(あるいは拡張定義)されていれば, thorn Bでも有効である. private登録されたものは,他のthornでは,利用できない.
- プログラミングの実際(1)CCTK_ARGUMENTS
プログラムをコンパイルするときには,CPP(C PreProcessor)が使われる.つまり,実際の ソースコードは,まずいったんCactusが所有するargumentを使って,書き直される.
例えば,典型的なFortran90コードのファイルの始まりは次のようになる.
!----------------------------------------------------------------------- #include "cctk.h" #include "cctk_Arguments.h" #include "cctk_DefineThorn.h" #include "cctk_Parameters.h" subroutine gr_initial (CCTK_ARGUMENTS) implicit none DECLARE_CCTK_ARGUMENTS DECLARE_CCTK_PARAMETERS DECLARE_CCTK_FUNCTIONS CCTK_REAL one,zero integer i,j,k one =1.0d0 zero=0.0d0 !-----------------------------------------------------------------------
- はじめの4行は,CPPを行う時に必要となる呪文である.これらのmacroの始めの2つは必須である.
- subroutine名の後のargumentにある,CCTK_ARGUMENTSは,CPP実行時に, そのthorn内で定義されているgrid functionを自動的に書き出す.
- DECLARE_CCTK_ARGUMENTSは,上記のCCTK_ARGUMENTS内の変数定義文に 自動的に置き換わる.
- DECLARE_CCTK_PARAMETERSは,そのthorn内で定義されているparameterを commonブロックとして 自動的に置き換わる.
- DECLARE_CCTK_FUNCTIONSは,もし,そのsubroutine内で,Cactusが定義する functionを使う場合に必要となる.
- CCTK_REAL は,コンパイル時に,そのマシンが好む実数設定(REAL*8 など)に 書き換わる.
理解するには, 実際に翻訳されたファイルを見て比べるのが,解りやすいと思う.
例えばCactusWaveのセットを使ってコンパイルをしたとする. configuration名がwaveFだったとしよう.CPP後の実際のファイルは,Cactus/configs/waveF/buildの下に thorn別に収納されており,xxx.f90という名前のファイルがそれに該当する.
CCTK_ARGUMENTSに関する補足
実際にどこで,CCTK_ARGUMENTSが定義されているのかを探し回った所,次のようだった. thornの名前が ADMだったとする.
Cactus/config/config-name/bindings/include/cctk_Arguments.hのファイルに書かれている通り,#define CCTK_FARGUMENTS ADM_FARGUMENTSと置き換えられており, これは,さらにCactus/config/config-name/bindings/include/ADM_arguments.hのファイルに書かれている通り,#define ADM_FARGUMENTS _CCTK_FARGUMENTS, ADM_PRIVATE_FARGUMENTS, ADM_PROTECTED_FARGUMENTS, ADM_PUBLIC_FARGUMENTSの要素からなる. 同様に DECLARE_CCTK_ARGUMENTS もDECLARE_ADM_FARGUMENTSに変換されているが,内訳は(ADM_arguments.h:)#define DECLARE_ADM_FARGUMENTS _DECLARE_CCTK_FARGUMENTS DECLARE_ADM_PRIVATE_FARGUMENTS DECLARE_ADM_PROTECTED_FARGUMENTS DECLARE_ADM_PUBLIC_FARGUMENTSである.この中に,_CCTK_FARGUMENTS というargumentが共通に流れていることがわかる. これについて次に補足する.
- プログラミングの実際(2)グリッドを支配する量
サブルーティン間に流れる引数(argument)には,_CCTK_FARGUMENTS というグループの量がある. この中には,Cactusが並列化を行うための引数が流れている.
例えば,次のようなプログラムの一部から想像されるように,dx,dy,dz,dtなどの基本量の他に localなprocessorそれぞれがもつ,計算グリッドの大きさ cctk_lsh(:) や,隣のprocessorとの overlapするグリッドの数 cctk_nghostzones(:) などがそうである.
!----------------------------------------------------------------------- DECLARE_CCTK_ARGUMENTS CCTK_REAL dx,dy,dz,dt integer i,j,k dx = CCTK_DELTA_SPACE(1) dy = CCTK_DELTA_SPACE(2) dz = CCTK_DELTA_SPACE(3) dt = CCTK_DELTA_TIME do k = 1+cctk_nghostzones(3), cctk_lsh(3)-cctk_nghostzones(3) do j = 1+cctk_nghostzones(2), cctk_lsh(2)-cctk_nghostzones(2) do i = 1+cctk_nghostzones(1), cctk_lsh(1)-cctk_nghostzones(1) alpha(i,j,k)=1.0 end do end do end do !-----------------------------------------------------------------------ちなみに,ユーザがパラメータファイルで指定するのは,全体のグリッド数であり, パラメータファイルで,例えば# parameters in CactusPUGH/PUGH driver::global_nx = 96 driver::global_ny = 96 driver::global_nz = 96と入力している部分である.この情報は, cctk_gsh(3) として流れている.並列計算を行う時に,どのprocessorが,どういう gridになるのかは,(デフォルトでは)自動設定である.そのgrid情報が,cctk_lsh(3) だった, というわけである.
- プログラミングの実際(3)他のthornのsubroutineをcallする
パラメータによって,他のthornのsubroutineをcallする場合がよく生じるかもしれない. しかし,利用者によっては,そのthornを含めてまでコンパイルする必要は無いかも知れない. そんな時は,CPPの特徴を活かして,次のように書く.
!----------------------------------------------------------------------- #include "cctk_DefineThorn.h" !----------------------------------------------------------------------- if (CCTK_EQUALS(lapse_condition, "maximal")) then #ifdef GR_LAPSEMAXIMAL call maximal_slice(CCTK_FARGUMENTS) #else call CCTK_WARN (0, "you need thorn GR-lapseMaximal.") #endif end if !-----------------------------------------------------------------------こうすれば,GR/lapseMaximalという名前のthornをThornListに入れないでコンパイルしても エラーになることはない.実行時にパラメータファイルで lapse_condition = "maximal" とすれば,警告文が出て途中で止まることになる.
- プログラミングの実際(4)他のthornのmoduleを使う
これは,ちょっと高級な技である.thorn_name/src 内のプログラムは,make.code.defn に,列記 することになるが,module部分があって,他のthornで定義されたmoduleを使う時には,コンパイル時に エラーにならないように,コンパイラーに依存性を前もって報告しておかないといけない.
そのためには,次の3つのファイルが必要である.例えば,thorn Riemannが,thorn GRmain の moduleをcallする場合を示す.
make.code.deps 中身は次のよう.これは,cut and pasteしておけばよい.
USESTHORNS = GRmain # Automatically create dependencies for Fortran modules and Fortran includes define F90_DEPENDENCIES $(F_DEPEND) $(INC_DIRS:%=-I%) $(EXTRA_DEFINES:%=-D%) -DFCODE $< $(F_DEPEND_OUT) $(DEPENDENCY_FIXER) dir=`pwd`; $(CPP) $(INC_DIRS:%=-I%) $(EXTRA_DEFINES:%=-D%) -DFCODE $< | $(PERL) $(SRCDIR)/depend.pl - $< $(basename $(notdir $<)).F90.o $(SRCDIR)/ ./ .F90 .F90.o $(USESTHORNS:%=$$dir/../%/) >> $@ || { rm $@; exit 1; } endefdepend.pl 中身は次のよう.これも,cut and pasteしておけばよい.
#!/usr/bin/perl -w # Create dependencies for Fortran 90 "use" and "include" statements $src = $ARGV[0]; $srcfile = $ARGV[1]; $dest = $ARGV[2]; $srcdir = $ARGV[3]; $moddir = $ARGV[4]; $srcsuffix = $ARGV[5]; $modsuffix = $ARGV[6]; @otherdirs = @ARGV[7..$#ARGV]; print "# $src¥n"; print "$dest:"; open (FILE, $src); while () { if (/^¥s*include¥s*['"]([^'"]+)['"]/i) { print " $srcdir$1"; } elsif (/^¥s*use¥s+(¥w+)/i) { $found = 0; if (! $found) { if (-e "$srcdir$1$srcsuffix") { $found = 1; print " $moddir$1$modsuffix"; } } if (! $found) { foreach $dir (@otherdirs) { if (-e "$dir$1$modsuffix") { $found = 1; print " $dir$1$modsuffix"; last; } } } if (! $found) { die "¥nWhile tracing depencencies:¥nFortran module $1 (referenced in file $srcfile) not found.¥nAborting.¥n¥n"; } } } close (FILE); print "¥n"; make.configuration.deps 中身は次のよう.一部に,自分の名前Riemannが登場していることに注目.
USESTHORNS = GRmain $(CCTK_LIBDIR)$(DIRSEP)libRiemann.a: $(USESTHORNS:%=$(CCTK_LIBDIR)$(DIRSEP)lib%.a)以上の3つのファイルを src 内に置いておけば,xxx.F90プログラムは,依存性をMakefileに 伝えていることになる.
本ページの,もう少しだけ詳しい解説は,2000年当時,PennState大学でのMayaコード開発時に, 私が書いたマニュアル(英語)にもある.Mayaコード自体は現在入手不能であるが,参考になるかも しれない.(ただし,上記の「プログラミングの実際(4)他のthornのmoduleを使う」に関する 記述は,上記の内容の方が新しい). [ps][tex]
Go back to the top page ofor
![]()
My current Email address is![]()