# Architecture Decision Records ## ADR-001: Solver Development Workflow Is Stage-Gated **Decision**: FESA solver features must follow this workflow: requirements, research, formulation, I/O contract, TDD reference models, implementation, reference comparison, tolerance decision, release. **Reason**: Structural solver correctness depends on more than code execution. Requirements, mathematical formulation, input/output contracts, reference artifacts, numerical comparison, and release evidence must be traceable. **Tradeoff**: Initial feature delivery is slower. The benefit is that implementation agents do not invent formulation, tolerance, or reference assumptions during coding. ## ADR-002: C++17/MSVC/CMake/CTest Remain The Baseline **Decision**: The project targets C++17 or newer, MSVC on Windows, CMake, and CTest. Default validation uses Visual Studio 17 2022, x64, Debug. **Reason**: The project is a Windows/MSVC structural solver. CMake/CTest gives a consistent build and test entry point for both harness validation and feature development. **Tradeoff**: Visual Studio solution-only workflows and non-MSVC toolchains are not the primary path. They can be introduced by explicit ADR when needed. ## ADR-003: MITC4 Linear Static Shell Is The Initial Solver Feature **Decision**: The first solver implementation target is `mitc4-linear-static-shell`: a 4-node MITC4 shell element for linear static structural analysis. **Reason**: MITC4 is a meaningful shell element target with strong research and OpenSees reference structure. It exercises element formulation, assembly, solver, I/O, and reference verification without immediately requiring nonlinear or dynamic analysis. **Tradeoff**: This is more complex than a truss/bar bootstrap. The project accepts the complexity because MITC4 is the requested initial element. ## ADR-004: OpenSees-Inspired Architecture, Modern C++ Ownership **Decision**: FESA follows OpenSees-like conceptual boundaries: `Domain`, `Node`, `Element`, `Material/Section`, `Analysis`, `SystemOfEqn`, and `Recorder/ResultWriter`. It does not clone OpenSees raw ownership style. **Reason**: OpenSees provides a useful solver architecture vocabulary, while modern C++17 RAII gives safer ownership and testable module boundaries. **Tradeoff**: FESA classes will not be drop-in compatible with OpenSees. Similarity is architectural, not API compatibility. ## ADR-005: MKL PARDISO For Global Linear Solves **Decision**: FESA uses Intel oneAPI MKL CSR matrices and PARDISO for the initial global linear static solve. **Reason**: Shell models need sparse linear algebra beyond toy dense solvers. MKL is already aligned with the Windows/MSVC toolchain and provides production-grade direct sparse solving. **Tradeoff**: oneAPI MKL becomes a required dependency for real solver builds. The CMake configuration must detect `MKLROOT` or a known oneAPI installation path. ## ADR-006: TBB For Parallel Element Work **Decision**: FESA uses Intel oneAPI TBB for parallel element stiffness, residual/result recovery, and other embarrassingly parallel solver phases. **Reason**: Element-level computation is a natural parallelism boundary. TBB integrates with oneAPI and avoids designing a custom thread pool. **Tradeoff**: Global assembly must be deterministic. FESA will use thread-local contribution buffers and deterministic merge rather than concurrent writes into global CSR arrays. ## ADR-007: HDF5 For Solver And Reference Results **Decision**: FESA writes solver results to HDF5 and compares against stored HDF5 reference artifacts. **Reason**: Shell results contain structured mesh, step/frame, nodal, element, Gauss point, resultant, stress, metadata, and tolerance data. HDF5 is better suited than flat CSV for this result hierarchy. **Tradeoff**: HDF5 becomes a required dependency. FESA will provide an internal RAII wrapper over the HDF5 C API, but the actual HDF5 C library must be supplied by `HDF5_ROOT` or `HDF5_DIR`. The current local Windows install is `C:\Program Files\HDF_Group\HDF5\2.1.1`; use `HDF5_ROOT` for that root or `HDF5_DIR` for `C:\Program Files\HDF_Group\HDF5\2.1.1\cmake`. ## ADR-008: Single Tolerance Policy **Decision**: Reference comparison uses a single tolerance value `1e-5`. A compared scalar passes when absolute error or relative error is within `1e-5`. **Reason**: A single tolerance policy is simple, explicit, and matches the current project decision. **Tradeoff**: Quantity-specific scaling is deferred. If future models show that one global tolerance is too strict or too loose for some quantities, a new ADR must revise this policy. ## ADR-009: Agents Do Not Run Reference Solvers **Decision**: Abaqus, Nastran, and other reference solvers are not run by agents. Agents only consume stored reference artifacts. **Reason**: Reference solver execution requires licensing, environment control, provenance, and human approval. Stored artifacts make validation reproducible inside the harness. **Tradeoff**: Implementation can be blocked until required reference artifacts are supplied. ## ADR-010: Domain, AnalysisModel, And AnalysisState Are Separate **Decision**: `Domain` owns parsed model definition, `AnalysisModel` owns the active step execution view, and `AnalysisState` owns mutable solution and iteration state. **Reason**: This prevents equation ids, displacement vectors, residuals, and future nonlinear/time states from leaking into input model objects. It also keeps the static solver compatible with future nonlinear, dynamic, and thermal workflows. **Tradeoff**: The initial implementation has more object boundaries than a single monolithic model container. ## ADR-011: Factory/Registry Handles Input Object Creation **Decision**: Abaqus keyword parsing and internal object creation are separated through factory/registry mechanisms. **Reason**: Adding elements, materials, loads, boundary conditions, sets, or properties should not require rewriting parser control flow. **Tradeoff**: The first parser implementation needs a small registry layer before many object types exist. ## ADR-012: Boundary Conditions Use DOF Elimination **Decision**: Essential boundary conditions are applied by constrained DOF elimination. Reactions are recovered from the full system as `K_full * U_full - F_full`. **Reason**: This gives a clear reduced solve while preserving physically meaningful reaction recovery for reference comparison. **Tradeoff**: The implementation must preserve enough full-system information for reaction recovery instead of only storing the reduced matrix. ## ADR-013: Results Use Step/Frame/Field/History Model **Decision**: HDF5 results are organized by step, frame, field output, and history output. **Reason**: The same result model can support static, nonlinear, dynamic, heat-transfer, and thermal-stress analyses. **Tradeoff**: The v0 linear static output is more structured than a flat single-step result file. ## ADR-014: Double Precision And 64-Bit Numbering **Decision**: Solver scalar calculations use `double`; ids, sparse indices, and equation numbering are designed around int64 boundaries. **Reason**: Structural solver verification needs double precision, and large sparse systems should not be blocked by 32-bit numbering assumptions. **Tradeoff**: Memory use may be higher than a 32-bit-only implementation. ## ADR-015: Units Are User-Consistent, Not Enforced **Decision**: FESA does not enforce a unit system. Inputs and reference artifacts must be unit-consistent and record units in metadata. **Reason**: Abaqus-style workflows commonly rely on user-consistent units. **Tradeoff**: The solver cannot automatically detect every unit mismatch. Reference metadata and validation reports must make unit assumptions visible.