#define NOMINMAX
#include <Windows.h>

#include "fesa/io/hdf5/hdf5_results_writer.hpp"

#include "fesa/analysis/analysis_model.hpp"
#include "fesa/build_info.hpp"
#include "fesa/fem/dof_manager.hpp"

#include <hdf5.h>

#include <algorithm>
#include <array>
#include <atomic>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <limits>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>

namespace fesa {
namespace {

constexpr std::size_t kDofsPerNode = 6U;
constexpr std::size_t kEndpointCount = 2U;
constexpr std::size_t kGaussPointCount = 2U;
constexpr std::size_t kEndActionComponentCount = 6U;
constexpr std::size_t kGeneralizedComponentCount = 4U;
constexpr std::size_t kShellNodeCount = 4U;
constexpr std::size_t kShellLocationCount = 4U;
constexpr std::size_t kShellGeneralizedComponentCount = 8U;
constexpr std::size_t kShellSectionPositionCount = 3U;
constexpr std::size_t kShellStressComponentCount = 3U;
constexpr const char* kStepName = "Step-1";
constexpr std::size_t kFrameIndex = 0U;
constexpr const char* kStepRoot = "/steps/Step-1/frames/0";

class Hdf5Handle {
public:
    using Closer = herr_t (*)(hid_t);

    Hdf5Handle() = default;
    Hdf5Handle(const hid_t value, Closer closer)
        : value_{value}, closer_{closer} {}
    Hdf5Handle(const Hdf5Handle&) = delete;
    Hdf5Handle& operator=(const Hdf5Handle&) = delete;
    Hdf5Handle(Hdf5Handle&& other) noexcept
        : value_{other.value_}, closer_{other.closer_} {
        other.value_ = -1;
        other.closer_ = nullptr;
    }
    Hdf5Handle& operator=(Hdf5Handle&& other) noexcept {
        if (this != &other) {
            reset();
            value_ = other.value_;
            closer_ = other.closer_;
            other.value_ = -1;
            other.closer_ = nullptr;
        }
        return *this;
    }
    ~Hdf5Handle() { reset(); }

    hid_t get() const noexcept { return value_; }
    herr_t closeChecked() noexcept {
        if (value_ < 0 || closer_ == nullptr) {
            return 0;
        }
        const hid_t value = value_;
        const Closer closer = closer_;
        value_ = -1;
        closer_ = nullptr;
        return closer(value);
    }

private:
    void reset() noexcept {
        if (value_ >= 0 && closer_ != nullptr) {
            (void)closer_(value_);
        }
        value_ = -1;
        closer_ = nullptr;
    }

