feat(linear-static-3d-euler-beam): step 23 - hdf5-results-writer

This commit is contained in:
KOKO\Mimi
2026-08-09 22:04:03 +09:00
parent 28de0099b5
commit e75cdee67b
9 changed files with 2725 additions and 3 deletions
+6 -3
View File
@@ -44,10 +44,13 @@ if(NOT TARGET TBB::tbb)
message(FATAL_ERROR "The oneTBB CONFIG package did not define TBB::tbb") message(FATAL_ERROR "The oneTBB CONFIG package did not define TBB::tbb")
endif() endif()
if(TARGET hdf5::hdf5-static) # Prefer the packaged shared C runtime when both variants exist. The Windows
set(_fesa_hdf5_target hdf5::hdf5-static) # static archive may carry compiler-runtime requirements that are not part of
elseif(TARGET hdf5::hdf5-shared) # the HDF5 imported target's transitive link interface.
if(TARGET hdf5::hdf5-shared)
set(_fesa_hdf5_target hdf5::hdf5-shared) set(_fesa_hdf5_target hdf5::hdf5-shared)
elseif(TARGET hdf5::hdf5-static)
set(_fesa_hdf5_target hdf5::hdf5-static)
elseif(TARGET HDF5::HDF5) elseif(TARGET HDF5::HDF5)
set(_fesa_hdf5_target HDF5::HDF5) set(_fesa_hdf5_target HDF5::HDF5)
else() else()
@@ -1130,3 +1130,82 @@
the subsequent uncontended serial build, targeted, discovery, full sequence the subsequent uncontended serial build, targeted, discovery, full sequence
followed by a separate successful audit command. followed by a separate successful audit command.
- concerns: none; no upstream-contract conflict or critical blocker remains. - concerns: none; no upstream-contract conflict or critical blocker remains.
## Step 23 — hdf5-results-writer
- task_id: `TASK-23`
- status: `completed`
- changed_files: `include/fesa/results/results_writer.hpp`,
`include/fesa/io/hdf5/hdf5_results_writer.hpp`,
`src/fesa/io/hdf5/hdf5_results_writer.cpp`,
`tests/unit/results/results_writer_test.cpp`,
`tests/unit/io/hdf5/hdf5_results_writer_test.cpp`,
`src/fesa/CMakeLists.txt`, `tests/CMakeLists.txt`,
`cmake/FesaDependencies.cmake`,
`docs/implementation-plans/linear-static-3d-euler-beam-implementation-report.md`,
`phases/linear-static-3d-euler-beam/index.json`
- requirement_ids: `FESA-REQ-LS3DEB-003`, `FESA-REQ-LS3DEB-015`,
`FESA-REQ-LS3DEB-019`, `FESA-REQ-LS3DEB-020`,
`FESA-REQ-LS3DEB-023`, `FESA-REQ-LS3DEB-025`,
`FESA-REQ-LS3DEB-028`, `FESA-REQ-LS3DEB-029`,
`FESA-REQ-LS3DEB-030`, `FESA-REQ-LS3DEB-031`,
`FESA-REQ-LS3DEB-032`, `FESA-REQ-LS3DEB-034`
- test_ids: `T23-HDF5-001`, `T23-HDF5-002`, `T23-HDF5-003`,
`T23-HDF5-004`, `T23-HDF5-005`
| stage | exact command | exit_code | expected_or_observed_result | evidence_tail |
| --- | --- | ---: | --- | --- |
| RED-build | `cmake --build .harness/build --config Debug --target fesa_tests` | 1 | All five ledger tests were registered before either public production header existed | MSVC C1083 reported missing `fesa/results/results_writer.hpp` and `fesa/io/hdf5/hdf5_results_writer.hpp` |
| INFRA-link | `cmake --build .harness/build --config Debug --target fesa_tests` | 1 | Production and tests compiled, but the packaged static HDF5 target could not link in this environment | LNK1104 reported missing `libircmt.lib`; this is infrastructure evidence, not the feature RED |
| INFRA-runtime-discovery | `cmake --build .harness/build --config Debug --target fesa_tests` | 1 | Shared HDF5 linked after normalized-target repair, but post-build GoogleTest discovery could not load a transitive runtime | discovery exited `0xc0000135`; `dumpbin /dependents hdf5.dll` identified `libmmd.dll` |
| GREEN-build | `cmake --build .harness/build --config Debug --target fesa_tests` | 0 | Minimum schema-v0 writer, tests, solver library, and unit executable compile/link after the approved runtime repair | `hdf5_results_writer.cpp` and both tests built under `/W4 /WX`; required runtime DLLs were staged before discovery |
| GREEN-test | `ctest --test-dir .harness/build -C Debug -R Hdf5ResultsWriter --output-on-failure` | 0 | Exact schema, mandatory outputs, diagnostics/centroid, failure preservation, and successful replacement pass | 5/5 exact `Hdf5ResultsWriter` tests passed |
| VERIFY-configure | `cmake -S . -B .harness/build -A x64 -DFESA_GTEST_SOURCE_DIR=C:/git/googletest "-DMKL_DIR=C:/Program Files (x86)/Intel/oneAPI/mkl/2026.1/lib/cmake/mkl" "-DTBB_DIR=C:/Program Files (x86)/Intel/oneAPI/tbb/2023.1/lib/cmake/tbb" "-DHDF5_DIR=C:/Program Files/HDF_Group/HDF5/2.1.1/cmake"` | 0 | Approved explicit-dependency MSVC x64 build tree generates | Visual Studio 18/MSVC x64, Windows SDK 10.0.26100.0, oneMKL, oneTBB, and shared HDF5 resolved; configure/generate completed |
| VERIFY-build | `cmake --build .harness/build --config Debug` | 0 | Full Debug build passes without a new FESA warning | `fesa_solver.lib` and `fesa_unit_tests.exe` built under `/W4 /WX` |
| VERIFY-targeted | `ctest --test-dir .harness/build -C Debug -R Hdf5ResultsWriter --output-on-failure` | 0 | Focused Step 23 suite remains green | 5/5 exact `Hdf5ResultsWriter` tests passed |
| VERIFY-discovery | `ctest --test-dir .harness/build -C Debug --show-only=json-v1` | 0 | CTest discovers the accumulated suite and all five exact ledger names | 73 tests discovered, including exactly 5 `Hdf5ResultsWriter` tests |
| VERIFY-full | `ctest --test-dir .harness/build -C Debug --output-on-failure` | 0 | Full accumulated C++ suite has zero failures | 73/73 tests passed in 2.75 seconds |
| VERIFY-runtime | `& 'C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\MSVC\14.51.36231\bin\Hostx64\x64\dumpbin.exe' /dependents 'C:\Program Files\HDF_Group\HDF5\2.1.1\bin\hdf5.dll'` | 0 | The package DLL's undeclared Intel runtime requirement is traceable | dependencies include `libmmd.dll`; the WIN32 staging guard copies `${OMP_DLL_DIR}/libmmd.dll` |
| VERIFY-contract-scans | Public HDF5/Win32 type scan, exact-test count, finalizer/RAII scope scan, forbidden shear/averaging/filter scan, `git diff --check`, and reference diff/status | 0 | Backend boundary, exact mandatory-output scope, atomic finalization, and reference immutability remain isolated | public backend leaks 0; exact tests 5; checked file closes and exact Replace/Move split present; forbidden scope 0; whitespace clean; reference unchanged |
- contract_checks: `ResultsWriter` and `Hdf5ResultsWriter` expose only the
approved backend-free signatures. HDF5, Win32 handles, macros, RAII wrappers,
schema construction, self-check, and atomic finalization stay private to the
implementation; `Fesa::HDF5` is linked privately.
- contract_checks: schema v0 writes every literal metadata, model, and
`/steps/Step-1/frames/0` path, including `generalized_resultant`. Numeric
fields use IEEE little-endian float64, stable identities use little-endian
uint64 compound members, text uses UTF-8 variable-length strings, and exact
component/unit/coordinate/location/step/frame attributes are pinned.
- contract_checks: non-axis-aligned element axes, node/element identity,
connectivity, and representative first/last nonzero values for displacement,
reaction, end action, section resultant, generalized strain, and generalized
resultant prove solved state is connected to output. Output requests do not
filter any mandatory field; shear/averaged stress was not added.
- contract_checks: diagnostics are stable-sorted and preserved, an empty input
produces an exact zero-row compound dataset, and the default centroid stress
row serializes axial `S11` only. Dimensions, row identity/order, source
identity, and all numeric values are validated before finalization.
- atomicity: a unique same-directory temporary file is fully written, flushed,
checked-closed, reopened read-only for exact schema self-check, and
checked-closed before finalization. Existing finals use only
`ReplaceFileW(final,temp,nullptr,...)`; new finals use only
`MoveFileExW(temp,final,MOVEFILE_WRITE_THROUGH)`. Failure removes the temp,
leaves no partial new final, and preserves pre-existing final bytes.
- infrastructure_resolution: the approved normalized HDF5 dependency now
prefers the package shared target, with static and `HDF5::HDF5` fallbacks.
Tests stage `$<TARGET_RUNTIME_DLLS:fesa_unit_tests>` plus the package DLL's
verified `${OMP_DLL_DIR}/libmmd.dll` dependency without directly naming an
HDF5 package target or hardcoding an Intel installation path.
- generated_evidence: `.harness/build/src/fesa/Debug/fesa_solver.lib`,
`.harness/build/tests/Debug/fesa_unit_tests.exe`; all test HDF5/temp artifacts
are confined to build-tree temporary directories and cleaned by their owners.
- reference_diff: unchanged; `git diff --exit-code -- reference/` and
`git status --short -- reference/` both report no change.
- handoff: Step 24 can construct the backend-free writer and rely on mandatory
schema-v0 output and fail-atomic replacement. Its production executable must
stage the selected HDF5 target runtime DLLs and `${OMP_DLL_DIR}/libmmd.dll`
with the same portable target-expression/runtime-guard policy used by tests.
- concerns: no remaining critical implementation or upstream-contract blocker.
The HDF5 static-link and shared-runtime environment blockers were resolved
and are recorded separately from the valid missing-API RED.
@@ -0,0 +1,17 @@
#pragma once
#include "fesa/results/results_writer.hpp"
namespace fesa {
// Writes schema-v0 output while keeping backend and platform types private.
class Hdf5ResultsWriter final : public ResultsWriter {
public:
Status write(
const std::filesystem::path& outputPath,
const Domain& domain,
const AnalysisState& state,
const std::vector<Diagnostic>& diagnostics) override;
};
} // namespace fesa
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include "fesa/analysis/analysis_state.hpp"
#include "fesa/core/diagnostic.hpp"
#include "fesa/core/status.hpp"
#include "fesa/model/domain.hpp"
#include <filesystem>
#include <vector>
namespace fesa {
// Keeps the solver core independent of the authoritative result-storage backend.
class ResultsWriter {
public:
virtual ~ResultsWriter() = default;
virtual Status write(
const std::filesystem::path& outputPath,
const Domain& domain,
const AnalysisState& state,
const std::vector<Diagnostic>& diagnostics) = 0;
};
} // namespace fesa
+2
View File
@@ -14,6 +14,7 @@ add_library(
fem/dof_manager.cpp fem/dof_manager.cpp
io/abaqus/domain_mapper.cpp io/abaqus/domain_mapper.cpp
io/abaqus/input_reader.cpp io/abaqus/input_reader.cpp
io/hdf5/hdf5_results_writer.cpp
math/matrix.cpp math/matrix.cpp
math/sparse_matrix.cpp math/sparse_matrix.cpp
math/vector.cpp math/vector.cpp
@@ -33,6 +34,7 @@ target_link_libraries(
PRIVATE PRIVATE
Fesa::MKL Fesa::MKL
Fesa::TBB Fesa::TBB
Fesa::HDF5
) )
# Product warnings are strict without imposing FESA policy on external targets. # Product warnings are strict without imposing FESA policy on external targets.
File diff suppressed because it is too large Load Diff
+15
View File
@@ -20,10 +20,12 @@ add_executable(
unit/io/abaqus/domain_mapper_test.cpp unit/io/abaqus/domain_mapper_test.cpp
unit/io/abaqus/input_reader_test.cpp unit/io/abaqus/input_reader_test.cpp
unit/io/abaqus/input_syntax_test.cpp unit/io/abaqus/input_syntax_test.cpp
unit/io/hdf5/hdf5_results_writer_test.cpp
unit/model/domain_test.cpp unit/model/domain_test.cpp
unit/model/model_types_test.cpp unit/model/model_types_test.cpp
unit/results/result_records_test.cpp unit/results/result_records_test.cpp
unit/results/result_recovery_test.cpp unit/results/result_recovery_test.cpp
unit/results/results_writer_test.cpp
unit/solvers/linear/linear_solver_test.cpp unit/solvers/linear/linear_solver_test.cpp
unit/solvers/linear/mkl_pardiso_solver_test.cpp unit/solvers/linear/mkl_pardiso_solver_test.cpp
) )
@@ -32,6 +34,7 @@ target_link_libraries(
fesa_unit_tests fesa_unit_tests
PRIVATE PRIVATE
fesa_solver fesa_solver
Fesa::HDF5
GTest::gtest_main GTest::gtest_main
) )
@@ -40,6 +43,9 @@ if(WIN32)
NOT OMP_DLL_DIR OR NOT OMP_DLLNAME) NOT OMP_DLL_DIR OR NOT OMP_DLLNAME)
message(FATAL_ERROR "The oneMKL runtime files required by tests were not resolved") message(FATAL_ERROR "The oneMKL runtime files required by tests were not resolved")
endif() endif()
if(NOT EXISTS "${OMP_DLL_DIR}/libmmd.dll")
message(FATAL_ERROR "The Intel runtime required by the selected HDF5 DLL was not resolved")
endif()
file(GLOB _fesa_mkl_dispatch_dlls "${MKL_ROOT}/bin/mkl_def.*.dll") file(GLOB _fesa_mkl_dispatch_dlls "${MKL_ROOT}/bin/mkl_def.*.dll")
if(NOT _fesa_mkl_dispatch_dlls) if(NOT _fesa_mkl_dispatch_dlls)
@@ -65,9 +71,18 @@ if(WIN32)
COMMAND "${CMAKE_COMMAND}" -E copy_if_different COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${OMP_DLL_DIR}/${OMP_DLLNAME}" "${OMP_DLL_DIR}/${OMP_DLLNAME}"
"$<TARGET_FILE_DIR:fesa_unit_tests>" "$<TARGET_FILE_DIR:fesa_unit_tests>"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${OMP_DLL_DIR}/libmmd.dll"
"$<TARGET_FILE_DIR:fesa_unit_tests>"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${_fesa_mkl_dispatch_dll}" "${_fesa_mkl_dispatch_dll}"
"$<TARGET_FILE_DIR:fesa_unit_tests>" "$<TARGET_FILE_DIR:fesa_unit_tests>"
# Stage runtime DLLs selected through imported targets, including the
# normalized HDF5 backend, without naming a package-specific target.
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"$<TARGET_RUNTIME_DLLS:fesa_unit_tests>"
"$<TARGET_FILE_DIR:fesa_unit_tests>"
COMMAND_EXPAND_LISTS
) )
unset(_fesa_mkl_dispatch_dll) unset(_fesa_mkl_dispatch_dll)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,24 @@
#include "fesa/results/results_writer.hpp"
#include "fesa/analysis/analysis_state.hpp"
#include "fesa/core/diagnostic.hpp"
#include "fesa/core/status.hpp"
#include "fesa/model/domain.hpp"
#include <filesystem>
#include <type_traits>
#include <vector>
namespace {
using WriteSignature = fesa::Status (fesa::ResultsWriter::*)(
const std::filesystem::path&,
const fesa::Domain&,
const fesa::AnalysisState&,
const std::vector<fesa::Diagnostic>&);
static_assert(std::has_virtual_destructor_v<fesa::ResultsWriter>);
static_assert(std::is_abstract_v<fesa::ResultsWriter>);
static_assert(std::is_same_v<decltype(&fesa::ResultsWriter::write), WriteSignature>);
} // namespace