Merged mmCIF: drop the scaled unmerged block
The unmerged observations already leave a run as the unmerged MTZ (and the scaled fulls as the .hkl), and deposition does not come straight from rugnux, so the _diffrn_refln block made the .cif up to ten times larger for no consumer. The .cif is one data block again; the keys, software rows, metadata, R_merge/R_pim/CC* and provenance stay. ScaledFull loses the scale and frame it carried only for that block. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SVmAWnzCmRKAXVUCdc4iNi
This commit is contained in:
@@ -140,7 +140,7 @@ void AddProvenanceHistory(gemmi::Mtz &mtz, const OutputProvenance &provenance) {
|
||||
add("Collected: ", provenance.collection_date);
|
||||
}
|
||||
|
||||
// _entry, _cell and _symmetry: what every data block of the file restates, so each one stands alone.
|
||||
// _entry, _cell and _symmetry.
|
||||
void WriteBlockHeader(std::ostream &out, const std::string &entry_id, const UnitCell &unitCell,
|
||||
const gemmi::SpaceGroup &sg) {
|
||||
out << "_entry.id " << entry_id << "\n";
|
||||
@@ -253,7 +253,6 @@ void WriteMmcifReflections(const std::vector<MergedReflection> &reflections,
|
||||
const MergeStatistics &statistics,
|
||||
const ErrorModelReport &error_model,
|
||||
const TwinningAnalysisResult &twinning,
|
||||
const std::vector<ScaledFull> &scaled_fulls,
|
||||
const OutputProvenance &provenance,
|
||||
const std::string &filename,
|
||||
size_t nthreads) {
|
||||
@@ -266,7 +265,7 @@ void WriteMmcifReflections(const std::vector<MergedReflection> &reflections,
|
||||
|
||||
// The keys PDBx asks for are written with the one value this file has for each: one entry, one
|
||||
// crystal, one diffraction experiment (diffrn_id 1, which _pdbx_reflns_twin below also points at)
|
||||
// and one wavelength. The merged data come first, as the wwPDB expects of a structure-factor file.
|
||||
// and one wavelength.
|
||||
const std::string entry_id = "sample";
|
||||
const gemmi::SpaceGroup &sg = experiment.GetSpaceGroupOrP1();
|
||||
|
||||
@@ -603,66 +602,6 @@ void WriteMmcifReflections(const std::vector<MergedReflection> &reflections,
|
||||
out << "#\n";
|
||||
out << "# End of reflections\n";
|
||||
|
||||
// ---------- the scaled unmerged observations, as a second data block ----------
|
||||
// The observations the merge above averaged - each full with the scale and the error-model sigma
|
||||
// the merge gave it, at the index it was measured at - which is what the wwPDB accepts as scaled
|
||||
// unmerged data. The same records as the .hkl: an observation without a usable sigma is in
|
||||
// neither. pdbx_image_id is the frame the full peaks on, numbered from 1 as the unmerged MTZ's
|
||||
// BATCH is. (The unmerged MTZ itself stays unscaled, for the programs that fit their own scales.)
|
||||
if (!scaled_fulls.empty()) {
|
||||
out << "data_sample_unmerged\n";
|
||||
out << "#\n";
|
||||
WriteBlockHeader(out, entry_id, unitCell, sg);
|
||||
out << "_exptl_crystal.id 1\n";
|
||||
out << "#\n";
|
||||
out << "_diffrn.id 1\n";
|
||||
out << "_diffrn.crystal_id 1\n";
|
||||
out << "#\n";
|
||||
out << "_diffrn_radiation_wavelength.id 1\n";
|
||||
out << "_diffrn_radiation_wavelength.wavelength " << Fmt(experiment.GetWavelength_A(), 5) << "\n";
|
||||
out << "#\n";
|
||||
out << "loop_\n";
|
||||
out << "_diffrn_refln.diffrn_id\n";
|
||||
out << "_diffrn_refln.id\n";
|
||||
out << "_diffrn_refln.pdbx_image_id\n";
|
||||
out << "_diffrn_refln.index_h\n";
|
||||
out << "_diffrn_refln.index_k\n";
|
||||
out << "_diffrn_refln.index_l\n";
|
||||
out << "_diffrn_refln.intensity_net\n";
|
||||
out << "_diffrn_refln.intensity_sigma\n";
|
||||
out << "_diffrn_refln.pdbx_scale_value\n";
|
||||
|
||||
// Numbered in order over the usable fulls, so the id of each is known before the rows are
|
||||
// formatted on several workers.
|
||||
std::vector<int64_t> id(scaled_fulls.size() + 1, 0);
|
||||
for (size_t i = 0; i < scaled_fulls.size(); ++i) {
|
||||
const auto &f = scaled_fulls[i];
|
||||
id[i + 1] = id[i] + ((std::isfinite(f.I) && std::isfinite(f.sigma) && f.sigma > 0.0f) ? 1 : 0);
|
||||
}
|
||||
const size_t nrow = scaled_fulls.size();
|
||||
const size_t nw = std::max<size_t>(nthreads, 1);
|
||||
const int nch = static_cast<int>(ThreadsForWork(nrow, nw, 4096));
|
||||
std::vector<std::string> block(nch);
|
||||
ParallelChunks(nch, nw, [&](int tlo, int thi) {
|
||||
for (int t = tlo; t < thi; ++t) {
|
||||
const size_t lo = nrow * t / nch, hi = nrow * (t + 1) / nch;
|
||||
std::string &s = block[t];
|
||||
s.reserve((hi - lo) * 64);
|
||||
for (size_t i = lo; i < hi; ++i) {
|
||||
if (id[i + 1] == id[i])
|
||||
continue;
|
||||
const auto &f = scaled_fulls[i];
|
||||
const long frame = std::isfinite(f.image_number) ? 1 + std::lround(f.image_number) : 0;
|
||||
s += "1 " + std::to_string(id[i + 1]) + " " + (frame > 0 ? std::to_string(frame) : "?") + " "
|
||||
+ std::to_string(f.h) + " " + std::to_string(f.k) + " " + std::to_string(f.l) + " "
|
||||
+ Fmt(f.I, 3) + " " + Fmt(f.sigma, 3) + " " + Fmt(f.scale, 5) + "\n";
|
||||
}
|
||||
}
|
||||
});
|
||||
for (const std::string &s : block)
|
||||
out.write(s.data(), static_cast<std::streamsize>(s.size()));
|
||||
out << "#\n";
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
@@ -1296,7 +1235,7 @@ void WriteReflections(const std::vector<MergedReflection> &reflections,
|
||||
// fulls where the merge provides them (rotation), the merged reflections otherwise (stills).
|
||||
WriteMtzReflections(reflections, unitCell, experiment, provenance, filename + ".mtz");
|
||||
WriteMmcifReflections(reflections, unitCell, experiment, statistics, error_model, twinning,
|
||||
scaled_fulls ? *scaled_fulls : std::vector<ScaledFull>{}, provenance,
|
||||
provenance,
|
||||
filename + ".cif", nthreads);
|
||||
if (scaled_fulls && !scaled_fulls->empty())
|
||||
WriteShelxHklReflections(*scaled_fulls, filename + ".hkl", nthreads);
|
||||
|
||||
Reference in New Issue
Block a user