# Step 5: analysis-state ## 읽어야 할 파일 먼저 아래 파일들을 읽고 프로젝트의 아키텍처와 이전 step 산출물을 파악하라: - `/AGENTS.md` - `/docs/PRD.md` - `/docs/ARCHITECTURE.md` - `/docs/ADR.md` - `/src/fesa/fem/dof_manager.hpp` - `/tests/unit/dof_manager_numbering_test.cpp` 이전 step에서 만들어진 DofManager를 꼼꼼히 읽고, 해석 중 변하는 물리량은 AnalysisState가 소유하도록 유지하라. ## 작업 displacement 중심의 최소 `AnalysisState`를 `/src/fesa/analysis/`에 구현한다. 필수 파일: - `/src/fesa/analysis/analysis_state.hpp` - `/tests/unit/analysis_state_vectors_test.cpp` 필수 interface: ```cpp namespace fesa::analysis { struct IterationState { double time = 0.0; int increment = 0; int iteration = 0; }; class AnalysisState { public: explicit AnalysisState(int total_dof_count); const std::vector& displacement() const; const std::vector& velocity() const; const std::vector& acceleration() const; const std::vector& temperature() const; const std::vector& external_force() const; const std::vector& internal_force() const; const std::vector& residual() const; void set_displacement(std::vector values); void set_external_force(std::vector values); void set_internal_force(std::vector values); void update_residual(); IterationState& iteration_state(); const IterationState& iteration_state() const; void set_element_state(core::ElementId element_id, std::vector state); const std::vector* element_state(core::ElementId element_id) const; }; } // namespace fesa::analysis ``` 구현 규칙: - 모든 vector는 `total_dof_count` 크기로 초기화한다. - `update_residual()`은 `external_force - internal_force`를 component-wise로 계산한다. - setter는 입력 vector 크기가 맞지 않으면 `std::invalid_argument`를 던진다. - temperature는 Phase skeleton에서 0.0 vector로 둔다. - element state는 향후 integration point state 확장을 위한 최소 map으로 둔다. - AnalysisState는 Domain, AnalysisModel, DofManager를 소유하지 않는다. ## Tests To Write First - `/tests/unit/analysis_state_vectors_test.cpp` - 생성 시 displacement/velocity/acceleration/temperature/force/residual vector 크기와 0.0 초기값을 확인한다. - displacement setter가 값을 보존한다. - external/internal force 설정 후 residual이 `Fext - Fint`가 되는지 확인한다. - 크기가 맞지 않는 vector setter가 `std::invalid_argument`를 던진다. - time/increment/iteration 값이 저장된다. - element state를 element id로 저장/조회한다. RED 확인: 1. 테스트 파일을 먼저 작성한다. 2. targeted CTest를 실행해 missing `analysis_state.hpp`로 실패함을 확인한다. 3. 그 뒤 production header를 작성한다. ## Acceptance Criteria ```powershell python -m unittest discover -s scripts -p "test_*.py" python scripts/validate_workspace.py ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R analysis_state_vectors_test ``` ## 검증 절차 1. 위 AC 커맨드를 실행한다. 2. 아키텍처 체크리스트를 확인한다: - AnalysisState가 해석 중 변하는 물리량을 소유하는가? - Domain이나 AnalysisModel을 복사/소유하지 않는가? - displacement 중심이되 velocity/acceleration/temperature 확장 지점을 유지하는가? 3. 결과에 따라 `phases/solver-core-skeleton/index.json`의 step 5를 업데이트한다: - 성공: `"status": "completed"`, `"summary": "AnalysisState vector ownership and residual update added"` - 3회 수정 시도 후 실패: `"status": "error"`, `"error_message": "구체적 에러 내용"` - 사용자 개입 필요: `"status": "blocked"`, `"blocked_reason": "구체적 사유"` 후 중단 ## 금지사항 - Solver backend나 numerical integration loop를 구현하지 마라. - HDF5 writer를 이 step에서 구현하지 마라. - JavaScript/TypeScript/npm fallback을 추가하지 마라.