    hid_t value_{-1};
    Closer closer_{nullptr};
};

// Expected backend failures become one structured FESA diagnostic, not an
// HDF5 error-stack dump mixed into deterministic CLI output.
class Hdf5ErrorSilencer {
public:
    Hdf5ErrorSilencer() {
        if (H5Eget_auto2(H5E_DEFAULT, &callback_, &clientData_) >= 0 &&
            H5Eset_auto2(H5E_DEFAULT, nullptr, nullptr) >= 0) {
            active_ = true;
        }
    }
    Hdf5ErrorSilencer(const Hdf5ErrorSilencer&) = delete;
    Hdf5ErrorSilencer& operator=(const Hdf5ErrorSilencer&) = delete;
    ~Hdf5ErrorSilencer() {
        if (active_) {
            (void)H5Eset_auto2(H5E_DEFAULT, callback_, clientData_);
        }
    }

private:
    H5E_auto2_t callback_{nullptr};
    void* clientData_{nullptr};
    bool active_{false};
};

class TemporaryFileGuard {
public:
    explicit TemporaryFileGuard(std::filesystem::path path)
        : path_{std::move(path)} {}
    TemporaryFileGuard(const TemporaryFileGuard&) = delete;
    TemporaryFileGuard& operator=(const TemporaryFileGuard&) = delete;
    ~TemporaryFileGuard() {
        if (active_) {
            std::error_code ignored;
            (void)std::filesystem::remove(path_, ignored);
        }
    }
    void release() noexcept { active_ = false; }

private:
    std::filesystem::path path_;
    bool active_{true};
};

class Hdf5Failure final : public std::runtime_error {
public:
    explicit Hdf5Failure(const std::string& message)
        : std::runtime_error{message} {}
};

void requireHdf5(const herr_t result, const char* message) {
    if (result < 0) {
        throw Hdf5Failure{message};
    }
}

hid_t requireHdf5Id(const hid_t result, const char* message) {
    if (result < 0) {
        throw Hdf5Failure{message};
    }
    return result;
}

Status outputFailure(const std::string& code, const std::string& message) {
    return Status::failure(
        FailureCategory::output,
        {{Severity::error, code, {}, "", "", message}});
}

bool isFinite(const std::array<double, 3>& values) {
    return std::all_of(values.begin(), values.end(), [](const double value) {
        return std::isfinite(value);
    });
}

template<std::size_t Size>
bool isFinite(const std::array<double, Size>& values) {
    return std::all_of(values.begin(), values.end(), [](const double value) {
        return std::isfinite(value);
    });
}

bool isValidUtf8(const std::string& value) {
    const auto* bytes = reinterpret_cast<const unsigned char*>(value.data());
    std::size_t index = 0U;
    while (index < value.size()) {
        const unsigned char first = bytes[index];
        if (first <= 0x7fU) {
            ++index;
            continue;
        }

        std::size_t continuationCount = 0U;
        std::uint32_t codePoint = 0U;
        if (first >= 0xc2U && first <= 0xdfU) {
            continuationCount = 1U;
            codePoint = first & 0x1fU;
        } else if (first >= 0xe0U && first <= 0xefU) {
            continuationCount = 2U;
            codePoint = first & 0x0fU;
        } else if (first >= 0xf0U && first <= 0xf4U) {
            continuationCount = 3U;
            codePoint = first & 0x07U;
        } else {
            return false;
        }
        if (index + continuationCount >= value.size()) {
            return false;
        }
        for (std::size_t offset = 1U; offset <= continuationCount; ++offset) {
            const unsigned char next = bytes[index + offset];
            if ((next & 0xc0U) != 0x80U) {
                return false;
            }
            codePoint = (codePoint << 6U) | (next & 0x3fU);
        }
        if ((continuationCount == 2U && codePoint < 0x800U) ||
            (continuationCount == 3U && codePoint < 0x10000U) ||
            (codePoint >= 0xd800U && codePoint <= 0xdfffU) ||
            codePoint > 0x10ffffU) {
            return false;
        }
        index += continuationCount + 1U;
    }
    return true;
}

bool sameIdentity(const SourceEntityId& left, const SourceEntityId& right) {
    return left.instanceName == right.instanceName &&
           left.sourceLabel == right.sourceLabel &&
           left.sourceLabelText == right.sourceLabelText;
}

using AxisSet = std::array<double, 9>;

struct WriterModelData {
    std::vector<AxisSet> beamLocalAxes;
    std::vector<std::uint8_t> constraintMask;
    std::vector<double> prescribedDisplacement;
};

bool isShellDomain(const Domain& domain) noexcept {
    return !domain.shellElements().empty();
}

const char* shellSourceTypeName(const ShellSourceElementType type) {
    return type == ShellSourceElementType::s4 ? "S4" : "S4R";
}

bool isOrthonormalRightHanded(
    const std::array<std::array<double, 3>, 3>& frame) {
    constexpr double tolerance = 1.0e-12;
    const auto dot = [](const std::array<double, 3>& left,
                        const std::array<double, 3>& right) {
        return left[0U] * right[0U] + left[1U] * right[1U] +
               left[2U] * right[2U];
    };
    for (const auto& axis : frame) {
        if (!isFinite(axis) || std::abs(dot(axis, axis) - 1.0) > tolerance) {
            return false;
        }
    }
    if (std::abs(dot(frame[0U], frame[1U])) > tolerance ||
        std::abs(dot(frame[0U], frame[2U])) > tolerance ||
        std::abs(dot(frame[1U], frame[2U])) > tolerance) {
        return false;
    }
    const std::array<double, 3> cross = {
        frame[0U][1U] * frame[1U][2U] - frame[0U][2U] * frame[1U][1U],
        frame[0U][2U] * frame[1U][0U] - frame[0U][0U] * frame[1U][2U],
        frame[0U][0U] * frame[1U][1U] - frame[0U][1U] * frame[1U][0U]};
    return dot(cross, frame[2U]) > 0.0 &&
           std::abs(dot(cross, frame[2U]) - 1.0) <= tolerance;
}

bool computeLocalAxes(
    const Domain& domain, const EulerBeam3DDefinition& element, AxisSet& axes) {
    if (element.nodeIndices[0U] >= domain.nodes().size() ||
        element.nodeIndices[1U] >= domain.nodes().size() ||
        element.sectionIndex >= domain.sections().size()) {
        return false;
    }
    const auto& first = domain.nodes()[element.nodeIndices[0U]].coordinates;
    const auto& second = domain.nodes()[element.nodeIndices[1U]].coordinates;
    const auto& guide = domain.sections()[element.sectionIndex].firstAxis;
    const std::array<double, 3> delta = {
        second[0U] - first[0U],
        second[1U] - first[1U],
        second[2U] - first[2U]};
    const double length = std::hypot(delta[0U], delta[1U], delta[2U]);
    if (!isFinite(first) || !isFinite(second) || !isFinite(guide) ||
        !isFinite(delta) || !std::isfinite(length) || !(length > 0.0)) {
        return false;
    }
    const std::array<double, 3> x = {
        delta[0U] / length, delta[1U] / length, delta[2U] / length};
    const double projection =
        guide[0U] * x[0U] + guide[1U] * x[1U] + guide[2U] * x[2U];
    const std::array<double, 3> yTrial = {
        guide[0U] - projection * x[0U],
        guide[1U] - projection * x[1U],
        guide[2U] - projection * x[2U]};
    const double yNorm = std::hypot(yTrial[0U], yTrial[1U], yTrial[2U]);
    if (!isFinite(yTrial) || !std::isfinite(yNorm) || !(yNorm > 0.0)) {
        return false;
    }
    const std::array<double, 3> y = {
        yTrial[0U] / yNorm, yTrial[1U] / yNorm, yTrial[2U] / yNorm};
    const std::array<double, 3> z = {
        x[1U] * y[2U] - x[2U] * y[1U],
        x[2U] * y[0U] - x[0U] * y[2U],
        x[0U] * y[1U] - x[1U] * y[0U]};
    axes = {
        x[0U], x[1U], x[2U],
        y[0U], y[1U], y[2U],
        z[0U], z[1U], z[2U]};
    return isFinite(axes);
}

bool sizeProductFits(
    const std::size_t left, const std::size_t right, std::size_t& product) {
    if (right != 0U && left > (std::numeric_limits<std::size_t>::max)() / right) {
        return false;
    }
    product = left * right;
    return true;
}

Status validateShellWriterInput(
    const Domain& domain, const AnalysisState& state) {
    if (!domain.elements().empty()) {
        return outputFailure(
            "invalid-result-identity",
            "Schema v0 does not combine B33 and FESA-MITC4 element inventories.");
    }
    for (const auto& material : domain.materials()) {
        if (material.name.empty() || !isValidUtf8(material.name) ||
            !std::isfinite(material.youngsModulus) ||
            !std::isfinite(material.poissonRatio) ||
            !(material.youngsModulus > 0.0)) {
            return outputFailure(
                "invalid-result-identity",
                "Every shell material requires a UTF-8 name and finite constitutive data.");
        }
    }
    for (const auto& section : domain.shellSections()) {
        if (section.name.empty() || !isValidUtf8(section.name) ||
            section.materialIndex >= domain.materials().size() ||
            !std::isfinite(section.thickness) || !(section.thickness > 0.0)) {
            return outputFailure(
                "invalid-result-identity",
                "Every shell section requires stable material identity and positive finite thickness.");
        }
    }
    for (const auto& element : domain.shellElements()) {
        if ((element.sourceType != ShellSourceElementType::s4 &&
             element.sourceType != ShellSourceElementType::s4r) ||
            element.sourceId.sourceLabel <= 0 ||
            element.sourceId.sourceLabelText.empty() ||
            !isValidUtf8(element.sourceId.instanceName) ||
            !isValidUtf8(element.sourceId.sourceLabelText) ||
            element.materialIndex >= domain.materials().size() ||
            element.sectionIndex >= domain.shellSections().size() ||
            domain.shellSections()[element.sectionIndex].materialIndex !=
                element.materialIndex) {
            return outputFailure(
                "invalid-result-identity",
                "Every shell element requires stable source, material, and section identity.");
        }
        std::array<EntityIndex, kShellNodeCount> sortedNodes = element.nodeIndices;
        std::sort(sortedNodes.begin(), sortedNodes.end());
        if (sortedNodes.back() >= domain.nodes().size() ||
            std::adjacent_find(sortedNodes.begin(), sortedNodes.end()) !=
                sortedNodes.end()) {
            return outputFailure(
                "invalid-result-identity",
                "Every shell element requires four distinct valid node identities.");
        }
    }
    if (domain.shellNodeInitialFrames().size() != domain.nodes().size()) {
        return outputFailure(
            "invalid-result-identity",
            "Shell output requires one initial director/frame per source-ordered node.");
    }
    for (std::size_t node = 0U;
         node < domain.shellNodeInitialFrames().size();
         ++node) {
        const auto& source = domain.shellNodeInitialFrames()[node];
        const std::array<std::array<double, 3>, 3> frame{
            source.tangentA, source.tangentB, source.director};
        if (source.nodeIndex != node || !isOrthonormalRightHanded(frame)) {
            return outputFailure(
                "invalid-result-identity",
                "Shell initial frames must be finite, orthonormal, right-handed, and node ordered.");
        }
    }

    std::size_t expectedRows = 0U;
    if (!sizeProductFits(
            domain.shellElements().size(), kShellLocationCount, expectedRows) ||
        state.shellResults().size() != expectedRows) {
        return outputFailure(
            "invalid-result-rows",
            "Shell output requires exactly GP1 through GP4 for every shell element.");
    }
    const double gauss = 1.0 / std::sqrt(3.0);
    const std::array<ShellMidsurfaceLocation, kShellLocationCount> locations{
        ShellMidsurfaceLocation::gp1,
        ShellMidsurfaceLocation::gp2,
        ShellMidsurfaceLocation::gp3,
        ShellMidsurfaceLocation::gp4};
    const std::array<std::array<double, 2>, kShellLocationCount> coordinates{{
        {-gauss, -gauss},
        {gauss, -gauss},
        {gauss, gauss},
        {-gauss, gauss}}};
    const std::array<ShellSectionPosition, kShellSectionPositionCount> positions{
        ShellSectionPosition::bottom,
        ShellSectionPosition::middle,
        ShellSectionPosition::top};
    constexpr std::array<double, kShellSectionPositionCount> zeta{-1.0, 0.0, 1.0};
    for (std::size_t rowIndex = 0U;
         rowIndex < state.shellResults().size();
         ++rowIndex) {
        const auto& row = state.shellResults()[rowIndex];
        const std::size_t element = rowIndex / kShellLocationCount;
        const std::size_t location = rowIndex % kShellLocationCount;
        if (row.element != element || row.location != locations[location] ||
            row.naturalCoordinates != coordinates[location] ||
            !isOrthonormalRightHanded(row.localFrame) ||
            !isFinite(row.generalizedStrain) ||
            !isFinite(row.sectionResultant)) {
            return outputFailure(
                "invalid-result-rows",
                "Shell result rows must be finite and preserve element/GP/frame identity.");
        }
        for (std::size_t position = 0U;
             position < kShellSectionPositionCount;
             ++position) {
            if (row.stress[position].position != positions[position] ||
                row.stress[position].zeta != zeta[position] ||
                !isFinite(row.stress[position].components)) {
                return outputFailure(
                    "invalid-result-rows",
                    "Shell stress rows must preserve BOTTOM, MIDDLE, TOP identity.");
            }
        }
    }
    if (!std::isfinite(state.physicalStrainEnergy()) ||
        !isFinite(state.equilibrium()) ||
        !isFinite(state.verificationMetrics())) {
        return outputFailure(
            "invalid-result-rows",
            "Shell energy, equilibrium, and verification metrics must be finite.");
    }
    return Status::ok();
}

Status validateWriterInput(
    const std::filesystem::path& outputPath,
    const Domain& domain,
    const AnalysisState& state,
    const std::vector<Diagnostic>& diagnostics,
    WriterModelData& modelData) {
    if (outputPath.empty() || outputPath.filename().empty()) {
        return outputFailure(
            "invalid-output-path", "The HDF5 output path must name a file.");
    }
    if (state.identity().stepName != kStepName ||
        state.identity().frameIndex != kFrameIndex) {
        return outputFailure(
            "invalid-result-state",
            "Schema v0 requires literal Step-1 and frame index 0.");
    }

    const bool shell = isShellDomain(domain);
    if (shell) {
        const Status shellValidation = validateShellWriterInput(domain, state);
        if (!shellValidation.isOk()) {
            return shellValidation;
        }
    } else if (!state.shellResults().empty()) {
        return outputFailure(
            "invalid-result-rows",
            "Beam output cannot contain shell recovery rows.");
    }

    std::size_t fullDofCount = 0U;
    if (!sizeProductFits(domain.nodes().size(), kDofsPerNode, fullDofCount)) {
        return outputFailure(
            "invalid-result-state", "The nodal result shape overflows size_t.");
    }
    const std::array<const Vector*, 5> vectors = {
        &state.displacement(),
        &state.externalForce(),
        &state.internalForce(),
        &state.residual(),
        &state.reaction()};
    for (const Vector* vector : vectors) {
        if (vector->size() != fullDofCount) {
            return outputFailure(
                "invalid-result-state",
                "Every V0 analysis vector must have node_count*6 values.");
        }
        for (std::size_t index = 0U; index < vector->size(); ++index) {
            if (!std::isfinite((*vector)[index])) {
                return outputFailure(
                    "invalid-result-state",
                    "Every V0 analysis vector value must be finite.");
            }
        }
    }

    if (domain.sourcePath().empty() || domain.sourceContentIdentity().empty() ||
        !isValidUtf8(domain.sourceContentIdentity())) {
        return outputFailure(
            "invalid-result-identity",
            "Source path and UTF-8 content identity are required.");
    }
    for (const Node& node : domain.nodes()) {
        if (node.sourceId.sourceLabel <= 0 ||
            node.sourceId.sourceLabelText.empty() ||
            !isValidUtf8(node.sourceId.instanceName) ||
            !isValidUtf8(node.sourceId.sourceLabelText) ||
            !isFinite(node.coordinates)) {
            return outputFailure(
                "invalid-result-identity",
                "Every node requires finite coordinates and UTF-8 source identity.");
        }
    }

    modelData.beamLocalAxes.clear();
    modelData.beamLocalAxes.reserve(domain.elements().size());
    for (const EulerBeam3DDefinition& element : domain.elements()) {
        AxisSet axes{};
        if (element.sourceId.sourceLabel <= 0 ||
            element.sourceId.sourceLabelText.empty() ||
            !isValidUtf8(element.sourceId.instanceName) ||
            !isValidUtf8(element.sourceId.sourceLabelText) ||
            element.nodeIndices[0U] == element.nodeIndices[1U] ||
            element.materialIndex >= domain.materials().size() ||
            !computeLocalAxes(domain, element, axes)) {
            return outputFailure(
                "invalid-result-identity",
                "Every element requires valid source, connectivity, property, and local-axis identity.");
        }
        modelData.beamLocalAxes.push_back(axes);
    }

    std::size_t endpointCount = 0U;
    std::size_t gaussCount = 0U;
    if (!sizeProductFits(domain.elements().size(), kEndpointCount, endpointCount) ||
        !sizeProductFits(domain.elements().size(), kGaussPointCount, gaussCount) ||
        state.endpointResults().size() != endpointCount ||
        state.gaussResults().size() != gaussCount) {
        return outputFailure(
            "invalid-result-rows",
            "Endpoint and Gauss row counts must match every element and location.");
    }
    for (std::size_t rowIndex = 0U;
         rowIndex < state.endpointResults().size();
         ++rowIndex) {
        const EntityIndex expectedElement =
            static_cast<EntityIndex>(rowIndex / kEndpointCount);
        const int expectedEndpoint = static_cast<int>(rowIndex % kEndpointCount);
        const EndpointResultRow& row = state.endpointResults()[rowIndex];
        const auto& element = domain.elements()[expectedElement];
        const auto& expectedNode =
            domain.nodes()[element.nodeIndices[static_cast<std::size_t>(expectedEndpoint)]];
        if (row.element != expectedElement || row.endpoint != expectedEndpoint ||
            !sameIdentity(row.node, expectedNode.sourceId) ||
            !isFinite(row.endAction) || !isFinite(row.sectionResultant)) {
            return outputFailure(
                "invalid-result-rows",
                "Endpoint result rows must follow element/endpoint order and identity.");
        }
    }
    for (std::size_t rowIndex = 0U;
         rowIndex < state.gaussResults().size();
         ++rowIndex) {
        const EntityIndex expectedElement =
            static_cast<EntityIndex>(rowIndex / kGaussPointCount);
        const int expectedGaussPoint =
            static_cast<int>(rowIndex % kGaussPointCount) + 1;
        const GaussResultRow& row = state.gaussResults()[rowIndex];
        if (row.element != expectedElement ||
            row.gaussPoint != expectedGaussPoint ||
            !isFinite(row.generalizedStrain) ||
            !isFinite(row.generalizedResultant)) {
            return outputFailure(
                "invalid-result-rows",
                "Gauss result rows must follow element/Gauss order and identity.");
        }
    }

    std::size_t stressIndex = 0U;
    for (std::size_t elementIndex = 0U;
         elementIndex < domain.elements().size();
         ++elementIndex) {
        const auto& element = domain.elements()[elementIndex];
        const auto& sectionPoints =
            domain.sections()[element.sectionIndex].sectionPoints;
        for (std::size_t gauss = 0U; gauss < kGaussPointCount; ++gauss) {
            const std::size_t count = sectionPoints.empty() ? 1U : sectionPoints.size();
            for (std::size_t point = 0U; point < count; ++point) {
                if (stressIndex >= state.stressResults().size()) {
                    return outputFailure(
                        "invalid-result-rows",
                        "Axial stress rows are missing required element/Gauss/section locations.");
                }
                const StressS11Row& row = state.stressResults()[stressIndex++];
                const std::size_t expectedPoint = sectionPoints.empty() ? 0U : point + 1U;
                const double expectedX1 = sectionPoints.empty() ? 0.0 : sectionPoints[point][0U];
                const double expectedX2 = sectionPoints.empty() ? 0.0 : sectionPoints[point][1U];
                const char* expectedSource = sectionPoints.empty() ? "fesa-default" : "input";
                if (row.element != static_cast<EntityIndex>(elementIndex) ||
                    row.gaussPoint != static_cast<int>(gauss + 1U) ||
                    row.sectionPoint != expectedPoint ||
                    row.x1 != expectedX1 || row.x2 != expectedX2 ||
                    row.source != expectedSource || !isValidUtf8(row.source) ||
                    !std::isfinite(row.x1) || !std::isfinite(row.x2) ||
                    !std::isfinite(row.s11)) {
                    return outputFailure(
                        "invalid-result-rows",
                        "Axial stress rows must follow exact element/Gauss/section identity.");
                }
            }
        }
    }
    if (stressIndex != state.stressResults().size()) {
        return outputFailure(
            "invalid-result-rows", "Axial stress output contains extra rows.");
    }

    for (const Diagnostic& diagnostic : diagnostics) {
        if (!isValidUtf8(diagnostic.code) ||
            !isValidUtf8(diagnostic.keyword) ||
            !isValidUtf8(diagnostic.entityIdentity) ||
            !isValidUtf8(diagnostic.message)) {
            return outputFailure(
                "invalid-result-diagnostic",
                "Diagnostic text must be valid UTF-8.");
        }
    }


    auto analysisModelResult = AnalysisModel::create(domain);
    if (!analysisModelResult.hasValue()) {
        return outputFailure(
            "invalid-result-state",
            "The HDF5 writer could not reconstruct the active model view.");
    }
    const AnalysisModel analysisModel =
        std::move(analysisModelResult.value());
    auto dofResult = DofManager::create(analysisModel);
    if (!dofResult.hasValue()) {
        return outputFailure(
            "invalid-result-state",
            "The HDF5 writer could not reconstruct stable constraint identity.");
    }
    const DofManager dofs = std::move(dofResult.value());
    modelData.constraintMask.assign(fullDofCount, 0U);
    modelData.prescribedDisplacement.assign(fullDofCount, 0.0);
    if (dofs.constrainedDofs().size() != dofs.prescribedValues().size()) {
        return outputFailure(
            "invalid-result-state",
            "Constraint identities and prescribed values have inconsistent sizes.");
    }
    for (std::size_t index = 0U;
         index < dofs.constrainedDofs().size();
         ++index) {
        const std::size_t fullDof = dofs.constrainedDofs()[index];
        const double prescribed = dofs.prescribedValues()[index];
        if (fullDof >= fullDofCount || !std::isfinite(prescribed)) {
            return outputFailure(
                "invalid-result-state",
                "Constraint identity and prescribed values must be finite and in range.");
        }
        modelData.constraintMask[fullDof] = 1U;
        modelData.prescribedDisplacement[fullDof] = prescribed;
    }
    return Status::ok();
}

std::string normalizedPathString(const std::filesystem::path& path) {
    if (path.empty()) {
        return {};
    }
    return std::filesystem::absolute(path).lexically_normal().generic_u8string();
}

std::string sourceInputIdentity(const Domain& domain) {
    return "path=" + normalizedPathString(domain.sourcePath()) +
           ";content_identity=" + domain.sourceContentIdentity();
}

Hdf5Handle makeUtf8StringType() {
    Hdf5Handle type{
        requireHdf5Id(H5Tcopy(H5T_C_S1), "Unable to copy an HDF5 string type."),
        H5Tclose};
    requireHdf5(
        H5Tset_size(type.get(), H5T_VARIABLE),
        "Unable to configure a variable-length HDF5 string.");
    requireHdf5(
        H5Tset_cset(type.get(), H5T_CSET_UTF8),
        "Unable to configure UTF-8 HDF5 strings.");
    requireHdf5(
        H5Tset_strpad(type.get(), H5T_STR_NULLTERM),
        "Unable to configure HDF5 string padding.");
    return type;
}

void writeStringAttribute(
    const hid_t object, const char* name, const std::string& value) {
    auto type = makeUtf8StringType();
    Hdf5Handle space{
        requireHdf5Id(H5Screate(H5S_SCALAR), "Unable to create an attribute space."),
        H5Sclose};
    Hdf5Handle attribute{
        requireHdf5Id(
            H5Acreate2(object, name, type.get(), space.get(), H5P_DEFAULT, H5P_DEFAULT),
            "Unable to create an HDF5 string attribute."),
        H5Aclose};
    const char* raw = value.c_str();
    requireHdf5(
        H5Awrite(attribute.get(), type.get(), &raw),
        "Unable to write an HDF5 string attribute.");
}

void writeUint64Attribute(
    const hid_t object, const char* name, const std::uint64_t value) {
    Hdf5Handle space{
        requireHdf5Id(H5Screate(H5S_SCALAR), "Unable to create an attribute space."),
        H5Sclose};
    Hdf5Handle attribute{
        requireHdf5Id(
            H5Acreate2(object, name, H5T_STD_U64LE, space.get(), H5P_DEFAULT, H5P_DEFAULT),
            "Unable to create an HDF5 integer attribute."),
        H5Aclose};
    requireHdf5(
        H5Awrite(attribute.get(), H5T_NATIVE_UINT64, &value),
        "Unable to write an HDF5 integer attribute.");
}

Hdf5Handle createGroup(const hid_t file, const char* path) {
    Hdf5Handle linkProperties{
        requireHdf5Id(H5Pcreate(H5P_LINK_CREATE), "Unable to create link properties."),
        H5Pclose};
    requireHdf5(
        H5Pset_create_intermediate_group(linkProperties.get(), 1U),
        "Unable to enable intermediate HDF5 groups.");
    return Hdf5Handle{
        requireHdf5Id(
            H5Gcreate2(file, path, linkProperties.get(), H5P_DEFAULT, H5P_DEFAULT),
            "Unable to create an HDF5 group."),
        H5Gclose};
}

Hdf5Handle createDatasetSpace(const std::vector<hsize_t>& dimensions) {
    return Hdf5Handle{
        requireHdf5Id(
            H5Screate_simple(
                static_cast<int>(dimensions.size()), dimensions.data(), nullptr),
            "Unable to create an HDF5 dataset space."),
        H5Sclose};
}

void writeResultAttributes(
    const hid_t dataset,
    const std::string& componentNames,
    const std::string& componentUnits,
    const std::string& coordinateSystem,
    const std::string& location) {
    writeStringAttribute(dataset, "component_names", componentNames);
    writeStringAttribute(
        dataset, "component_unit_dimensions", componentUnits);
    writeStringAttribute(dataset, "coordinate_system", coordinateSystem);
    writeStringAttribute(dataset, "location", location);
    writeStringAttribute(dataset, "step_name", kStepName);
    writeUint64Attribute(dataset, "frame_index", 0U);
}

Hdf5Handle writeDoubleValues(
    const hid_t file,
    const std::string& path,
    const std::vector<hsize_t>& dimensions,
    const double* values,
    const std::size_t valueCount) {
    auto space = createDatasetSpace(dimensions);
    Hdf5Handle dataset{
        requireHdf5Id(
            H5Dcreate2(
                file, path.c_str(), H5T_IEEE_F64LE, space.get(),
                H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT),
            "Unable to create a floating-point HDF5 dataset."),
        H5Dclose};
    if (valueCount != 0U) {
        requireHdf5(
            H5Dwrite(
                dataset.get(), H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
                H5P_DEFAULT, values),
            "Unable to write a floating-point HDF5 dataset.");
    }
    return dataset;
}

void writeDoubleDataset(
    const hid_t file,
    const std::string& path,
    const std::vector<hsize_t>& dimensions,
    const double* values,
    const std::size_t valueCount,
    const std::string& componentNames,
    const std::string& componentUnits,
    const std::string& coordinateSystem,
    const std::string& location) {
    auto dataset = writeDoubleValues(
        file, path, dimensions, values, valueCount);
    writeResultAttributes(
        dataset.get(), componentNames, componentUnits, coordinateSystem, location);
}

void writeModelDoubleDataset(
    const hid_t file,
    const std::string& path,
    const std::vector<hsize_t>& dimensions,
    const double* values,
    const std::size_t valueCount,
    const std::string& componentNames,
    const std::string& componentUnits,
    const std::string& coordinateSystem,
    const std::string& location) {
    auto dataset = writeDoubleValues(
        file, path, dimensions, values, valueCount);
    writeStringAttribute(dataset.get(), "component_names", componentNames);
    writeStringAttribute(
        dataset.get(), "component_unit_dimensions", componentUnits);
    writeStringAttribute(dataset.get(), "coordinate_system", coordinateSystem);
    writeStringAttribute(dataset.get(), "location", location);
}

void writeUint8Dataset(
    const hid_t file,
    const std::string& path,
    const std::vector<hsize_t>& dimensions,
    const std::uint8_t* values,
    const std::size_t valueCount) {
    auto space = createDatasetSpace(dimensions);
    Hdf5Handle dataset{
        requireHdf5Id(
            H5Dcreate2(
                file, path.c_str(), H5T_STD_U8LE, space.get(),
                H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT),
            "Unable to create a uint8 HDF5 dataset."),
        H5Dclose};
    if (valueCount != 0U) {
        requireHdf5(
            H5Dwrite(
                dataset.get(), H5T_NATIVE_UINT8, H5S_ALL, H5S_ALL,
                H5P_DEFAULT, values),
            "Unable to write a uint8 HDF5 dataset.");
    }
    writeStringAttribute(dataset.get(), "component_names", "UX,UY,UZ,URX,URY,URZ");
    writeStringAttribute(dataset.get(), "value_meaning", "0=free,1=constrained");
}

struct NodeWriteRow {
    std::uint64_t internalNodeId;
    const char* instanceName;
    const char* sourceLabel;
    double coordinates[3];
};

struct ElementWriteRow {
    std::uint64_t internalElementId;
    const char* instanceName;
    const char* sourceLabel;
    std::uint64_t nodeInternalIds[2];
    double localAxes[9];
};

struct ShellElementWriteRow {
    std::uint64_t internalElementId;
    const char* instanceName;
    const char* sourceLabel;
    const char* sourceElementType;
    const char* internalFormulation;
    std::uint64_t nodeInternalIds[4];
    std::uint64_t shellSectionInternalId;
    std::uint64_t materialInternalId;
};

struct ShellMaterialWriteRow {
    std::uint64_t internalMaterialId;
    const char* name;
    double youngsModulus;
    double poissonRatio;
};

struct ShellSectionWriteRow {
    std::uint64_t internalSectionId;
    const char* sourceFile;
    std::uint64_t sourceLine;
    const char* sourceElset;
    std::uint64_t materialInternalId;
    double thickness;
};

struct StressWriteRow {
    std::uint64_t internalElementId;
    std::uint64_t gaussPointIndex;
    std::uint64_t sectionPointIndex;
    double x1;
    double x2;
    const char* source;
    double s11;
};

struct DiagnosticWriteRow {
    const char* severity;
    const char* code;
    const char* file;
    std::uint64_t line;
    const char* keyword;
    const char* entityIdentity;
    const char* message;
};

Hdf5Handle writeCompoundDataset(
    const hid_t file,
    const char* path,
    const std::size_t rowCount,
    const hid_t fileType,
    const hid_t memoryType,
    const void* rows) {
    const std::vector<hsize_t> dimensions = {
        static_cast<hsize_t>(rowCount)};
    auto space = createDatasetSpace(dimensions);
    Hdf5Handle dataset{
        requireHdf5Id(
            H5Dcreate2(
                file, path, fileType, space.get(), H5P_DEFAULT,
                H5P_DEFAULT, H5P_DEFAULT),
            "Unable to create a compound HDF5 dataset."),
        H5Dclose};
    if (rowCount != 0U) {
        requireHdf5(
            H5Dwrite(
                dataset.get(), memoryType, H5S_ALL, H5S_ALL,
                H5P_DEFAULT, rows),
            "Unable to write a compound HDF5 dataset.");
    }
    return dataset;
}

void writeMetadata(const hid_t file, const Domain& domain) {
    auto metadata = createGroup(file, "/metadata");
    writeUint64Attribute(metadata.get(), "schema_version", 0U);
    writeStringAttribute(
        metadata.get(), "solver_version", std::string{solverVersion()});
    writeStringAttribute(
        metadata.get(), "source_input_identity", sourceInputIdentity(domain));
    writeStringAttribute(
        metadata.get(), "unit_system_label", "user-consistent-unspecified");
    if (isShellDomain(domain)) {
        writeStringAttribute(
            metadata.get(), "feature_id", "linear-static-mitc4-shell");
        writeStringAttribute(
            metadata.get(),
            "coordinate_convention",
            "global-cartesian; shell-local=(e1,e2,e3); positive-thickness=+zeta");
        writeStringAttribute(
            metadata.get(), "internal_formulation", "FESA-MITC4");
        writeStringAttribute(
            metadata.get(),
            "integration_rule",
            "2x2x2-gauss; mitc4-edge-midpoint-shear");
    } else {
        writeStringAttribute(
            metadata.get(), "feature_id", "linear-static-3d-euler-beam");
        writeStringAttribute(
            metadata.get(),
            "coordinate_convention",
            "global-cartesian; beam-local=(t,n1,t-cross-n1)");
        writeStringAttribute(
            metadata.get(), "element_formulation", "B33-3D-Euler-Bernoulli");
    }
    writeStringAttribute(metadata.get(), "step_name", kStepName);
    writeUint64Attribute(metadata.get(), "frame_index", 0U);
}

void writeNodes(const hid_t file, const Domain& domain) {
    std::vector<NodeWriteRow> rows;
    rows.reserve(domain.nodes().size());
    for (std::size_t index = 0U; index < domain.nodes().size(); ++index) {
        const Node& node = domain.nodes()[index];
        rows.push_back({
            static_cast<std::uint64_t>(index),
            node.sourceId.instanceName.c_str(),
            node.sourceId.sourceLabelText.c_str(),
            {node.coordinates[0U], node.coordinates[1U], node.coordinates[2U]}});
    }

    auto stringType = makeUtf8StringType();
    const hsize_t coordinateDimensions[] = {3U};
    Hdf5Handle fileCoordinates{
        requireHdf5Id(
            H5Tarray_create2(H5T_IEEE_F64LE, 1, coordinateDimensions),
            "Unable to create the node coordinate file type."),
        H5Tclose};
    Hdf5Handle memoryCoordinates{
        requireHdf5Id(
            H5Tarray_create2(H5T_NATIVE_DOUBLE, 1, coordinateDimensions),
            "Unable to create the node coordinate memory type."),
        H5Tclose};
    Hdf5Handle fileType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(NodeWriteRow)),
            "Unable to create the node file type."),
        H5Tclose};
    Hdf5Handle memoryType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(NodeWriteRow)),
            "Unable to create the node memory type."),
        H5Tclose};
    requireHdf5(
        H5Tinsert(fileType.get(), "internal_node_id",
                  HOFFSET(NodeWriteRow, internalNodeId), H5T_STD_U64LE),
        "Unable to define the node internal ID field.");
    requireHdf5(
        H5Tinsert(fileType.get(), "instance_name",
                  HOFFSET(NodeWriteRow, instanceName), stringType.get()),
        "Unable to define the node instance field.");
    requireHdf5(
        H5Tinsert(fileType.get(), "source_label",
                  HOFFSET(NodeWriteRow, sourceLabel), stringType.get()),
        "Unable to define the node source-label field.");
    requireHdf5(
        H5Tinsert(fileType.get(), "coordinates",
                  HOFFSET(NodeWriteRow, coordinates), fileCoordinates.get()),
        "Unable to define the node coordinate field.");
    requireHdf5(
        H5Tinsert(memoryType.get(), "internal_node_id",
                  HOFFSET(NodeWriteRow, internalNodeId), H5T_NATIVE_UINT64),
        "Unable to define the node internal ID memory field.");
    requireHdf5(
        H5Tinsert(memoryType.get(), "instance_name",
                  HOFFSET(NodeWriteRow, instanceName), stringType.get()),
        "Unable to define the node instance memory field.");
    requireHdf5(
        H5Tinsert(memoryType.get(), "source_label",
                  HOFFSET(NodeWriteRow, sourceLabel), stringType.get()),
        "Unable to define the node source-label memory field.");
    requireHdf5(
        H5Tinsert(memoryType.get(), "coordinates",
                  HOFFSET(NodeWriteRow, coordinates), memoryCoordinates.get()),
        "Unable to define the node coordinate memory field.");

    auto dataset = writeCompoundDataset(
        file, "/model/nodes", rows.size(), fileType.get(), memoryType.get(),
        rows.data());
    writeStringAttribute(dataset.get(), "coordinate_system", "global-cartesian");
    writeStringAttribute(dataset.get(), "units_label", "length");
}

