Add MITC4 drilling diagnostics output and comparison contract

This commit is contained in:
KOKO\Mimi
2026-10-20 09:45:58 +09:00
parent 3d5c296651
commit a73d3fc9ca
31 changed files with 1175 additions and 45 deletions
@@ -18,6 +18,10 @@
#include "io/hdf5/hdf5_primitives.h"
#include "io/hdf5/hdf5_raii.h"
#include "io/hdf5/mitc4_drilling_diagnostics.h"
#include "io/hdf5/mitc4_file_hooks.h"
namespace fesa {
namespace {
@@ -849,13 +853,13 @@ void CheckTables(const hid_t file, const DynamicAnalysisState& state,
Status SelfCheck(const std::filesystem::path& path, const Domain& domain,
const DynamicAnalysisState& state,
const hdf5_internal::WriterModelData& model,
const std::vector<Diagnostic>& diagnostics) {
const std::vector<Diagnostic>& diagnostics, herr_t (*close_reader)(hid_t)) {
try {
Hdf5Handle file{
hdf5_internal::RequireHdf5Id(
H5Fopen(path.string().c_str(), H5F_ACC_RDONLY, H5P_DEFAULT),
"Unable to reopen dynamic candidate."),
H5Fclose};
close_reader};
Hdf5Handle metadata{hdf5_internal::RequireHdf5Id(
H5Gopen2(file.Get(), "/metadata", H5P_DEFAULT),
"The dynamic metadata group is missing."),
@@ -902,9 +906,16 @@ Status SelfCheck(const std::filesystem::path& path, const Domain& domain,
"Unable to inspect accepted frame group.");
Check(information.nlinks == state.AcceptedFrames().size(),
"Unexpected frame group inventory.");
const auto drilling = hdf5_internal::RequireDrillingDiagnostics(
file.Get(), state.AcceptedFrames().front().mitc4_drilling->mode);
hdf5_internal::RequireDrilling(drilling.frames.size() == state.AcceptedFrames().size());
std::size_t drilling_index = 0U;
for (const auto& frame : state.AcceptedFrames()) {
hdf5_internal::CheckDrillingFrame(drilling.frames[drilling_index++], frame.frame_index,
frame.global_equilibrium, *frame.mitc4_drilling);
WriteFrame(file.Get(), domain, frame, true);
}
hdf5_internal::RequireHdf5(file.CloseChecked(), "Unable to close dynamic readback.");
return Status::Ok();
} catch (const std::exception& error) {
return Failure("dynamic-output-schema", error.what());
@@ -913,10 +924,10 @@ Status SelfCheck(const std::filesystem::path& path, const Domain& domain,
} // namespace
Status DynamicHdf5ResultsWriter::Write(
Status hdf5_internal::WriteDynamicFile(
const std::filesystem::path& output_path, const Domain& domain,
const DynamicAnalysisState& state,
const std::vector<Diagnostic>& diagnostics) {
const std::vector<Diagnostic>& diagnostics, const Mitc4FileHooks& hooks) {
if (output_path.empty() || output_path.filename().empty() ||
!state.IsInitialized() || state.AcceptedFrames().empty() ||
domain.Dynamic() == nullptr)
@@ -924,6 +935,11 @@ Status DynamicHdf5ResultsWriter::Write(
"Dynamic output requires a named path, initialized state, "
"and accepted frames.");
try {
for (const auto& frame : state.AcceptedFrames()) {
hdf5_internal::ValidateDrillingEvidence(frame.global_equilibrium, frame.mitc4_drilling);
hdf5_internal::RequireDrilling(frame.mitc4_drilling->mode ==
state.AcceptedFrames().front().mitc4_drilling->mode);
}
hdf5_internal::Hdf5ErrorSilencer silence;
const auto& step = *domain.Dynamic();
Check(state.AcceptedFrames().size() ==
@@ -965,24 +981,28 @@ Status DynamicHdf5ResultsWriter::Write(
H5Fcreate(candidate_path.string().c_str(), H5F_ACC_EXCL,
H5P_DEFAULT, H5P_DEFAULT),
"Unable to create dynamic candidate."),
H5Fclose};
hooks.candidate_close};
(void)hdf5_internal::CreateGroup(file.Get(), "/model/shell");
hdf5_internal::WriteModel(file.Get(), domain, model);
WriteMetadata(file.Get(), domain, state.AcceptedFrames().front());
hdf5_internal::WriteDrillingMetadata(file.Get(), state.AcceptedFrames().front().mitc4_drilling->mode);
WriteDensity(file.Get(), domain);
(void)hdf5_internal::CreateGroup(file.Get(), "/steps");
(void)hdf5_internal::CreateGroup(file.Get(), "/steps/Step-1");
WriteAcceptedFrames(file.Get(), state.AcceptedFrames());
for (const auto& frame : state.AcceptedFrames()) {
WriteFrame(file.Get(), domain, frame);
hdf5_internal::WriteDrillingFrame(file.Get(),
"/steps/Step-1/frames/" + std::to_string(frame.frame_index), *frame.mitc4_drilling);
}
WriteDiagnostics(file.Get(), diagnostics);
hdf5_internal::RequireHdf5(H5Fflush(file.Get(), H5F_SCOPE_GLOBAL),
"Unable to flush dynamic candidate.");
hdf5_internal::RequireHdf5(file.CloseChecked(),
"Unable to close dynamic candidate.");
if (hooks.before_self_check) hooks.before_self_check(candidate_path);
const Status check =
SelfCheck(candidate_path, domain, state, model, diagnostics);
SelfCheck(candidate_path, domain, state, model, diagnostics, hooks.reader_close);
const Status finalization = hdf5_internal::AtomicFinalizeValidatedCandidate(
candidate_path, output_path, check);
if (finalization.IsOk()) cleanup.Release();
@@ -994,4 +1014,10 @@ Status DynamicHdf5ResultsWriter::Write(
}
}
Status DynamicHdf5ResultsWriter::Write(
const std::filesystem::path& output_path, const Domain& domain,
const DynamicAnalysisState& state, const std::vector<Diagnostic>& diagnostics) {
return hdf5_internal::WriteDynamicFile(output_path, domain, state, diagnostics);
}
} // namespace fesa