Files

167 lines
9.5 KiB
Markdown

# 환경 준비와 실행
## 준비 순서
저장소 root에서 VS x64 개발 환경을 사용한다. 직접 프로젝트는 v145 toolset과 Windows SDK를
요구한다. 필요한 로컬 설치는 MKL·TBB·HDF5·Intel 수학 runtime과 승인된 GoogleTest
source checkout이다. CMake 경로에는 추가로 CMake 3.25 이상과 Ninja가 필요하다.
Dependency 설치·다운로드·외부 source 수정은 아래 명령에 포함되지 않는다.
직접 MSBuild 설정은 다음 환경변수 또는 ignored `msvc/Fesa.Local.props`로 주입한다.
| 변수 | 값의 의미 |
| --- | --- |
| `FESA_GTEST_SOURCE_DIR` | `googletest/include`와 source를 포함한 승인된 checkout root |
| `FESA_MKL_ROOT` | MKL의 include·lib·runtime을 포함한 설치 root |
| `FESA_TBB_ROOT` | TBB 설치 root; Debug와 Release runtime을 구분한다. |
| `FESA_HDF5_ROOT` | HDF5 C library의 include·lib·runtime 설치 root |
| `FESA_OMP_ROOT` | HDF5가 요구하는 `bin/libmmd.dll`의 Intel compiler runtime 설치 root; 기존 변수명을 유지한다. |
| `MKL_DIR`·`TBB_DIR`·`HDF5_DIR` | CMake에서만 사용하는 각 CONFIG package 디렉터리; 설치 root와 혼동하지 않는다. |
VS x64 Developer PowerShell에서 다음을 확인한다. 누락되면 해당 로컬 설치 경로를 설정한
뒤 다시 확인한다. 개인 경로를 repository의 추적 파일에 기록하지 않는다.
```powershell
Get-Command cl.exe, MSBuild.exe
$required_roots = 'FESA_GTEST_SOURCE_DIR','FESA_MKL_ROOT','FESA_TBB_ROOT','FESA_HDF5_ROOT','FESA_OMP_ROOT'
foreach ($root_name in $required_roots) {
$root_path = [Environment]::GetEnvironmentVariable($root_name)
if (-not $root_path -or -not (Test-Path -LiteralPath $root_path -PathType Container)) {
throw "Missing local dependency root: $root_name"
}
}
```
위 확인은 환경변수 방식의 준비 절차다. `Fesa.Local.props`를 사용하는 경우에는 그 파일의
동일 MSBuild property 값을 확인한다. CMake는 `Fesa.Local.props`를 읽지 않으며,
HDF5용 `libmmd.dll`을 찾을 때 `FESA_OMP_ROOT` 환경변수를 사용한다.
MKL은 ILP64·dynamic·TBB threading으로 연결한다. Debug는 `mkl_tbb_threadd`와
`tbb12_debug.dll`, Release는 `mkl_tbb_thread`와 `tbb12.dll`을 사용한다. CLI와 세
테스트 실행 파일 곁에 같은 구성의 DLL을 준비한다. MKL용 `mkl_intel_thread`와
`libiomp5md.dll`은 연결·복사하지 않으며 HDF5의 `libmmd.dll`은 별도로 유지한다.
## 주 개발 빌드와 직접 검사
저장소 root의 VS x64 개발 환경에서 실행한다. 앞 명령이 실패하면 뒤 명령으로 진행하지 않는다.
```powershell
MSBuild FESA.sln /m:2 /p:Configuration=Debug /p:Platform=x64
if ($LASTEXITCODE -ne 0) { throw 'MSBuild failed' }
```
출력은 `.build/native/Debug`다. Solver CLI는 `src/fesa/fesa.exe`, 세 검사 실행기는
`tests/fesa_unit_tests.exe`, `tests/fesa_integration_tests.exe`,
`tests/fesa_reference_tests.exe`에 있다. Release는 별도의 `Release` 디렉터리를 사용한다.
직접 MSBuild는 CMake·Ninja·Doxygen을 선행 실행하지 않는다.
다음은 한 번의 전체 직접 검사 예시다. 각 실행기는 새 process이므로 직렬로 실행한다.
고유 디렉터리의 raw 출력·XML과 discovery를 보관한다. 이 예시는 현재 PowerShell
process의 TMP/TEMP와 GoogleTest 선택 환경을 변경한다.
```powershell
$verify_run = Join-Path $env:LOCALAPPDATA ('fv-' + [guid]::NewGuid().ToString('N').Substring(0,8))
New-Item -ItemType Directory -Path $verify_run -ErrorAction Stop | Out-Null
$env:TMP = $verify_run
$env:TEMP = $verify_run
foreach ($filter_name in 'GTEST_FILTER','GTEST_TOTAL_SHARDS','GTEST_SHARD_INDEX','GTEST_SHARD_STATUS_FILE','GTEST_OUTPUT') {
Remove-Item -LiteralPath ('Env:' + $filter_name) -ErrorAction SilentlyContinue
}
foreach ($test_name in 'fesa_unit_tests','fesa_integration_tests','fesa_reference_tests') {
$test_exe = Join-Path '.build/native/Debug/tests' ($test_name + '.exe')
& $test_exe --gtest_list_tests > (Join-Path $verify_run ($test_name + '-discovery.txt'))
if ($LASTEXITCODE -ne 0) { throw "Discovery failed: $test_name" }
& $test_exe ('--gtest_output=xml:' + (Join-Path $verify_run ($test_name + '.xml'))) *> (Join-Path $verify_run ($test_name + '-raw.txt'))
if ($LASTEXITCODE -ne 0) { throw "Tests failed: $test_name; records: $verify_run" }
}
```
생성된 경로에서도 실제 최장 lease 경로를 확인한다. 너무 길면 승인된 짧은 작업 위치를 사용한다.
## MITC4 drilling 방식 변경
`src/fesa/elements/mitc4_drilling_internal.h`의 `kProductionDrillingMode` 한 곳을 바꾼다.
기본값은 `Mitc4DrillingMode::kDirectSpring`, 기존 방식은
`Mitc4DrillingMode::kLegacyCorotatedTwist`다. 변경 후 solver·CLI·검사를 모두 rebuild한다.
같은 모델의 모든 MITC4 정적·pressure·frequency·HHT에 적용되며 CLI/INP/환경변수나
section별 override는 현재 없다. 시험용 명시적 alternate mode 경로는 production 설정이 아니다.
서로 다른 mode의 실행물·DLL·입력 sibling 결과를 별도 위치에 두고 실제 metadata marker로
선택을 확인한다. 선형 변위와 원형상 eigen값이 두 방식에서 같아도 정상이다.
## CMake 보조 빌드
같은 VS x64 환경에서 로컬 CONFIG package 환경변수를 설정한 뒤 실행한다.
한국어 MSVC의 include 추적을 위해 configure/build의 code page를 65001로 맞춘다.
직접 검사와 별개의 짧고 고유한 TMP/TEMP를 만들고 상속된 필터·sharding을 제거한다.
```powershell
Get-Command cmake.exe, ninja.exe
chcp 65001
$cmake_verify_run = Join-Path $env:LOCALAPPDATA ('fc-' + [guid]::NewGuid().ToString('N').Substring(0,8))
New-Item -ItemType Directory -Path $cmake_verify_run -ErrorAction Stop | Out-Null
$env:TMP = $cmake_verify_run
$env:TEMP = $cmake_verify_run
foreach ($filter_name in 'GTEST_FILTER','GTEST_TOTAL_SHARDS','GTEST_SHARD_INDEX','GTEST_SHARD_STATUS_FILE','GTEST_OUTPUT') {
Remove-Item -LiteralPath ('Env:' + $filter_name) -ErrorAction SilentlyContinue
}
cmake --preset windows-msvc-ninja-debug
if ($LASTEXITCODE -ne 0) { throw 'Configure failed' }
cmake --build --preset windows-msvc-ninja-debug --parallel 2
if ($LASTEXITCODE -ne 0) { throw 'Build failed' }
ctest --preset windows-msvc-ninja-debug --show-only=json-v1
if ($LASTEXITCODE -ne 0) { throw 'Discovery failed' }
ctest --preset windows-msvc-ninja-debug --output-on-failure -j 1
if ($LASTEXITCODE -ne 0) { throw 'CTest failed' }
```
Debug tree는 `.build/cmake-debug`, Release tree는 `.build/cmake-release`다.
CLI는 각각의 tree에서 `src/fesa/fesa.exe`에 있다. Native와 CMake의 실행 기록을 분리하고
discovery가 0건이 아닌지, 전체 identity가 일치하는지 확인한다. CTest label만으로
물리 기능을 선별하지 않는다. 현재 공통 label에는 beam 이름이 들어 있으며 전체 검사의 procedure 분류가 아니다.
`fesa_docs`는 Doxygen을 검출했을 때만 존재하는 선택적 target이다.
## Python 비교기와 실제 모델
Python suite는 pytest·NumPy·h5py를 사용한다. 설치된 환경에서 다음을 실행한다.
```powershell
python -c "import pytest, numpy, h5py"
if ($LASTEXITCODE -ne 0) { throw 'Python dependencies are missing' }
python -m pytest tests -q
if ($LASTEXITCODE -ne 0) { throw 'Python tests failed' }
```
`scripts/verification/compare_hex8.py`와 `compare_hht_dynamic.py`는 입력·reference·HDF5를
읽고 지정한 JSON report를 쓴다. Solver는 실행하지 않는다. 실행 전에 각 script의 `--help`로
필수 인자와 덮어쓰기 방지 조건을 확인하고 기존 report와 다른 출력 위치를 사용한다.
실제 모델은 원본 INP hash를 확인해 새 작업 디렉터리로 복사한 뒤
`fesa.exe <작업복사본.inp>`로 실행한다. 출력은 해당 입력의 sibling이다.
Exit·로그·새 HDF5의 identity를 확인한 뒤 대응하는 정식 reference와 비교한다.
`reference/temp`는 사용하지 않는다. 원본 폴더 안에서 solver를 실행하지 않는다.
다음은 Debug 빌드 뒤 정식 beam 입력을 새 위치에서 실행하는 예시다. 원본 폴더에 쓰지 않으며
비교 CSV는 복사·수정하지 않는다. 실행 성공은 후속 reference 비교를 대신하지 않는다.
```powershell
$model_source = 'reference/cantilever beam/cantilever beam.inp'
$model_run = Join-Path $env:LOCALAPPDATA ('fm-' + [guid]::NewGuid().ToString('N').Substring(0,8))
New-Item -ItemType Directory -Path $model_run -ErrorAction Stop | Out-Null
$model_copy = Join-Path $model_run 'beam.inp'
Copy-Item -LiteralPath $model_source -Destination $model_copy -ErrorAction Stop
if ((Get-FileHash -LiteralPath $model_source).Hash -ne (Get-FileHash -LiteralPath $model_copy).Hash) {
throw 'Input copy hash mismatch'
}
& '.build/native/Debug/src/fesa/fesa.exe' $model_copy
if ($LASTEXITCODE -ne 0) { throw "Solver failed; records: $model_run" }
Get-Item -LiteralPath (Join-Path $model_run 'beam_results.h5'), (Join-Path $model_run 'beam_log.txt')
```
## 시간 측정과 배포의 경계
성능 판정은 Ryzen 7 5800H의 Windows/MSVC x64 최적화 Release가 기준이다.
같은 thread·runtime·전원·compiler 조건에서 워밍업 없이 모델별 process를 한 번 측정한다.
Process 시작 요청 직전부터 종료 직후까지 입력·계산·복구·로그·HDF5 최종화를 포함한다.
빌드·복사·VTune·비교는 측정 구간 밖이다. Debug 시간이나 반복 최솟값으로 대체하지 않는다.
배포 형식·installer·dependency 재배포 조건은 미확정이며 개발 빌드 절차를 배포 절차로 간주하지 않는다.