void writeBeamElements(
    const hid_t file, const Domain& domain, const std::vector<AxisSet>& axes) {
    std::vector<ElementWriteRow> rows;
    rows.reserve(domain.elements().size());
    for (std::size_t index = 0U; index < domain.elements().size(); ++index) {
        const auto& element = domain.elements()[index];
        ElementWriteRow row{
            static_cast<std::uint64_t>(index),
            element.sourceId.instanceName.c_str(),
            element.sourceId.sourceLabelText.c_str(),
            {static_cast<std::uint64_t>(element.nodeIndices[0U]),
             static_cast<std::uint64_t>(element.nodeIndices[1U])},
            {}};
        std::copy(axes[index].begin(), axes[index].end(), row.localAxes);
        rows.push_back(row);
    }

    auto stringType = makeUtf8StringType();
    const hsize_t nodeDimensions[] = {2U};
    const hsize_t axisDimensions[] = {3U, 3U};
    Hdf5Handle fileNodes{
        requireHdf5Id(
            H5Tarray_create2(H5T_STD_U64LE, 1, nodeDimensions),
            "Unable to create the element connectivity file type."),
        H5Tclose};
    Hdf5Handle memoryNodes{
        requireHdf5Id(
            H5Tarray_create2(H5T_NATIVE_UINT64, 1, nodeDimensions),
            "Unable to create the element connectivity memory type."),
        H5Tclose};
    Hdf5Handle fileAxes{
        requireHdf5Id(
            H5Tarray_create2(H5T_IEEE_F64LE, 2, axisDimensions),
            "Unable to create the local-axis file type."),
        H5Tclose};
    Hdf5Handle memoryAxes{
        requireHdf5Id(
            H5Tarray_create2(H5T_NATIVE_DOUBLE, 2, axisDimensions),
            "Unable to create the local-axis memory type."),
        H5Tclose};
    Hdf5Handle fileType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(ElementWriteRow)),
            "Unable to create the element file type."),
        H5Tclose};
    Hdf5Handle memoryType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(ElementWriteRow)),
            "Unable to create the element memory type."),
        H5Tclose};
    const auto insertFields = [&](const hid_t type,
                                  const hid_t integerType,
                                  const hid_t nodeType,
                                  const hid_t axesType) {
        requireHdf5(
            H5Tinsert(type, "internal_element_id",
                      HOFFSET(ElementWriteRow, internalElementId), integerType),
            "Unable to define the element internal ID field.");
        requireHdf5(
            H5Tinsert(type, "instance_name",
                      HOFFSET(ElementWriteRow, instanceName), stringType.get()),
            "Unable to define the element instance field.");
        requireHdf5(
            H5Tinsert(type, "source_label",
                      HOFFSET(ElementWriteRow, sourceLabel), stringType.get()),
            "Unable to define the element source-label field.");
        requireHdf5(
            H5Tinsert(type, "node_internal_ids",
                      HOFFSET(ElementWriteRow, nodeInternalIds), nodeType),
            "Unable to define the element connectivity field.");
        requireHdf5(
            H5Tinsert(type, "local_axes",
                      HOFFSET(ElementWriteRow, localAxes), axesType),
            "Unable to define the element local-axis field.");
    };
    insertFields(fileType.get(), H5T_STD_U64LE, fileNodes.get(), fileAxes.get());
    insertFields(
        memoryType.get(), H5T_NATIVE_UINT64, memoryNodes.get(), memoryAxes.get());
    auto dataset = writeCompoundDataset(
        file, "/model/elements", rows.size(), fileType.get(), memoryType.get(),
        rows.data());
    writeStringAttribute(
        dataset.get(), "formulation", "B33-3D-Euler-Bernoulli");
}

