외부 인자를 받아 실행되는 Bash 스크립트는 C/C++의 main(int argc, char* argv[])와 동일한 방식으로 동작합니다. 이를 활용해 Projected-Hartree-Fock 계산을 자동화하는 파이프라인을 구성해보겠습니다.
단일 핵종 PHF 계산 스크립트
Calvin Johnson 연구팀이 개발한 PHF 패키지는 두 개의 핵심 실행 파일로 구성됩니다. Hartree-Fock 부분인 Sherpa와 투영(projection)을 담당하는 LAMP입니다. 먼저 단일 핵종을 처리하는 run_phf_single.sh를 작성합니다.
#!/bin/bash
# Usage: ./run_phf_single.sh <sps_file> <proton_count> <neutron_count> [<interaction> <core_mass>]
orbitals=$1
valence_p=$2
valence_n=$3
hamiltonian=${4:-usdb}
core_A=${5:-16}
target="p${valence_p}n${valence_n}"
mass_ref=$((core_A + 2))
mass_full=$((core_A + valence_p + valence_n))
scale_factor=0.3
angular_max=20
echo "=== Initializing SHERPA for ${target} ==="
# 기존 산출물 제거 (상호작용 프롬프트 방지)
rm -f ${target}.sd ${target}.res
./sherpa19.x << EOF
${orbitals}
${valence_p}
${valence_n}
n
i
1
${hamiltonian}
1 ${mass_ref} ${mass_full} ${scale_factor}
n
test
19911
1000
15
-1
w
${target}
${hamiltonian}
x
r
e
x
x
EOF
mv hf.basis ${target}.hf.basis
echo "Hartree-Fock basis saved: ${target}.hf.basis"
echo "=== Launching LAMP projection ==="
./lamp.x << EOF
${orbitals}
${valence_p} ${valence_n}
1
${target}
${angular_max}
n
y
${hamiltonian}
1 ${mass_ref} ${mass_full} ${scale_factor}
end
0.0001
20
0.001
y
${target}
n
EOF
mkdir -p results
mv ${target}.res results/
echo "Completed: ${target}.res stored in results/"
sd-shell 순회 자동화
이제 N ≥ Z 조건을 만족하는 sd-shell 짝짝수 핵종을 순회하는 상위 스크립트를 작성합니다.
#!/bin/bash
echo "PHF batch calculation started at $(date '+%Y-%m-%d %H:%M:%S')"
for p_count in {0..6}; do
for n_count in $(seq ${p_count} 6); do
num_protons=$((p_count * 2))
num_neutrons=$((n_count * 2))
echo "Processing: p=${num_protons}, n=${num_neutrons}"
bash run_phf_single.sh sd ${num_protons} ${num_neutrons} usdb 16
done
done
echo "All calculations finished at $(date '+%Y-%m-%d %H:%M:%S')"
결과 파일 파싱: C++ 추출 유틸리티
생성된 .res 파일에서 기대 에너지를 추출하는 C++ 유틸리티입니다. 파일명 패턴과 파싱 로직을 모듈화하여 재사용성을 높였습니다.
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
string ConstructFilename(int proton_valence, int neutron_valence) {
const string prefix = "results/p";
const string middle = "n";
const string suffix = ".res";
auto to_digits = [](int val) -> string {
if (val < 10) return string(1, '0' + val);
return to_string(val);
};
return prefix + to_digits(proton_valence)
+ middle + to_digits(neutron_valence) + suffix;
}
void ExtractGroundStateEnergies(double energy_table[7][7]) {
const string sentinel = "State";
const string delimiter_line(60, '-');
for (int p = 0; p <= 12; p += 2) {
for (int n = p; n <= 12; n += 2) {
string filepath = ConstructFilename(p, n);
ifstream reader(filepath);
if (!reader.is_open()) {
cerr << "Warning: Cannot access " << filepath << endl;
continue;
}
string buffer, keyword;
bool found_header = false;
// 헤더 탐색: "State" 키워드 검출
while (getline(reader, buffer)) {
istringline parser(buffer);
parser >> keyword;
if (keyword == sentinel) {
found_header = true;
break;
}
}
if (!found_header) {
cerr << "Malformed output: " << filepath << endl;
reader.close();
continue;
}
// 구분선 및 데이터 행 스킵
getline(reader, buffer); // separator
// 실제 에너지 값 읽기
getline(reader, buffer);
istringstream data_stream(buffer);
int level_idx;
double ground_energy;
data_stream >> level_idx >> ground_energy;
int p_idx = p / 2;
int n_idx = n / 2;
energy_table[p_idx][n_idx] = ground_energy;
energy_table[n_idx][p_idx] = ground_energy; // 대칭성 활용
cout << fixed << setprecision(4);
cout << "Extracted [" << p << "," << n << "]: "
<< ground_energy << " MeV" << endl;
reader.close();
}
}
}
데이터 비교 파이프라인
추출된 PHF 기대 에너지와 기존 shell-model 대각화 결과를 비교하여 상관 에너지를 정량화할 수 있습니다. 두 방법론 간 에너지 차이 ΔE = E_PHF - E_SM는 PHF가 shell-model 상限으로부터 개선되는 정도를 나타냅니다.
void ComputeEnergyDeficiency(
const double phf_data[7][7],
const double sm_data[7][7],
double discrepancy[7][7]
) {
for (int i = 0; i < 7; ++i) {
for (int j = 0; j < 7; ++j) {
discrepancy[i][j] = phf_data[i][j] - sm_data[i][j];
}
}
}
이 파이프라인을 통해 sd-shell 전역에서의 PHF 성능을 체계적으로 평가할 수 있습니다.