geant4

はじめに

どうも日本の原子核の業界でGeant4の需要がそれなりにあるようだが、
最近fortran77と同じ感覚で話ているのをよく耳にして少しうんざりしている。
そもそもGeant4はシミュレータではなくてtoolkitである。
ここでは若者が人生を無駄にしないために有用な情報を公開していきたい。

それと、ここでupしているものの中には公式のexampleを流用してたり 北里大の講習会で公開されたsampleを流用してたりします。
(2012/9/14現在上記リンクをクリックしたらリンク切れになってました。 必要な方がいましたら連絡くれれば個人的にお渡しできるかもしれません。 一応KEKとかの著作権を宣言されているので不特定多数への再配布はできません。 beにkitasato_lecture_tumeawase.tar.gzと言う名前で置いてあるのでlocateとかで漁ってください。 知人への個別の配布もダメな場合は著作者の方、連絡ください。 俺が連絡取れって?すみません。)

何か問題がありましたら「ryukiあっとmailどっとnuclどっとapどっとtitechどっとacどっとjp」にメールください。
質問等は気分が向いたら答えるかもしれません。


あと、僕よりわかってる人がここの文書を徹底的に叩くとかは勘弁してください。

Geant4関連の雑感

とりあえず言いたいことをここに列挙する。

Geant4を解析PCでとりあえず遊ぶ

解析PCに入って、以下を実行するととりあえずGeant4で遊ぶことが出来る。
ただし、versionが修論と違ったり(4.9.6)デバッグしていないソースだったりします。
cd
mkdir g4work
emacs .bashrc # 追記する内容は以下をみてください
source .bashrc
cp -r /usr/local/share/Geant4-9.5.1/examples g4work/
cd g4work/example/basic/B1
make
~/g4work/bin/Linux-g++/exampleB1
.bashrcに追記する内容は、
# Geant4
export G4WORKDIR=$HOME/g4work
source /usr/local/share/Geant4-9.5.1/geant4make/geant4make.sh
export G4VRMLFILE_VIEWER=vrmlview
.bashrcを変更した後にsourceするのを忘れずに。


Geant4のinstall

基本的にここ を見てやった。

let's install

と、いきなりびっくり。なんか4.9.5からinstall方法が変わった様。あとあとトラブルになりそうだが知ったこっちゃない。
ということで今までとの違いで気がついたところを列挙。 過去にinstallしたことがある人なら特に難しいことはないかんじ。

今日は2012/8/10です。この時点の安定版(4.9.5.p01)を入れていきます(一部srcをいじった。installとは関係ないので下の方のエントリーに)。
data fileはcmakeが勝手にいれてくれたのでバージョンは調べてません。

グラフィックまわりはいつも問題になるけど、nvidia(gefore 210が載っている)のドライバーではいれてなくて、
どうも汎用のmesa?がyumのgroup installでX Software Developmentを入れた時点で入った感。
openGLのライブラリはこれでとりあえずいくことに。
visualization用のライブラリだが、Qtがかっこ良かったのでとりあえず、
# yum install qt-devel
しておいた。qt本体は既に入っていたっぽい。
X11のdevelは既に入っている。

cmakeに引数を渡すよりもccmakeを使った方が何か面白い。
ccmakeの中では設定がokならconfigureで先に進んで、最後までいくとgでgenerateできるみたい。
一番初めの設定画面は何も表示されないのでとりあえずcで先に進む。
cd
mkdir geant4
cd geant4
tar xzvf geant4.9.5.p01.tar.gz
mkdir geant4.9.5.p01-build
cd geant4.9.5.p01-build
ccmake /home/samurai/geant4/geant4.9.5.p01
defultから変更したoptionは、
CMAKE_BUILD_TYPE : (DEFAULT : Release) Debug
GEANT4_INSTALL_DATA : (DEFAULT : OFF) on
GEANT4_USE_QT (DEFAULT : OFF) on
GEANT4_USE_OPENGL_X11 (DEFAULT : OFF, Unix Only) on
GEANT4_USE_RAYTRACER_X11 on
GEANT4_INSTALL_EXAMPLES : (DEFAULT : OFF) on
ぐらい。
ReleaseではなくDebugにしたのは4.9.4からの移行とかで結局sourceのどこで落ちたか見たくなったから。
てか、やっぱsourceにちょこちょこバグあるし。
であとはmake, make installする。ちなみに8コアx3.6GHzをフルに使うと6m15sでコンパイルが終わった。
結局qtのライブラリ入れただけで他はなんにもerror出なかった。

環境変数等のsetup

各userのセットアップだが、.bashrcに
# Geant4
source /usr/local/bin/geant4.sh # cmake使う人用
source /usr/local/share/Geant4-9.5.1/geant4make/geant4make.sh # 今までのmakefileを使う人用
export G4VRMLFILE_VIEWER=vrmlview # どちらか好きな方
export G4VRMLFILE_VIEWER=view3dscene # どちらか好きな方
と書いとけば良い。1・2行目はcmakeを使うか今までのGNUmakefileを使うかで切り替えてください。
ちなみに、今までであればLD_LIBRARY_PATHに追加していたけど多分スクリプトの中で等価なことをやってくれてる。
G4WORKDIRはデフォルトはgeant4_workになっているけど、結局make fileの中で再定義するからどっちでもいいかと。

viewerについて