void writeShellElements(const hid_t file, const Domain& domain) {
    std::vector<ShellElementWriteRow> rows;
    rows.reserve(domain.shellElements().size());
    for (std::size_t index = 0U; index < domain.shellElements().size(); ++index) {
        const auto& element = domain.shellElements()[index];
        rows.push_back({
            static_cast<std::uint64_t>(index),
            element.sourceId.instanceName.c_str(),
            element.sourceId.sourceLabelText.c_str(),
            shellSourceTypeName(element.sourceType),
            kMitc4InternalFormulation.data(),
            {static_cast<std::uint64_t>(element.nodeIndices[0U]),
             static_cast<std::uint64_t>(element.nodeIndices[1U]),
             static_cast<std::uint64_t>(element.nodeIndices[2U]),
             static_cast<std::uint64_t>(element.nodeIndices[3U])},
            static_cast<std::uint64_t>(element.sectionIndex),
            static_cast<std::uint64_t>(element.materialIndex)});
    }

    auto stringType = makeUtf8StringType();
    const hsize_t nodeDimensions[] = {kShellNodeCount};
    Hdf5Handle fileNodes{
        requireHdf5Id(
            H5Tarray_create2(H5T_STD_U64LE, 1, nodeDimensions),
            "Unable to create shell connectivity file type."),
        H5Tclose};
    Hdf5Handle memoryNodes{
        requireHdf5Id(
            H5Tarray_create2(H5T_NATIVE_UINT64, 1, nodeDimensions),
            "Unable to create shell connectivity memory type."),
        H5Tclose};
    Hdf5Handle fileType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(ShellElementWriteRow)),
            "Unable to create shell element file type."),
        H5Tclose};
    Hdf5Handle memoryType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(ShellElementWriteRow)),
            "Unable to create shell element memory type."),
        H5Tclose};
    const auto insertFields = [&](const hid_t type,
                                  const hid_t integerType,
                                  const hid_t nodeType) {
        requireHdf5(
            H5Tinsert(type, "internal_element_id",
                      HOFFSET(ShellElementWriteRow, internalElementId), integerType),
            "Unable to define shell element ID field.");
        requireHdf5(
            H5Tinsert(type, "instance_name",
                      HOFFSET(ShellElementWriteRow, instanceName), stringType.get()),
            "Unable to define shell element instance field.");
        requireHdf5(
            H5Tinsert(type, "source_label",
                      HOFFSET(ShellElementWriteRow, sourceLabel), stringType.get()),
            "Unable to define shell element source-label field.");
        requireHdf5(
            H5Tinsert(type, "source_element_type",
                      HOFFSET(ShellElementWriteRow, sourceElementType), stringType.get()),
            "Unable to define shell source-type field.");
        requireHdf5(
            H5Tinsert(type, "internal_formulation",
                      HOFFSET(ShellElementWriteRow, internalFormulation), stringType.get()),
            "Unable to define shell formulation field.");
        requireHdf5(
            H5Tinsert(type, "node_internal_ids",
                      HOFFSET(ShellElementWriteRow, nodeInternalIds), nodeType),
            "Unable to define shell connectivity field.");
        requireHdf5(
            H5Tinsert(type, "shell_section_internal_id",
                      HOFFSET(ShellElementWriteRow, shellSectionInternalId), integerType),
            "Unable to define shell section ID field.");
        requireHdf5(
            H5Tinsert(type, "material_internal_id",
                      HOFFSET(ShellElementWriteRow, materialInternalId), integerType),
            "Unable to define shell material ID field.");
    };
    insertFields(fileType.get(), H5T_STD_U64LE, fileNodes.get());
    insertFields(memoryType.get(), H5T_NATIVE_UINT64, memoryNodes.get());
    auto dataset = writeCompoundDataset(
        file, "/model/elements", rows.size(), fileType.get(), memoryType.get(),
        rows.data());
    writeStringAttribute(dataset.get(), "formulation", "FESA-MITC4");
}

void writeShellMaterials(const hid_t file, const Domain& domain) {
    std::vector<ShellMaterialWriteRow> rows;
    rows.reserve(domain.materials().size());
    for (std::size_t index = 0U; index < domain.materials().size(); ++index) {
        const auto& material = domain.materials()[index];
        rows.push_back({
            static_cast<std::uint64_t>(index),
            material.name.c_str(),
            material.youngsModulus,
            material.poissonRatio});
    }
    auto stringType = makeUtf8StringType();
    Hdf5Handle fileType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(ShellMaterialWriteRow)),
            "Unable to create shell material file type."),
        H5Tclose};
    Hdf5Handle memoryType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(ShellMaterialWriteRow)),
            "Unable to create shell material memory type."),
        H5Tclose};
    const auto insertFields = [&](const hid_t type,
                                  const hid_t integerType,
                                  const hid_t doubleType) {
        requireHdf5(
            H5Tinsert(type, "internal_material_id",
                      HOFFSET(ShellMaterialWriteRow, internalMaterialId), integerType),
            "Unable to define shell material ID field.");
        requireHdf5(
            H5Tinsert(type, "name",
                      HOFFSET(ShellMaterialWriteRow, name), stringType.get()),
            "Unable to define shell material name field.");
        requireHdf5(
            H5Tinsert(type, "E", HOFFSET(ShellMaterialWriteRow, youngsModulus),
                      doubleType),
            "Unable to define shell material E field.");
        requireHdf5(
            H5Tinsert(type, "nu", HOFFSET(ShellMaterialWriteRow, poissonRatio),
                      doubleType),
            "Unable to define shell material nu field.");
    };
    insertFields(fileType.get(), H5T_STD_U64LE, H5T_IEEE_F64LE);
    insertFields(memoryType.get(), H5T_NATIVE_UINT64, H5T_NATIVE_DOUBLE);
    auto dataset = writeCompoundDataset(
        file, "/model/shell/materials", rows.size(), fileType.get(),
        memoryType.get(), rows.data());
    writeStringAttribute(dataset.get(), "component_unit_dimensions", "force/length^2,1");
}

void writeShellSections(const hid_t file, const Domain& domain) {
    std::vector<std::string> sourceFiles;
    sourceFiles.reserve(domain.shellSections().size());
    for (const auto& section : domain.shellSections()) {
        sourceFiles.push_back(normalizedPathString(section.location.file));
    }
    std::vector<ShellSectionWriteRow> rows;
    rows.reserve(domain.shellSections().size());
    for (std::size_t index = 0U; index < domain.shellSections().size(); ++index) {
        const auto& section = domain.shellSections()[index];
        rows.push_back({
            static_cast<std::uint64_t>(index),
            sourceFiles[index].c_str(),
            static_cast<std::uint64_t>(section.location.line),
            section.name.c_str(),
            static_cast<std::uint64_t>(section.materialIndex),
            section.thickness});
    }
    auto stringType = makeUtf8StringType();
    Hdf5Handle fileType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(ShellSectionWriteRow)),
            "Unable to create shell section file type."),
        H5Tclose};
    Hdf5Handle memoryType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(ShellSectionWriteRow)),
            "Unable to create shell section memory type."),
        H5Tclose};
    const auto insertFields = [&](const hid_t type,
                                  const hid_t integerType,
                                  const hid_t doubleType) {
        requireHdf5(
            H5Tinsert(type, "internal_section_id",
                      HOFFSET(ShellSectionWriteRow, internalSectionId), integerType),
            "Unable to define shell section ID field.");
        requireHdf5(
            H5Tinsert(type, "source_file",
                      HOFFSET(ShellSectionWriteRow, sourceFile), stringType.get()),
            "Unable to define shell section source-file field.");
        requireHdf5(
            H5Tinsert(type, "source_line",
                      HOFFSET(ShellSectionWriteRow, sourceLine), integerType),
            "Unable to define shell section source-line field.");
        requireHdf5(
            H5Tinsert(type, "source_elset",
                      HOFFSET(ShellSectionWriteRow, sourceElset), stringType.get()),
            "Unable to define shell section ELSET field.");
        requireHdf5(
            H5Tinsert(type, "material_internal_id",
                      HOFFSET(ShellSectionWriteRow, materialInternalId), integerType),
            "Unable to define shell section material ID field.");
        requireHdf5(
            H5Tinsert(type, "thickness",
                      HOFFSET(ShellSectionWriteRow, thickness), doubleType),
            "Unable to define shell section thickness field.");
    };
    insertFields(fileType.get(), H5T_STD_U64LE, H5T_IEEE_F64LE);
    insertFields(memoryType.get(), H5T_NATIVE_UINT64, H5T_NATIVE_DOUBLE);
    auto dataset = writeCompoundDataset(
        file, "/model/shell/sections", rows.size(), fileType.get(),
        memoryType.get(), rows.data());
    writeStringAttribute(dataset.get(), "thickness_unit_dimension", "length");
    writeStringAttribute(dataset.get(), "layering", "centered-single-layer");
}

