feat: implement consistent-mass HHT shell dynamics
This commit is contained in:
@@ -258,6 +258,68 @@ Result<std::string> SerializeRecord(const NewtonIterationLogRecord& record,
|
||||
return Result<std::string>::Success(std::move(line));
|
||||
}
|
||||
|
||||
/// @brief Serializes dynamic evidence without static load-factor semantics.
|
||||
Result<std::string> SerializeRecord(
|
||||
const DynamicNewtonIterationLogRecord& record,
|
||||
const std::filesystem::path& log_path) {
|
||||
const auto time = FormatFiniteNumber(record.time, log_path);
|
||||
if (!time.HasValue()) return Result<std::string>::Failure(time.GetStatus());
|
||||
if (record.time < 0.0 || record.stage.empty() || record.outcome.empty()) {
|
||||
return Result<std::string>::Failure(LogOutputFailure(
|
||||
log_path,
|
||||
"A dynamic Newton log requires nonnegative time, stage, and outcome."));
|
||||
}
|
||||
std::vector<std::string> fields;
|
||||
fields.reserve(24U);
|
||||
AppendField(&fields, "record", "dynamic-newton-iteration");
|
||||
AppendField(&fields, "schema", "hht-log-v1");
|
||||
AppendField(&fields, "increment", std::to_string(record.increment_index));
|
||||
AppendField(&fields, "time", time.Value());
|
||||
AppendField(&fields, "iteration", std::to_string(record.iteration_index));
|
||||
AppendField(&fields, "stage", EscapeText(record.stage));
|
||||
const std::array<const char*, 2U> channels{"u", "phi"};
|
||||
for (std::size_t channel = 0U; channel < channels.size(); ++channel) {
|
||||
const std::string suffix{channels[channel]};
|
||||
const std::array<std::pair<std::string, double>, 6U> metrics{{
|
||||
{"residual_" + suffix + "_numerator",
|
||||
record.residual_numerator[channel]},
|
||||
{"residual_" + suffix + "_scale", record.residual_scale[channel]},
|
||||
{"coordinate_correction_" + suffix,
|
||||
record.coordinate_correction[channel]},
|
||||
{"velocity_correction_" + suffix, record.velocity_correction[channel]},
|
||||
{"acceleration_correction_" + suffix,
|
||||
record.acceleration_correction[channel]},
|
||||
{"algorithmic_correction_" + suffix,
|
||||
record.algorithmic_correction[channel]},
|
||||
}};
|
||||
for (const auto& metric : metrics) {
|
||||
const auto formatted = FormatFiniteNumber(metric.second, log_path);
|
||||
if (!formatted.HasValue()) {
|
||||
return Result<std::string>::Failure(formatted.GetStatus());
|
||||
}
|
||||
if (metric.second < 0.0) {
|
||||
return Result<std::string>::Failure(LogOutputFailure(
|
||||
log_path, "A dynamic Newton log norm or scale is negative."));
|
||||
}
|
||||
AppendField(&fields, metric.first, formatted.Value());
|
||||
}
|
||||
AppendField(
|
||||
&fields, "residual_" + suffix + "_branch",
|
||||
record.residual_scale[channel] == 0.0 ? "zero-scale" : "relative");
|
||||
}
|
||||
AppendField(&fields, "residual_pass", record.residual_pass ? "1" : "0");
|
||||
AppendField(&fields, "correction_pass", record.correction_pass ? "1" : "0");
|
||||
AppendField(&fields, "outcome", EscapeText(record.outcome));
|
||||
AppendField(&fields, "failure_code", EscapeText(record.failure_code));
|
||||
std::string line;
|
||||
for (std::size_t index = 0U; index < fields.size(); ++index) {
|
||||
if (index != 0U) line += '\t';
|
||||
line += fields[index];
|
||||
}
|
||||
line += '\n';
|
||||
return Result<std::string>::Success(std::move(line));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Status NewtonIterationLogWriter::Open(const std::filesystem::path& log_path) {
|
||||
@@ -296,6 +358,27 @@ Status NewtonIterationLogWriter::Write(const NewtonIterationLogRecord& record) {
|
||||
return Status::Ok();
|
||||
}
|
||||
|
||||
Status NewtonIterationLogWriter::Write(
|
||||
const DynamicNewtonIterationLogRecord& record) {
|
||||
if (state_ != State::kOpen) {
|
||||
state_ = State::kFailed;
|
||||
return LogOutputFailure(log_path_, "The Newton log writer is not open.");
|
||||
}
|
||||
const auto line = SerializeRecord(record, log_path_);
|
||||
if (!line.HasValue()) {
|
||||
state_ = State::kFailed;
|
||||
return line.GetStatus();
|
||||
}
|
||||
stream_.write(line.Value().data(),
|
||||
static_cast<std::streamsize>(line.Value().size()));
|
||||
if (!stream_) {
|
||||
state_ = State::kFailed;
|
||||
return LogOutputFailure(log_path_,
|
||||
"The dynamic Newton log record could not write.");
|
||||
}
|
||||
return Status::Ok();
|
||||
}
|
||||
|
||||
Status NewtonIterationLogWriter::Flush() {
|
||||
if (state_ != State::kOpen) {
|
||||
state_ = State::kFailed;
|
||||
|
||||
Reference in New Issue
Block a user