# PIConGPU
## 關於 PIC 軟體
PIC 的功能,是模擬一個空間中的粒子運動,並藉此計算出電場、磁場或是輻射
- 模擬的整個空間大小,稱為 **domain**
- 一個 domain 會被切成多個網格 (**grid**)
- PIC 做的事情就是計算每個網格中的粒子分布情況
- 每一次更新網格,叫做一個 step;一個 step 代表一小段物理時間(e.g., 10ns)
- 對於相同內容的模擬,每一個 step 做的運算是相同的
- 但根據國展老師的經驗,因為 domain 中的粒子總數可能會變化,所以有可能隨著模擬的 step 越多 (粒子總量越多),計算量越大
- **賽後經驗**: 也可能隨著模擬時間、粒子密度的分布也有所變化,導致不同方向所需的計算資源(GPU 數量)有變化
PIC 的軟體,通常是給一個基礎的運算框架
- 一些固定的物理常數 (光速、電荷...)
- 一些可調的實驗參數 (磁場、外加能量、邊界條件...)
- 一個固定的運算框架
- Grid 怎麼切
- 每個 step 做哪些事情
- 粒子間怎麼交互作用
粒子模擬中,大部分的參數都和物理相關,會影響到模擬結果的物理表現
- 進行的模擬內容相同的情況下,不論參數如何調整,所需運算量應該都相同
- 之前上課的教授說,這些物理面的參數就只是參與運算的一個數字,不影響效能 (可以想成 1000 * a 和 10000 * a 複雜度一樣)
- 會影響運算量的有
- 網格數量
- VSim: domain 大小/網格大小
- PIConGPU: grid_x * grid_y * grid_z
- step 數量 (影響總時間)
粒子模擬是個很複雜的應用,所以 PIC 軟體本身不會包含所有運算
- 只會提供通用的框架、以及必要的運算(基本物理的運算)
- 每個 user 要模擬的環境(外加電場/磁場、雷射源...)都不一樣,所以 PIC 軟體會讓 user 可以插入自己寫的運算模組
- VSim: user 可插入自己寫的 Python 檔案 (所以不需要重新編譯)
- PIConGPU: 用 C/C++ 寫,所以如果有運算內容相關的設定,就需要重新編譯
:::success
**PIConGPU 在這方面的設計**
- PIC 模擬,需要能讓 user 改動程式碼
- 所以 PIConGPU 不是直接 build 出來一個通用的軟體,然後吃不同的輸入檔案
- 做的模擬不一樣,跑的程式碼其實也不太像同 (只有大架構一樣)
- PIConGPU 提供方便 build 的工具 (底層還是 CMake),讓 user 改好東西後,用它的指令重新 build
- 有些要傳進去 Cmake 的參數會以環境變數的形式存在
- 操作上會和以往的軟體不太一樣,但其實做的事情是差不多的
- 所以讀文件時覺得怪怪的是正常的
:::
## 安裝
參考官方範例:
1. 先做這個 [PIConGPU - Install](https://github.com/ComputationalRadiationPhysics/picongpu/blob/dev/INSTALL.rst)
2. 再做這個: [PIConGPU - Usage](https://github.com/ComputationalRadiationPhysics/picongpu/blob/dev/USAGE.rst)
裡面有提到大量 dependency,建議全部啟用,才有辦法跑它執行的模擬範例
- 只有 ROCm 可省略,因為我們不是 AMD GPU/CPU
- ISAAC 也可以省略,確定本次競賽用不到
## 安裝必要工具
- git
```
sudo apt install git
```
- rsync
```
sudo apt install rsync
```
- 編譯器
```
sudo apt install build-essential gfortran
```
- Cmake (3.22.0+)
```
# For ubuntu22
sudo apt install cmake file cmake-curses-gui
```
- **注意**: Ubuntu20 上,用 apt 載到的 cmake 版本過舊,要用 snap 安裝
```
sudo snap install cmake --classic
```
## 準備 dependency
這邊的所有 dependency 可以選擇 build from source 或 apt 安裝,但是要注意 apt 上可能裝到過舊的版本
dependency 裝好還需要設定額外的**環境變數**,這些環境變數會在編譯 PIC 時用到
### MPI (2.3+)
- 對應 OpenMPI 版本須高於 1.7
- 注意: MPI 版本不等於 OpenMPI 版本或
- **建議**:
- 後面用到的 lib 也用到 MPI,但是使用到 MPI3.0 棄用的 API
- 這邊就準備 Openmpi 2.1.6 就可以了
- 建議使用的 MPI 要啟用 CUDA (GPU aware)
- **環境變數**
```
export MPI_ROOT=path/to/your/mpi
```
:::info
**建議**
- 可以順便 module load openmpi,這樣後面的套件,如果可以 MPI 優化的話,就會自動偵測到
:::
### Boost (1.74.0+)
- For Ubuntu22
```
sudo apt install libboost-program-options-dev libboost-atomic-dev
```
- For 20 (build from source)
```=
wget https://archives.boost.io/release/1.74.0/source/boost_1_74_0.tar.gz
tar xf boost_1_74_0.tar.gz
cd boost_1_74_0
./bootstrap.sh --with-libraries=atomic,program_options --prefix=<Install path>
./b2 cxxflags="-std=c++17" -j 8 && sudo ./b2 install
```
- **環境變數** (只有 build from source 需要)
```
export CMAKE_PREFIX_PATH=<Install path>:$CMAKE_PREFIX_PATH
```
### CUDA
安裝好 CUDA 後,須設定**環境變數**
```
export CMAKE_PREFIX_PATH=<CUDA_INSTALL>:$CMAKE_PREFIX_PATH
```
### libpng (1.2.9+)
- libpng 需要 zlib,下方指令一次安裝
```
sudo apt install zlib1g-dev libpng-dev
```
### pngwriter
```=
git clone -b 0.7.0 https://github.com/pngwriter/pngwriter.git
mkdir ./pngwriter/build && cd ./pngwriter/build
cmake .. -DCMAKE_INSTALL_PREFIX=<Install path>
make -j
sudo make install
```
- **環境變數**
```
export CMAKE_PREFIX_PATH=<Install path>:$CMAKE_PREFIX_PATH
```
### HDF5 (for openPMD API)
```=
wget "https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.10/hdf5-1.10.1/src/CMake-hdf5-1.10.1.tar.gz"
tar xf CMake-hdf5-1.10.1.tar.gz
cd CMake-hdf5-1.10.1/hdf5-1.10.1
mkdir build && cd ./build
cmake .. -DHDF5_BUILD_CPP_LIB=OFF -DHDF5_ENABLE_PARALLEL=ON --install-prefix=<Install path>
make -j
sudo make install
```
- **環境變數**
```
export CMAKE_PREFIX_PATH=<Install path>:$CMAKE_PREFIX_PATH
```
- 這是為了後面編譯 openPMD API 的時候,可以偵測到有 HDF5
### ADIOS2 (for openPMD API)
```=
git clone https://github.com/ornladios/ADIOS2.git
mkdir ./ADIOS2/build && cd ./ADIOS2/build
cmake .. -DADIOS2_BUILD_EXAMPLES=ON --install-prefix=<Install path>
make -j
sudo make install
```
- **環境變數**
```
export CMAKE_PREFIX_PATH=<Install path>:$CMAKE_PREFIX_PATH
```
- 這是為了後面編譯 openPMD API 的時候,可以偵測到有 ADIOS2
### openPMD API
```=
git clone -b 0.15.0 https://github.com/openPMD/openPMD-api.git
cd openPMD-api
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=<Install path> \
-DopenPMD_USE_MPI=ON -DopenPMD_USE_ADIOS2=ON -DopenPMD_USE_HDF5=ON
make -j
sudo make install
```
- **環境變數**
```
export CMAKE_PREFIX_PATH=<Install path>:$CMAKE_PREFIX_PATH
```
### c-blosc
- 唯一的真 optional
```
sudo apt-get install libblosc-dev
```
- 我還沒測試過,不確定能不能用
### FFTW3
```=
wget -O fftw-3.3.10.tar.gz http://fftw.org/fftw-3.3.10.tar.gz
tar -xf fftw-3.3.10.tar.gz
mkdir fftw-3.3.10/build && cd fftw-3.3.10/build
../configure --prefix=<Install path>
make -j
sudo make install
```
- **環境變數**
```
export FFTW3_ROOT=<Install path>
export LD_LIBRARY_PATH=$FFTW3_ROOT/lib:$LD_LIBRARY_PATH
```
## 下載 PIConGPU
```
git clone https://github.com/ComputationalRadiationPhysics/picongpu.git
```
- 環境變數
```=
export PICSRC=$PWD/picongpu
export PIC_EXAMPLES=$PICSRC/share/picongpu/examples
export PATH=$PATH:$PICSRC
export PATH=$PATH:$PICSRC/bin
export PATH=$PATH:$PICSRC/src/tools/bin
export PYTHONPATH=$PICSRC/lib/python:$PYTHONPATH
```
## 範例模擬
### 前置作業
- 選擇一個存放編譯結果的目錄 (不可以在 PIConGPU 的 source code 中)
```
export SCRATCH=<Path of PIC runtime>
```
- 建立兩個目錄
```=
# Input file
mkdir $SCRATCH/picInputs
# simulation output
mkdir $SCRATCH/runs
```
### 建立 Inputfile
這邊使用官方範例
```=
pic-create $PIC_EXAMPLES/LaserWakefield $SCRATCH/picInputs/myLWFA
cd $SCRATCH/picInputs/myLWFA
```
### 編譯
```
pic-build
```
### 執行模擬
```
tbg -s bash -c etc/picongpu/1.cfg -t etc/picongpu/bash/mpiexec.tpl $SCRATCH/runs/lwfa_001
```
- 執行結果存在 `runs/lwfa_001`
:::warning
- 如果執行到一半失敗,`runs/lwfa_001` 也會建立
- 如果同樣指令重新執行,會顯示路徑已經存在的錯誤
- 可以先將 `runs/lwfa_001` 刪除,就可以再跑一次 (或是換個名字,例如 `runs/lwfa_XXX`)
:::
### 參數
#### 模擬大小和 step 數量

- TBG_gridSize: 模擬的空間大小 (domain)
- TBG_steps: 模擬的 step 數量
- TBG_devices_x/y/z: 每個維度上使用的 GPU 數量
- 三個數字相乘要等於總 GPU 數量
#### Dump
- 模擬的過程,會每隔幾個 step 就存一個檔案,但是這個存檔的大小超大
- 中間的間隔可以在 `$SCRATCH/picInputs/myLWFA/etc/picongpu/1.cfg` 中設定
- 將設定檔中的所有 `period` 參數都改大,就可以減少輸出檔案的大小

- 預設是 100,這邊我全部改 500
## Benchmark
### 2080ti * 1 - 260.43sec

### 2080ti * 2 - 198.42 sec

### V100 * 8 (1, 1, 8) - 44.315 sec

### V100 * 8 (1, 8 ,1) - 29.180 sec

### V100 * 8 (8, 1, 1) - 52.484 sec

### V100 * 8 (2, 2, 2) - 33.708 sec

### V100 * 8 (1, 2, 4) - 34.799 sec

### V100 * 8 (1, 4, 2) - 31.523 sec

### V100 * 8 (2, 1, 4) - 36.292 sec

### V100 * 8 (2, 4, 1) - 34.85 sec

### V100 * 8 (2, 2, 2) - 41.226 sec

### V100 * 8 (2, 1, 4) - 52.12 sec

### V100 * 8 (1, 4, 2) - 37.397 sec

### V100 * 8 (1, 8, 1) - 33.601 sec

### V100 * 16 (4, 4, 1) - 30.996 sec

### V100 * 16 (2, 4, 2) - 26.48 sec

### V100 * 16 (2, 4, 2)B - 23.550 sec

### V100 * 16 (1, 16, 1) - 24.388 sec

### V100 * 16 (1, 16, 1)B - 22.319 sec

# Runtime 參數
Job 指令
```
tbg -s <啟動方式> -c <cfg檔> -t <tpl檔> <output path>
```
- 啟動方式: 執行 job 的方法
- bash: 直接在 shell 裡面執行
- sbatch: submit slurm job
- cfg: PIConGPU 層級的參數
- 例如: 模擬的空間大小、模擬的 step 數量、每個方向使用的 GPU 數量
- tpl: 環境層級的參數
- 例如 MPI 參數、Slurm 參數、環境變數
## CFG
有打 * 是我覺得可能跟效能相關 (且不影響結果)
### Required Variables
#### TBG_wallTime
```
TBG_wallTime="1:00:00"
```
好像是時間上限的樣子
#### *TBG_devices_x/y/z
```
TBG_devices_x=1
TBG_devices_y=1
TBG_devices_z=1
```
- 每個方向上使用的 GPU 數量
- 相乘必須等於使用的 GPU 總數
#### TBG_gridSize、TBG_steps
```
TBG_gridSize="192 1024 192"
TBG_steps="2000"
```
- 模擬的空間大小
- 模擬的步數
#### TBG_periodic
```
TBG_periodic="--periodic 0 0 1"
```
- 不知道什麼的週期,需要有人查一下
>在你的例子中,TBG_periodic="--periodic 1 0 1" 表示:
>X 維度是週期性的 (1)。
>Y 維度不是週期性的 (0)。
>Z 維度是週期性的 (1)。
>這意味著,在 X 和 Z 維度上,粒子離開模擬空間的一側時會進入對應的另一側,類似於一個無窮長的環狀空間。而 Y 維度則有固定的邊界,粒子到達邊界時會反彈或消失,取決於其他的邊界條件設定。這樣的設計可以用來模擬某些特定的物理現象,比如在長波長尺度上假設空間的無限延伸性。
> By ChatGPT
### Optional Variables
- 範例中,這一段的參數都在設定和 output 相關的參數
- PIConGPU 的 output 支援多種格式,每個格式都有對應的模組負責處理
- 這邊比較重要的是輸出週期 (多少個 step 輸出一次)
#### TBG_pngYX
```
TBG_pngYX="--e_png.period 100 \
--e_png.axis yx --e_png.slicePoint 0.5 \
--e_png.folder pngElectronsYX"
```
- Output 是 YX 平面的渲染圖
- `--e_png.period 100` 表示 100 step 輸出一次
#### 其他模組
- 其他模組各有各的參數
- 應該不影響效能(time per step),但是會影響輸出結果和總執行時間 (輸出寫檔會很久)
**建議**
- 測試的時候可以只開 pngYX 的模組
- 預設設定長這樣
```
TBG_plugins="!TBG_pngYX \
!TBG_e_histogram \
!TBG_e_PSypy \
!TBG_e_macroCount \
!TBG_openPMD"
```
- 可以改這樣,減少輸出時間和節省硬碟空間
```
TBG_plugins="!TBG_pngYX"
```