void writeShellModelData(
    const hid_t file, const Domain& domain, const WriterModelData& modelData) {
    std::vector<double> directors;
    directors.reserve(domain.nodes().size() * 3U);
    std::vector<double> frames;
    frames.reserve(domain.nodes().size() * 9U);
    for (const auto& frame : domain.shellNodeInitialFrames()) {
        directors.insert(
            directors.end(), frame.director.begin(), frame.director.end());
        frames.insert(frames.end(), frame.tangentA.begin(), frame.tangentA.end());
        frames.insert(frames.end(), frame.tangentB.begin(), frame.tangentB.end());
        frames.insert(frames.end(), frame.director.begin(), frame.director.end());
    }
    writeModelDoubleDataset(
        file, "/model/shell/nodal_director",
        {static_cast<hsize_t>(domain.nodes().size()), 3U},
        directors.data(), directors.size(), "D1,D2,D3", "1,1,1",
        "global-cartesian", "nodal");
    writeModelDoubleDataset(
        file, "/model/shell/nodal_frame",
        {static_cast<hsize_t>(domain.nodes().size()), 3U, 3U},
        frames.data(), frames.size(), "X,Y,Z", "1,1,1",
        "global-cartesian", "nodal-frame");
    {
        Hdf5Handle dataset{
            requireHdf5Id(
                H5Dopen2(file, "/model/shell/nodal_frame", H5P_DEFAULT),
                "Unable to reopen the nodal-frame dataset."),
            H5Dclose};
        writeStringAttribute(dataset.get(), "axis_names", "A,B,D");
    }

    writeShellMaterials(file, domain);
    writeShellSections(file, domain);
    const std::vector<hsize_t> nodalDimensions{
        static_cast<hsize_t>(domain.nodes().size()), kDofsPerNode};
    writeUint8Dataset(
        file, "/model/nodal_constraint_mask", nodalDimensions,
        modelData.constraintMask.data(), modelData.constraintMask.size());
    writeModelDoubleDataset(
        file, "/model/prescribed_displacement", nodalDimensions,
        modelData.prescribedDisplacement.data(),
        modelData.prescribedDisplacement.size(),
        "UX,UY,UZ,URX,URY,URZ",
        "length,length,length,radian,radian,radian",
        "global-cartesian", "nodal-prescribed-value");

    const double gauss = 1.0 / std::sqrt(3.0);
    const std::array<double, 8> locations{
        -gauss, -gauss,
        gauss, -gauss,
        gauss, gauss,
        -gauss, gauss};
    writeModelDoubleDataset(
        file, "/model/shell/midsurface_locations", {4U, 2U},
        locations.data(), locations.size(), "XI,ETA", "1,1",
        "shell-natural", "midsurface-location");
    const std::array<double, 3> sectionPositions{-1.0, 0.0, 1.0};
    writeModelDoubleDataset(
        file, "/model/shell/section_positions", {3U},
        sectionPositions.data(), sectionPositions.size(), "ZETA", "1",
        "shell-natural", "section-position");
    {
        Hdf5Handle dataset{
            requireHdf5Id(
                H5Dopen2(file, "/model/shell/section_positions", H5P_DEFAULT),
                "Unable to reopen shell section positions."),
            H5Dclose};
        writeStringAttribute(dataset.get(), "position_names", "BOTTOM,MIDDLE,TOP");
    }
}

std::vector<double> flattenEndpointValues(
    const std::vector<EndpointResultRow>& rows,
    const bool sectionResultants) {
    const std::size_t components =
        sectionResultants ? kGeneralizedComponentCount : kEndActionComponentCount;
    std::vector<double> values;
    values.reserve(rows.size() * components);
    for (const auto& row : rows) {
        if (sectionResultants) {
            values.insert(
                values.end(), row.sectionResultant.begin(), row.sectionResultant.end());
        } else {
            values.insert(values.end(), row.endAction.begin(), row.endAction.end());
        }
    }
    return values;
}

std::vector<double> flattenGaussValues(
    const std::vector<GaussResultRow>& rows,
    const bool resultants) {
    std::vector<double> values;
    values.reserve(rows.size() * kGeneralizedComponentCount);
    for (const auto& row : rows) {
        const auto& rowValues =
            resultants ? row.generalizedResultant : row.generalizedStrain;
        values.insert(values.end(), rowValues.begin(), rowValues.end());
    }
    return values;
}

void writeStress(const hid_t file, const AnalysisState& state) {
    std::vector<StressWriteRow> rows;
    rows.reserve(state.stressResults().size());
    for (const auto& row : state.stressResults()) {
        rows.push_back({
            static_cast<std::uint64_t>(row.element),
            static_cast<std::uint64_t>(row.gaussPoint),
            static_cast<std::uint64_t>(row.sectionPoint),
            row.x1,
            row.x2,
            row.source.c_str(),
            row.s11});
    }
    auto stringType = makeUtf8StringType();
    Hdf5Handle fileType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(StressWriteRow)),
            "Unable to create the stress file type."),
        H5Tclose};
    Hdf5Handle memoryType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(StressWriteRow)),
            "Unable to create the stress memory type."),
        H5Tclose};
    const auto insertFields = [&](const hid_t type,
                                  const hid_t integerType,
                                  const hid_t doubleType) {
        requireHdf5(
            H5Tinsert(type, "internal_element_id",
                      HOFFSET(StressWriteRow, internalElementId), integerType),
            "Unable to define the stress element field.");
        requireHdf5(
            H5Tinsert(type, "gauss_point_index",
                      HOFFSET(StressWriteRow, gaussPointIndex), integerType),
            "Unable to define the stress Gauss field.");
        requireHdf5(
            H5Tinsert(type, "section_point_index",
                      HOFFSET(StressWriteRow, sectionPointIndex), integerType),
            "Unable to define the stress section-point field.");
        requireHdf5(
            H5Tinsert(type, "x1", HOFFSET(StressWriteRow, x1), doubleType),
            "Unable to define the stress x1 field.");
        requireHdf5(
            H5Tinsert(type, "x2", HOFFSET(StressWriteRow, x2), doubleType),
            "Unable to define the stress x2 field.");
        requireHdf5(
            H5Tinsert(type, "source", HOFFSET(StressWriteRow, source), stringType.get()),
            "Unable to define the stress source field.");
        requireHdf5(
            H5Tinsert(type, "S11", HOFFSET(StressWriteRow, s11), doubleType),
            "Unable to define the stress S11 field.");
    };
    insertFields(fileType.get(), H5T_STD_U64LE, H5T_IEEE_F64LE);
    insertFields(memoryType.get(), H5T_NATIVE_UINT64, H5T_NATIVE_DOUBLE);
    auto dataset = writeCompoundDataset(
        file,
        "/steps/Step-1/frames/0/element/stress_s11",
        rows.size(),
        fileType.get(),
        memoryType.get(),
        rows.data());
    writeResultAttributes(
        dataset.get(), "S11", "force/length^2", "beam-local", "section-point");
}

void writeShellResultIdentity(
    const hid_t file,
    const std::string& path,
    const bool usesSectionPositions) {
    Hdf5Handle dataset{
        requireHdf5Id(
            H5Dopen2(file, path.c_str(), H5P_DEFAULT),
            "Unable to reopen a shell result dataset."),
        H5Dclose};
    writeStringAttribute(
        dataset.get(),
        "source_element_type_dataset",
        "/model/elements.source_element_type");
    writeStringAttribute(dataset.get(), "internal_formulation", "FESA-MITC4");
    writeStringAttribute(
        dataset.get(),
        "midsurface_location_dataset",
        "/model/shell/midsurface_locations");
    writeStringAttribute(
        dataset.get(),
        "local_frame_dataset",
        "/steps/Step-1/frames/0/element/shell/local_frame");
    if (usesSectionPositions) {
        writeStringAttribute(
            dataset.get(),
            "section_position_dataset",
            "/model/shell/section_positions");
    }
}

void writeShellResultDatasets(
    const hid_t file, const Domain& domain, const AnalysisState& state) {
    std::vector<double> localFrames;
    std::vector<double> generalizedStrains;
    std::vector<double> sectionResultants;
    std::vector<double> stresses;
    localFrames.reserve(state.shellResults().size() * 9U);
    generalizedStrains.reserve(
        state.shellResults().size() * kShellGeneralizedComponentCount);
    sectionResultants.reserve(
        state.shellResults().size() * kShellGeneralizedComponentCount);
    stresses.reserve(
        state.shellResults().size() * kShellSectionPositionCount *
        kShellStressComponentCount);
    for (const auto& row : state.shellResults()) {
        for (const auto& axis : row.localFrame) {
            localFrames.insert(localFrames.end(), axis.begin(), axis.end());
        }
        generalizedStrains.insert(
            generalizedStrains.end(),
            row.generalizedStrain.begin(),
            row.generalizedStrain.end());
        sectionResultants.insert(
            sectionResultants.end(),
            row.sectionResultant.begin(),
            row.sectionResultant.end());
        for (const auto& position : row.stress) {
            stresses.insert(
                stresses.end(),
                position.components.begin(),
                position.components.end());
        }
    }

    const hsize_t elementCount =
        static_cast<hsize_t>(domain.shellElements().size());
    const std::string root = std::string{kStepRoot} + "/element/shell";
    const std::string framePath = root + "/local_frame";
    writeDoubleDataset(
        file, framePath, {elementCount, 4U, 3U, 3U},
        localFrames.data(), localFrames.size(), "X,Y,Z", "1,1,1",
        "global-cartesian", "shell-local-frame");
    {
        Hdf5Handle dataset{
            requireHdf5Id(
                H5Dopen2(file, framePath.c_str(), H5P_DEFAULT),
                "Unable to reopen shell local-frame results."),
            H5Dclose};
        writeStringAttribute(dataset.get(), "axis_names", "E1,E2,E3");
        writeStringAttribute(
            dataset.get(),
            "source_element_type_dataset",
            "/model/elements.source_element_type");
        writeStringAttribute(dataset.get(), "internal_formulation", "FESA-MITC4");
        writeStringAttribute(
            dataset.get(),
            "midsurface_location_dataset",
            "/model/shell/midsurface_locations");
    }

    const std::string strainPath = root + "/generalized_strain";
    writeDoubleDataset(
        file, strainPath, {elementCount, 4U, 8U},
        generalizedStrains.data(), generalizedStrains.size(),
        "E11,E22,G12,K11,K22,K12,G13,G23",
        "1,1,1,1/length,1/length,1/length,1,1",
        "shell-local", "midsurface");
    writeShellResultIdentity(file, strainPath, false);

    const std::string resultantPath = root + "/section_resultant";
    writeDoubleDataset(
        file, resultantPath, {elementCount, 4U, 8U},
        sectionResultants.data(), sectionResultants.size(),
        "N11,N22,N12,M11,M22,M12,Q13,Q23",
        "force/length,force/length,force/length,force,force,force,force/length,force/length",
        "shell-local", "midsurface");
    writeShellResultIdentity(file, resultantPath, false);

    const std::string stressPath = root + "/stress";
    writeDoubleDataset(
        file, stressPath, {elementCount, 4U, 3U, 3U},
        stresses.data(), stresses.size(), "S11,S22,S12",
        "force/length^2,force/length^2,force/length^2",
        "shell-local", "section-position");
    writeShellResultIdentity(file, stressPath, true);

    const double energy = state.physicalStrainEnergy();
    writeDoubleDataset(
        file, std::string{kStepRoot} + "/global/energy", {1U},
        &energy, 1U, "PHYSICAL_STRAIN_ENERGY", "force*length",
        "global", "global");
    writeDoubleDataset(
        file, std::string{kStepRoot} + "/global/equilibrium", {6U},
        state.equilibrium().data(), state.equilibrium().size(),
        "FORCE_1,FORCE_2,FORCE_3,MOMENT_1,MOMENT_2,MOMENT_3",
        "force,force,force,force*length,force*length,force*length",
        "global-cartesian", "global-origin");
    const std::string metricsPath =
        std::string{kStepRoot} + "/global/verification_metrics";
    writeDoubleDataset(
        file, metricsPath, {3U}, state.verificationMetrics().data(),
        state.verificationMetrics().size(),
        "FREE_RESIDUAL_NORMALIZED,FORCE_BALANCE_NORMALIZED,MOMENT_BALANCE_NORMALIZED",
        "1,1,1", "global", "verification");
    {
        Hdf5Handle dataset{
            requireHdf5Id(
                H5Dopen2(file, metricsPath.c_str(), H5P_DEFAULT),
                "Unable to reopen shell verification metrics."),
            H5Dclose};
        writeStringAttribute(
            dataset.get(),
            "metric_definition_ids",
            "free-residual-l2-over-max-free-force-l2,force-balance-l2-over-max-force-sum,moment-balance-l2-over-max-moment-sum");
        writeStringAttribute(
            dataset.get(), "acceptance_thresholds", "1e-10,1e-10,1e-10");
    }
}

