Files
Jungfraujoch/common/Logger.h
T
leonarski_fandClaude Opus 5.5 b0b217a795 Make the P1 cross-check merge while the model validation runs
With --model, model validation and the P1 cross-check merge ran one after the other at the end of
the run. Neither reads anything the other writes, so the first ValidateAgainstModel now runs on its
own thread while the main thread makes the P1 merge (rsm->Run in P1); the merge's result is kept and
reported at the cross-check, where it used to be made, through a new `already_run` argument of
scale_and_merge.

Why it is exact: the validation reads the adopted merge, the cell, the group and the wavelength,
all captured before the thread starts, and nothing else. The scaling engine merges its own copy of
the observations under the group set on the experiment (P1 for the merge, restored after, as at the
cross-check), holds its own copy of the cell, reads the outcomes' lattices and mosaicities only at
Ingest, and writes back per-image G, CC and mosaicity - which nothing between the validation and
the cross-check reads (the unmerged MTZ build reads the mosaicity but replaces it after the merge,
as before). Every relabelling the validation decides reaches the P1 merge afterwards through
merge_to_written, exactly as when it was made later. The result fields scale_and_merge sets are
still set at the cross-check, so the report and the finalist ledger read the same values. Without
--model, or without a P1 cross-check, nothing changes.

The validation logs into a Logger::Buffered() and the lines are replayed as one block when it is
done, so the two do not interleave; the P1 merge's log lines now come before the validation's.

Checked against rc173 (rugnux_r4int_77710e1ce, output-identical to it) on 8tyy, 9hnc, 8sa8, 6oel,
7ph1 with --model and on myob: p.hkl, p.mtz, p.cif, p_P1.mtz, p_unmerged.mtz, the maps and the
placed model are byte-identical, and so is p_report.txt apart from date/command/timing lines. A
last-digit flip of one image's bkg in p_plot.txt (8sa8, one of two runs) is image-loop
nondeterminism the baseline shows too (8tyy, base vs base).

Tail wall (sweep-quality line to unmerged MTZ written), paired back-to-back runs on a loaded box:
8tyy 110.3 -> 87.3 s, 6oel 77.8 -> 63.3 s, 8sa8 171.4 -> 154.6 s; unpaired 9hnc 368.8 -> 337.0 s,
7ph1 21.1 -> 15.7 s. The saving is the P1 merge's time; the validation still sets the floor.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D1G8gJVAy6gp1K5Dz3NE5C
2026-09-27 21:21:42 +02:00

65 lines
2.0 KiB
C++

// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <cstdint>
#include <chrono>
#include <iostream>
#include <mutex>
#include <memory>
#include <spdlog/spdlog.h>
#include <spdlog/fmt/fmt.h>
namespace spdlog {
class logger;
}
class LogBufferSink;
class Logger {
std::shared_ptr<spdlog::logger> spdlog_logger;
std::shared_ptr<LogBufferSink> buffer; // only on a Buffered() logger
explicit Logger(std::shared_ptr<LogBufferSink> sink);
std::string service;
std::string hostname;
public:
Logger(const std::string &service_name, const std::string &file_name = "");
void ErrorException(const std::exception &e);
void Info(const std::string& msg) { spdlog_logger->info(msg); }
void Warning(const std::string& msg) { spdlog_logger->warn(msg); }
void Error(const std::string& msg) { spdlog_logger->error(msg); }
void Debug(const std::string& msg) { spdlog_logger->debug(msg); }
template<typename... Args>
void Info(fmt::format_string<Args...> fmt, Args &&... args) {
spdlog_logger->info(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void Error(fmt::format_string<Args...> fmt, Args &&... args) {
spdlog_logger->error(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void Debug(fmt::format_string<Args...> fmt, Args &&... args) {
spdlog_logger->debug(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void Warning(fmt::format_string<Args...> fmt, Args &&... args) {
spdlog_logger->warn(fmt, std::forward<Args>(args)...);
}
Logger& Verbose(bool input);
// A logger that keeps its lines instead of printing them, for work run beside other work that
// logs: ReplayInto hands them to `to` afterwards, in order and as one block, so the two do not
// interleave.
static Logger Buffered();
void ReplayInto(Logger &to) const;
};