後々HepRepを入れる気もするが、とりあえずお手軽なのはvrml。
だけどいつまでもなぞのviewerであるvrmlviewを使うわけにもいかないので、ちょろちょろ探してみると、こんな 便利なサイトが。
vrmlで直接調べるよりも、3D一般のviewerに組み込まれているものを探すと吉みたい(firefox vrmlで検索したけど...)。
その中でLinux、standalone、free(srcが公開されていてコンパイル可と言う意味で)なものだと、 とりあえずview3dsceneが良さそう。
binaryだとどうせ後々困るので、コンパイルして入れる。
文章の通りやれば普通に入るが、一応メモを残しておく。
まずここの一つ目の項目の sources of view3dsceneと、 latest engine をダウンロードする。で、これらを同じディレクトリに展開する。
$HOME/geant4/castle_game_engine
$HOME/geant4/view3dscene
で、あとはview3dsceneのなかのcompile.shを実行して、成果物をインストールするだけ。
$ ./compile.sh
# cp tovrmlx3d view3dscene /usr/bin/
解析PCの場合だが、コンパイルするためにgeant4をインストールした時点から追加して入れたライブラリは、
# yum install fpc
# yum install gtk2-devel
# yum install gtkglext-devel
ちなみに、-lhoge-2.0がありませんと起こられたら、
yum provides */libhoge-2.0.so
とかで検索すると大体見つかる。searchはpackage名を検索するのでhitしない。
aptの場合はapt-fileを使えばよかった気がする。

実は先にvrmlviewを入れていたので一応そのログも残しておく(freewrlというのはyumでポコッと入ったので入れてみたけど使えない)。
vrmlviewは検索すると謎のbinaryが落ちている。
これを落として実行すると、
libstdc++-libc6.1-1.so.2: cannot open shared object file
と起こられるので、yum providesで"libstdc++-libc6"を検索してhitしたcompat-libstdc++-296をいれた。
# yum install compat-libstdc++-296
あとは無理やりこれに入っているlibstdc++-libc6.2-2.so.3にリンクをはる、
# ln -s libstdc++-libc6.2-2.so.3 libstdc++-libc6.1-1.so.2
ってしたけど、そもそもlibstdc++-libc6.2-2.so.3が違うファイルを参照してた...まぁいいや。

remoteアクセスだとやっぱり動作が微妙ちょっと工夫した。
geant4ではG4VRML2FileSceneHandler.ccをみると、G4VRMLFILE_VIEWERで指定したプログラムの第一引数にファイル名を渡しているだけみたい。
なので、例えばremoteでgeantを動かしている場合は生成されたvrmlファイルをlocalにコピーして、
localのviewerを立ち上げるような、そんなスクリプトを書いておくとうまく行く気がする。
例えばこんな感じ(環境依存が強いとかは知らない)。
#!/bin/bash
 
CLIENT_NAME=`echo $SSH_CONNECTION | awk '{print $1}' | xargs host | awk '{print $5}'`
TEMP_DIR=/tmp
VRML_VIEWER=view3dscene

scp $1 $CLIENT_NAME:$TEMP_DIR/
ssh $CLIENT_NAME -X "$VRML_VIEWER $TEMP_DIR/$1"
解析PCではこのスクリプトをremote-view3dsceneという名前で/usr/binに置いた。
パスワードを回避するために鍵認証にしておくと吉。
このスクリプトを使う場合はview3dsceneをlocalのpcにインストールしてね。
残念なことに、相互に直接sshでアクセスできる環境じゃないとないとこのスクリプトは使えない(奥の手?のnetcatを使えばどうにでもなるが...)

Qtを殺す

ということで普通に動いたんだが...なぜがGUIが立ち上がる。
....
どうもQtを有効にして、usersrcのmainの中でG4UIExecutiveをつかっていることが原因っぽい。
G4UIExecutiveは適当に使えるUIを提供してくれるが、今回はQtをいれたので優先順位からQtが立ち上がる。
が、、、Qtは無駄に重いので昔に戻したい。
そこでG4UIExecutiveではなくてG4UIterminal+G4UItcshを使うか、もしくはGNUmakefileに
CPPFLAGS += -UG4UI_USE_QT
と書いてQtを使えなくすることもできる。結果的にtcshが呼ばれるはず。

細かい使い方

ここを見てね。
というか、exampleを見るか、もしくは該当するクラスのsource, header file、さらにはsourceに対してgrepをかければかなりのことが分かる。
ROOT見たいにonlineのreferenceがまとまっているとうれしいんだけどなー。。。

有用なsrc

locate DirectAccess.cc
物質で定義されている断面積とかに直接アクセスする方法
locate MaxTimeCuts.cc
時間で制限をかける方法
locate MinEkineCuts.cc
エネルギーで制限をかける方法

単位 unit categoryとか

http://xilinayi.blogspot.jp/2011/10/table-of-units-in-geant4.html
ありがたや
#include "G4UnitsTable.hh"
G4UnitDefinition::PrintUnitsTable(); 
//print out the default units in unitsTable
../bin/Linux-g++/Hwater002 > h2o.txt
Here Hwater002 is the executable file, and the output will be kept in h20.txt.

Idle> /units/list
This UI command is used to show the units defined in Geant4.
だそうです。

global time(時間でcut)

