Files
FESADev/phases/solver-core-skeleton/step2.md
T
2026-06-12 01:31:31 +09:00

5.8 KiB

Step 2: domain-model-entities

읽어야 할 파일

먼저 아래 파일들을 읽고 프로젝트의 아키텍처와 이전 step 산출물을 파악하라:

  • /AGENTS.md
  • /docs/PRD.md
  • /docs/ARCHITECTURE.md
  • /docs/ADR.md
  • /src/fesa/core/ids.hpp
  • /src/fesa/core/status.hpp
  • /tests/unit/core_primitives_test.cpp

이전 step에서 만들어진 core primitive를 꼼꼼히 읽고, ID ownership과 diagnostic convention을 유지하라.

작업

입력 파일에서 생성된 전체 semantic model을 소유하는 최소 model layer를 /src/fesa/model/에 구현한다.

필수 파일:

  • /src/fesa/model/node.hpp
  • /src/fesa/model/element.hpp
  • /src/fesa/model/material.hpp
  • /src/fesa/model/property.hpp
  • /src/fesa/model/boundary_condition.hpp
  • /src/fesa/model/load.hpp
  • /src/fesa/model/analysis_step.hpp
  • /src/fesa/model/domain.hpp
  • /tests/unit/model_domain_test.cpp

필수 interface:

namespace fesa::model {

class Node {
public:
    Node(core::NodeId id, std::array<double, 3> coordinates);
    core::NodeId id() const;
    const std::array<double, 3>& coordinates() const;
};

enum class ElementTopology { truss2, bar2, unknown };

class Element {
public:
    Element(core::ElementId id, ElementTopology topology,
            std::vector<core::NodeId> node_ids, core::PropertyId property_id);
    core::ElementId id() const;
    ElementTopology topology() const;
    const std::vector<core::NodeId>& node_ids() const;
    core::PropertyId property_id() const;
};

class Material {
public:
    Material(core::MaterialId id, std::string name);
    core::MaterialId id() const;
    const std::string& name() const;
};

class Property {
public:
    Property(core::PropertyId id, std::string name, core::MaterialId material_id);
    core::PropertyId id() const;
    const std::string& name() const;
    core::MaterialId material_id() const;
};

enum class DofComponent { ux, uy, uz, rx, ry, rz, temperature };

class BoundaryCondition {
public:
    BoundaryCondition(core::NodeId node_id, DofComponent component, double value);
    core::NodeId node_id() const;
    DofComponent component() const;
    double value() const;
};

class Load {
public:
    Load(core::NodeId node_id, DofComponent component, double value);
    core::NodeId node_id() const;
    DofComponent component() const;
    double value() const;
};

class AnalysisStep {
public:
    AnalysisStep(core::StepId id, std::string name);
    core::StepId id() const;
    const std::string& name() const;
    void add_boundary_condition(BoundaryCondition bc);
    void add_load(Load load);
    const std::vector<BoundaryCondition>& boundary_conditions() const;
    const std::vector<Load>& loads() const;
};

class Domain {
public:
    void add_node(Node node);
    void add_element(Element element);
    void add_material(Material material);
    void add_property(Property property);
    void add_step(AnalysisStep step);

    const std::vector<Node>& nodes() const;
    const std::vector<Element>& elements() const;
    const std::vector<Material>& materials() const;
    const std::vector<Property>& properties() const;
    const std::vector<AnalysisStep>& steps() const;

    const Node* find_node(core::NodeId id) const;
    const Element* find_element(core::ElementId id) const;
    const Material* find_material(core::MaterialId id) const;
    const Property* find_property(core::PropertyId id) const;
    const AnalysisStep* find_step(core::StepId id) const;
};

} // namespace fesa::model

구현 규칙:

  • Domain은 semantic model 객체를 소유한다.
  • nodes(), elements(), materials(), properties(), steps()는 const reference를 반환한다.
  • find_*는 없으면 nullptr을 반환한다.
  • Node와 Element 내부에 equation id, constrained/free equation mapping, sparse pattern 정보를 저장하지 않는다.
  • DofComponent는 아직 equation number가 아니라 물리 DOF component만 표현한다.
  • Abaqus keyword 문자열이나 parser detail을 model object에 저장하지 않는다.

Tests To Write First

  • /tests/unit/model_domain_test.cpp
    • Node가 id와 3D coordinates를 보존한다.
    • Element가 topology, connectivity, property id를 보존한다.
    • Material과 Property가 id/name/material link를 보존한다.
    • AnalysisStep이 boundary condition과 load를 저장한다.
    • Domain이 add/find를 통해 각 객체를 조회한다.
    • 없는 id는 nullptr을 반환한다.
    • Node/Element public interface에 equation id를 노출하지 않는다는 점을 테스트 코드 사용 방식으로 확인한다.

RED 확인:

  1. 테스트 파일을 먼저 작성한다.
  2. targeted CTest를 실행해 missing model headers로 실패함을 확인한다.
  3. 그 뒤 production headers를 작성한다.

Acceptance Criteria

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 model_domain_test

검증 절차

  1. 위 AC 커맨드를 실행한다.
  2. 아키텍처 체크리스트를 확인한다:
    • Domain이 전체 모델 정의를 소유하는가?
    • model layer가 parser keyword 문자열이나 analysis state를 소유하지 않는가?
    • Node/Element에 equation id가 분산 저장되지 않는가?
  3. 결과에 따라 phases/solver-core-skeleton/index.json의 step 2를 업데이트한다:
    • 성공: "status": "completed", "summary": "Model entities and Domain ownership API added with tests"
    • 3회 수정 시도 후 실패: "status": "error", "error_message": "구체적 에러 내용"
    • 사용자 개입 필요: "status": "blocked", "blocked_reason": "구체적 사유" 후 중단

금지사항

  • Parser, assembler, solver backend를 만들지 마라.
  • Domain을 실행 중 state container로 사용하지 마라.
  • JavaScript/TypeScript/npm fallback을 추가하지 마라.