void writeDiagnostics(
    const hid_t file, const std::vector<Diagnostic>& inputDiagnostics) {
    std::vector<Diagnostic> diagnostics = inputDiagnostics;
    sortDiagnostics(diagnostics);
    std::vector<std::string> files;
    files.reserve(diagnostics.size());
    for (const auto& diagnostic : diagnostics) {
        files.push_back(normalizedPathString(diagnostic.location.file));
    }
    std::vector<DiagnosticWriteRow> rows;
    rows.reserve(diagnostics.size());
    for (std::size_t index = 0U; index < diagnostics.size(); ++index) {
        const auto& diagnostic = diagnostics[index];
        rows.push_back({
            diagnostic.severity == Severity::warning ? "warning" : "error",
            diagnostic.code.c_str(),
            files[index].c_str(),
            static_cast<std::uint64_t>(diagnostic.location.line),
            diagnostic.keyword.c_str(),
            diagnostic.entityIdentity.c_str(),
            diagnostic.message.c_str()});
    }

    auto stringType = makeUtf8StringType();
    Hdf5Handle fileType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(DiagnosticWriteRow)),
            "Unable to create the diagnostic file type."),
        H5Tclose};
    Hdf5Handle memoryType{
        requireHdf5Id(
            H5Tcreate(H5T_COMPOUND, sizeof(DiagnosticWriteRow)),
            "Unable to create the diagnostic memory type."),
        H5Tclose};
    const auto insertFields = [&](const hid_t type, const hid_t integerType) {
        requireHdf5(
            H5Tinsert(type, "severity", HOFFSET(DiagnosticWriteRow, severity),
                      stringType.get()),
            "Unable to define diagnostic severity.");
        requireHdf5(
            H5Tinsert(type, "code", HOFFSET(DiagnosticWriteRow, code),
                      stringType.get()),
            "Unable to define diagnostic code.");
        requireHdf5(
            H5Tinsert(type, "file", HOFFSET(DiagnosticWriteRow, file),
                      stringType.get()),
            "Unable to define diagnostic file.");
        requireHdf5(
            H5Tinsert(type, "line", HOFFSET(DiagnosticWriteRow, line), integerType),
            "Unable to define diagnostic line.");
        requireHdf5(
            H5Tinsert(type, "keyword", HOFFSET(DiagnosticWriteRow, keyword),
                      stringType.get()),
            "Unable to define diagnostic keyword.");
        requireHdf5(
            H5Tinsert(type, "entity_identity",
                      HOFFSET(DiagnosticWriteRow, entityIdentity), stringType.get()),
            "Unable to define diagnostic entity identity.");
        requireHdf5(
            H5Tinsert(type, "message", HOFFSET(DiagnosticWriteRow, message),
                      stringType.get()),
            "Unable to define diagnostic message.");
    };
    insertFields(fileType.get(), H5T_STD_U64LE);
    insertFields(memoryType.get(), H5T_NATIVE_UINT64);
    (void)writeCompoundDataset(
        file, "/diagnostics", rows.size(), fileType.get(), memoryType.get(),
        rows.data());
}

void writeResultDatasets(
    const hid_t file, const Domain& domain, const AnalysisState& state) {
    const std::vector<hsize_t> nodalDimensions = {
        static_cast<hsize_t>(domain.nodes().size()), kDofsPerNode};
    writeDoubleDataset(
        file,
        std::string{kStepRoot} + "/nodal/displacement",
        nodalDimensions,
        state.displacement().data(),
        state.displacement().size(),
        "UX,UY,UZ,URX,URY,URZ",
        "length,length,length,radian,radian,radian",
        "global-cartesian",
        "nodal");
    writeDoubleDataset(
        file,
        std::string{kStepRoot} + "/nodal/reaction",
        nodalDimensions,
        state.reaction().data(),
        state.reaction().size(),
        "RF1,RF2,RF3,RM1,RM2,RM3",
        "force,force,force,force*length,force*length,force*length",
        "global-cartesian",
        "nodal");

    if (isShellDomain(domain)) {
        writeShellResultDatasets(file, domain, state);
        return;
    }

    const std::vector<hsize_t> endpointActionDimensions = {
        static_cast<hsize_t>(domain.elements().size()),
        kEndpointCount,
        kEndActionComponentCount};
    const std::vector<hsize_t> generalizedDimensions = {
        static_cast<hsize_t>(domain.elements().size()),
        kEndpointCount,
        kGeneralizedComponentCount};
    const auto endActions = flattenEndpointValues(state.endpointResults(), false);
    writeDoubleDataset(
        file,
        std::string{kStepRoot} + "/element/end_force_local",
        endpointActionDimensions,
        endActions.data(),
        endActions.size(),
        "FX,FY,FZ,MX,MY,MZ",
        "force,force,force,force*length,force*length,force*length",
        "beam-local",
        "endpoint-outward-action");
    const auto sectionResultants =
        flattenEndpointValues(state.endpointResults(), true);
    writeDoubleDataset(
        file,
        std::string{kStepRoot} + "/element/section_resultant",
        generalizedDimensions,
        sectionResultants.data(),
        sectionResultants.size(),
        "N,T,My,Mz",
        "force,force*length,force*length,force*length",
        "beam-local",
        "endpoint-positive-local-x-section-cut");
    const auto generalizedStrains =
        flattenGaussValues(state.gaussResults(), false);
    writeDoubleDataset(
        file,
        std::string{kStepRoot} + "/element/generalized_strain",
        generalizedDimensions,
        generalizedStrains.data(),
        generalizedStrains.size(),
        "epsilon0,kappa_x,kappa_y,kappa_z",
        "1,1/length,1/length,1/length",
        "beam-local",
        "integration-point");
    const auto generalizedResultants =
        flattenGaussValues(state.gaussResults(), true);
    writeDoubleDataset(
        file,
        std::string{kStepRoot} + "/element/generalized_resultant",
        generalizedDimensions,
        generalizedResultants.data(),
        generalizedResultants.size(),
        "N,T,My,Mz",
        "force,force*length,force*length,force*length",
        "beam-local",
        "integration-point");
    writeStress(file, state);
}

void writeFile(
    const std::filesystem::path& temporaryPath,
    const Domain& domain,
    const AnalysisState& state,
    const std::vector<Diagnostic>& diagnostics,
    const WriterModelData& modelData) {
    Hdf5Handle file{
        requireHdf5Id(
            H5Fcreate(
                temporaryPath.string().c_str(), H5F_ACC_EXCL,
                H5P_DEFAULT, H5P_DEFAULT),
            "Unable to create the temporary HDF5 file."),
        H5Fclose};
    writeMetadata(file.get(), domain);
    (void)createGroup(file.get(), "/model");
    (void)createGroup(file.get(), "/steps/Step-1/frames/0/nodal");
    (void)createGroup(file.get(), "/steps/Step-1/frames/0/element");
    if (isShellDomain(domain)) {
        (void)createGroup(file.get(), "/model/shell");
        (void)createGroup(file.get(), "/steps/Step-1/frames/0/element/shell");
        (void)createGroup(file.get(), "/steps/Step-1/frames/0/global");
    }
    writeNodes(file.get(), domain);
    if (isShellDomain(domain)) {
        writeShellElements(file.get(), domain);
        writeShellModelData(file.get(), domain, modelData);
    } else {
        writeBeamElements(file.get(), domain, modelData.beamLocalAxes);
    }
    writeResultDatasets(file.get(), domain, state);
    writeDiagnostics(file.get(), diagnostics);
    requireHdf5(
        H5Fflush(file.get(), H5F_SCOPE_GLOBAL),
        "Unable to flush the temporary HDF5 file.");
    requireHdf5(
        file.closeChecked(),
        "Unable to close the temporary HDF5 file after writing.");
}

Hdf5Handle openDatasetForCheck(const hid_t file, const char* path) {
    return Hdf5Handle{
        requireHdf5Id(
            H5Dopen2(file, path, H5P_DEFAULT),
            "A mandatory HDF5 dataset is missing."),
        H5Dclose};
}

std::vector<hsize_t> checkedDimensions(const hid_t dataset) {
    Hdf5Handle space{
        requireHdf5Id(
            H5Dget_space(dataset), "Unable to inspect an HDF5 dataspace."),
        H5Sclose};
    const int rank = H5Sget_simple_extent_ndims(space.get());
    if (rank < 0) {
        throw Hdf5Failure{"Unable to inspect an HDF5 dataset rank."};
    }
    std::vector<hsize_t> dimensions(static_cast<std::size_t>(rank));
    if (rank > 0) {
        requireHdf5(
            H5Sget_simple_extent_dims(space.get(), dimensions.data(), nullptr),
            "Unable to inspect HDF5 dataset dimensions.");
    }
    return dimensions;
}

void requireStringAttribute(
    const hid_t object, const char* name, const std::string& expected) {
    Hdf5Handle attribute{
        requireHdf5Id(
            H5Aopen(object, name, H5P_DEFAULT),
            "A mandatory HDF5 string attribute is missing."),
        H5Aclose};
    Hdf5Handle type{
        requireHdf5Id(
            H5Aget_type(attribute.get()), "Unable to inspect an HDF5 attribute type."),
        H5Tclose};
    if (H5Tget_class(type.get()) != H5T_STRING ||
        H5Tis_variable_str(type.get()) <= 0 ||
        H5Tget_cset(type.get()) != H5T_CSET_UTF8) {
        throw Hdf5Failure{"An HDF5 string attribute is not variable-length UTF-8."};
    }
    char* raw = nullptr;
    requireHdf5(
        H5Aread(attribute.get(), type.get(), &raw),
        "Unable to read an HDF5 string attribute.");
    const std::string actual = raw == nullptr ? std::string{} : std::string{raw};
    if (raw != nullptr) {
        requireHdf5(H5free_memory(raw), "Unable to release an HDF5 string value.");
    }
    if (actual != expected) {
        throw Hdf5Failure{"An HDF5 string attribute has the wrong value."};
    }
}

void requireUint64Attribute(
    const hid_t object, const char* name, const std::uint64_t expected) {
    Hdf5Handle attribute{
        requireHdf5Id(
            H5Aopen(object, name, H5P_DEFAULT),
            "A mandatory HDF5 integer attribute is missing."),
        H5Aclose};
    Hdf5Handle type{
        requireHdf5Id(
            H5Aget_type(attribute.get()),
            "Unable to inspect an HDF5 integer attribute type."),
        H5Tclose};
    if (H5Tget_class(type.get()) != H5T_INTEGER ||
        H5Tget_size(type.get()) != sizeof(std::uint64_t) ||
        H5Tget_sign(type.get()) != H5T_SGN_NONE ||
        H5Tequal(type.get(), H5T_STD_U64LE) <= 0) {
        throw Hdf5Failure{"An HDF5 integer attribute is not portable uint64."};
    }
    std::uint64_t actual = 0U;
    requireHdf5(
        H5Aread(attribute.get(), H5T_NATIVE_UINT64, &actual),
        "Unable to read an HDF5 integer attribute.");
    if (actual != expected) {
        throw Hdf5Failure{"An HDF5 integer attribute has the wrong value."};
    }
}

void requirePortableCompoundMember(
    const hid_t compoundType, const unsigned index, const std::string& name) {
    Hdf5Handle memberType{
        requireHdf5Id(
            H5Tget_member_type(compoundType, index),
            "Unable to inspect a compound HDF5 field type."),
        H5Tclose};
    const bool isUint64 =
        name == "internal_node_id" || name == "internal_element_id" ||
        name == "internal_material_id" || name == "internal_section_id" ||
        name == "shell_section_internal_id" ||
        name == "material_internal_id" || name == "source_line" ||
        name == "gauss_point_index" || name == "section_point_index" ||
        name == "line";
    const bool isFloat64 =
        name == "x1" || name == "x2" || name == "S11" ||
        name == "E" || name == "nu" || name == "thickness";
    const bool isString =
        name == "instance_name" || name == "source_label" ||
        name == "source_element_type" || name == "internal_formulation" ||
        name == "name" || name == "source_file" || name == "source_elset" ||
        name == "source" || name == "severity" || name == "code" ||
        name == "file" || name == "keyword" ||
        name == "entity_identity" || name == "message";
    if (isUint64) {
        if (H5Tget_class(memberType.get()) != H5T_INTEGER ||
            H5Tget_size(memberType.get()) != sizeof(std::uint64_t) ||
            H5Tget_sign(memberType.get()) != H5T_SGN_NONE ||
            H5Tequal(memberType.get(), H5T_STD_U64LE) <= 0) {
            throw Hdf5Failure{"A compound HDF5 field is not portable uint64."};
        }
        return;
    }
    if (isFloat64) {
        if (H5Tget_class(memberType.get()) != H5T_FLOAT ||
            H5Tget_size(memberType.get()) != sizeof(double) ||
            H5Tequal(memberType.get(), H5T_IEEE_F64LE) <= 0) {
            throw Hdf5Failure{"A compound HDF5 field is not float64."};
        }
        return;
    }
    if (isString) {
        if (H5Tget_class(memberType.get()) != H5T_STRING ||
            H5Tis_variable_str(memberType.get()) <= 0 ||
            H5Tget_cset(memberType.get()) != H5T_CSET_UTF8) {
            throw Hdf5Failure{"A compound HDF5 field is not UTF-8."};
        }
        return;
    }

    if (H5Tget_class(memberType.get()) != H5T_ARRAY) {
        throw Hdf5Failure{"A compound HDF5 array field has the wrong type."};
    }
    const int rank = H5Tget_array_ndims(memberType.get());
    if (rank <= 0) {
        throw Hdf5Failure{"Unable to inspect a compound HDF5 array rank."};
    }
    std::vector<hsize_t> dimensions(static_cast<std::size_t>(rank));
    requireHdf5(
        H5Tget_array_dims2(memberType.get(), dimensions.data()),
        "Unable to inspect compound HDF5 array dimensions.");
    Hdf5Handle baseType{
        requireHdf5Id(
            H5Tget_super(memberType.get()),
            "Unable to inspect a compound HDF5 array base type."),
        H5Tclose};
    if (name == "node_internal_ids") {
        if ((dimensions != std::vector<hsize_t>{2U} &&
             dimensions != std::vector<hsize_t>{4U}) ||
            H5Tequal(baseType.get(), H5T_STD_U64LE) <= 0) {
            throw Hdf5Failure{"Element connectivity is not uint64[2] or uint64[4]."};
        }
    } else if (name == "coordinates") {
        if (dimensions != std::vector<hsize_t>{3U} ||
            H5Tequal(baseType.get(), H5T_IEEE_F64LE) <= 0) {
            throw Hdf5Failure{"Node coordinates are not float64[3]."};
        }
    } else if (name == "local_axes") {
        if (dimensions != std::vector<hsize_t>{3U, 3U} ||
            H5Tequal(baseType.get(), H5T_IEEE_F64LE) <= 0) {
            throw Hdf5Failure{"Element local axes are not float64[3,3]."};
        }
    } else {
        throw Hdf5Failure{"A compound HDF5 field has an unknown type contract."};
    }
}

