Model validation: warm up on the GPU when the broker gets a model
WarmUpModelValidation runs one throwaway validation of the uploaded model against its own calculated intensities on a background thread (holding a GPUWorkBeside), so kernels, cuFFT kernels and contexts on every card the null's replicates use are loaded before the collection's validation. ValidateAgainstModel waits for a warm-up still running, so a real validation never shares the cards with it and computes what it computes without one (test ModelValidation_WarmUpChangesNothing; CLI run with and without warm-up: identical p.mtz, p_maps.mtz, report and validation lines). The broker logs the warm-up's time at upload, which measures the first-use cost on the machine directly (local RTX 5080: 0.88 s first, 0.78 s second). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
This commit is contained in:
1 parent
8261b7354e
commit
0ff6442765
4 files changed
+107
No files matched your search
@@ -864,6 +864,41 @@ TEST_CASE("ModelValidation_CCModelFollowsTheSignalByShell", "[ModelValidation]")
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
|
||||
// A warm-up (WarmUpModelValidation) only loads what the GPU loads on first use: the validation after it,
|
||||
// which waits for it, gives what it gives without one.
|
||||
TEST_CASE("ModelValidation_WarmUpChangesNothing", "[ModelValidation]") {
|
||||
Logger logger("ModelValidation_WarmUpChangesNothing");
|
||||
|
||||
const auto path = WriteTemp("warm_up_test.pdb", ClusterPdb().c_str());
|
||||
auto obs = ModelReferenceIntensities(ReadModel(path), {}, {}, 2.5, logger);
|
||||
REQUIRE(obs.size() > 1000);
|
||||
std::mt19937 rng(20261019);
|
||||
std::normal_distribution<double> normal(0.0, 1.0);
|
||||
for (size_t i = 0; i < obs.size(); i++) {
|
||||
obs[i].I = static_cast<float>(obs[i].I * (1.0 + 0.1 * normal(rng)));
|
||||
obs[i].F = std::sqrt(std::max(0.0f, obs[i].I));
|
||||
obs[i].rfree_flag = (i % 20) == 0;
|
||||
}
|
||||
const UnitCell cell{.a = 30, .b = 34, .c = 38, .alpha = 90, .beta = 90, .gamma = 90};
|
||||
const auto model = std::make_shared<const RugnuxModel>(ReadModel(path));
|
||||
const gemmi::SpaceGroup *sg = gemmi::find_spacegroup_by_name("P 21 21 21");
|
||||
|
||||
const auto cold = ValidateAgainstModel(obs, cell, *model, logger, sg, false, 4);
|
||||
WarmUpModelValidation(model, 4, logger);
|
||||
const auto warm = ValidateAgainstModel(obs, cell, *model, logger, sg, false, 4);
|
||||
|
||||
REQUIRE(cold.ok);
|
||||
REQUIRE(warm.ok);
|
||||
CHECK(warm.r_work == cold.r_work);
|
||||
CHECK(warm.r_free == cold.r_free);
|
||||
CHECK(warm.rigid_body_angle_deg == cold.rigid_body_angle_deg);
|
||||
CHECK(warm.null_r_work_mean == cold.null_r_work_mean);
|
||||
CHECK(warm.null_r_work_sd == cold.null_r_work_sd);
|
||||
CHECK(warm.r_work_sigma == cold.r_work_sigma);
|
||||
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
|
||||
// The model path's structure factors come from FFTW; they must be gemmi's own transform to float
|
||||
// precision, in the same layout, so prepare_asu_data() reads the same reflections from either.
|
||||
|
||||
|
||||
Reference in new issue
Block a user