我々はたかだか100 nsもsimulationすればあとはいらないが、この時間のカットをかけるのがどうもぱっとできない。
neutronは特別に時間でかけることが想定されていて、カットしやすいが(QGSP_BIC.ccなどでG4NeutronTrackingCut::SetTimeLimitが使われている)他はなんとも。
でどうもexamples/advanced/underground_physicsでは時間のカットを手動で入れている。
で、これをどうやってQGSP_BICに潜り込ませるかだが、
結局物理クラスというのは
必ずG4VUserPhysicsListを継承していて、ConstructParticle()とConstructProcess()の実装が要求される。
で、QGSP_BICとかパッケージ化されている物理クラスはG4VModularPhysicsListを継承していて一見なんのこっちゃと思うが、
G4VModularPhysicsListは普通にG4VUserPhysicsListを継承している。
で、なんでG4VModularPhysicsListをはさんでいるかというと、まさにANAROOTのEncと同じで、物理のconstructの仮定を登録しておいて、まとめて
constructするためのまさにmodularクラスとなっている。
で、時間のカットを紛れ込ませたいが、DMXPhysicsList.cc(underground_physicsの中の一つのファイル)では、AddTransportationの中で親のAddTransportationを呼んだあとに、
カットをかけている。
で、QGSP_BIC_HPではAddTransportationを別段実装していないけど、親のG4VModularPhysicsListのConostructProcessのなかで親のAddTransportationを呼んでいる。
ていうか、AddTransportationと名前はついているが、実際は単に物理をまとめただけで、特別な意味はないっぽい。
ということで、DMXPhysicsListと同じようにQGSP_BIC_HPの中で実装してしまおう。。。とおもったが、G4VModularPhysicsListは子のAddTransportationを呼んでくれるわけではない。
かと言って、G4VModularPhysicsListのConstructProcessをオーバーロードしても、デフォルトのAddTransportation(多分ジオメトリを抜けたらとかそんなのが書いてあるんだと思うが..)
と他の物理クラスの間に入れることが出来ない。
ならばmodule化してこれを他の物理クラスと同じようにRegisterPhysicsしてしまえばいいではないか。
registerするのはG4VPhysicsConstructorなのでこれをみると、んー、というかんじ。
だがしかし、G4HadronElasticPhysics.hhを見てみれば、なんのことはない、ちょろちょろっとかけばいいだけっぽい。
ということで、G4HadronElasticPhysicsをパクってNeutronDetectoryPhysicsをつくってRegisterPhysicsし、
Physicsの中身はAddTransportationと同じにした。
また、DMXSpecialCutsというのは標準で存在するSpecialCutsとおなじなので、MaxTimeCutsとかはこれを継承した。

AddDiscreteProcessで登録するが、この中で先に登録した条件の方がさきに判定される??と信じたい。

ちなみにSetCutsWithDefaultではProductionCutしか定義していないように見える。
これも下は1keV?, 1mm?とものすごく小さいが、とりあえず無視。

一応これで動いたが、1.5倍ぐらいしか早くならなかった。
つまり、そもそものNEBULAを計算するのが大変みたい....そんなものかなー。。。

PhysListのHPのcrosssection

なぜかQGSP_BIC_HPのcrosssectionを見ようとすると落ちる。
HPを取ると問題ないのでHPが関わっているみたい。
そこで、gdbでバックトレースしたくなったので、cmakeのoptionの
CMAKE_BUILD_TYPE : (DEFAULT : Release) Debug
と変更。
これでとりあえずgdbでbtできるようになった。
で、gdbに以下を入れろといわれるので(改行は僕が入れた)、geant4の関数はこれ入れなくてもdebugできるけどとりあえずいれる。
debuginfo-install expat-2.0.1-11.fc15.i686 fontconfig-2.8.0-3.fc15.i686 freetype-2.4.4-7.fc15.i686 glib2-2.28.8-1.fc15.i686 keyutils-libs-1.2-7.fc15.i686
krb5-libs-1.9.3-1.fc15.i686 libICE-1.0.6-3.fc15.i686 libSM-1.2.0-2.fc15.i686 libXcursor-1.1.11-3.fc15.i686 libXdamage-1.1.3-2.fc15.i686 libXfixes-5.0-1.fc15.i686
libXi-1.4.3-3.fc15.i686 libXinerama-1.1.1-2.fc15.i686 libXmu-1.1.0-2.fc15.i686 libXrandr-1.3.1-2.fc15.i686 libXrender-0.9.6-2.fc15.i686 libXt-1.1.0-1.fc15.i686
libXxf86vm-1.1.1-2.fc15.i686 libcom_err-1.41.14-2.fc15.i686 libdrm-2.4.26-2.fc15.i686 libpng-1.2.48-1.fc15.i686 libselinux-2.0.99-4.fc15.i686 libuuid-2.19.1-1.4.fc15.i686
mesa-libGL-7.11.2-1.fc15.i686 mesa-libGLU-7.11.2-1.fc15.i686 openssl-1.0.0g-1.fc15.i686 qt-4.7.4-10.fc15.i686 qt-x11-4.7.4-10.fc15.i686 zlib-1.2.5-6.fc15.i686
結局、この問題はGetElasticCrossSectionPerAtomという関数の定義が微妙に変わって、materialを通じて温度を渡さないとHP(QGSP_BIC_HPのHPね)の場合は計算が落ちるみたい。


INCLXXでエネルギーを上げると落ちる件について

どうもA=1,Z=1、つまり水素との反応でinitUniverseRadiusが正常に計算できていない。
そこで行き当たりバッタリだが、エネルギーが低い場合は水素とのinelasticは無視できるので、
いっそのことまるごと無視してしまう。
これは、INCL::prepareReactionの中のinitUniverseRadiusが呼ばれる前に
if(A==1 && Z==1) return false;

と書いておけばとりあえずは回避できる。
これで正しくシミュレーションできるかは知らない。
まぁきっと大体あってるだろう。

たぶんn,p elasticしたときにneutronの速度が更新されていない

4.9.5でも4.9.6でも確認された。bug report済み(problem 1451)
以下はその手直しのログ。

