---
# System prepended metadata

title: PIConGPU
tags: [APP]

---

# 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 數量

![image](https://hackmd.io/_uploads/SkGIaax_0.png)
- TBG_gridSize: 模擬的空間大小 (domain)
- TBG_steps: 模擬的 step 數量
- TBG_devices_x/y/z: 每個維度上使用的 GPU 數量
	- 三個數字相乘要等於總 GPU 數量

#### Dump

- 模擬的過程，會每隔幾個 step 就存一個檔案，但是這個存檔的大小超大
- 中間的間隔可以在 `$SCRATCH/picInputs/myLWFA/etc/picongpu/1.cfg` 中設定
- 將設定檔中的所有 `period` 參數都改大，就可以減少輸出檔案的大小
	![image](https://hackmd.io/_uploads/Hypon6lO0.png)
	- 預設是 100，這邊我全部改 500

## Benchmark

### 2080ti * 1 - 260.43sec

![image](https://hackmd.io/_uploads/SJ-mxmeuR.png)

### 2080ti * 2 - 198.42 sec

![image](https://hackmd.io/_uploads/BkkSWQxOR.png)

### V100 * 8 (1, 1, 8) - 44.315 sec
![image](https://hackmd.io/_uploads/SJk2CbCFC.png)

### V100 * 8 (1, 8 ,1) - 29.180 sec
![image](https://hackmd.io/_uploads/SkKpRZCKR.png)

### V100 * 8 (8, 1, 1) - 52.484 sec
![image](https://hackmd.io/_uploads/rkzgyfAKR.png)

### V100 * 8 (2, 2, 2) - 33.708 sec
![image](https://hackmd.io/_uploads/r1gBfJGAYR.png)

### V100 * 8 (1, 2, 4) - 34.799 sec
![image](https://hackmd.io/_uploads/SyK4kfAFR.png)

### V100 * 8 (1, 4, 2) - 31.523 sec
![image](https://hackmd.io/_uploads/S1SPkMCFC.png)

### V100 * 8 (2, 1, 4) - 36.292 sec
![image](https://hackmd.io/_uploads/rk7uJfRFA.png)


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

![image](https://hackmd.io/_uploads/ryeRumPYC.png)

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

![image](https://hackmd.io/_uploads/ByRknmDKC.png)

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

![image](https://hackmd.io/_uploads/Sy6Cj7DK0.png)

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

![image](https://hackmd.io/_uploads/Syt7aXwKR.png)

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

![image](https://hackmd.io/_uploads/SkD46QPKR.png)

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

![image](https://hackmd.io/_uploads/Sy6j9qnYA.png)

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

![image](https://hackmd.io/_uploads/H1TF5cnYR.png)

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

![image](https://hackmd.io/_uploads/H17lh93YR.png)

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

![image](https://hackmd.io/_uploads/SJr6q53KA.png)

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

![image](https://hackmd.io/_uploads/BJhRcq3FC.png)

# 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"
			```
