modify documents
This commit is contained in:
+9
-9
@@ -1,7 +1,7 @@
|
||||
# Architecture Decision Records
|
||||
|
||||
## 철학
|
||||
Abaqus User Subroutine 개발은 일반 application code 개발보다 ABI, solver execution, compiler integration, reference artifact provenance의 영향을 크게 받는다. 이 프로젝트의 결정은 Abaqus 실행을 기본 전제로 삼지 않으면서도, Fortran code와 numerical behavior를 검증 가능한 단위로 나누는 방향을 따른다.
|
||||
Abaqus User Subroutine 개발은 일반 application code 개발보다 ABI, solver execution, compiler integration, reference artifact provenance의 영향을 크게 받는다. 이 프로젝트의 결정은 Abaqus 실행을 저장소 내부 기본 전제로 삼지 않으면서도, Fortran code와 ODB에서 추출된 numerical behavior를 검증 가능한 단위로 나누는 방향을 따른다.
|
||||
|
||||
---
|
||||
|
||||
@@ -26,12 +26,12 @@ Abaqus User Subroutine 개발은 일반 application code 개발보다 ABI, solve
|
||||
|
||||
**트레이드오프**: 작은 변경에도 문서화 비용이 생긴다. 단, 단순 correction은 기존 approved contract 안에서 Correction Agent가 최소 수정으로 처리할 수 있다.
|
||||
|
||||
### ADR-004: 기본 검증은 no-Abaqus path로 유지한다
|
||||
**결정**: `python scripts/validate_workspace.py`는 기본 검증 entry point이며 Abaqus job을 자동 실행하지 않는다. Abaqus 실행은 `HARNESS_ABAQUS_VALIDATION=run`과 `HARNESS_ABAQUS_VALIDATION_COMMANDS`가 명시된 경우에만 수행한다.
|
||||
### ADR-004: 기본 검증은 no-Abaqus path와 외부 생성 CSV artifact validation으로 유지한다
|
||||
**결정**: `python scripts/validate_workspace.py`는 기본 검증 entry point이며 Abaqus job을 자동 실행하지 않는다. Abaqus 해석과 ODB CSV 추출은 사용자가 외부 Abaqus PC에서 수행하고, 이 저장소는 `references/<feature-id>/<model-id>/`에 등록된 extracted CSV artifact를 검증한다.
|
||||
|
||||
**이유**: Abaqus 실행은 설치, 라이선스, target version, compiler integration, working directory, scratch behavior에 의존한다. 기본 검증이 Abaqus에 의존하면 개발 재현성이 떨어진다.
|
||||
**이유**: Abaqus 실행은 설치, 라이선스, target version, compiler integration, working directory, scratch behavior에 의존한다. 또한 ODB는 일반 Python이 아니라 Abaqus scripting environment가 필요한 결과 database이므로, 이 프로젝트의 기본 검증이 Abaqus 실행 또는 ODB 직접 파싱에 의존하면 개발 재현성이 떨어진다.
|
||||
|
||||
**트레이드오프**: 기본 검증만으로 Abaqus runtime symbol resolution이나 actual solver behavior를 완전히 보장할 수 없다. 해당 evidence는 opt-in validation과 approved reference artifacts로 보완한다.
|
||||
**트레이드오프**: 기본 검증만으로 Abaqus runtime symbol resolution이나 actual solver behavior를 완전히 보장할 수 없다. 해당 evidence는 사용자가 외부에서 수행한 Abaqus 해석 결과, ODB 추출 CSV, log tail, metadata provenance를 approved reference artifacts로 등록해 보완한다.
|
||||
|
||||
### ADR-005: Abaqus ABI wrapper는 얇게 유지하고 계산 kernel은 no-Abaqus로 검증한다
|
||||
**결정**: Subroutine source는 가능한 한 thin Abaqus ABI wrapper와 testable kernel 또는 driver logic으로 분리한다.
|
||||
@@ -40,12 +40,12 @@ Abaqus User Subroutine 개발은 일반 application code 개발보다 ABI, solve
|
||||
|
||||
**트레이드오프**: Wrapper와 kernel 사이의 mapping code가 추가된다. 이 mapping 자체는 interface contract와 wrapper-level compile/smoke test로 검증해야 한다.
|
||||
|
||||
### ADR-006: Reference artifacts는 metadata contract로 검증한다
|
||||
**결정**: Abaqus reference artifacts는 `references/<feature-id>/<model-id>/metadata.json`과 함께 보관하고, `scripts/validate_reference_artifacts.py`로 metadata, source hash, required files를 검증한다.
|
||||
### ADR-006: Reference artifacts는 extracted CSV와 metadata contract로 검증한다
|
||||
**결정**: Abaqus reference artifacts는 `references/<feature-id>/<model-id>/metadata.json`과 함께 보관하고, `scripts/validate_reference_artifacts.py`로 metadata, source hash, required files를 검증한다. 최소 bundle은 `model.inp`, extracted CSV, `.msg/.dat/.log/.sta` tail files를 포함한다. ODB 파일은 직접 parsing하지 않으며, 필요하면 opaque artifact 또는 hash/provenance로만 기록한다.
|
||||
|
||||
**이유**: Abaqus output CSV만 있으면 어떤 source, Abaqus version, compiler, precision, command에서 생성됐는지 추적할 수 없다. Source hash와 log tail을 포함해야 comparison evidence로 사용할 수 있다.
|
||||
**이유**: Abaqus output CSV만 있으면 어떤 source, Abaqus version, compiler, precision, extraction script에서 생성됐는지 추적할 수 없다. Source hash와 log tail을 포함해야 comparison evidence로 사용할 수 있다. `.sta` tail은 해석 진행과 종료 상태를 확인하는 보조 evidence로 필요하다.
|
||||
|
||||
**트레이드오프**: Reference artifact 준비 비용이 증가한다. 대신 stale artifact, source mismatch, missing provenance를 자동으로 탐지할 수 있다.
|
||||
**트레이드오프**: Reference artifact 준비 비용이 증가하고, 사용자는 Abaqus PC에서 ODB-to-CSV extraction을 별도로 수행해야 한다. 대신 stale artifact, source mismatch, missing provenance, schema mismatch를 자동으로 탐지할 수 있다.
|
||||
|
||||
### ADR-007: Fortran production 변경은 TDD guard 대상이다
|
||||
**결정**: `.f`, `.for`, `.f90`, `.f95`, `.f03`, `.f08` production source 변경은 관련 test file이 없으면 guard가 차단한다.
|
||||
|
||||
+25
-7
@@ -1,13 +1,14 @@
|
||||
# Architecture: Abaqus User Subroutine Development
|
||||
|
||||
## 목표
|
||||
이 저장소는 Abaqus User Subroutine 개발을 위한 agent-driven workflow와 검증 체계를 제공한다. 핵심 아키텍처는 단계별 specialist agent, gate 문서, no-Abaqus Fortran TDD, opt-in Abaqus validation, reference artifact metadata validation으로 구성된다.
|
||||
이 저장소는 Abaqus User Subroutine 개발을 위한 agent-driven workflow와 검증 체계를 제공한다. 핵심 아키텍처는 단계별 specialist agent, gate 문서, no-Abaqus Fortran TDD, 외부 생성 ODB 추출 CSV validation, reference artifact metadata validation으로 구성된다.
|
||||
|
||||
## 주요 원칙
|
||||
- Abaqus User Subroutine 개발이 프로젝트의 중심이다.
|
||||
- Fortran source는 Abaqus ABI wrapper와 testable kernel/driver logic을 가능한 한 분리한다.
|
||||
- 기본 검증은 Abaqus를 실행하지 않는다.
|
||||
- Abaqus 실행과 reference artifact 생성은 명시적으로 승인된 환경에서만 수행한다.
|
||||
- Abaqus 해석 실행과 ODB CSV 추출은 사용자가 외부 Abaqus PC에서 수행한다.
|
||||
- 이 프로젝트는 ODB를 직접 파싱하지 않고, 추출된 CSV와 metadata를 검증한다.
|
||||
- Requirements, research, formulation, interface, test model, implementation, validation 산출물을 섞지 않는다.
|
||||
|
||||
## 디렉토리 구조
|
||||
@@ -38,7 +39,7 @@ scripts/
|
||||
tests/
|
||||
└── fortran/manifest.json # Optional no-Abaqus Fortran test manifest
|
||||
references/
|
||||
└── <feature-id>/<model-id>/ # Optional approved Abaqus reference artifacts
|
||||
└── <feature-id>/<model-id>/ # External Abaqus result artifacts for CSV comparison
|
||||
phases/
|
||||
└── <phase-id>/ # Optional staged execution plans
|
||||
```
|
||||
@@ -98,10 +99,17 @@ references/<feature-id>/<model-id>/
|
||||
├── job.msg.tail.txt
|
||||
├── job.dat.tail.txt
|
||||
├── job.log.tail.txt
|
||||
└── *.csv
|
||||
├── job.sta.tail.txt
|
||||
├── result.odb.sha256 # Optional when ODB cannot or should not be stored
|
||||
├── extraction/
|
||||
│ └── extract_odb_to_csv.py # Optional provenance copy of user-run extraction script
|
||||
└── extracted/
|
||||
└── *.csv
|
||||
```
|
||||
|
||||
`metadata.json` schema version은 `abaqus-user-subroutine-artifact-v1`이다. `artifact_status=ready-for-comparison`인 artifact는 Abaqus version, precision, command, compiler vendor/name/version, entry points, source file hashes, input file, output tails, declared CSV files를 모두 가져야 한다.
|
||||
`metadata.json` schema version은 `abaqus-user-subroutine-artifact-v1`이다. `artifact_status=ready-for-comparison`인 artifact는 Abaqus version, precision, compiler vendor/name/version, entry points, source file hashes, input file, output tails, ODB extraction provenance, declared CSV files를 모두 가져야 한다.
|
||||
|
||||
수치 검증은 ODB 직접 parsing이 아니라 `extracted/*.csv`의 schema/tolerance comparison이다. CSV row는 비교 가능한 최소 식별자로 step, frame/time, instance, node 또는 element label, integration point, section point, output position, component, coordinate system, unit, value를 포함해야 한다. Feature별 interface contract는 필요한 column과 tolerance를 더 좁게 정의한다.
|
||||
|
||||
Reference artifacts는 생성 후 검증 입력으로 취급한다. Validation agent는 source code, tests, tolerances, reference artifacts를 임의 수정하지 않는다.
|
||||
|
||||
@@ -114,10 +122,20 @@ Default workspace validation:
|
||||
-> scripts/validate_reference_artifacts.py
|
||||
-> scripts/validate_fortran.py
|
||||
-> optional CMake/CTest path if CMake project exists
|
||||
-> optional Abaqus command path only when HARNESS_ABAQUS_VALIDATION=run
|
||||
```
|
||||
|
||||
`HARNESS_ABAQUS_VALIDATION=detect`는 Abaqus executable 탐지만 보고한다. `HARNESS_ABAQUS_VALIDATION=run`은 `HARNESS_ABAQUS_VALIDATION_COMMANDS`가 없으면 configuration error로 실패한다.
|
||||
Standard numerical validation flow:
|
||||
```text
|
||||
Fortran subroutine implemented
|
||||
-> user-authored model.inp
|
||||
-> user runs Abaqus with the subroutine on another PC
|
||||
-> user extracts ODB quantities to CSV
|
||||
-> user places model.inp, extracted CSV, msg/dat/log/sta tails, and metadata under references/
|
||||
-> scripts/validate_reference_artifacts.py checks artifact completeness
|
||||
-> comparison tooling checks CSV schema, IDs, units, coordinate systems, and tolerances
|
||||
```
|
||||
|
||||
Existing Abaqus execution environment variables are treated as legacy/diagnostic script capabilities, not the project validation workflow. New documents and agents should describe solver evidence as externally generated artifacts, not as commands run by this repository.
|
||||
|
||||
## Hook 흐름
|
||||
```text
|
||||
|
||||
+12
-9
@@ -3,7 +3,7 @@
|
||||
## 목표
|
||||
이 프로젝트는 Abaqus User Subroutine을 요구조건 분석, 연구, 유한요소 정식화, ABI 정의, TDD test model 설계, Fortran 구현, 검증까지 일관된 agent-driven workflow로 개발하게 한다.
|
||||
|
||||
기본 목표는 Abaqus가 없는 환경에서도 가능한 검증을 최대화하고, Abaqus 실행이 필요한 검증은 명시적으로 opt-in한 환경에서만 수행하는 것이다.
|
||||
기본 목표는 Abaqus가 없는 환경에서도 가능한 검증을 최대화하고, 수치 결과 검증은 사용자가 다른 Abaqus PC에서 수행한 해석의 ODB 추출 CSV를 schema/tolerance로 비교하는 것이다. 이 프로젝트는 Abaqus job 해석을 직접 실행하지 않는다.
|
||||
|
||||
## 사용자
|
||||
- Abaqus User Subroutine을 개발하는 엔지니어
|
||||
@@ -14,8 +14,9 @@
|
||||
## 문제 정의
|
||||
- Abaqus User Subroutine은 Abaqus ABI, analysis procedure, tensor ordering, state variable, compiler/linker, reference artifact provenance가 모두 맞아야 한다.
|
||||
- Abaqus 실행은 설치, 라이선스, compiler integration에 의존하므로 모든 개발 단계의 기본 검증 수단으로 삼기 어렵다.
|
||||
- ODB는 Abaqus 환경의 scripting interface가 필요한 solver result database이므로 이 프로젝트의 기본 검증에서 직접 파싱하지 않는다.
|
||||
- LLM agent가 요구조건, formulation, interface, test, implementation, validation을 한 번에 섞으면 검증 불가능한 Fortran code가 생성되기 쉽다.
|
||||
- 따라서 단계별 gate, 문서 산출물, no-Abaqus TDD, reference artifact metadata 검증이 필요하다.
|
||||
- 따라서 단계별 gate, 문서 산출물, no-Abaqus TDD, 외부 생성 extracted CSV artifact metadata 검증이 필요하다.
|
||||
|
||||
## 핵심 워크플로우
|
||||
1. Requirement Agent가 feature requirement와 Requirement Verification Matrix를 작성한다.
|
||||
@@ -23,9 +24,9 @@
|
||||
3. Formulation Agent가 finite element formulation, stress update, tangent, state variable, numerical integration을 정의한다.
|
||||
4. Numerical Review Agent가 formulation consistency, tangent consistency, stability risk, patch/tangent check 필요성을 검토한다.
|
||||
5. I/O Definition Agent가 Abaqus ABI arguments, input/output direction, tensor component order, unit, CSV schema를 정의한다.
|
||||
6. Reference Model Agent가 no-Abaqus driver tests와 Abaqus reference artifact bundle 계약을 설계한다.
|
||||
6. Reference Model Agent가 no-Abaqus driver tests와 외부 생성 Abaqus reference artifact bundle 계약을 설계한다.
|
||||
7. Implementation Planning Agent와 Implementation Agent가 RED -> GREEN -> VERIFY 순서로 Fortran code를 구현한다.
|
||||
8. Build/Test Executor, Reference Verification, Physics Evaluation, Release Agent가 validation evidence와 readiness를 검토한다.
|
||||
8. Build/Test Executor, Reference Verification, Physics Evaluation, Release Agent가 extracted CSV comparison evidence와 readiness를 검토한다.
|
||||
|
||||
## 핵심 기능
|
||||
1. `.codex/agents/`와 `.codex/skills/` 기반 단계별 specialist workflow
|
||||
@@ -34,7 +35,7 @@
|
||||
4. Intel oneAPI Fortran 기반 no-Abaqus kernel/fake-driver validation
|
||||
5. `tests/fortran/manifest.json` 기반 Fortran compile/run test discovery
|
||||
6. `references/<feature-id>/<model-id>/metadata.json` 기반 reference artifact metadata validation
|
||||
7. Abaqus job 실행을 기본 검증에서 제외하고 `HARNESS_ABAQUS_VALIDATION=run`에서만 수행하는 opt-in validation
|
||||
7. `model.inp`, extracted CSV, `.msg/.dat/.log/.sta` tail files를 포함한 외부 생성 result artifact validation
|
||||
8. Optional CMake/CTest validation path for supporting native code when a CMake project exists
|
||||
|
||||
## 대표 Subroutine 범위
|
||||
@@ -49,17 +50,19 @@
|
||||
- Interface contract는 Abaqus ABI argument direction, update responsibility, tensor order, unit, coordinate system, CSV schema를 명시한다.
|
||||
- Fortran implementation은 RED -> GREEN -> VERIFY evidence를 남긴다.
|
||||
- `python scripts/validate_workspace.py`가 기본 검증 entry point로 성공한다.
|
||||
- Abaqus reference comparison은 approved reference artifacts가 `ready-for-comparison` 상태일 때만 수행한다.
|
||||
- Abaqus reference comparison은 ODB에서 추출된 CSV와 approved reference artifacts가 `ready-for-comparison` 상태일 때만 수행한다.
|
||||
- Reference artifact bundle은 최소 `model.inp`, extracted CSV, `.msg/.dat/.log/.sta` tail files를 포함한다.
|
||||
|
||||
## 제외 사항
|
||||
- 프로젝트 정체성을 Abaqus User Subroutine development 외의 다른 개발 체계로 정의하지 않는다.
|
||||
- 기본 validation에서 Abaqus job을 자동 실행하지 않는다.
|
||||
- Agent가 reference CSV, `.msg`, `.dat`, `.log` evidence를 임의 생성하거나 승인하지 않는다.
|
||||
- Agent가 reference CSV, `.msg`, `.dat`, `.log`, `.sta` evidence를 임의 생성하거나 승인하지 않는다.
|
||||
- 프로젝트는 ODB 파일을 직접 파싱하지 않는다. ODB 추출은 사용자가 Abaqus PC에서 수행하고, 이 프로젝트는 추출된 CSV와 metadata를 검증한다.
|
||||
- 특정 재료모델, 요소모델, plasticity model, damage model의 물리적 타당성을 이 PRD에서 승인하지 않는다.
|
||||
- Public example repository code를 license 검토 없이 복사하거나 acceptance evidence로 사용하지 않는다.
|
||||
- Visual Studio `.sln`/`.vcxproj` 전용 workflow를 기본 지원하지 않는다.
|
||||
|
||||
## 운영 제약
|
||||
- 문서 산출물은 Korean narrative를 기본으로 하되, Abaqus keyword, subroutine name, status value, command, schema key는 English를 유지한다.
|
||||
- Abaqus version, compiler version, precision, command line, source hash, output tail, CSV schema는 reference artifact metadata에 기록한다.
|
||||
- Abaqus execution이 필요한 검증은 user 또는 승인된 환경이 명시적으로 설정해야 한다.
|
||||
- Abaqus version, compiler version, precision, source hash, output tail, CSV schema, ODB extraction provenance는 reference artifact metadata에 기록한다.
|
||||
- Abaqus execution은 user가 외부 Abaqus PC에서 수행한다. 이 프로젝트의 validation command는 해석 실행이 아니라 extracted CSV artifact 검증을 수행한다.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
이 디렉터리는 Build/Test Executor Agent가 작성하거나 제안하는 기능별 build/test 실행 리포트를 보관하는 위치다.
|
||||
|
||||
Build/Test Executor Agent는 Implementation Agent 이후 독립적으로 C++/MSVC/CMake/CTest 검증을 실행하고, 실패를 분류해 다음 agent로 handoff한다. 이 agent는 source code, tests, CMake files, requirements, formulations, I/O contracts, reference artifacts, tolerance policies를 수정하지 않는다. build artifacts와 test outputs는 `build/` 아래 생성될 수 있다.
|
||||
Build/Test Executor Agent는 Implementation Agent 이후 독립적으로 Fortran no-Abaqus validation, reference artifact validation, workspace validation을 실행하고, 실패를 분류해 다음 agent로 handoff한다. 이 agent는 source code, tests, requirements, formulations, I/O contracts, reference artifacts, tolerance policies를 수정하지 않는다. build artifacts와 test outputs는 `build/` 아래 생성될 수 있다.
|
||||
|
||||
기본 문서명은 `docs/build-test-reports/<feature-id>-build-test.md` 형식을 사용한다.
|
||||
|
||||
@@ -21,7 +21,7 @@ Build/Test Executor Agent는 Implementation Agent 이후 독립적으로 C++/MSV
|
||||
- tests를 수정하지 않는다.
|
||||
- CMake files를 수정하지 않는다.
|
||||
- requirements, formulations, I/O contracts, reference artifacts, tolerance policies를 수정하지 않는다.
|
||||
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV를 생성하지 않는다.
|
||||
- release readiness, reference tolerance success, physics validation success를 승인하지 않는다.
|
||||
- 최종 reference verification report를 작성하지 않는다.
|
||||
@@ -55,7 +55,7 @@ For Abaqus UserSubroutine work, workspace validation also supports:
|
||||
- `HARNESS_ABAQUS_VALIDATION_COMMANDS=<newline commands>`
|
||||
- `HARNESS_ABAQUS_USE_ONEAPI_ENV=auto|on|off`
|
||||
|
||||
Default validation does not run Abaqus jobs. Abaqus execution is valid only when `HARNESS_ABAQUS_VALIDATION=run` and explicit commands are provided.
|
||||
Default validation does not run Abaqus jobs. Solver-result evidence must come from externally generated ODB-extracted CSV artifacts.
|
||||
|
||||
기본 CMake/MSVC x64 Debug 명령은 다음과 같다.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
이 디렉터리는 Coordinator Agent가 작성하거나 제안하는 기능별 workflow coordination report를 보관하는 위치다.
|
||||
|
||||
Coordinator Agent는 FESA solver 기능 개발의 전체 lifecycle에서 gate evidence, handoff, rework loop, blocker, user decision을 관리한다. 이 Agent는 specialist agent의 기술 판정을 대체하지 않고, 다음 agent가 어떤 입력으로 무엇을 산출해야 하는지 명확히 기록한다.
|
||||
Coordinator Agent는 Abaqus User Subroutine 개발의 전체 lifecycle에서 gate evidence, handoff, rework loop, blocker, user decision을 관리한다. 이 Agent는 specialist agent의 기술 판정을 대체하지 않고, 다음 agent가 어떤 입력으로 무엇을 산출해야 하는지 명확히 기록한다.
|
||||
|
||||
기본 문서명은 `docs/coordination/<feature-id>-coordination.md` 형식을 사용한다.
|
||||
|
||||
@@ -25,7 +25,7 @@ Coordinator Agent는 FESA solver 기능 개발의 전체 lifecycle에서 gate ev
|
||||
- physics evaluation을 실행하지 않는다.
|
||||
- requirements, formulations, I/O contracts, numerical review reports를 수정하지 않는다.
|
||||
- reference artifacts 또는 tolerance policies를 수정하지 않는다.
|
||||
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV를 생성하지 않는다.
|
||||
- subagents를 자동 spawn하지 않는다.
|
||||
- release readiness를 독립적으로 승인하지 않는다.
|
||||
|
||||
@@ -23,7 +23,7 @@ Correction Agent는 Build/Test Executor Agent, Reference Verification Agent, Phy
|
||||
- numerical review reports를 수정하지 않는다.
|
||||
- reference artifacts를 수정하지 않는다.
|
||||
- tolerance policies를 수정하지 않는다.
|
||||
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV를 생성하지 않는다.
|
||||
- release readiness, reference tolerance success, physics validation success를 승인하지 않는다.
|
||||
- 최종 reference verification report 또는 physics validation report를 작성하지 않는다.
|
||||
@@ -49,7 +49,7 @@ python -m unittest discover -s scripts -p "test_*.py"
|
||||
## Failure Classification
|
||||
|
||||
- `configure`: CMake configure, preset, generator, cache setup 실패
|
||||
- `compile`: C++ compilation 실패
|
||||
- `compile`: Fortran compilation 실패
|
||||
- `link`: linker, symbol resolution, target dependency 실패
|
||||
- `test`: CTest, unit, integration, parser/I/O, ordinary regression test 실패
|
||||
- `reference-comparison`: 저장된 reference artifact와 deterministic comparison 실패
|
||||
@@ -145,7 +145,7 @@ Excluded files:
|
||||
|
||||
- 수정 전 failure classification을 기록해야 한다.
|
||||
- 모든 변경은 실패 로그 또는 implementation plan acceptance criterion에 trace되어야 한다.
|
||||
- production C++ 수정에는 관련 테스트 또는 기존 실패 테스트가 있어야 한다.
|
||||
- production Fortran 수정에는 관련 테스트 또는 기존 실패 테스트가 있어야 한다.
|
||||
- requirements, formulations, I/O contracts, reference artifacts, tolerance policies는 수정하지 않는다.
|
||||
- 실패 로그는 전체 원문을 복제하지 않고 핵심 tail과 원인 요약만 기록한다.
|
||||
- 동일 classification이 두 번 반복되면 Coordinator Agent 또는 관련 upstream agent로 handoff한다.
|
||||
|
||||
@@ -17,9 +17,9 @@ Formulation Agent는 구현 가능한 FEM 정식화 문서를 작성한다.
|
||||
- Numerical Review Agent가 검토할 handoff 항목을 남긴다.
|
||||
|
||||
수행하지 않는다:
|
||||
- C++ 코드를 구현하지 않는다.
|
||||
- C++ API나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||
- Fortran 코드를 구현하지 않는다.
|
||||
- Fortran source layout이나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV 결과를 생성하지 않는다.
|
||||
- release readiness를 승인하지 않는다.
|
||||
- Numerical Review Agent 검토 전 정식화를 최종 승인하지 않는다.
|
||||
@@ -108,7 +108,7 @@ Formulation Agent는 구현 가능한 FEM 정식화 문서를 작성한다.
|
||||
## Algorithm Pseudocode
|
||||
```text
|
||||
math-level element routine and assembly flow only
|
||||
no C++ signatures, class names, or file paths
|
||||
no Fortran signatures, source layout, or file paths
|
||||
```
|
||||
|
||||
## Numerical Risks
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
이 디렉터리는 Implementation Planning Agent가 작성하거나 제안한 기능별 구현계획 문서를 보관하는 위치다.
|
||||
|
||||
Implementation Planning Agent는 승인된 요구조건, 연구 브리프, 정식화, 수치 리뷰, I/O 정의, reference model 계약을 C++/MSVC 구현 전 TDD 작업계획으로 변환한다. Agent는 코드, 테스트, CMake 파일을 작성하지 않고, Abaqus/Nastran을 실행하지 않으며, reference CSV 생성이나 solver 결과 비교, release readiness 승인도 하지 않는다.
|
||||
Implementation Planning Agent는 승인된 요구조건, 연구 브리프, 정식화, 수치 리뷰, I/O 정의, reference model 계약을 Fortran Abaqus User Subroutine 구현 전 TDD 작업계획으로 변환한다. Agent는 코드와 테스트를 작성하지 않고, Abaqus 해석을 실행하지 않으며, reference CSV 생성이나 solver 결과 비교, release readiness 승인도 하지 않는다.
|
||||
|
||||
기본 파일명은 `docs/implementation-plans/<feature-id>-implementation-plan.md` 형식을 사용한다. 각 문서는 Implementation Agent가 먼저 작성해야 할 실패 테스트, 최소 구현 순서, CMake/CTest 등록 계획, acceptance traceability를 제공해야 한다.
|
||||
|
||||
@@ -18,15 +18,15 @@ Implementation Planning Agent는 승인된 요구조건, 연구 브리프, 정
|
||||
- `python scripts/validate_workspace.py`를 포함한 validation command를 명시한다.
|
||||
|
||||
수행하지 않는다:
|
||||
- C++ 코드를 구현하지 않는다.
|
||||
- Fortran 코드를 구현하지 않는다.
|
||||
- 테스트 파일을 작성하지 않는다.
|
||||
- CMake 파일을 수정하지 않는다.
|
||||
- CMake/CTest를 실행하지 않는다.
|
||||
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV를 생성하지 않는다.
|
||||
- solver 결과를 비교하지 않는다.
|
||||
- release readiness를 승인하지 않는다.
|
||||
- C++ API, class name, storage layout, file ownership을 확정하지 않는다.
|
||||
- Fortran source layout, entry point ownership, file ownership을 확정하지 않는다.
|
||||
|
||||
## 문서 템플릿
|
||||
|
||||
@@ -132,7 +132,7 @@ ctest -C Debug -R <feature-or-label>
|
||||
## 품질 기준
|
||||
|
||||
- 모든 `must` requirement는 최소 하나의 task와 test에 연결되어야 한다.
|
||||
- C++ production 변경마다 선행 테스트 파일 또는 테스트 추가 계획이 있어야 한다.
|
||||
- Fortran production 변경마다 선행 테스트 파일 또는 테스트 추가 계획이 있어야 한다.
|
||||
- reference artifact가 필요한 기능은 `references/<feature-id>/<model-id>/`와 CSV 비교 테스트 계획을 가져야 한다.
|
||||
- CMake/CTest 계획은 MSVC x64 Debug 검증 경로와 호환되어야 한다.
|
||||
- 구현 계획은 테스트 작성, 실패 확인, 최소 구현, validation 순서를 명시해야 한다.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
이 디렉터리는 I/O Definition Agent가 작성하거나 제안한 기능별 입출력 정의 문서를 보관하는 위치다.
|
||||
|
||||
FESA 솔버의 입력 파일은 Abaqus input file이다. 다만 초기 FESA는 Abaqus 전체 문법 호환을 목표로 하지 않고, 기능별로 지원할 Abaqus keyword subset과 내부 모델 매핑을 명확히 정의한다.
|
||||
Abaqus User Subroutine 검증 모델의 입력 파일은 Abaqus input file이다. 이 프로젝트는 Abaqus 전체 문법 호환 parser 개발을 목표로 하지 않고, 기능별로 필요한 Abaqus keyword subset과 결과 CSV schema를 명확히 정의한다.
|
||||
|
||||
기본 파일명은 `docs/io-definitions/<feature-id>-io.md` 형식을 사용한다. 각 문서는 Requirement Agent, Formulation Agent, Numerical Review Agent의 산출물을 입력으로 받아 Abaqus `.inp` 입력 계약과 결과 CSV schema를 정의해야 한다.
|
||||
|
||||
@@ -19,8 +19,8 @@ I/O Definition Agent는 Abaqus input file subset, 내부 solver model mapping, o
|
||||
|
||||
수행하지 않는다:
|
||||
- parser를 구현하지 않는다.
|
||||
- C++ API나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||
- Fortran source layout이나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV 결과를 생성하지 않는다.
|
||||
- solver 결과와 reference 결과를 비교하지 않는다.
|
||||
- release readiness를 승인하지 않는다.
|
||||
@@ -44,7 +44,7 @@ I/O Definition Agent는 Abaqus input file subset, 내부 solver model mapping, o
|
||||
## Abaqus Input Scope
|
||||
- input_format: Abaqus input file (`.inp`)
|
||||
- abaqus_documentation_source: <version/source URL>
|
||||
- compatibility_disclaimer: FESA supports only the keyword subset defined in this document.
|
||||
- compatibility_disclaimer: This feature supports only the keyword subset defined in this document.
|
||||
|
||||
| keyword | support_status | level | required_parameters | mapped_internal_concept | notes |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
@@ -176,5 +176,5 @@ I/O Definition Agent는 Abaqus input file subset, 내부 solver model mapping, o
|
||||
- Abaqus full compatibility를 주장하지 않고 기능별 supported keyword subset을 명시해야 한다.
|
||||
- model data와 history data의 매핑을 구분해야 한다.
|
||||
- unsupported keyword 처리 정책을 명확히 해야 한다.
|
||||
- 내부 모델 계약은 semantic fields로 작성하고 C++ class/function/API를 확정하지 않는다.
|
||||
- 내부 모델 계약은 semantic fields로 작성하고 Fortran source layout이나 helper API를 확정하지 않는다.
|
||||
- CSV schema는 column name, ID field, component naming, coordinate system, units, step/frame identity, quantity location을 포함해야 한다.
|
||||
|
||||
@@ -16,10 +16,10 @@ Numerical Review Agent는 정식화의 수학적 일관성, 수치 안정성 위
|
||||
- 구현 계획 전에 필요한 정식화 수정, 연구 보강, reference model 요구사항을 작성한다.
|
||||
|
||||
수행하지 않는다:
|
||||
- C++ 코드를 구현하지 않는다.
|
||||
- Fortran 코드를 구현하지 않는다.
|
||||
- 정식화 문서를 직접 수정하지 않는다.
|
||||
- C++ API나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||
- Fortran source layout이나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV 결과를 생성하지 않는다.
|
||||
- release readiness를 승인하지 않는다.
|
||||
- 레퍼런스 결과와 구현 솔버 결과의 일치 여부를 판정하지 않는다.
|
||||
|
||||
@@ -22,7 +22,7 @@ Physics Evaluation Agent는 Reference Verification Agent가 `pass-for-physics-ev
|
||||
- CMake files를 수정하지 않는다.
|
||||
- requirements, formulations, I/O contracts, reference model contracts를 수정하지 않는다.
|
||||
- reference artifacts 또는 tolerance policies를 수정하지 않는다.
|
||||
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV를 생성하지 않는다.
|
||||
- reference tolerance를 다시 판정하지 않는다.
|
||||
- release readiness를 승인하지 않는다.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
이 디렉터리는 Reference Model Agent가 작성하거나 제안한 기능별 reference model 설계 문서를 보관하는 위치다.
|
||||
|
||||
Reference Model Agent는 FESA 기능 검증에 필요한 Abaqus `.inp` 기반 테스트 모델 포트폴리오와 `references/<feature-id>/<model-id>/` artifact bundle 계약을 정의한다. Agent는 Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않고, reference CSV 값을 생성하지 않으며, solver 결과 비교나 release readiness 승인도 하지 않는다.
|
||||
Reference Model Agent는 Abaqus User Subroutine 검증에 필요한 Abaqus `.inp` 기반 테스트 모델 포트폴리오와 `references/<feature-id>/<model-id>/` artifact bundle 계약을 정의한다. Agent는 Abaqus 해석을 직접 실행하지 않고, reference CSV 값을 생성하지 않으며, solver 결과 비교나 release readiness 승인도 하지 않는다.
|
||||
|
||||
기본 파일명은 `docs/reference-models/<feature-id>-reference-models.md` 형식을 사용한다. 각 문서는 요구조건, 연구 브리프, 정식화, 수치 리뷰, I/O 정의를 입력으로 받아 구현 전에 준비해야 할 테스트 모델과 reference artifact 요구사항을 정의해야 한다.
|
||||
|
||||
@@ -17,10 +17,10 @@ Reference Model Agent는 FESA 기능 검증에 필요한 Abaqus `.inp` 기반
|
||||
- requirement와 model, compared quantity, tolerance, artifact status를 연결하는 Coverage Matrix를 작성한다.
|
||||
|
||||
수행하지 않는다:
|
||||
- C++ 코드를 구현하지 않는다.
|
||||
- Fortran 코드를 구현하지 않는다.
|
||||
- parser를 구현하지 않는다.
|
||||
- C++ API나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||
- Fortran source layout이나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV를 생성하지 않는다.
|
||||
- solver 결과를 비교하지 않는다.
|
||||
- release readiness를 승인하지 않는다.
|
||||
@@ -67,7 +67,7 @@ Reference Model Agent는 FESA 기능 검증에 필요한 Abaqus `.inp` 기반
|
||||
- purpose: <what this model proves>
|
||||
- verified_requirements: [<requirement-id>]
|
||||
- analysis_type: <linear static | nonlinear static | modal | other>
|
||||
- element_type: <Abaqus element type and FESA feature element>
|
||||
- element_type: <Abaqus element type and subroutine feature scope>
|
||||
- material: <material model and values>
|
||||
- boundary_conditions: <BC summary>
|
||||
- loads: <load summary>
|
||||
@@ -92,25 +92,33 @@ references/
|
||||
<model-id>/
|
||||
model.inp
|
||||
metadata.json
|
||||
displacements.csv
|
||||
reactions.csv
|
||||
element_forces.csv
|
||||
stresses.csv
|
||||
job.msg.tail.txt
|
||||
job.dat.tail.txt
|
||||
job.log.tail.txt
|
||||
job.sta.tail.txt
|
||||
result.odb.sha256
|
||||
extraction/
|
||||
extract_odb_to_csv.py
|
||||
extracted/
|
||||
displacements.csv
|
||||
reactions.csv
|
||||
element_forces.csv
|
||||
stresses.csv
|
||||
README.md
|
||||
```
|
||||
|
||||
Required files:
|
||||
- `model.inp`: Abaqus input file for the reference model.
|
||||
- `metadata.json`: provenance and model contract metadata.
|
||||
- `displacements.csv`: nodal displacement reference results.
|
||||
- `reactions.csv`: nodal reaction force reference results.
|
||||
- `element_forces.csv`: element internal force reference results.
|
||||
- `stresses.csv`: stress reference results.
|
||||
- `.msg/.dat/.log/.sta` tail files: externally generated Abaqus job evidence.
|
||||
- `extracted/*.csv`: ODB-extracted CSV reference results declared in `metadata.json`.
|
||||
- `README.md`: short description, generation notes, and limitations.
|
||||
|
||||
Optional files:
|
||||
- `strains.csv`: strain reference results when required.
|
||||
- `energy_or_residual.csv`: energy, residual, or convergence reference results when required.
|
||||
- `result.odb.sha256`: ODB hash evidence when the ODB itself is not stored.
|
||||
- `extraction/extract_odb_to_csv.py`: copy of the user-run extraction script when available.
|
||||
- `extracted/strains.csv`: strain reference results when required.
|
||||
- `extracted/energy_or_residual.csv`: energy, residual, or convergence reference results when required.
|
||||
- `notes.md`: manual review notes.
|
||||
|
||||
## Metadata JSON Contract
|
||||
@@ -216,8 +224,7 @@ For Fortran Abaqus UserSubroutine work, each stored artifact bundle may include
|
||||
"artifact_status": "draft | needs-reference-artifacts | ready-for-comparison | blocked",
|
||||
"abaqus": {
|
||||
"version": "<Abaqus version>",
|
||||
"precision": "single | double",
|
||||
"command": "abaqus job=<job> user=<subroutine>"
|
||||
"precision": "single | double"
|
||||
},
|
||||
"compiler": {
|
||||
"vendor": "Intel oneAPI",
|
||||
@@ -239,13 +246,59 @@ For Fortran Abaqus UserSubroutine work, each stored artifact bundle may include
|
||||
"tails": {
|
||||
"msg": "job.msg.tail.txt",
|
||||
"dat": "job.dat.tail.txt",
|
||||
"log": "job.log.tail.txt"
|
||||
"log": "job.log.tail.txt",
|
||||
"sta": "job.sta.tail.txt"
|
||||
},
|
||||
"csv": {
|
||||
"stresses": "stresses.csv"
|
||||
"stresses": "extracted/stresses.csv"
|
||||
}
|
||||
},
|
||||
"extraction": {
|
||||
"source_odb": "job.odb",
|
||||
"tool": "Abaqus Python",
|
||||
"extracted_at": "<ISO-8601 datetime>",
|
||||
"csv_directory": "extracted",
|
||||
"script": "extraction/extract_odb_to_csv.py",
|
||||
"odb_sha256_file": "result.odb.sha256"
|
||||
},
|
||||
"comparisons": {
|
||||
"stresses": {
|
||||
"reference_csv": "extracted/stresses.csv",
|
||||
"actual_csv": "extracted/stresses.csv",
|
||||
"required_columns": [
|
||||
"step",
|
||||
"frame",
|
||||
"instance",
|
||||
"element_label",
|
||||
"integration_point",
|
||||
"section_point",
|
||||
"output_position",
|
||||
"component",
|
||||
"coordinate_system",
|
||||
"unit",
|
||||
"value"
|
||||
],
|
||||
"key_columns": [
|
||||
"step",
|
||||
"frame",
|
||||
"instance",
|
||||
"element_label",
|
||||
"integration_point",
|
||||
"section_point",
|
||||
"output_position",
|
||||
"component"
|
||||
],
|
||||
"value_column": "value",
|
||||
"unit_column": "unit",
|
||||
"coordinate_system_column": "coordinate_system",
|
||||
"tolerance": {
|
||||
"absolute": 1.0e-8,
|
||||
"relative": 1.0e-6,
|
||||
"relative_floor": 1.0e-12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`artifact_status=ready-for-comparison` means `scripts/validate_reference_artifacts.py` must find all declared files and confirm source SHA-256 values. Agents must not generate or edit the declared reference CSVs unless an explicit reference-artifact phase authorizes that work.
|
||||
`artifact_status=ready-for-comparison` means `scripts/validate_reference_artifacts.py` must find all declared files, confirm source SHA-256 values, require `.msg/.dat/.log/.sta` tails, require ODB extraction provenance, and require declared CSVs to match `extracted/*.csv`. `comparisons` defines the executable CSV schema, row key, and tolerance contract for `scripts/compare_extracted_csv.py`. Agents must not generate or edit the declared reference CSVs unless an explicit reference-artifact phase authorizes that work.
|
||||
|
||||
@@ -14,7 +14,7 @@ Reference Verification Agent는 Build/Test Executor Agent 통과 후 generated s
|
||||
- `displacements.csv`, `reactions.csv`, `element_forces.csv`, `stresses.csv`를 기본 비교 대상으로 삼는다.
|
||||
- upstream 문서가 요구할 때만 `strains.csv`, `energy_or_residual.csv`를 추가 비교한다.
|
||||
- max absolute error, max relative error, RMS error, norm error, worst node/element/component, missing rows, extra rows, pass/fail을 보고한다.
|
||||
- 실패를 missing-reference-artifact, missing-solver-output, schema-mismatch, id-mismatch, unit-or-coordinate-mismatch, tolerance-failure, nonfinite-result, upstream-contract, environment로 분류한다.
|
||||
- 실패를 missing-reference-artifact, missing-generated-output, schema-mismatch, id-mismatch, unit-or-coordinate-mismatch, tolerance-failure, nonfinite-result, upstream-contract, environment로 분류한다.
|
||||
|
||||
수행하지 않는다:
|
||||
- source code를 수정하지 않는다.
|
||||
@@ -22,7 +22,7 @@ Reference Verification Agent는 Build/Test Executor Agent 통과 후 generated s
|
||||
- CMake files를 수정하지 않는다.
|
||||
- requirements, formulations, I/O contracts, reference model contracts를 수정하지 않는다.
|
||||
- reference artifacts 또는 tolerance policies를 수정하지 않는다.
|
||||
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV를 생성하지 않는다.
|
||||
- solver output CSV를 tolerance에 맞추기 위해 보정하지 않는다.
|
||||
- physics validation success 또는 release readiness를 승인하지 않는다.
|
||||
@@ -63,7 +63,7 @@ ARTIFACT CHECK -> COMPARE -> CLASSIFY -> REPORT
|
||||
## Failure Classification
|
||||
|
||||
- `missing-reference-artifact`: required stored reference file 또는 provenance가 없다.
|
||||
- `missing-solver-output`: generated solver result CSV 또는 comparison command가 없다.
|
||||
- `missing-generated-output`: externally generated actual CSV 또는 comparison command가 없다.
|
||||
- `schema-mismatch`: reference CSV와 solver CSV column/schema가 다르다.
|
||||
- `id-mismatch`: node id, element id, step/frame, integration point, component matching이 실패했다.
|
||||
- `unit-or-coordinate-mismatch`: units 또는 coordinate system이 비교 가능하지 않다.
|
||||
@@ -120,7 +120,7 @@ ARTIFACT CHECK -> COMPARE -> CLASSIFY -> REPORT
|
||||
| stress | <model-id> | stresses.csv | <n> | <n> | <n> | <value> | <value> | <value> | <value or N/A> | <element/ip id> | <component> | pass | fail |
|
||||
|
||||
## Failure Classification
|
||||
- classification: missing-reference-artifact | missing-solver-output | schema-mismatch | id-mismatch | unit-or-coordinate-mismatch | tolerance-failure | nonfinite-result | upstream-contract | environment | N/A
|
||||
- classification: missing-reference-artifact | missing-generated-output | schema-mismatch | id-mismatch | unit-or-coordinate-mismatch | tolerance-failure | nonfinite-result | upstream-contract | environment | N/A
|
||||
- primary_failure: <short summary>
|
||||
- evidence: <short relevant excerpt or computed metric>
|
||||
|
||||
@@ -166,3 +166,19 @@ ARTIFACT CHECK -> COMPARE -> CLASSIFY -> REPORT
|
||||
- NaN 또는 infinite value는 `nonfinite-result`로 분류한다.
|
||||
- pass는 reference tolerance 통과만 의미한다.
|
||||
- physics validation과 release readiness는 각각 Physics Evaluation Agent와 Release Agent가 판정한다.
|
||||
|
||||
## CSV Comparison Command
|
||||
|
||||
Run explicit external-result comparison with:
|
||||
|
||||
```bash
|
||||
python scripts/compare_extracted_csv.py --metadata references/<feature-id>/<model-id>/metadata.json --actual-root external-results/<feature-id>/<model-id>
|
||||
```
|
||||
|
||||
Optional quantity filtering and JSON report output:
|
||||
|
||||
```bash
|
||||
python scripts/compare_extracted_csv.py --metadata references/umat/single-element/metadata.json --actual-root external-results/umat/single-element --quantity stresses --report-json build/reference-verification/umat-single-element.json
|
||||
```
|
||||
|
||||
This command does not run Abaqus and does not parse ODB files. It compares approved `references/.../extracted/*.csv` files with externally generated actual CSV files under `--actual-root` using the `comparisons` block in `metadata.json`.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
이 디렉터리는 Release Agent가 작성하거나 제안하는 기능별 release readiness report를 보관하는 위치다.
|
||||
|
||||
Release Agent는 Physics Evaluation Agent가 `pass-for-release-agent`로 넘긴 기능에 대해 최종 gate evidence를 감사한다. 이 Agent는 source code, tests, CMake, upstream 계약, reference artifacts, tolerance policies를 수정하지 않는다. 또한 Abaqus/Nastran 실행, reference CSV 생성, 외부 publish/deploy/package/tag/commit 작업을 수행하지 않는다.
|
||||
Release Agent는 Physics Evaluation Agent가 `pass-for-release-agent`로 넘긴 기능에 대해 최종 gate evidence를 감사한다. 이 Agent는 source code, tests, upstream 계약, reference artifacts, tolerance policies를 수정하지 않는다. 또한 Abaqus 해석 실행, reference CSV 생성, 외부 publish/deploy/package/tag/commit 작업을 수행하지 않는다.
|
||||
|
||||
기본 문서명은 `docs/releases/<feature-id>-release.md` 형식을 사용한다.
|
||||
|
||||
@@ -23,7 +23,7 @@ Release Agent는 Physics Evaluation Agent가 `pass-for-release-agent`로 넘긴
|
||||
- CMake files 또는 build configuration을 수정하지 않는다.
|
||||
- requirements, formulations, I/O contracts, numerical review reports, reference verification reports, physics evaluation reports를 수정하지 않는다.
|
||||
- reference artifacts 또는 tolerance policies를 수정하지 않는다.
|
||||
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV를 생성하지 않는다.
|
||||
- 실패하거나 누락된 upstream gate를 우회하지 않는다.
|
||||
- 사용자 명시 요청 없이 publish, deploy, package, tag, commit, external release를 수행하지 않는다.
|
||||
@@ -168,4 +168,4 @@ GATE AUDIT -> TRACEABILITY CHECK -> RELEASE DOCUMENTATION -> RELEASE VERDICT
|
||||
- 모든 `must` requirement는 acceptance criterion, test/reference evidence, release scope에 trace되어야 한다.
|
||||
- known limitations와 deferred/open issue는 Release Notes Draft에 명확히 기록되어야 한다.
|
||||
- missing evidence, contradictory upstream reports, unresolved defects, incomplete reference artifacts는 release pass가 아니라 적절한 `needs-*` 상태로 분류한다.
|
||||
- 이 문서는 FESA 내부 feature release readiness 판정을 위한 것이며, 외부 publish/deploy/package/tag/commit 자동화는 포함하지 않는다.
|
||||
- 이 문서는 Abaqus User Subroutine feature의 내부 readiness 판정을 위한 것이며, 외부 publish/deploy/package/tag/commit 자동화는 포함하지 않는다.
|
||||
|
||||
@@ -16,10 +16,10 @@ Requirement Agent는 솔버 기능 요청을 검증 가능한 요구조건으로
|
||||
- Requirement Verification Matrix를 작성한다.
|
||||
|
||||
수행하지 않는다:
|
||||
- C++ 코드를 구현하지 않는다.
|
||||
- Fortran 코드를 구현하지 않는다.
|
||||
- 유한요소 정식화를 확정하지 않는다.
|
||||
- C++ API나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||
- Fortran source layout이나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV 결과를 생성하지 않는다.
|
||||
- 기능 완료 여부를 승인하지 않는다.
|
||||
|
||||
@@ -87,7 +87,7 @@ Expected location: `references/<feature-id>/`
|
||||
|
||||
| id | statement | category | rationale | source | priority | verification_method | acceptance_criteria | tolerance | downstream_agents | status |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| FESA-REQ-<FEATURE>-001 | The FESA solver shall ... | functional | ... | user | must | reference-comparison | ... | ... | Reference Model Agent; Implementation Planning Agent | draft |
|
||||
| ABAQUS-USUB-REQ-<FEATURE>-001 | The user subroutine shall ... | functional | ... | user | must | reference-comparison | ... | ... | Reference Model Agent; Implementation Planning Agent | draft |
|
||||
|
||||
## Open Questions
|
||||
- <미확정 값 또는 사용자 결정 필요 사항>
|
||||
@@ -116,4 +116,4 @@ Expected location: `references/<feature-id>/`
|
||||
- 모든 수치 요구조건은 단위, 좌표계, tolerance 또는 `TBD with owner`를 가져야 한다.
|
||||
- reference 비교가 필요한 요구조건은 필요한 CSV artifact를 명시해야 한다.
|
||||
- "빠르게", "정확하게", "Abaqus처럼" 같은 문장은 검증 가능한 기준으로 바꾸거나 open question으로 남겨야 한다.
|
||||
- 구현 방법, 정식화 세부식, C++ API는 이 문서에서 확정하지 않는다.
|
||||
- 구현 방법, 정식화 세부식, Fortran source layout은 이 문서에서 확정하지 않는다.
|
||||
|
||||
@@ -11,15 +11,15 @@ Research Agent는 FEM 이론, benchmark, verification reference, solver manual,
|
||||
수행한다:
|
||||
- 기능 요구조건과 관련된 이론 자료를 조사한다.
|
||||
- 요소별 benchmark, patch test, MMS, MES, convergence study 후보를 찾는다.
|
||||
- Abaqus/Nastran 결과와 비교 가능한 공개 benchmark 또는 문헌 해를 정리한다.
|
||||
- Abaqus 결과와 비교 가능한 공개 benchmark 또는 문헌 해를 정리한다.
|
||||
- 자료의 신뢰도, 적용 범위, 한계, 상충 여부를 평가한다.
|
||||
- downstream agent가 사용할 수 있도록 출처와 근거를 추적 가능하게 남긴다.
|
||||
|
||||
수행하지 않는다:
|
||||
- C++ 코드를 구현하지 않는다.
|
||||
- Fortran 코드를 구현하지 않는다.
|
||||
- 유한요소 정식화를 확정하지 않는다.
|
||||
- C++ API나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||
- Fortran source layout이나 파일 구조를 설계하지 않는다.
|
||||
- Abaqus 해석을 직접 실행하지 않는다.
|
||||
- reference CSV 결과를 생성하지 않는다.
|
||||
- 기능 완료 여부를 승인하지 않는다.
|
||||
|
||||
|
||||
@@ -0,0 +1,706 @@
|
||||
# CSV Schema/Tolerance Comparison Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add a no-Abaqus CSV comparison script that validates externally generated ODB-extracted actual CSV files against approved reference CSV artifacts by schema, row identity, units/coordinate metadata, and tolerance.
|
||||
|
||||
**Architecture:** Keep `scripts/validate_reference_artifacts.py` responsible for artifact completeness only. Add `scripts/compare_extracted_csv.py` as an explicit CLI tool that reads `references/<feature-id>/<model-id>/metadata.json`, validates the reference bundle, loads actual CSVs from a user-provided external result bundle, compares rows using declared schema/tolerance rules, and emits pass/fail plus optional JSON evidence. Do not integrate this into default `scripts/validate_workspace.py` because actual CSVs are generated outside this project and may not exist on every machine.
|
||||
|
||||
**Tech Stack:** Python standard library only (`argparse`, `csv`, `json`, `math`, `dataclasses`, `pathlib`, `statistics` or direct RMS math), existing `unittest` test style, existing reference artifact metadata contract.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
- Create: `scripts/compare_extracted_csv.py`
|
||||
- CLI and importable functions for loading metadata, resolving CSV paths, validating CSV schema, matching rows, computing tolerance metrics, classifying failures, and emitting text/JSON reports.
|
||||
- Create: `scripts/test_compare_extracted_csv.py`
|
||||
- TDD coverage for pass, schema mismatch, missing actual output, ID mismatch, unit/coordinate mismatch, nonfinite values, and tolerance failure.
|
||||
- Modify: `docs/reference-verifications/README.md`
|
||||
- Document CLI usage, metadata comparison contract, failure classifications, and expected report fields.
|
||||
- Modify: `docs/reference-models/README.md`
|
||||
- Add optional `comparisons` metadata block to the artifact bundle example.
|
||||
- Do not modify: `scripts/validate_workspace.py`
|
||||
- CSV comparison needs explicit actual output paths, so it stays outside default workspace validation.
|
||||
|
||||
## Metadata Contract
|
||||
|
||||
Add an optional `comparisons` block to `metadata.json`. The comparison script requires this block for quantities it compares, but `validate_reference_artifacts.py` does not need to require it for all `ready-for-comparison` bundles.
|
||||
|
||||
```json
|
||||
{
|
||||
"comparisons": {
|
||||
"stresses": {
|
||||
"reference_csv": "extracted/stresses.csv",
|
||||
"actual_csv": "extracted/stresses.csv",
|
||||
"required_columns": [
|
||||
"step",
|
||||
"frame",
|
||||
"instance",
|
||||
"element_label",
|
||||
"integration_point",
|
||||
"section_point",
|
||||
"output_position",
|
||||
"component",
|
||||
"coordinate_system",
|
||||
"unit",
|
||||
"value"
|
||||
],
|
||||
"key_columns": [
|
||||
"step",
|
||||
"frame",
|
||||
"instance",
|
||||
"element_label",
|
||||
"integration_point",
|
||||
"section_point",
|
||||
"output_position",
|
||||
"component"
|
||||
],
|
||||
"value_column": "value",
|
||||
"unit_column": "unit",
|
||||
"coordinate_system_column": "coordinate_system",
|
||||
"tolerance": {
|
||||
"absolute": 1.0e-8,
|
||||
"relative": 1.0e-6,
|
||||
"relative_floor": 1.0e-12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Tolerance rule:
|
||||
|
||||
```text
|
||||
absolute_error = abs(actual - reference)
|
||||
relative_error = absolute_error / max(abs(reference), relative_floor)
|
||||
allowed_error = absolute + relative * max(abs(reference), relative_floor)
|
||||
row_pass = absolute_error <= allowed_error
|
||||
quantity_pass = all rows pass and no schema/id/unit/coordinate/nonfinite errors exist
|
||||
```
|
||||
|
||||
## CLI Contract
|
||||
|
||||
Primary command:
|
||||
|
||||
```bash
|
||||
python scripts/compare_extracted_csv.py --metadata references/<feature-id>/<model-id>/metadata.json --actual-root external-results/<feature-id>/<model-id>
|
||||
```
|
||||
|
||||
Optional filters and report output:
|
||||
|
||||
```bash
|
||||
python scripts/compare_extracted_csv.py --metadata references/umat/single-element/metadata.json --actual-root external-results/umat/single-element --quantity stresses --report-json build/reference-verification/umat-single-element.json
|
||||
```
|
||||
|
||||
Exit codes:
|
||||
|
||||
- `0`: every requested quantity passed.
|
||||
- `1`: comparison completed and one or more quantities failed.
|
||||
- `2`: invalid CLI arguments, invalid metadata, missing files, or unreadable CSV.
|
||||
|
||||
## Failure Classification
|
||||
|
||||
The script should produce one primary classification per failed quantity:
|
||||
|
||||
- `missing-reference-artifact`: declared reference CSV is absent after metadata validation.
|
||||
- `missing-generated-output`: actual CSV under `--actual-root` is absent.
|
||||
- `schema-mismatch`: required columns are missing, duplicate headers exist, or duplicate key rows exist.
|
||||
- `id-mismatch`: missing or extra key rows exist.
|
||||
- `unit-or-coordinate-mismatch`: matched rows disagree on unit or coordinate system.
|
||||
- `nonfinite-result`: reference or actual `value` is NaN or infinite.
|
||||
- `tolerance-failure`: schema, IDs, unit, and coordinate checks pass, but numeric error exceeds tolerance.
|
||||
- `upstream-contract`: requested quantity has no `comparisons.<quantity>` contract.
|
||||
- `environment`: file cannot be read due to encoding or OS errors.
|
||||
|
||||
## Report Contract
|
||||
|
||||
Text output should be concise and machine-adjacent:
|
||||
|
||||
```text
|
||||
PASS stresses rows=8 max_abs_error=1.2e-10 max_rel_error=3.0e-9 rms_error=8.1e-11 worst_key=Step-1|1|PART-1-1|1|1||INTEGRATION_POINT|S11
|
||||
```
|
||||
|
||||
Failed quantity example:
|
||||
|
||||
```text
|
||||
FAIL stresses classification=tolerance-failure rows=8 max_abs_error=2.4e-4 max_rel_error=1.2e-2 rms_error=8.5e-5 worst_key=Step-1|1|PART-1-1|1|1||INTEGRATION_POINT|S11
|
||||
```
|
||||
|
||||
JSON report should contain:
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": "references/umat/single-element/metadata.json",
|
||||
"actual_root": "external-results/umat/single-element",
|
||||
"overall_result": "pass",
|
||||
"quantities": [
|
||||
{
|
||||
"quantity": "stresses",
|
||||
"result": "pass",
|
||||
"classification": "N/A",
|
||||
"compared_rows": 8,
|
||||
"missing_rows": 0,
|
||||
"extra_rows": 0,
|
||||
"max_abs_error": 1.2e-10,
|
||||
"max_rel_error": 3.0e-9,
|
||||
"rms_error": 8.1e-11,
|
||||
"worst_key": "Step-1|1|PART-1-1|1|1||INTEGRATION_POINT|S11",
|
||||
"worst_component": "S11"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Write Pass-Case Test Fixture
|
||||
|
||||
**Files:**
|
||||
- Create: `scripts/test_compare_extracted_csv.py`
|
||||
|
||||
- [ ] **Step 1: Write dynamic import and fixture helpers**
|
||||
|
||||
```python
|
||||
import csv
|
||||
import importlib.util
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def load_compare_extracted_csv():
|
||||
module_path = Path(__file__).resolve().parent / "compare_extracted_csv.py"
|
||||
spec = importlib.util.spec_from_file_location("compare_extracted_csv", module_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def write_json(path: Path, payload: dict):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
||||
|
||||
|
||||
def write_csv(path: Path, rows: list[dict[str, str]]):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with path.open("w", newline="", encoding="utf-8") as handle:
|
||||
writer = csv.DictWriter(handle, fieldnames=list(rows[0]))
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
|
||||
|
||||
def metadata_payload() -> dict:
|
||||
return {
|
||||
"schema_version": "abaqus-user-subroutine-artifact-v1",
|
||||
"feature_id": "umat",
|
||||
"model_id": "single-element",
|
||||
"artifact_status": "ready-for-comparison",
|
||||
"abaqus": {"version": "2024", "precision": "double"},
|
||||
"compiler": {"vendor": "Intel oneAPI", "name": "ifx", "version": "2024"},
|
||||
"subroutine": {"entry_points": ["UMAT"], "source_files": []},
|
||||
"input_file": "model.inp",
|
||||
"outputs": {
|
||||
"tails": {
|
||||
"msg": "job.msg.tail.txt",
|
||||
"dat": "job.dat.tail.txt",
|
||||
"log": "job.log.tail.txt",
|
||||
"sta": "job.sta.tail.txt"
|
||||
},
|
||||
"csv": {"stresses": "extracted/stresses.csv"}
|
||||
},
|
||||
"extraction": {
|
||||
"source_odb": "job.odb",
|
||||
"tool": "Abaqus Python",
|
||||
"extracted_at": "2026-06-10T00:00:00+09:00",
|
||||
"csv_directory": "extracted"
|
||||
},
|
||||
"comparisons": {
|
||||
"stresses": {
|
||||
"reference_csv": "extracted/stresses.csv",
|
||||
"actual_csv": "extracted/stresses.csv",
|
||||
"required_columns": [
|
||||
"step", "frame", "instance", "element_label", "integration_point",
|
||||
"section_point", "output_position", "component",
|
||||
"coordinate_system", "unit", "value"
|
||||
],
|
||||
"key_columns": [
|
||||
"step", "frame", "instance", "element_label", "integration_point",
|
||||
"section_point", "output_position", "component"
|
||||
],
|
||||
"value_column": "value",
|
||||
"unit_column": "unit",
|
||||
"coordinate_system_column": "coordinate_system",
|
||||
"tolerance": {"absolute": 1.0e-8, "relative": 1.0e-6, "relative_floor": 1.0e-12}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def stress_rows(value: str = "100.0") -> list[dict[str, str]]:
|
||||
return [
|
||||
{
|
||||
"step": "Step-1",
|
||||
"frame": "1",
|
||||
"instance": "PART-1-1",
|
||||
"element_label": "1",
|
||||
"integration_point": "1",
|
||||
"section_point": "",
|
||||
"output_position": "INTEGRATION_POINT",
|
||||
"component": "S11",
|
||||
"coordinate_system": "GLOBAL",
|
||||
"unit": "MPa",
|
||||
"value": value
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Write passing comparison test**
|
||||
|
||||
```python
|
||||
class CompareExtractedCsvTests(unittest.TestCase):
|
||||
def test_quantity_passes_when_schema_keys_units_and_values_match_within_tolerance(self):
|
||||
compare = load_compare_extracted_csv()
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
reference = root / "references" / "umat" / "single-element"
|
||||
actual = root / "external-results" / "umat" / "single-element"
|
||||
write_json(reference / "metadata.json", metadata_payload())
|
||||
write_csv(reference / "extracted" / "stresses.csv", stress_rows("100.0"))
|
||||
write_csv(actual / "extracted" / "stresses.csv", stress_rows("100.00000001"))
|
||||
|
||||
report = compare.compare_metadata(reference / "metadata.json", actual, quantities=["stresses"], validate_artifacts=False)
|
||||
|
||||
self.assertEqual(report["overall_result"], "pass")
|
||||
self.assertEqual(report["quantities"][0]["result"], "pass")
|
||||
self.assertEqual(report["quantities"][0]["classification"], "N/A")
|
||||
self.assertEqual(report["quantities"][0]["compared_rows"], 1)
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Run test to verify RED**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python -m unittest scripts.test_compare_extracted_csv
|
||||
```
|
||||
|
||||
Expected: FAIL because `scripts/compare_extracted_csv.py` does not exist.
|
||||
|
||||
### Task 2: Implement Minimal Pass-Case Comparison
|
||||
|
||||
**Files:**
|
||||
- Create: `scripts/compare_extracted_csv.py`
|
||||
|
||||
- [ ] **Step 1: Add importable API skeleton and minimal comparison**
|
||||
|
||||
Implement these functions:
|
||||
|
||||
```python
|
||||
def compare_metadata(metadata_path: Path, actual_root: Path, *, quantities: list[str] | None = None, validate_artifacts: bool = True) -> dict:
|
||||
...
|
||||
|
||||
def load_csv_rows(path: Path) -> tuple[list[str], list[dict[str, str]]]:
|
||||
...
|
||||
|
||||
def compare_quantity(quantity: str, contract: dict, reference_root: Path, actual_root: Path) -> dict:
|
||||
...
|
||||
```
|
||||
|
||||
Minimum behavior for GREEN:
|
||||
- Load metadata JSON.
|
||||
- Resolve `comparisons.<quantity>.reference_csv` under `metadata_path.parent`.
|
||||
- Resolve `comparisons.<quantity>.actual_csv` under `actual_root`.
|
||||
- Load both CSV files with `csv.DictReader`.
|
||||
- Check required columns are present.
|
||||
- Match rows by `key_columns`.
|
||||
- Parse `value_column` as finite float.
|
||||
- Compute `max_abs_error`, `max_rel_error`, `rms_error`, `worst_key`.
|
||||
- Return `overall_result=pass` if no errors exceed tolerance.
|
||||
|
||||
- [ ] **Step 2: Run pass-case test**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python -m unittest scripts.test_compare_extracted_csv
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 3: Add Schema and Contract Failure Tests
|
||||
|
||||
**Files:**
|
||||
- Modify: `scripts/test_compare_extracted_csv.py`
|
||||
- Modify: `scripts/compare_extracted_csv.py`
|
||||
|
||||
- [ ] **Step 1: Add missing actual output test**
|
||||
|
||||
```python
|
||||
def test_missing_actual_csv_is_missing_generated_output(self):
|
||||
compare = load_compare_extracted_csv()
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
reference = root / "references" / "umat" / "single-element"
|
||||
actual = root / "external-results" / "umat" / "single-element"
|
||||
write_json(reference / "metadata.json", metadata_payload())
|
||||
write_csv(reference / "extracted" / "stresses.csv", stress_rows("100.0"))
|
||||
|
||||
report = compare.compare_metadata(reference / "metadata.json", actual, quantities=["stresses"], validate_artifacts=False)
|
||||
|
||||
self.assertEqual(report["overall_result"], "fail")
|
||||
self.assertEqual(report["quantities"][0]["classification"], "missing-generated-output")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add missing required column test**
|
||||
|
||||
```python
|
||||
def test_missing_required_column_is_schema_mismatch(self):
|
||||
compare = load_compare_extracted_csv()
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
reference = root / "references" / "umat" / "single-element"
|
||||
actual = root / "external-results" / "umat" / "single-element"
|
||||
write_json(reference / "metadata.json", metadata_payload())
|
||||
row = stress_rows("100.0")[0]
|
||||
write_csv(reference / "extracted" / "stresses.csv", [row])
|
||||
actual_row = dict(row)
|
||||
actual_row.pop("coordinate_system")
|
||||
write_csv(actual / "extracted" / "stresses.csv", [actual_row])
|
||||
|
||||
report = compare.compare_metadata(reference / "metadata.json", actual, quantities=["stresses"], validate_artifacts=False)
|
||||
|
||||
self.assertEqual(report["quantities"][0]["classification"], "schema-mismatch")
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Add missing comparison contract test**
|
||||
|
||||
```python
|
||||
def test_missing_quantity_contract_is_upstream_contract(self):
|
||||
compare = load_compare_extracted_csv()
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
reference = root / "references" / "umat" / "single-element"
|
||||
actual = root / "external-results" / "umat" / "single-element"
|
||||
payload = metadata_payload()
|
||||
payload["comparisons"].pop("stresses")
|
||||
write_json(reference / "metadata.json", payload)
|
||||
|
||||
report = compare.compare_metadata(reference / "metadata.json", actual, quantities=["stresses"], validate_artifacts=False)
|
||||
|
||||
self.assertEqual(report["quantities"][0]["classification"], "upstream-contract")
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run tests to verify RED**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python -m unittest scripts.test_compare_extracted_csv
|
||||
```
|
||||
|
||||
Expected: FAIL on the new failure classifications.
|
||||
|
||||
- [ ] **Step 5: Implement missing file, schema, and contract classification**
|
||||
|
||||
Add helper functions:
|
||||
|
||||
```python
|
||||
def failed_quantity(quantity: str, classification: str, message: str) -> dict:
|
||||
...
|
||||
|
||||
def validate_columns(headers: list[str], required_columns: list[str]) -> list[str]:
|
||||
...
|
||||
```
|
||||
|
||||
Return stable fields even on failure:
|
||||
|
||||
```python
|
||||
{
|
||||
"quantity": quantity,
|
||||
"result": "fail",
|
||||
"classification": classification,
|
||||
"message": message,
|
||||
"compared_rows": 0,
|
||||
"missing_rows": 0,
|
||||
"extra_rows": 0,
|
||||
"max_abs_error": None,
|
||||
"max_rel_error": None,
|
||||
"rms_error": None,
|
||||
"worst_key": None,
|
||||
"worst_component": None
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Run tests to verify GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python -m unittest scripts.test_compare_extracted_csv
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 4: Add Row Matching, Unit, Coordinate, Nonfinite, and Tolerance Tests
|
||||
|
||||
**Files:**
|
||||
- Modify: `scripts/test_compare_extracted_csv.py`
|
||||
- Modify: `scripts/compare_extracted_csv.py`
|
||||
|
||||
- [ ] **Step 1: Add ID mismatch test**
|
||||
|
||||
Change actual `element_label` from `1` to `2`. Expected classification: `id-mismatch`, with `missing_rows=1` and `extra_rows=1`.
|
||||
|
||||
- [ ] **Step 2: Add unit mismatch test**
|
||||
|
||||
Change actual `unit` from `MPa` to `Pa`. Expected classification: `unit-or-coordinate-mismatch`.
|
||||
|
||||
- [ ] **Step 3: Add coordinate mismatch test**
|
||||
|
||||
Change actual `coordinate_system` from `GLOBAL` to `LOCAL-1`. Expected classification: `unit-or-coordinate-mismatch`.
|
||||
|
||||
- [ ] **Step 4: Add nonfinite test**
|
||||
|
||||
Set actual `value` to `nan`. Expected classification: `nonfinite-result`.
|
||||
|
||||
- [ ] **Step 5: Add tolerance failure test**
|
||||
|
||||
Set actual `value` to `101.0` for reference `100.0`. Expected classification: `tolerance-failure`, `max_abs_error=1.0`, and `result=fail`.
|
||||
|
||||
- [ ] **Step 6: Run tests to verify RED**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python -m unittest scripts.test_compare_extracted_csv
|
||||
```
|
||||
|
||||
Expected: FAIL until these classifications are implemented.
|
||||
|
||||
- [ ] **Step 7: Implement row matching and classification precedence**
|
||||
|
||||
Use this precedence:
|
||||
|
||||
```text
|
||||
missing-reference-artifact
|
||||
missing-generated-output
|
||||
upstream-contract
|
||||
schema-mismatch
|
||||
id-mismatch
|
||||
nonfinite-result
|
||||
unit-or-coordinate-mismatch
|
||||
tolerance-failure
|
||||
N/A
|
||||
```
|
||||
|
||||
Implement row keys as:
|
||||
|
||||
```python
|
||||
def make_key(row: dict[str, str], key_columns: list[str]) -> tuple[str, ...]:
|
||||
return tuple(row.get(column, "") for column in key_columns)
|
||||
```
|
||||
|
||||
Detect duplicate keys in either CSV as `schema-mismatch`.
|
||||
|
||||
- [ ] **Step 8: Run tests to verify GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python -m unittest scripts.test_compare_extracted_csv
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 5: Add CLI and JSON Report Tests
|
||||
|
||||
**Files:**
|
||||
- Modify: `scripts/test_compare_extracted_csv.py`
|
||||
- Modify: `scripts/compare_extracted_csv.py`
|
||||
|
||||
- [ ] **Step 1: Add CLI pass test using `main(argv)`**
|
||||
|
||||
Test:
|
||||
|
||||
```python
|
||||
exit_code = compare.main([
|
||||
"--metadata", str(reference / "metadata.json"),
|
||||
"--actual-root", str(actual),
|
||||
"--quantity", "stresses",
|
||||
"--report-json", str(report_json)
|
||||
])
|
||||
self.assertEqual(exit_code, 0)
|
||||
self.assertEqual(json.loads(report_json.read_text(encoding="utf-8"))["overall_result"], "pass")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add CLI fail test**
|
||||
|
||||
Use a tolerance failure fixture. Expected `main(...) == 1` and JSON `overall_result == "fail"`.
|
||||
|
||||
- [ ] **Step 3: Add CLI invalid argument test**
|
||||
|
||||
Call without `--metadata` or `--actual-root`. Expected `main(...) == 2`.
|
||||
|
||||
- [ ] **Step 4: Run tests to verify RED**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python -m unittest scripts.test_compare_extracted_csv
|
||||
```
|
||||
|
||||
Expected: FAIL until CLI exists.
|
||||
|
||||
- [ ] **Step 5: Implement CLI**
|
||||
|
||||
Implement:
|
||||
|
||||
```python
|
||||
def build_arg_parser() -> argparse.ArgumentParser:
|
||||
...
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
...
|
||||
```
|
||||
|
||||
CLI behavior:
|
||||
- `--quantity` may be repeated.
|
||||
- If no `--quantity` is supplied, compare all keys under `metadata["comparisons"]`.
|
||||
- `--report-json` creates parent directories and writes UTF-8 JSON.
|
||||
- Print one summary line per quantity.
|
||||
- Return `0`, `1`, or `2` according to the CLI contract.
|
||||
|
||||
- [ ] **Step 6: Run tests to verify GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python -m unittest scripts.test_compare_extracted_csv
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 6: Optional Artifact Validator Integration
|
||||
|
||||
**Files:**
|
||||
- Modify: `scripts/compare_extracted_csv.py`
|
||||
- Modify: `scripts/test_compare_extracted_csv.py`
|
||||
|
||||
- [ ] **Step 1: Add test that default comparison calls metadata validation**
|
||||
|
||||
Use a metadata file missing required ready-for-comparison fields and call `compare_metadata(..., validate_artifacts=True)`. Expected classification: `missing-reference-artifact` or exit code `2` with validation errors.
|
||||
|
||||
- [ ] **Step 2: Implement reuse of `validate_reference_artifacts.validate_metadata`**
|
||||
|
||||
Import safely:
|
||||
|
||||
```python
|
||||
try:
|
||||
from validate_reference_artifacts import validate_metadata
|
||||
except ImportError:
|
||||
from scripts.validate_reference_artifacts import validate_metadata
|
||||
```
|
||||
|
||||
Run validation before comparison when `validate_artifacts=True`.
|
||||
|
||||
- [ ] **Step 3: Keep tests able to bypass validation**
|
||||
|
||||
Continue supporting `validate_artifacts=False` in unit tests that only exercise comparison logic.
|
||||
|
||||
### Task 7: Documentation Updates
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/reference-verifications/README.md`
|
||||
- Modify: `docs/reference-models/README.md`
|
||||
|
||||
- [ ] **Step 1: Update reference verification README**
|
||||
|
||||
Add a section:
|
||||
|
||||
````markdown
|
||||
## CSV Comparison Command
|
||||
|
||||
Run explicit external-result comparison with:
|
||||
|
||||
```bash
|
||||
python scripts/compare_extracted_csv.py --metadata references/<feature-id>/<model-id>/metadata.json --actual-root external-results/<feature-id>/<model-id>
|
||||
```
|
||||
|
||||
The command does not run Abaqus and does not parse ODB files. It compares approved `references/.../extracted/*.csv` files with externally generated actual CSV files under `--actual-root`.
|
||||
````
|
||||
|
||||
- [ ] **Step 2: Update reference model README metadata example**
|
||||
|
||||
Add the `comparisons` JSON block shown in this plan.
|
||||
|
||||
- [ ] **Step 3: Run documentation-sensitive search**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
rg -n "compare_extracted_csv|comparisons|extracted/.*\\.csv" docs scripts
|
||||
```
|
||||
|
||||
Expected: The new script, tests, and docs mention the comparison contract.
|
||||
|
||||
### Task 8: Full Verification
|
||||
|
||||
**Files:**
|
||||
- No new edits unless failures reveal a bug in this task's changes.
|
||||
|
||||
- [ ] **Step 1: Run targeted tests**
|
||||
|
||||
```bash
|
||||
python -m unittest scripts.test_compare_extracted_csv
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 2: Run full script tests**
|
||||
|
||||
```bash
|
||||
python -m unittest discover -s scripts -p "test_*.py"
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 3: Run reference artifact validation**
|
||||
|
||||
```bash
|
||||
python scripts/validate_reference_artifacts.py
|
||||
```
|
||||
|
||||
Expected: `Reference artifact metadata validation succeeded.`
|
||||
|
||||
- [ ] **Step 4: Run Fortran validation**
|
||||
|
||||
```bash
|
||||
python scripts/validate_fortran.py
|
||||
```
|
||||
|
||||
Expected: PASS, or `No Fortran validation commands configured.` when no manifest exists.
|
||||
|
||||
- [ ] **Step 5: Run workspace validation**
|
||||
|
||||
```bash
|
||||
python scripts/validate_workspace.py
|
||||
```
|
||||
|
||||
Expected: PASS. It should not require actual CSV outputs because `compare_extracted_csv.py` is explicit-use only.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- The project never runs Abaqus and never opens ODB files during CSV comparison.
|
||||
- Reference bundle completeness remains checked by `scripts/validate_reference_artifacts.py`.
|
||||
- CSV numeric validation is performed by explicit command only.
|
||||
- Actual generated CSVs are read from a user-supplied `--actual-root`.
|
||||
- Comparison requires declared schema, key columns, value column, unit/coordinate columns, and absolute/relative tolerance.
|
||||
- Missing files, schema mismatch, ID mismatch, unit/coordinate mismatch, nonfinite results, and tolerance failures have distinct classifications.
|
||||
- JSON report includes enough metrics for Reference Verification Agent handoff: compared rows, missing rows, extra rows, max absolute error, max relative error, RMS error, worst key, and pass/fail.
|
||||
|
||||
## Open Decisions
|
||||
|
||||
- Whether actual result bundles should live under a conventional ignored path such as `external-results/` or `runs/`. The script should accept any `--actual-root`, so this can remain a documentation convention.
|
||||
- Whether comparison metadata should later move from `metadata.json` into feature-specific I/O definition documents. For the first implementation, keep executable comparison rules in `metadata.json` so the script has one deterministic contract source.
|
||||
Reference in New Issue
Block a user