物理過程はQGSP_BERTとかQGSP_BICとかでまとめてコンストラクトしてくれるので、きっとこれをたどればどこかに書いてあると考える。
まずはQGSP_BERT.ccを探す(locateとか)。だけどないのでQGSP_BERT.hhを探す。
QGSP_BERT.hhの中でQGSP_BERT.iccを呼んでいるので、ここに実体がかかれてる。
見てみると、G4HadronElasticPhysicsってのをnewしてるのでこれがelasticっぽいのでG4HadronElasticPhysics.ccを探す(.ccつけないといっぱいヒットするので)。
なんかいっぱい粒子があるけどneutronで検索すると、AddDiscreteProcessでG4WHadronElasticProcessをnewしてるのでこれっぽなーと考える。
G4WHadronElasticProcess.ccの中のPostStepDoItが物理過程の実体(menate_r.ccを読むとPostStepDoItが実体ということがわかりやすい)。
よんでると、aParticleChangeが入射した粒子で、散乱後の物理量はこれにセットする感じと読める。
ここで、aParticleChangeはenergy,momentum,velocityとsetできるけどPostStepDoItのなかでvelocityをセットしていないことがわかる。
aParticleChange(G4ParticleChangeクラス)の中身を見てみると、velocityをセットしなかったときはisVelocityChangedがfalseとなり、このときはvelocityがトラックのvelocityに付け替わるようになっている。
だけどこれでは前のstepのvelocityじゃね?!
ということで、そもそもPostStepDoItの中でaParticleChangeのvelocityを設定しなかったのがいけないのではないかと思う。
結論は、G4WHadronElasticProcess.ccのPostStepDoItの中の
  // primary change
  aParticleChange.ProposeEnergy(efinal);
の下に、
  {
    G4double mass = dynParticle->GetMass();
    G4double T = efinal/mass;
    G4double velocity = c_light*std::sqrt(T*(T+2.))/(T+1.0);
    aParticleChange.ProposeVelocity(velocity);
    // theTotalResult->ProposeVelocity(velocity); // for 4.9.6
  }
とでも書いておけばよい(geant4.9.5以前。geant4.9.6以降はaParticleChangeはなくなってtheTotalResult(ポインタ)になったのでそちらを使う)。
4.9.6ではG4WHadronElasticProcess.ccのほかにG4HadronElasticProcess.ccが使われているのでこっちも編集しないといけない。
isVelocityChangedフラグはProposeVelocityを呼んだ時点でtrueとなるので明示的に変更する必要はない。

ちなみに、反応後の情報はG4HadFinalStateから取ってくるみたいだが、ここにはvelocityの情報はない。
なので、上記の様に直にvelocity計算した。

もしかしたらG4ParticleChangeの方を書き換えるべきなのかもしれないけど、、、、まぁしらない。
hadronの時間情報がおかしくなるのもG4ParticleChange側の問題だったし、これもそっちを直すべきなのかなー...
G4ParticleChangeを直す場合は、
  if (!isVelocityChanged) theVelocityChange = pStep->GetTrack()->CalculateVelocity();
なので、
// G4Step* G4ParticleChange::UpdateStepForAlongStep(G4Step* pStep)
  if (!isVelocityChanged){
    const G4DynamicParticle*  pParticle = pStep->GetTrack()->GetDynamicParticle();
    G4double mass = pParticle->GetMass();
    G4double T = energy/mass;
    if(T > 0.0){
      theVelocityChange = c_light*std::sqrt(T*(T+2.))/(T+1.0);
    }else{
      theVelocityChange = 0;
    }
  }

// G4Step* G4ParticleChange::UpdateStepForPostStep(G4Step* pStep)
// G4Step* G4ParticleChange::UpdateStepForAtRest(G4Step* pStep)
  if (!isVelocityChanged){
    const G4DynamicParticle*  pParticle = pStep->GetTrack()->GetDynamicParticle();
    G4double mass = pParticle->GetMass();
    G4double T = theEnergyChange/mass;
    theVelocityChange = c_light*std::sqrt(T*(T+2.))/(T+1.0);
  }
とすればよいはず。
ただし、G4ParticleChangeはいろんなものから呼ばれており、これを編集すると何が起こるのかわからないので
いまのところは上記に示したようにG4HadronElasticProcess側を修正している。

neutronを打ち込むと、変なtimingのeventがいる件について

neutronをうちこむと、global timeがおかしなイベントがでてくる。
こちらにあるように、
http://bugzilla-geant4.kek.jp/show_bug.cgi?id=1305
hadron elasticの場合のみおかしくなるよう。
4.9.6では直っているようなので、とりあえずG4ParticleChange.ccを差し替えてみた。

two neutron

two neutronをシミュレーションするには、反応がどっちのneutronによって起きたかおきたか知りたくなる。
これがずっと分からなかったが、こちら、
http://geant4.slac.stanford.edu/Tips/
にのっていた。てか、普通に、
examples/extended/runAndEvent/RE01
にものっている。
でも、無駄に複雑になるので、簡単に済ませるなら、一発づつ撃ったあとにコンバインする方が早いと思われる。


compile error