void requireResultAttributes(
    const hid_t dataset,
    const char* componentNames,
    const char* componentUnits,
    const char* coordinateSystem,
    const char* location) {
    requireStringAttribute(dataset, "component_names", componentNames);
    requireStringAttribute(
        dataset, "component_unit_dimensions", componentUnits);
    requireStringAttribute(dataset, "coordinate_system", coordinateSystem);
    requireStringAttribute(dataset, "location", location);
    requireStringAttribute(dataset, "step_name", kStepName);
    requireUint64Attribute(dataset, "frame_index", 0U);
}

void requireShellResultIdentity(
    const hid_t file, const char* path, const bool usesSectionPositions) {
    auto dataset = openDatasetForCheck(file, path);
    requireStringAttribute(
        dataset.get(),
        "source_element_type_dataset",
        "/model/elements.source_element_type");
    requireStringAttribute(
        dataset.get(), "internal_formulation", "FESA-MITC4");
    requireStringAttribute(
        dataset.get(),
        "midsurface_location_dataset",
        "/model/shell/midsurface_locations");
    requireStringAttribute(
        dataset.get(),
        "local_frame_dataset",
        "/steps/Step-1/frames/0/element/shell/local_frame");
    if (usesSectionPositions) {
        requireStringAttribute(
            dataset.get(),
            "section_position_dataset",
            "/model/shell/section_positions");
    }
}

void requireDoubleDataset(
    const hid_t file,
    const char* path,
    const std::vector<hsize_t>& expectedDimensions,
    const char* componentNames,
    const char* componentUnits,
    const char* coordinateSystem,
    const char* location) {
    auto dataset = openDatasetForCheck(file, path);
    if (checkedDimensions(dataset.get()) != expectedDimensions) {
        throw Hdf5Failure{"A floating-point HDF5 dataset has the wrong shape."};
    }
    Hdf5Handle type{
        requireHdf5Id(
            H5Dget_type(dataset.get()), "Unable to inspect an HDF5 dataset type."),
        H5Tclose};
    if (H5Tget_class(type.get()) != H5T_FLOAT ||
        H5Tget_size(type.get()) != sizeof(double) ||
        H5Tequal(type.get(), H5T_IEEE_F64LE) <= 0) {
        throw Hdf5Failure{"A result dataset is not IEEE-754 float64 little-endian."};
    }
    requireResultAttributes(
        dataset.get(), componentNames, componentUnits, coordinateSystem, location);
    std::size_t valueCount = 1U;
    for (const hsize_t dimension : expectedDimensions) {
        std::size_t next = 0U;
        if (!sizeProductFits(
                valueCount, static_cast<std::size_t>(dimension), next)) {
            throw Hdf5Failure{"A result dataset shape overflows size_t."};
        }
        valueCount = next;
    }
    std::vector<double> values(valueCount);
    if (!values.empty()) {
        requireHdf5(
            H5Dread(
                dataset.get(), H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
                H5P_DEFAULT, values.data()),
            "Unable to read a result dataset during self-check.");
    }
    if (!std::all_of(values.begin(), values.end(), [](const double value) {
            return std::isfinite(value);
        })) {
        throw Hdf5Failure{"A result dataset contains a nonfinite value."};
    }
}

void requireModelDoubleDataset(
    const hid_t file,
    const char* path,
    const std::vector<hsize_t>& expectedDimensions,
    const char* componentNames,
    const char* componentUnits,
    const char* coordinateSystem,
    const char* location,
    const std::vector<double>* expectedValues = nullptr) {
    auto dataset = openDatasetForCheck(file, path);
    if (checkedDimensions(dataset.get()) != expectedDimensions) {
        throw Hdf5Failure{"A model floating-point dataset has the wrong shape."};
    }
    Hdf5Handle type{
        requireHdf5Id(
            H5Dget_type(dataset.get()), "Unable to inspect a model dataset type."),
        H5Tclose};
    if (H5Tget_class(type.get()) != H5T_FLOAT ||
        H5Tget_size(type.get()) != sizeof(double) ||
        H5Tequal(type.get(), H5T_IEEE_F64LE) <= 0) {
        throw Hdf5Failure{"A model dataset is not IEEE-754 float64 little-endian."};
    }
    requireStringAttribute(dataset.get(), "component_names", componentNames);
    requireStringAttribute(
        dataset.get(), "component_unit_dimensions", componentUnits);
    requireStringAttribute(dataset.get(), "coordinate_system", coordinateSystem);
    requireStringAttribute(dataset.get(), "location", location);
    std::size_t valueCount = 1U;
    for (const hsize_t dimension : expectedDimensions) {
        std::size_t next = 0U;
        if (!sizeProductFits(
                valueCount, static_cast<std::size_t>(dimension), next)) {
            throw Hdf5Failure{"A model dataset shape overflows size_t."};
        }
        valueCount = next;
    }
    std::vector<double> values(valueCount);
    if (!values.empty()) {
        requireHdf5(
            H5Dread(
                dataset.get(), H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
                H5P_DEFAULT, values.data()),
            "Unable to read a model dataset during self-check.");
    }
    if (!std::all_of(values.begin(), values.end(), [](const double value) {
            return std::isfinite(value);
        })) {
        throw Hdf5Failure{"A model dataset contains a nonfinite value."};
    }
    if (expectedValues != nullptr && values != *expectedValues) {
        throw Hdf5Failure{"A fixed model dataset has the wrong value order."};
    }
}

void requireUint8Dataset(
    const hid_t file,
    const char* path,
    const std::vector<hsize_t>& expectedDimensions,
    const std::vector<std::uint8_t>& expectedValues) {
    auto dataset = openDatasetForCheck(file, path);
    if (checkedDimensions(dataset.get()) != expectedDimensions) {
        throw Hdf5Failure{"A uint8 HDF5 dataset has the wrong shape."};
    }
    Hdf5Handle type{
        requireHdf5Id(
            H5Dget_type(dataset.get()), "Unable to inspect a uint8 dataset type."),
        H5Tclose};
    if (H5Tget_class(type.get()) != H5T_INTEGER ||
        H5Tget_size(type.get()) != sizeof(std::uint8_t) ||
        H5Tget_sign(type.get()) != H5T_SGN_NONE ||
        H5Tequal(type.get(), H5T_STD_U8LE) <= 0) {
        throw Hdf5Failure{"A constraint mask is not portable uint8."};
    }
    std::vector<std::uint8_t> values(expectedValues.size());
    if (!values.empty()) {
        requireHdf5(
            H5Dread(
                dataset.get(), H5T_NATIVE_UINT8, H5S_ALL, H5S_ALL,
                H5P_DEFAULT, values.data()),
            "Unable to read the constraint mask during self-check.");
    }
    if (values != expectedValues) {
        throw Hdf5Failure{"The constraint mask has the wrong value order."};
    }
    requireStringAttribute(dataset.get(), "component_names", "UX,UY,UZ,URX,URY,URZ");
    requireStringAttribute(dataset.get(), "value_meaning", "0=free,1=constrained");
}

void requireCompoundDataset(
    const hid_t file,
    const char* path,
    const hsize_t expectedRows,
    const std::vector<const char*>& expectedMembers) {
    auto dataset = openDatasetForCheck(file, path);
    if (checkedDimensions(dataset.get()) != std::vector<hsize_t>{expectedRows}) {
        throw Hdf5Failure{"A compound HDF5 dataset has the wrong shape."};
    }
    Hdf5Handle type{
        requireHdf5Id(
            H5Dget_type(dataset.get()), "Unable to inspect a compound type."),
        H5Tclose};
    if (H5Tget_class(type.get()) != H5T_COMPOUND ||
        H5Tget_nmembers(type.get()) != static_cast<int>(expectedMembers.size())) {
        throw Hdf5Failure{"A compound HDF5 dataset has the wrong field count."};
    }
    for (std::size_t index = 0U; index < expectedMembers.size(); ++index) {
        char* rawName = H5Tget_member_name(
            type.get(), static_cast<unsigned>(index));
        if (rawName == nullptr) {
            throw Hdf5Failure{"Unable to inspect a compound HDF5 field name."};
        }
        const std::string actualName{rawName};
        requireHdf5(
            H5free_memory(rawName), "Unable to release a compound field name.");
        if (actualName != expectedMembers[index]) {
            throw Hdf5Failure{"A compound HDF5 field has the wrong identity."};
        }
        requirePortableCompoundMember(
            type.get(), static_cast<unsigned>(index), expectedMembers[index]);
    }
}

