diff --git a/CMakeLists.txt b/CMakeLists.txt index 2720ab1..6638490 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,11 @@ cmake_minimum_required(VERSION 3.20) project(FESA VERSION 0.1.0 LANGUAGES CXX) -add_library(fesa_core STATIC src/fesa.cpp) +file(GLOB_RECURSE FESA_CORE_SOURCES CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" +) + +add_library(fesa_core STATIC ${FESA_CORE_SOURCES}) target_include_directories(fesa_core PUBLIC $ ) diff --git a/PLAN.md b/PLAN.md index 0c78d3a..e47687a 100644 --- a/PLAN.md +++ b/PLAN.md @@ -13,7 +13,7 @@ Every new agent session must read this file together with `PROGRESS.md` before p - If an item becomes obsolete, move it to `PROGRESS.md` with a short reason instead of silently deleting it. ## Current Objective -Execute the Phase 1 structure-alignment refactor in `phases/1-structure-alignment-refactor`, starting with P1A-01 module scaffold and facade. P1A-00 completed the architecture drift audit and recorded the migration map in `phases/1-structure-alignment-refactor/step0-architecture-map.md`. This phase must align the current monolithic `include/fesa/fesa.hpp` implementation with the module ownership model in `docs/ARCHITECTURE.md` without changing solver behavior. Product-level Phase 1 reference gaps R-010 and R-013 remain open and must not be hidden by the refactor. +Execute the Phase 1 structure-alignment refactor in `phases/1-structure-alignment-refactor`, continuing with P1A-02 Core/Util extraction. P1A-00 completed the architecture drift audit and P1A-01 created the module scaffold, source directories, CMake source boundary, and include smoke test without moving production behavior. This phase must align the current monolithic `include/fesa/fesa.hpp` implementation with the module ownership model in `docs/ARCHITECTURE.md` without changing solver behavior. Product-level Phase 1 reference gaps R-010 and R-013 remain open and must not be hidden by the refactor. ## Required Reading For New Agents 1. `AGENTS.md` @@ -37,7 +37,7 @@ Execute the Phase 1 structure-alignment refactor in `phases/1-structure-alignmen ## Phase Files - Active phase directory: `phases/1-structure-alignment-refactor` - Execute with: `python scripts/execute.py 1-structure-alignment-refactor` -- Step numbering is zero-based. `step0.md` is complete and wrote `phases/1-structure-alignment-refactor/step0-architecture-map.md`; `step1.md` creates module scaffold and umbrella facade policy; `step2.md` extracts Core/Util domain, diagnostics, DofManager ownership, and Phase 1 Boundary/Load/Property model ownership; `step3.md` extracts Math and solver adapter boundaries; `step4.md` extracts the Abaqus parser into IO; `step5.md` extracts Results and reference comparison code; `step6.md` extracts MITC4 geometry/strain helpers; `step7.md` extracts MITC4 material/stiffness helpers; `step8.md` extracts Assembly and Analysis workflow; `step9.md` is the independent architecture evaluator closeout. +- Step numbering is zero-based. `step0.md` is complete and wrote `phases/1-structure-alignment-refactor/step0-architecture-map.md`; `step1.md` is complete and created module scaffold headers, source directories, CMake source discovery, and umbrella compatibility smoke coverage; `step2.md` extracts Core/Util domain, diagnostics, DofManager ownership, and Phase 1 Boundary/Load/Property model ownership; `step3.md` extracts Math and solver adapter boundaries; `step4.md` extracts the Abaqus parser into IO; `step5.md` extracts Results and reference comparison code; `step6.md` extracts MITC4 geometry/strain helpers; `step7.md` extracts MITC4 material/stiffness helpers; `step8.md` extracts Assembly and Analysis workflow; `step9.md` is the independent architecture evaluator closeout. - Completed phase directory: `phases/1-linear-static-mitc4-rebaseline` - Historical execution command: `python scripts/execute.py 1-linear-static-mitc4-rebaseline` - Step numbering is zero-based. `step0.md` is complete and recorded in `phases/1-linear-static-mitc4-rebaseline/step0-audit.md`; `step1.md` is complete and created the `quad_02_phase1.inp` normalized reference path; `step2.md` is complete and revalidated core harness guardrails; `step3.md` is complete and revalidated the Phase 1 parser/domain subset; `step4.md` is complete and strengthened validation/singular diagnostics; `step5.md` is complete and revalidated the DofManager/reaction foundation; `step6.md` is complete and revalidated the minimum result model plus displacement CSV comparator; `step7.md` is complete and revalidated MITC4 natural coordinates, tying points, center directors, and integration bases; `step8.md` is complete and revalidated degenerated-continuum displacement, direct covariant strain rows, and MITC shear tying rows; `step9.md` is complete and revalidated plane-stress material, convected-to-local transform, and `2 x 2 x 2` material integration scaffolding; `step10.md` is complete and revalidated MITC4 stiffness, internal force, six-DOF transform, and drilling stabilization; `step11.md` is complete and added MITC4 membrane, bending, shear, twist, drilling-sensitivity, and thin-cantilever locking-sensitivity tests; `step12.md` is complete and revalidated full-space assembly, reduced projection, deterministic sparse-pattern scaffold, solver adapter injection, and full-vector internal/reaction force state; `step13.md` is complete and revalidated active AnalysisModel construction plus input-to-AnalysisState-to-U/RF result workflow; `step14.md` is complete and added the first stored Abaqus displacement regression for `quad_02_phase1`; `step15.md` is complete and recorded the independent evaluator closeout in `phases/1-linear-static-mitc4-rebaseline/step15-evaluator-report.md`. @@ -58,7 +58,7 @@ This phase is an architecture-preserving refactor. It must not change Phase 1 so | ID | Status | Owner | Objective | Depends On | Acceptance Focus | |---|---|---|---|---|---| | P1A-00 | completed | planner/evaluator | Audit `fesa.hpp` architecture drift and create a symbol-to-module migration map. | P1R-15 | Complete migration map and validation baseline | -| P1A-01 | pending | generator | Create module directory scaffold, CMake source boundaries, and umbrella facade policy. | P1A-00 | Module include smoke tests and build stability | +| P1A-01 | completed | generator | Create module directory scaffold, CMake source boundaries, and umbrella facade policy. | P1A-00 | Module include smoke tests and build stability | | P1A-02 | pending | generator | Extract Core/Util domain, diagnostics, aliases, DOF mapping, `AnalysisModel`, `DofManager`, and Phase 1 Boundary/Load/Property model ownership. | P1A-01 | Core has no dependency on higher layers; Boundary/Load/Property types are no longer hidden in the umbrella header; DOF tests unchanged | | P1A-03 | pending | generator | Extract Math and solver adapter boundaries. | P1A-02 | Linear solver interface remains adapter-ready; int64 paths unchanged | | P1A-04 | pending | generator | Extract Abaqus parser into IO. | P1A-02 | Parser subset and unsupported-feature diagnostics unchanged | diff --git a/PROGRESS.md b/PROGRESS.md index e52a426..a2139d5 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -13,10 +13,62 @@ Every new agent session must read this file together with `PLAN.md` before plann - Do not remove history unless the user explicitly asks for archival cleanup. ## Current Status -Phase 1 has a completed rebaseline execution path in `phases/1-linear-static-mitc4-rebaseline`. Steps 0 through 15 are complete, and P1R-15 recorded a pass-with-documented-gaps evaluator closeout. A follow-up architecture refactor phase is now planned in `phases/1-structure-alignment-refactor` because the current production implementation is concentrated in `include/fesa/fesa.hpp` instead of the module directories documented in `docs/ARCHITECTURE.md`. `quad_02_phase1.inp` is the normalized Phase 1-compatible input path for the stored `quad_02` S4 reference pair, while the original `quad_02.inp` remains preserved unsupported provenance. Core numeric aliases, DOF mapping, validation harness, model diagnostic context, the Phase 1 parser/domain subset, validation/singular diagnostics, DofManager/reaction foundation, minimum result model metadata, displacement CSV comparator foundation, MITC4 geometry/director scaffolding, MITC4 displacement/strain/tying row scaffolding, MITC4 material/transform/integration scaffolding, MITC4 stiffness/drilling/internal-force scaffolding, MITC4 patch/locking-sensitivity tests, full-space assembly, reduced projection, sparse-pattern scaffold, solver adapter injection, full-vector internal/reaction force state, active AnalysisModel construction, input-to-AnalysisState-to-U/RF result workflow, and the first stored Abaqus displacement regression have been revalidated. Full PRD Phase 1 completion still depends on the open architecture/reference gaps R-014, R-010, and R-013. The old `phases/1-linear-static-mitc4` path is historical and superseded after the MITC4 formulation reset. +Phase 1 has a completed rebaseline execution path in `phases/1-linear-static-mitc4-rebaseline`. Steps 0 through 15 are complete, and P1R-15 recorded a pass-with-documented-gaps evaluator closeout. The follow-up architecture refactor phase in `phases/1-structure-alignment-refactor` is underway because the current production implementation is concentrated in `include/fesa/fesa.hpp` instead of the module directories documented in `docs/ARCHITECTURE.md`; P1A-00 and P1A-01 are complete, so the next step is P1A-02 Core/Util extraction. `quad_02_phase1.inp` is the normalized Phase 1-compatible input path for the stored `quad_02` S4 reference pair, while the original `quad_02.inp` remains preserved unsupported provenance. Core numeric aliases, DOF mapping, validation harness, model diagnostic context, the Phase 1 parser/domain subset, validation/singular diagnostics, DofManager/reaction foundation, minimum result model metadata, displacement CSV comparator foundation, MITC4 geometry/director scaffolding, MITC4 displacement/strain/tying row scaffolding, MITC4 material/transform/integration scaffolding, MITC4 stiffness/drilling/internal-force scaffolding, MITC4 patch/locking-sensitivity tests, full-space assembly, reduced projection, sparse-pattern scaffold, solver adapter injection, full-vector internal/reaction force state, active AnalysisModel construction, input-to-AnalysisState-to-U/RF result workflow, and the first stored Abaqus displacement regression have been revalidated. Full PRD Phase 1 completion still depends on the open architecture/reference gaps R-014, R-010, and R-013. The old `phases/1-linear-static-mitc4` path is historical and superseded after the MITC4 formulation reset. ## Completed Work +### 2026-05-05 - P1A-01 module scaffold and facade completed +Author: Codex + +Changed files: +- `CMakeLists.txt` +- `include/fesa/ModuleInfo.hpp` +- `include/fesa/Analysis/Analysis.hpp` +- `include/fesa/Assembly/Assembly.hpp` +- `include/fesa/Boundary/Boundary.hpp` +- `include/fesa/Core/Core.hpp` +- `include/fesa/Element/Element.hpp` +- `include/fesa/IO/IO.hpp` +- `include/fesa/Load/Load.hpp` +- `include/fesa/Math/Math.hpp` +- `include/fesa/Material/Material.hpp` +- `include/fesa/Property/Property.hpp` +- `include/fesa/Results/Results.hpp` +- `include/fesa/Util/Util.hpp` +- `include/fesa/fesa.hpp` +- `src/Analysis/Analysis.cpp` +- `src/Assembly/Assembly.cpp` +- `src/Boundary/Boundary.cpp` +- `src/Core/Core.cpp` +- `src/Element/Element.cpp` +- `src/IO/IO.cpp` +- `src/Load/Load.cpp` +- `src/Math/Math.cpp` +- `src/Material/Material.cpp` +- `src/Property/Property.cpp` +- `src/Results/Results.cpp` +- `src/Util/Util.cpp` +- `tests/test_main.cpp` +- `phases/1-structure-alignment-refactor/index.json` +- `PLAN.md` +- `PROGRESS.md` + +Summary: +- Added architecture module scaffold headers and matching source directories for `Analysis`, `Assembly`, `Boundary`, `Core`, `Element`, `IO`, `Load`, `Math`, `Material`, `Property`, `Results`, and `Util`. +- Added `include/fesa/ModuleInfo.hpp` to record the module list and stable umbrella facade header policy without changing solver behavior, and exposed it through the existing `fesa/fesa.hpp` umbrella. +- Updated CMake to discover current and future `src/**/*.cpp` files under the module directories. +- Added an include compatibility smoke test that includes all module headers before `fesa/fesa.hpp` and checks the module list plus existing DOF mapping still works. +- No production symbols were moved from `include/fesa/fesa.hpp` in this step. + +Verification: +- First ran `python scripts/validate_workspace.py` after adding the smoke test; it failed as expected because `fesa/Analysis/Analysis.hpp` did not exist yet. +- After adding the scaffold and CMake wiring, `python scripts/validate_workspace.py` configured CMake, built `fesa_core` and `fesa_tests`, and ran CTest successfully. +- CTest result: 1 test executable passed. + +Follow-up: +- Continue with P1A-02 Core/Util extraction while preserving all public symbols and behavior. +- Keep R-014 open until P1A-09 independently accepts the final architecture alignment. + ### 2026-05-05 - P1A-00 architecture drift audit completed Author: Codex diff --git a/include/fesa/Analysis/Analysis.hpp b/include/fesa/Analysis/Analysis.hpp new file mode 100644 index 0000000..dad2066 --- /dev/null +++ b/include/fesa/Analysis/Analysis.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kAnalysis = "Analysis"; + +} // namespace fesa::module diff --git a/include/fesa/Assembly/Assembly.hpp b/include/fesa/Assembly/Assembly.hpp new file mode 100644 index 0000000..a0c7fff --- /dev/null +++ b/include/fesa/Assembly/Assembly.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kAssembly = "Assembly"; + +} // namespace fesa::module diff --git a/include/fesa/Boundary/Boundary.hpp b/include/fesa/Boundary/Boundary.hpp new file mode 100644 index 0000000..5a79710 --- /dev/null +++ b/include/fesa/Boundary/Boundary.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kBoundary = "Boundary"; + +} // namespace fesa::module diff --git a/include/fesa/Core/Core.hpp b/include/fesa/Core/Core.hpp new file mode 100644 index 0000000..9a16d9e --- /dev/null +++ b/include/fesa/Core/Core.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kCore = "Core"; + +} // namespace fesa::module diff --git a/include/fesa/Element/Element.hpp b/include/fesa/Element/Element.hpp new file mode 100644 index 0000000..26adae0 --- /dev/null +++ b/include/fesa/Element/Element.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kElement = "Element"; + +} // namespace fesa::module diff --git a/include/fesa/IO/IO.hpp b/include/fesa/IO/IO.hpp new file mode 100644 index 0000000..80e0230 --- /dev/null +++ b/include/fesa/IO/IO.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kIO = "IO"; + +} // namespace fesa::module diff --git a/include/fesa/Load/Load.hpp b/include/fesa/Load/Load.hpp new file mode 100644 index 0000000..e053c2f --- /dev/null +++ b/include/fesa/Load/Load.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kLoad = "Load"; + +} // namespace fesa::module diff --git a/include/fesa/Material/Material.hpp b/include/fesa/Material/Material.hpp new file mode 100644 index 0000000..8359ce8 --- /dev/null +++ b/include/fesa/Material/Material.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kMaterial = "Material"; + +} // namespace fesa::module diff --git a/include/fesa/Math/Math.hpp b/include/fesa/Math/Math.hpp new file mode 100644 index 0000000..6c6c6f0 --- /dev/null +++ b/include/fesa/Math/Math.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kMath = "Math"; + +} // namespace fesa::module diff --git a/include/fesa/ModuleInfo.hpp b/include/fesa/ModuleInfo.hpp new file mode 100644 index 0000000..13b02b4 --- /dev/null +++ b/include/fesa/ModuleInfo.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace fesa { + +using ModuleList = std::array; + +inline constexpr ModuleList kArchitectureModules = { + "Analysis", "Assembly", "Boundary", "Core", "Element", "IO", + "Load", "Math", "Material", "Property", "Results", "Util", +}; + +constexpr const ModuleList& architectureModules() noexcept { + return kArchitectureModules; +} + +constexpr std::string_view umbrellaFacadeHeader() noexcept { + return "fesa/fesa.hpp"; +} + +} // namespace fesa diff --git a/include/fesa/Property/Property.hpp b/include/fesa/Property/Property.hpp new file mode 100644 index 0000000..c5507ee --- /dev/null +++ b/include/fesa/Property/Property.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kProperty = "Property"; + +} // namespace fesa::module diff --git a/include/fesa/Results/Results.hpp b/include/fesa/Results/Results.hpp new file mode 100644 index 0000000..b24e9c7 --- /dev/null +++ b/include/fesa/Results/Results.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kResults = "Results"; + +} // namespace fesa::module diff --git a/include/fesa/Util/Util.hpp b/include/fesa/Util/Util.hpp new file mode 100644 index 0000000..4ed8e9e --- /dev/null +++ b/include/fesa/Util/Util.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "fesa/ModuleInfo.hpp" + +namespace fesa::module { + +inline constexpr std::string_view kUtil = "Util"; + +} // namespace fesa::module diff --git a/include/fesa/fesa.hpp b/include/fesa/fesa.hpp index f89c92e..10ee56c 100644 --- a/include/fesa/fesa.hpp +++ b/include/fesa/fesa.hpp @@ -1,5 +1,7 @@ #pragma once +#include "fesa/ModuleInfo.hpp" + #include #include #include diff --git a/phases/1-structure-alignment-refactor/index.json b/phases/1-structure-alignment-refactor/index.json index e731a64..65a1564 100644 --- a/phases/1-structure-alignment-refactor/index.json +++ b/phases/1-structure-alignment-refactor/index.json @@ -3,7 +3,7 @@ "phase": "1-structure-alignment-refactor", "steps": [ { "step": 0, "name": "architecture-drift-audit", "status": "completed", "artifact": "step0-architecture-map.md" }, - { "step": 1, "name": "module-scaffold-and-facade", "status": "pending" }, + { "step": 1, "name": "module-scaffold-and-facade", "status": "completed" }, { "step": 2, "name": "core-domain-dof-extraction", "status": "pending" }, { "step": 3, "name": "math-solver-extraction", "status": "pending" }, { "step": 4, "name": "io-parser-extraction", "status": "pending" }, diff --git a/src/Analysis/Analysis.cpp b/src/Analysis/Analysis.cpp new file mode 100644 index 0000000..b1d6cd8 --- /dev/null +++ b/src/Analysis/Analysis.cpp @@ -0,0 +1 @@ +#include "fesa/Analysis/Analysis.hpp" diff --git a/src/Assembly/Assembly.cpp b/src/Assembly/Assembly.cpp new file mode 100644 index 0000000..ffaabf3 --- /dev/null +++ b/src/Assembly/Assembly.cpp @@ -0,0 +1 @@ +#include "fesa/Assembly/Assembly.hpp" diff --git a/src/Boundary/Boundary.cpp b/src/Boundary/Boundary.cpp new file mode 100644 index 0000000..51af5af --- /dev/null +++ b/src/Boundary/Boundary.cpp @@ -0,0 +1 @@ +#include "fesa/Boundary/Boundary.hpp" diff --git a/src/Core/Core.cpp b/src/Core/Core.cpp new file mode 100644 index 0000000..dd9e527 --- /dev/null +++ b/src/Core/Core.cpp @@ -0,0 +1 @@ +#include "fesa/Core/Core.hpp" diff --git a/src/Element/Element.cpp b/src/Element/Element.cpp new file mode 100644 index 0000000..198358f --- /dev/null +++ b/src/Element/Element.cpp @@ -0,0 +1 @@ +#include "fesa/Element/Element.hpp" diff --git a/src/IO/IO.cpp b/src/IO/IO.cpp new file mode 100644 index 0000000..2a5f91e --- /dev/null +++ b/src/IO/IO.cpp @@ -0,0 +1 @@ +#include "fesa/IO/IO.hpp" diff --git a/src/Load/Load.cpp b/src/Load/Load.cpp new file mode 100644 index 0000000..c989cf4 --- /dev/null +++ b/src/Load/Load.cpp @@ -0,0 +1 @@ +#include "fesa/Load/Load.hpp" diff --git a/src/Material/Material.cpp b/src/Material/Material.cpp new file mode 100644 index 0000000..4b8f664 --- /dev/null +++ b/src/Material/Material.cpp @@ -0,0 +1 @@ +#include "fesa/Material/Material.hpp" diff --git a/src/Math/Math.cpp b/src/Math/Math.cpp new file mode 100644 index 0000000..0b8a4ec --- /dev/null +++ b/src/Math/Math.cpp @@ -0,0 +1 @@ +#include "fesa/Math/Math.hpp" diff --git a/src/Property/Property.cpp b/src/Property/Property.cpp new file mode 100644 index 0000000..e4b2b32 --- /dev/null +++ b/src/Property/Property.cpp @@ -0,0 +1 @@ +#include "fesa/Property/Property.hpp" diff --git a/src/Results/Results.cpp b/src/Results/Results.cpp new file mode 100644 index 0000000..9872fba --- /dev/null +++ b/src/Results/Results.cpp @@ -0,0 +1 @@ +#include "fesa/Results/Results.hpp" diff --git a/src/Util/Util.cpp b/src/Util/Util.cpp new file mode 100644 index 0000000..de349a9 --- /dev/null +++ b/src/Util/Util.cpp @@ -0,0 +1 @@ +#include "fesa/Util/Util.hpp" diff --git a/tests/test_main.cpp b/tests/test_main.cpp index dc64c44..bedf691 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -1,3 +1,15 @@ +#include "fesa/Analysis/Analysis.hpp" +#include "fesa/Assembly/Assembly.hpp" +#include "fesa/Boundary/Boundary.hpp" +#include "fesa/Core/Core.hpp" +#include "fesa/Element/Element.hpp" +#include "fesa/IO/IO.hpp" +#include "fesa/Load/Load.hpp" +#include "fesa/Math/Math.hpp" +#include "fesa/Material/Material.hpp" +#include "fesa/Property/Property.hpp" +#include "fesa/Results/Results.hpp" +#include "fesa/Util/Util.hpp" #include "fesa/fesa.hpp" #include @@ -7,6 +19,7 @@ #include #include #include +#include #include static_assert(std::is_same_v, "Real must remain double"); @@ -330,6 +343,25 @@ FESA_TEST(core_types_and_dof_mapping_are_stable) { FESA_CHECK(!fesa::dofFromAbaqus(7).has_value()); } +FESA_TEST(module_scaffold_headers_are_include_compatible_with_umbrella) { + const auto modules = fesa::architectureModules(); + FESA_CHECK(modules.size() == 12); + FESA_CHECK(modules[0] == std::string_view("Analysis")); + FESA_CHECK(modules[1] == std::string_view("Assembly")); + FESA_CHECK(modules[2] == std::string_view("Boundary")); + FESA_CHECK(modules[3] == std::string_view("Core")); + FESA_CHECK(modules[4] == std::string_view("Element")); + FESA_CHECK(modules[5] == std::string_view("IO")); + FESA_CHECK(modules[6] == std::string_view("Load")); + FESA_CHECK(modules[7] == std::string_view("Math")); + FESA_CHECK(modules[8] == std::string_view("Material")); + FESA_CHECK(modules[9] == std::string_view("Property")); + FESA_CHECK(modules[10] == std::string_view("Results")); + FESA_CHECK(modules[11] == std::string_view("Util")); + FESA_CHECK(fesa::umbrellaFacadeHeader() == std::string_view("fesa/fesa.hpp")); + FESA_CHECK(fesa::dofFromAbaqus(1).value() == fesa::Dof::UX); +} + FESA_TEST(parser_accepts_phase1_subset) { fesa::AbaqusInputParser parser; auto parsed = parser.parseString(phase1Input());