GNUmakefileとかを使ってGeant4のuser srcをコンパイルしたときに、
touch: `/home/ryuki/g4work/save/neutrondetector1/tmp/Linux-g++/neutrondetectory/exe/obj.last' に touch できません: そのようなファイルやディレクトリはありません
とエラーが出た場合は、GNUmakefileの中のnameとmainがかかれているhoge.ccの
名前が異なっているからとか、そんな理由だった。
あるとき気づかないで微妙にmakefile内の名前が変わっていたらしく、あうあう。
http://ubuntuforums.org/showthread.php?t=1242533
によると、ディレクトリの名前も同じでないといけないらしい。
僕はリンクをはってるけど、これは問題ないみたい。

Physics list

physics listを使うと簡単にそれっぽいシミュレーションができる。
中性子なひとはQGSP_BIC_HPとかを使うとシミュレーションに一応なる。
で、なんかエレマグのオプションがあるみたいで、
http://geant4.cern.ch/geant4/collaboration/working_groups/electromagnetic/physlist9.5.shtml
ここを読むとgamma線検出器とかをやるならoption3をつけるといいかもしれない。
ピーターのコードはどうしてんのかなー。
Physics listの使い方はexampleにあるのでそれを見てください。

4.9.5で使えるG4PhysListFactoryのメモ

  G4String s[19] = {
    "CHIPS",
    "FTFP_BERT","FTFP_BERT_TRV","FTF_BIC",
    "LBE","LHEP","QBBC",
    "QGSC_BERT","QGSP","QGSP_BERT","QGSP_BERT_CHIPS","QGSP_BERT_HP",
    "QGSP_BIC","QGSP_BIC_HP",
    "QGSP_FTFP_BERT","QGS_BIC","QGSP_INCLXX","QGSP_INCL_ABLA",
    "Shielding"};

  G4String s1[6] = {"","_EMV","_EMX","_EMY","_LIV","_PEN"};



G4PhysListFactory

G4PhysListFactoryに物理の登録をまかせているが、 これをちょこっと追ってくと物理ライブラリの登録の実装が見える。 実は、QGSP_BIC_HPという名前をG4PhysListFactoryに投げるとそういう名前の クラスをつかって物理過程を登録しているだけだった。 で、CarbonのElasticのcross sectionがガタガタだったので、調べてみると、 03.06.2011からG4HadronElasticPhysics.ccという共通のElastic processの登録ルーチン を使っていて、その中で、
    //neutronProcess->AddDataSet(new G4BGGNucleonElasticXS(particle));
    neutronProcess->AddDataSet(new G4CHIPSElasticXS());
と、G4BGG...がコメントアウトされてCHIPSになっている。 で、G4BGGNucleonElasticXS.ccを見てみると、
    
void G4BGGNucleonElasticXS::CrossSectionDescription(std::ostream& outFile) const
{
  outFile << "The Barashenkov-Glauber-Gribov cross section handles elastic\n"
          << "scattering of protons and neutrons from nuclei using the\n"
          << "Barashenkov parameterization below 91 GeV and the Glauber-Gribov\n"
          << "parameterization above 91 GeV. n";
}
となんかいろいろ書いてある。 一方CHIPSの方は、
    
    outFile << "G4CHIPSElasticXS provides hadron-nuclear elastic scattering\n"
            << "cross sections for protons and neutrons with incident energies\n"
            << "between 19 MeV and X GeV.  These cross sections represent\n"
            << "parameterizations developed by M. Kossov. (more detail)\n";
と書いてある。
んー、これだけじゃなんとも分からんが、しかしcross sectionがガタガタだし、たぶんずれている。
ということで、srcを書き換えてみるとあら不思議、(n,p)が今度はだめになった。
てか、古いソースみると、普通にCHIPSを使っていた...
結局、
    //neutronProcess->AddDataSet(new G4BGGNucleonElasticXS(particle));
    //neutronProcess->AddDataSet(new G4CHIPSElasticXS());
    neutronProcess->AddDataSet(new G4NeutronElasticXS());
と書き換えてしまえば、精度の良いクロスセクションを使ってくれる。
だけど、srcを書き換えるのもあんまりで、いろいろ見ていたら、
QBBCというクラスはわりとまっとうみたい。
ただ、20MeV以下のneutronに対して精度をあげるHPをつけたものがない。
これも無理やりHP付きを作ってしまえばいい気もするが、
我々は別にレゾナンスがちゃんと再現されている必要もないので無視。
もしかしたらクロストークとかevapolationまわりの解析で効いてくるかもしれないど...


QGSP_BIC_HP
    
                                  Hadronic Processes for 
                                  -----------------------------------
          hadElastic  Models:                hElasticCHIPS: Emin(GeV)= 0.0195  Emax(GeV)= 100000
                                          NeutronHPElastic: Emin(GeV)=    0  Emax(GeV)= 0.02

          hadElastic  Crs sctns:        NeutronHPElasticXS: Emin(GeV)=    0  Emax(GeV)= 0.02
                                        G4NeutronElasticXS: Emin(GeV)=    0  Emax(GeV)= 100000
                                            GheishaElastic: Emin(GeV)=    0  Emax(GeV)= 100000

    NeutronInelastic  Models:                         QGSP: Emin(GeV)=   12  Emax(GeV)= 100000
                                      G4LENeutronInelastic: Emin(GeV)=  9.5  Emax(GeV)= 25
                                            Binary Cascade: Emin(GeV)= 0.0199  Emax(GeV)= 9.9
                                        NeutronHPInelastic: Emin(GeV)=    0  Emax(GeV)= 0.02

    NeutronInelastic  Crs sctns:      NeutronHPInelasticXS: Emin(GeV)=    0  Emax(GeV)= 0.02
                                      G4CrossSectionPairGG: Emin(GeV)=    0  Emax(GeV)= 100000
                         G4CrossSectionPairGG: Wellisch-Laidlaw cross sections 
                           below 91 GeV, Glauber-Gribov above 
                                          GheishaInelastic: Emin(GeV)=    0  Emax(GeV)= 100000

            nCapture  Models:                   G4LCapture: Emin(GeV)= 0.0199  Emax(GeV)= 20000
                                          NeutronHPCapture: Emin(GeV)=    0  Emax(GeV)= 0.02

            nCapture  Crs sctns:        NeutronHPCaptureXS: Emin(GeV)=    0  Emax(GeV)= 0.02
                                          GheishaCaptureXS: Emin(GeV)=    0  Emax(GeV)= 100000

            nFission  Models:                   G4LFission: Emin(GeV)= 0.0199  Emax(GeV)= 20000
                                          NeutronHPFission: Emin(GeV)=    0  Emax(GeV)= 0.02

            nFission  Crs sctns:        NeutronHPFissionXS: Emin(GeV)=    0  Emax(GeV)= 0.02
                                          GheishaFissionXS: Emin(GeV)=    0  Emax(GeV)= 100000
QBBCの物理
    
                                  Hadronic Processes for 
                                  -----------------------------------
          hadElastic  Models:                hElasticCHIPS: Emin(GeV)=    0  Emax(GeV)= 100000

          hadElastic  Crs sctns:        G4NeutronElasticXS: Emin(GeV)=    0  Emax(GeV)= 100000
                                            CHIPSElasticXS: Emin(GeV)=    0  Emax(GeV)= 100000
                                            GheishaElastic: Emin(GeV)=    0  Emax(GeV)= 100000

          hInelastic  Models:                         FTFP: Emin(GeV)=    3  Emax(GeV)= 100000
                                            BertiniCascade: Emin(GeV)=    1  Emax(GeV)= 12
                                            Binary Cascade: Emin(GeV)=    0  Emax(GeV)= 1.5

          hInelastic  Crs sctns:      G4NeutronInelasticXS: Emin(GeV)=    0  Emax(GeV)= 100000
                                          GheishaInelastic: Emin(GeV)=    0  Emax(GeV)= 100000

            nCapture  Models:                  nRadCapture: Emin(GeV)=    0  Emax(GeV)= 100000

            nCapture  Crs sctns:        G4NeutronCaptureXS: Emin(GeV)=    0  Emax(GeV)= 100000
                                          GheishaCaptureXS: Emin(GeV)=    0  Emax(GeV)= 100000
といういことで、これを見ていると、QGSP_BIC_HPとQBBCを合体したものを作りたくなる。。。
んー。

cross section

corss sectionはこんな感じで取ってこれる。
void CrossSection(G4String elementName, G4String particleName)
{
  const G4Element* elm = G4NistManager::Instance()->FindOrBuildElement(elementName);
  const G4ParticleDefinition* particle = G4ParticleTable::GetParticleTable()->FindParticle(particleName);

  if(!particle || !elm) {
    G4cout << "HistoManager WARNING Particle or element undefined" << G4endl;
    return;
  }

  G4cout << "### Fill Cross Sections for " << particleName << " of " << elementName << G4endl;

  G4HadronicProcessStore* store = G4HadronicProcessStore::Instance();

  G4double eu = G4UnitDefinition::GetValueOf(energyunit);
  G4double cu = G4UnitDefinition::GetValueOf(crosssectionunit);

  for(G4double e = emin; e < emax; e = e*estep){
    G4Material*  targetMaterial = G4NistManager::Instance()->FindOrBuildMaterial("G4_PLASTIC_SC_VINYLTOLUENE");

    G4double elastic = store->GetElasticCrossSectionPerAtom(particle,e,elm,targetMaterial);
    G4double inelastic = store->GetInelasticCrossSectionPerAtom(particle,e,elm,targetMaterial);
  }
}


G4UIsession

Qtを導入したら、
  //       使えるUIを適当に
  G4UIExecutive* ui = new G4UIExecutive(argc, argv);
  ui->SessionStart();
  delete ui;
て書くと勝手にQtが立ち上がった。 Qtはかっこいいけど重いので、元に戻したくなるが、uiは明示的にコンストラクトできて、
#include "G4UIterminal.hh"
#include "G4UItcsh.hh"
#include "G4UIQt.hh"
#include "G4Qt.hh"

  // command line
  G4VUIshell* shell= new G4UItcsh;
  G4UIsession* session = new G4UIterminal(shell);
  session->SessionStart();
  delete session;
  
  // Qt 
  G4UIsession session = new G4UIQt(argc, argv);
  session->SessionStart();
  delete session;
とすればよい。
他にも、G4UIExecutiveを使ったまま、
CPPFLAGS += -UG4UI_USE_QT
とMakefileに書いてQtを使わないようにすることもできる。
お好きなように。
G4UIExecutive.iccとかを見るとなんとなくわかる。


G4UIdirectory

既にあるディレクトリにどうやって追加しようか悩んでしまった。
何のことはない。new G4UIdirectoryとかまったく書かずに単に そのディレクトリを指定すればいいだけだった。
filenameCmd = new G4UIcmdWithAString("/run/filename",this);
みたいに。

visualize

Qt(キュートと読むらしい)でもVRMLでもどちらでもよいが、とにかくvisualizeするには、
/vis/open VRML2FILE # vrmlviewを使う場合
/vis/open OGLIQt # Qtを使う場合
/vis/drawVolume
/vis/scene/endOfEventAction accumulate 10
/vis/scene/add/trajectories
/vis/scene/add/hits
/run/beamOn 10
という感じのことをコマンドとして入力する。
VRMLでもQtでもどちらでも好きな方を使ってください。
詳しくはこちら

おそらくgeant4のガチバグ


DetectorConstructionできっちり物質をセットすると思うが、どうも物質の境界にビームを入射してしまうと
境界の出入りの計算が頻発してしまうのか、数千eventぐらいでuserの関数ではなく内部の関数で落ちてしまう。
detectorを1mmでもずらせばこの問題は起きない。
というか、境界に入射するとやたらと重くなることからも、この様な特異なことは苦手なようである。

DetectorMessenger

動作時にコマンドを与えてparticleとかジオメトリとか変更したくなる。
これは、特にいろんなジオメトリでアクセプタンス評価したいときとか特に。
で、これをやるにはいわゆるDetectorMessengerクラスを作る。
基本的にはexampleをパクるだけだが、前半に***::GetInstance->Clean()としている。
これはnewしたものを一旦削除していると思われるが、
SensitiveDetectorをDetectorConstructionで生成している場合、これを削除するコマンドが
どうも見つからない。
なんで、
if(!himeSD){
  G4SDManager* SDman = G4SDManager::GetSDMpointer();
  himeSD = new HimeSD("/HimeSD");
  SDman->AddNewDetector(himeSD);
}
logicTarget->SetSensitiveDetector(himeSD);

と、クラス内にSDのポインタを持っておいて、コンストラクタで=0としておけば、二回めに来たときにはnewされないので
誤爆しない。
こういうことをするために、わざわざポインタをクラス内に持っておくのだろうか。
とりあえず、これで/***/updateとかしても落ちなくなった。
例のごとくsampleはこちら(hime3b.tar)
MotheVolumeも使ってるし、そのコピーナンバーも拾ってたりする。

MotherVolume

mothervolumeという概念があって(孫、曾孫(ry)、
一塊まりのディテクターはとりあえず空のmothervolumeにぶち込むと、
あとはmothervolumeを配置したりコピーしたりするだけなので、便利。
というか、これをしないと大変。
で、そもそも普通に使ってれば、worldLVとかをmothervolumeとして使ってるんだけど、
それと同じように、LogicalVolumeをMotherVolumeとしたいLogicalVolumeの中に登録
してしまえばよい。ただそれだけ。
つまり、worldLVとしていたところを他のにするだけ。
これで検出器を動かすのも回すのも増やすのも簡単だー!!

以下にdata回収のエントリーがあるが、ROOTになれている人はROOTが楽

ROOTをデータ回収に使うとかなり楽。
beam情報、sdのdata、parameter、全てもroot fileに入れておけばそれ一つでsimulationのdataが完結する。
Geant4標準の回収方法を下に書いたけど複雑だしあまりおすすめしない。

data回収にapplication managerを使わない方法

北里大のgeant4のテキストではApplicationManagerなるものを使っている。
確かにこれはこれで便利だが、これしかわかってないと、geant4のsampleを読んでも意味が分からなくなってしまう。
http://www-jlc.kek.jp/~hoshina/geant4/Geant4Lecture2003/5-2a.html#3
ここを参考にした。
sampleソースで参考になるのはextend/analysis/A01とか。

つまり、
G4HCofThisEvent* HCE;
っていう箱が用意されている。これはEventごとの箱
これに、
class A01HadCalorimeterHit : public G4VHit という感じで継承したSDごとの箱をつめていく。
この箱の初期化とかはソースなり上記のサイトを参照。
で、集めていって、
void A01EventAction::EndOfEventAction(const G4Event* evt)
この中で処理する。
呼び方はextend/analysis/A01/src/A01EventAction.ccを参照
G4HCofThisEvent * HCE = evt->GetHCofThisEvent();
A01HadCalorimeterHitsCollection* HCHC = 0;
if(HCE)
{
HCHC = (A01HadCalorimeterHitsCollection*)(HCE->GetHC(HCHCID));
}
こんな感じ。

総Hit數等のEventをまたがるものは、
Geant内でやらずに、外部でやるべきとの思想。

data回収にapplication managerを使わない方法:データの処理

データの処理をするために、ディテクターの名前を登録して、それを取ってくるようにする。
これは、まぁ、A01を真似するだけなんだが、パッと見完全に複写したとおもっても、実行時にそんな名前の
SDはないと怒られることがある。
これは、main.cc(一番もとにあるsrc)のところで、initializeを呼ぶ前に、EventAtionとかを登録してしまうとそうなる。
SDはInitialize内で名前を付けてるので、先にInitializeして、そのあとEventActionとかRunActionを呼ばないといかん。
つまり、本質的にInitializeはDetectorconstructionとPhysicsを登録した後に先に呼ぶもので、
そのあとにEventAction,RunActionを登録する。PrimaryGeneratAtionもInitialize後に呼ぶべき。
Exampleだとそうなっているが、北里大のsrcではそうなっていないのではまった。

で、Application Managerを使わないソースのsample(hime2.tar)をアップする。
比較的シンプルなものにした。
回収しているデータは、copyNo., PV name, time, energy lossだけである。
上の内容を実際にソースに書くとこんな感じです。


回転思考編

回転がわかってきた。
普通に回転しようとして、PVPlacementの回転の項に回転行列rotationmatrixを渡すと、
自分を中心に自転する。
ちなみに、
G4RotationMatrix rm;
rm.rotateX(phi);
とかを一番目の引数に渡した場合。。
回転と位置を渡すPVPlacementのコンストラクタに渡す、
http://geant4.cern.ch/bin/SRM/G4GenDoc.exe.pl?flag=2&FileName=G4PVPlacement.hh&FileDir=source/geometry/volumes/include
場合は、newしたりしなかったり。
http://www-geant4.kek.jp/g4users/g4tut07/exercise-2.html
ここが詳しい。
で、G4Transform3D(rm, tv)
を渡す場合は、内部でコピーをつくるのでローカル変数でよいらしい。
あとは回転がpassiveかactiveの違いがあるらしい。俺は知らん。
ここまでで、とりあえず、
G4ThreeVector tv(x,y,z);
G4RotationMatrix rm;
G4double phi(60*deg);
tv.rotateZ(phi);
rm.rotateZ(phi);
G4PVPlacement(G4Transform3D(rm,tv),....);

とかで、z軸について回転できる。
これだと不便だけど何故か書いてくれてる文書が見つからない。
ということで.hhを見てみると、
void rotate(G4double, const G4ThreeVector &);
// Rotates around the axis specified by another G4ThreeVector.

というのがあるじゃないかと。
ということで、これを使ってみる。
これを使って、
tv.rotate(phi, axis);
rm.rotate(phi, axis);

とかで渡せば全体をある軸に対して回すことを可能じゃないかと。
っていうのは、うそだったー
これは世界の中心での軸の方向を決めるみたいだ。
ということで、物体を回転させるための中心だけまずずらして、
それから回転して、またもとに戻すということをしないといけないかと。
まぁ、これでできるからいいんだが。
G4ThreeVector ax(x,y,z);
tv -= ax;
tv.rotateZ(phi);
rm.rotateZ(phi);
tv += ax;

とか。
んー、自由な軸回りに回転できるのはいいんだが、
(これだと、平行な軸にしか回転できない。
自由な軸に対してはどうすればいいのか。。。。。
標準で実装してくれーーーーーーーーー)
物体をその軸の方向にalignしたい。
しかし、その関数がようわからん。
てか、ローテーションマトリックスってのがいまいちよくわからん。
三次元ベクトルを三つもってるみたい。

回転解決篇


(あとでわかったが、mothervolumeという概念(volumeの中にvolume)を使えば、こんなことはしなくても実現できる。)
sr/local/geant4/src/geant4/source/global/managemant/include/G4RotationMatrix.hh
sr/local/CLHEP/include/CLHEP/VectorThreeVector.h

G4double innerRadiusOfTheTube = 0.*cm;
G4double outerRadiusOfTheTube = 30.*cm;
G4double hightOfTheTube = 20.*cm;
G4double startAngleOfTheTube = 0.*deg;
G4double spanningAngleOfTheTube = 360.*deg;
G4Tubs* tracker_tube
  = new G4Tubs("tracker_tube",innerRadiusOfTheTube,
		 outerRadiusOfTheTube,hightOfTheTube,
		 startAngleOfTheTube,spanningAngleOfTheTube);
tracker_log = new G4LogicalVolume(tracker_tube,Al,"tracker_log",0,0,0);

G4double trackerPos_x = -3.0*m;
G4double trackerPos_y = 0.*m;
G4double trackerPos_z = 0.*m;
G4ThreeVector tv(trackerPos_x,trackerPos_y,trackerPos_z);//new しなくてよい

G4double shiftPos_x = 3.0*m;
G4double shiftPos_y = 3.0*m;
G4double shiftPos_z = 3.0*m;
G4ThreeVector sh(shiftPos_x,shiftPos_y,shiftPos_z);//new しなくてよい

G4double phi = 60.0*deg;

G4double zaxis_x = 0.0*m;
G4double zaxis_y = 0.0*m;
G4double zaxis_z = 1.0*m;
G4ThreeVector zaxis(zaxis_x, zaxis_y, zaxis_z);  
zaxis = zaxis.unit();

G4double rotateaxis_x = 1.0*m;
G4double rotateaxis_y = 1.0*m;
G4double rotateaxis_z = 1.0*m;
G4ThreeVector rotateaxis(rotateaxis_x, rotateaxis_y, rotateaxis_z);
rotateaxis = rotateaxis.unit();

G4RotationMatrix rm;//new しなくてよい  
rm.rotate(zaxis.angle(rotateaxis), zaxis.cross(rotateaxis));
//  G4cout << rm.rep3x3() << G4endl;

for(int i = 0; i < 6 ; ++i){
  tracker_phys
    = new G4PVPlacement(G4Transform3D(rm,tv),
                        tracker_log, "tracker_P",
                        experimentalHall_log,false,i);
  tv -= sh;
  tv.rotate(phi, rotateaxis);
  rm.rotate(phi, rotateaxis);
  tv += sh;
}
記号は気持ちで。
これで任意のz軸を定めて、それを任意の軸の方向にアラインして、
その軸の回りに回転できる。
単なる幾何学なので、G4ThreeVectorとかG4RotationMtrixに
実装された関数を呼べば大体のことはできる。
上の例は、順次detectorを設置していった。

物質の定義を標準の実装から持ってくる方法

http://geant4.web.cern.ch/geant4/G4UsersDocuments/UsersGuides/ForApplicationDeveloper/html/Detector/material.html
これは最終的な方法としては適切ではないが、テストにはバグを減らせるのでよいと思う。
	    #include "G4NistManager.hh"
	    //  targetMaterial = G4NistManager::Instance()->FindOrBuildMaterial("G4_Al");
			     targetMaterial = G4NistManager::Instance()->FindOrBuildMaterial("G4_PLASTIC_SC_VINYLTOLUENE");
			     worldMaterial = G4NistManager::Instance()->FindOrBuildMaterial("G4_Galactic");
	      

て感じ
new G4Materialするごとになんか勝手に登録されてるっぽい。
とりあえず、
	    G4cout << *(G4Material::GetMaterialTable()) << G4end;
							   
してみると、ただしそう。
ということで、まずはこのテーブルから引っ張ってくるか。


北里大のソースのバグ?


G4MultipleScattering.hh
http://hypernews.slac.stanford.edu/HyperNews/geant4/get/installconfig/1352/1.html
新しいバージョンでは使わないようになった。
代わりに、
G4eMultipleScattering.hh e- e+
G4hMultipleScattering.hh any charged particle
G4MuMultipleScattering.hh muon
と、それぞれで関数があるみたい。

パスの通し方によっては、
GNUmakefile
G4WORKDIR = .
ていうのを、
G4WORKDIR =$(shell pwd)
にしないとだめかも。

new

newするかしないかは、
newした場合は勝手に消されることはない。
単にobjとして生成すると、そのスコープを抜けたときに捨てられる。
で、引数として、ポインタを要求しているものはおそらく内部でコピーしないので、
newして渡さないと消滅してしまう。
逆に、参照でもらっているものはおそらく内部でコピーをつくっているのでnewしなくてよい。
deleteしなければならないことを考えると、これらは明確に使い分けたほうが良い気が。
もっとも、newして渡したものはいつ消えるのかなぞだけど。
まぁ、ディテクターは消える必要ないからいいか。

で、newで作ったのをdeleteするしない問題はGeant4内でよく起こる。
これはGeant4の良くないところだと思うが、よく調べて使うしかない。