void selfCheckFile(
    const std::filesystem::path& path,
    const Domain& domain,
    const AnalysisState& state,
    const std::size_t diagnosticCount,
    const WriterModelData& modelData) {
    if (H5Fis_hdf5(path.string().c_str()) <= 0) {
        throw Hdf5Failure{"The temporary output is not an HDF5 file."};
    }
    Hdf5Handle file{
        requireHdf5Id(
            H5Fopen(path.string().c_str(), H5F_ACC_RDONLY, H5P_DEFAULT),
            "Unable to reopen the temporary HDF5 file read-only."),
        H5Fclose};
    Hdf5Handle metadata{
        requireHdf5Id(
            H5Gopen2(file.get(), "/metadata", H5P_DEFAULT),
            "The HDF5 metadata group is missing."),
        H5Gclose};
    requireUint64Attribute(metadata.get(), "schema_version", 0U);
    requireStringAttribute(
        metadata.get(), "solver_version", std::string{solverVersion()});
    requireStringAttribute(
        metadata.get(), "source_input_identity", sourceInputIdentity(domain));
    requireStringAttribute(
        metadata.get(), "unit_system_label", "user-consistent-unspecified");
    if (isShellDomain(domain)) {
        requireStringAttribute(
            metadata.get(), "feature_id", "linear-static-mitc4-shell");
        requireStringAttribute(
            metadata.get(),
            "coordinate_convention",
            "global-cartesian; shell-local=(e1,e2,e3); positive-thickness=+zeta");
        requireStringAttribute(
            metadata.get(), "internal_formulation", "FESA-MITC4");
        requireStringAttribute(
            metadata.get(),
            "integration_rule",
            "2x2x2-gauss; mitc4-edge-midpoint-shear");
    } else {
        requireStringAttribute(
            metadata.get(), "feature_id", "linear-static-3d-euler-beam");
        requireStringAttribute(
            metadata.get(),
            "coordinate_convention",
            "global-cartesian; beam-local=(t,n1,t-cross-n1)");
        requireStringAttribute(
            metadata.get(), "element_formulation", "B33-3D-Euler-Bernoulli");
    }
    requireStringAttribute(metadata.get(), "step_name", kStepName);
    requireUint64Attribute(metadata.get(), "frame_index", 0U);

    requireCompoundDataset(
        file.get(),
        "/model/nodes",
        static_cast<hsize_t>(domain.nodes().size()),
        {"internal_node_id", "instance_name", "source_label", "coordinates"});
    auto nodes = openDatasetForCheck(file.get(), "/model/nodes");
    requireStringAttribute(nodes.get(), "coordinate_system", "global-cartesian");
    requireStringAttribute(nodes.get(), "units_label", "length");
    const std::vector<hsize_t> nodalDimensions = {
        static_cast<hsize_t>(domain.nodes().size()), kDofsPerNode};
    requireDoubleDataset(
        file.get(),
        "/steps/Step-1/frames/0/nodal/displacement",
        nodalDimensions,
        "UX,UY,UZ,URX,URY,URZ",
        "length,length,length,radian,radian,radian",
        "global-cartesian",
        "nodal");
    requireDoubleDataset(
        file.get(),
        "/steps/Step-1/frames/0/nodal/reaction",
        nodalDimensions,
        "RF1,RF2,RF3,RM1,RM2,RM3",
        "force,force,force,force*length,force*length,force*length",
        "global-cartesian",
        "nodal");

    if (isShellDomain(domain)) {
        requireCompoundDataset(
            file.get(),
            "/model/elements",
            static_cast<hsize_t>(domain.shellElements().size()),
            {"internal_element_id", "instance_name", "source_label",
             "source_element_type", "internal_formulation", "node_internal_ids",
             "shell_section_internal_id", "material_internal_id"});
        auto elements = openDatasetForCheck(file.get(), "/model/elements");
        requireStringAttribute(elements.get(), "formulation", "FESA-MITC4");
        requireCompoundDataset(
            file.get(),
            "/model/shell/materials",
            static_cast<hsize_t>(domain.materials().size()),
            {"internal_material_id", "name", "E", "nu"});
        requireCompoundDataset(
            file.get(),
            "/model/shell/sections",
            static_cast<hsize_t>(domain.shellSections().size()),
            {"internal_section_id", "source_file", "source_line", "source_elset",
             "material_internal_id", "thickness"});

        std::vector<double> directors;
        std::vector<double> frames;
        directors.reserve(domain.nodes().size() * 3U);
        frames.reserve(domain.nodes().size() * 9U);
        for (const auto& frame : domain.shellNodeInitialFrames()) {
            directors.insert(
                directors.end(), frame.director.begin(), frame.director.end());
            frames.insert(frames.end(), frame.tangentA.begin(), frame.tangentA.end());
            frames.insert(frames.end(), frame.tangentB.begin(), frame.tangentB.end());
            frames.insert(frames.end(), frame.director.begin(), frame.director.end());
        }
        requireModelDoubleDataset(
            file.get(), "/model/shell/nodal_director",
            {static_cast<hsize_t>(domain.nodes().size()), 3U},
            "D1,D2,D3", "1,1,1", "global-cartesian", "nodal", &directors);
        requireModelDoubleDataset(
            file.get(), "/model/shell/nodal_frame",
            {static_cast<hsize_t>(domain.nodes().size()), 3U, 3U},
            "X,Y,Z", "1,1,1", "global-cartesian", "nodal-frame", &frames);
        auto nodalFrame = openDatasetForCheck(
            file.get(), "/model/shell/nodal_frame");
        requireStringAttribute(nodalFrame.get(), "axis_names", "A,B,D");
        requireUint8Dataset(
            file.get(), "/model/nodal_constraint_mask", nodalDimensions,
            modelData.constraintMask);
        requireModelDoubleDataset(
            file.get(), "/model/prescribed_displacement", nodalDimensions,
            "UX,UY,UZ,URX,URY,URZ",
            "length,length,length,radian,radian,radian",
            "global-cartesian", "nodal-prescribed-value",
            &modelData.prescribedDisplacement);
        const double gauss = 1.0 / std::sqrt(3.0);
        const std::vector<double> locations{
            -gauss, -gauss, gauss, -gauss,
            gauss, gauss, -gauss, gauss};
        requireModelDoubleDataset(
            file.get(), "/model/shell/midsurface_locations", {4U, 2U},
            "XI,ETA", "1,1", "shell-natural", "midsurface-location",
            &locations);
        const std::vector<double> sectionPositions{-1.0, 0.0, 1.0};
        requireModelDoubleDataset(
            file.get(), "/model/shell/section_positions", {3U},
            "ZETA", "1", "shell-natural", "section-position",
            &sectionPositions);
        auto positions = openDatasetForCheck(
            file.get(), "/model/shell/section_positions");
        requireStringAttribute(
            positions.get(), "position_names", "BOTTOM,MIDDLE,TOP");

        const hsize_t elementCount =
            static_cast<hsize_t>(domain.shellElements().size());
        const std::string shellRoot = std::string{kStepRoot} + "/element/shell";
        requireDoubleDataset(
            file.get(), (shellRoot + "/local_frame").c_str(),
            {elementCount, 4U, 3U, 3U}, "X,Y,Z", "1,1,1",
            "global-cartesian", "shell-local-frame");
        auto localFrame = openDatasetForCheck(
            file.get(), (shellRoot + "/local_frame").c_str());
        requireStringAttribute(localFrame.get(), "axis_names", "E1,E2,E3");
        requireStringAttribute(
            localFrame.get(), "internal_formulation", "FESA-MITC4");
        requireStringAttribute(
            localFrame.get(),
            "source_element_type_dataset",
            "/model/elements.source_element_type");
        requireStringAttribute(
            localFrame.get(),
            "midsurface_location_dataset",
            "/model/shell/midsurface_locations");
        requireDoubleDataset(
            file.get(), (shellRoot + "/generalized_strain").c_str(),
            {elementCount, 4U, 8U},
            "E11,E22,G12,K11,K22,K12,G13,G23",
            "1,1,1,1/length,1/length,1/length,1,1",
            "shell-local", "midsurface");
        requireShellResultIdentity(
            file.get(), (shellRoot + "/generalized_strain").c_str(), false);
        requireDoubleDataset(
            file.get(), (shellRoot + "/section_resultant").c_str(),
            {elementCount, 4U, 8U},
            "N11,N22,N12,M11,M22,M12,Q13,Q23",
            "force/length,force/length,force/length,force,force,force,force/length,force/length",
            "shell-local", "midsurface");
        requireShellResultIdentity(
            file.get(), (shellRoot + "/section_resultant").c_str(), false);
        requireDoubleDataset(
            file.get(), (shellRoot + "/stress").c_str(),
            {elementCount, 4U, 3U, 3U}, "S11,S22,S12",
            "force/length^2,force/length^2,force/length^2",
            "shell-local", "section-position");
        requireShellResultIdentity(
            file.get(), (shellRoot + "/stress").c_str(), true);
        requireDoubleDataset(
            file.get(), "/steps/Step-1/frames/0/global/energy", {1U},
            "PHYSICAL_STRAIN_ENERGY", "force*length", "global", "global");
        requireDoubleDataset(
            file.get(), "/steps/Step-1/frames/0/global/equilibrium", {6U},
            "FORCE_1,FORCE_2,FORCE_3,MOMENT_1,MOMENT_2,MOMENT_3",
            "force,force,force,force*length,force*length,force*length",
            "global-cartesian", "global-origin");
        requireDoubleDataset(
            file.get(), "/steps/Step-1/frames/0/global/verification_metrics", {3U},
            "FREE_RESIDUAL_NORMALIZED,FORCE_BALANCE_NORMALIZED,MOMENT_BALANCE_NORMALIZED",
            "1,1,1", "global", "verification");
        auto metrics = openDatasetForCheck(
            file.get(), "/steps/Step-1/frames/0/global/verification_metrics");
        requireStringAttribute(
            metrics.get(),
            "metric_definition_ids",
            "free-residual-l2-over-max-free-force-l2,force-balance-l2-over-max-force-sum,moment-balance-l2-over-max-moment-sum");
        requireStringAttribute(
            metrics.get(), "acceptance_thresholds", "1e-10,1e-10,1e-10");
        for (const char* forbidden : {
                 "/steps/Step-1/frames/0/element/shell/drilling",
                 "/steps/Step-1/frames/0/element/shell/drilling_energy",
                 "/steps/Step-1/frames/0/element/shell/S33",
                 "/steps/Step-1/frames/0/element/shell/S13",
                 "/steps/Step-1/frames/0/element/shell/S23"}) {
            if (H5Lexists(file.get(), forbidden, H5P_DEFAULT) != 0) {
                throw Hdf5Failure{"A forbidden shell result path exists."};
            }
        }
    } else {
        requireCompoundDataset(
            file.get(),
            "/model/elements",
            static_cast<hsize_t>(domain.elements().size()),
            {"internal_element_id", "instance_name", "source_label",
             "node_internal_ids", "local_axes"});
        auto elements = openDatasetForCheck(file.get(), "/model/elements");
        requireStringAttribute(
            elements.get(), "formulation", "B33-3D-Euler-Bernoulli");
        const std::vector<hsize_t> endDimensions = {
            static_cast<hsize_t>(domain.elements().size()),
            kEndpointCount,
            kEndActionComponentCount};
        const std::vector<hsize_t> generalizedDimensions = {
            static_cast<hsize_t>(domain.elements().size()),
            kGaussPointCount,
            kGeneralizedComponentCount};
        requireDoubleDataset(
            file.get(), "/steps/Step-1/frames/0/element/end_force_local",
            endDimensions, "FX,FY,FZ,MX,MY,MZ",
            "force,force,force,force*length,force*length,force*length",
            "beam-local", "endpoint-outward-action");
        requireDoubleDataset(
            file.get(), "/steps/Step-1/frames/0/element/section_resultant",
            generalizedDimensions, "N,T,My,Mz",
            "force,force*length,force*length,force*length",
            "beam-local", "endpoint-positive-local-x-section-cut");
        requireDoubleDataset(
            file.get(), "/steps/Step-1/frames/0/element/generalized_strain",
            generalizedDimensions, "epsilon0,kappa_x,kappa_y,kappa_z",
            "1,1/length,1/length,1/length", "beam-local", "integration-point");
        requireDoubleDataset(
            file.get(), "/steps/Step-1/frames/0/element/generalized_resultant",
            generalizedDimensions, "N,T,My,Mz",
            "force,force*length,force*length,force*length",
            "beam-local", "integration-point");
        requireCompoundDataset(
            file.get(), "/steps/Step-1/frames/0/element/stress_s11",
            static_cast<hsize_t>(state.stressResults().size()),
            {"internal_element_id", "gauss_point_index", "section_point_index",
             "x1", "x2", "source", "S11"});
        auto stress = openDatasetForCheck(
            file.get(), "/steps/Step-1/frames/0/element/stress_s11");
        requireResultAttributes(
            stress.get(), "S11", "force/length^2", "beam-local", "section-point");
    }
    requireCompoundDataset(
        file.get(),
        "/diagnostics",
        static_cast<hsize_t>(diagnosticCount),
        {"severity", "code", "file", "line", "keyword",
         "entity_identity", "message"});
    requireHdf5(
        file.closeChecked(),
        "Unable to close the read-only HDF5 schema self-check handle.");
}

std::filesystem::path makeTemporaryPath(
    const std::filesystem::path& outputPath) {
    static std::atomic<std::uint64_t> sequence{0U};
    const std::filesystem::path parent = outputPath.parent_path();
    for (std::size_t attempt = 0U; attempt < 1024U; ++attempt) {
        const std::wstring filename =
            L"." + outputPath.filename().wstring() + L".tmp." +
            std::to_wstring(GetCurrentProcessId()) + L"." +
            std::to_wstring(sequence.fetch_add(1U));
        const std::filesystem::path candidate = parent / filename;
        std::error_code error;
        const bool exists = std::filesystem::exists(candidate, error);
        if (error) {
            throw Hdf5Failure{"Unable to inspect the temporary output path."};
        }
        if (!exists) {
            return candidate;
        }
    }
    throw Hdf5Failure{"Unable to allocate a unique temporary output path."};
}

bool finalizeFile(
    const std::filesystem::path& temporaryPath,
    const std::filesystem::path& outputPath) {
    const DWORD attributes = GetFileAttributesW(outputPath.c_str());
    if (attributes != INVALID_FILE_ATTRIBUTES) {
        // ReplaceFileW is the one-operation existing-final policy: failure
        // leaves the old authoritative bytes in place.
        return ReplaceFileW(
                   outputPath.c_str(),
                   temporaryPath.c_str(),
                   nullptr,
                   0U,
                   nullptr,
                   nullptr) != FALSE;
    }
    const DWORD error = GetLastError();
    if (error != ERROR_FILE_NOT_FOUND && error != ERROR_PATH_NOT_FOUND) {
        return false;
    }
    // A new final uses a same-directory write-through move after close/check.
    return MoveFileExW(
               temporaryPath.c_str(),
               outputPath.c_str(),
               MOVEFILE_WRITE_THROUGH) != FALSE;
}

} // namespace

Status Hdf5ResultsWriter::write(
    const std::filesystem::path& outputPath,
    const Domain& domain,
    const AnalysisState& state,
    const std::vector<Diagnostic>& diagnostics) {
    WriterModelData modelData;
    try {
        const Status validation = validateWriterInput(
            outputPath, domain, state, diagnostics, modelData);
        if (!validation.isOk()) {
            return validation;
        }

        Hdf5ErrorSilencer silenceBackendErrors;
        const std::filesystem::path temporaryPath = makeTemporaryPath(outputPath);
        TemporaryFileGuard cleanup{temporaryPath};
        writeFile(temporaryPath, domain, state, diagnostics, modelData);
        // Close occurs when writeFile returns; only the reopened read-only file
        // can approve this temp artifact for authoritative replacement.
        selfCheckFile(
            temporaryPath, domain, state, diagnostics.size(), modelData);
        if (!finalizeFile(temporaryPath, outputPath)) {
            return outputFailure(
                "hdf5-finalization-failure",
                "The checked temporary HDF5 file could not replace the final output.");
        }
        cleanup.release();
        return Status::ok();
    } catch (const Hdf5Failure& failure) {
        return outputFailure("hdf5-write-failure", failure.what());
    } catch (const std::exception& failure) {
        return outputFailure("hdf5-write-failure", failure.what());
    }
}

} // namespace fesa
