Gemmi C++ API
Loading...
Searching...
No Matches
mtz.hpp
Go to the documentation of this file.
1// Copyright 2019 Global Phasing Ltd.
2//
3// MTZ reflection file format.
4
5#ifndef GEMMI_MTZ_HPP_
6#define GEMMI_MTZ_HPP_
7
8#include <cassert>
9#include <cstdint> // for int32_t
10#include <cstring> // for memcpy
11#include <cmath> // for isnan
12#include <algorithm> // for sort, any_of
13#include <array>
14#include <initializer_list>
15#include <ostream>
16#include <string>
17#include <vector>
18#include "atox.hpp" // for simple_atoi, read_word
19#include "atof.hpp" // for fast_atof
20#include "input.hpp" // for FileStream, CharArray
21#include "iterator.hpp" // for StrideIter
22#include "fail.hpp" // for fail
23#include "fileutil.hpp" // for file_open, is_little_endian, fileptr_t, ...
24#include "math.hpp" // for rad, Mat33
25#include "symmetry.hpp" // for find_spacegroup_by_name, SpaceGroup
26#include "unitcell.hpp" // for UnitCell
27#include "util.hpp" // for ialpha4_id, rtrim_str, ialpha3_id, ...
28
29namespace gemmi {
30
31template <typename T, typename FP=typename std::iterator_traits<T>::value_type>
32std::array<FP,2> calculate_min_max_disregarding_nans(T begin, T end) {
33 std::array<FP,2> minmax = {{NAN, NAN}};
34 T i = begin;
35 while (i != end && std::isnan(*i))
36 ++i;
37 if (i != end) {
38 minmax[0] = minmax[1] = *i;
39 while (++i != end) {
40 if (*i < minmax[0])
41 minmax[0] = *i;
42 else if (*i > minmax[1])
43 minmax[1] = *i;
44 }
45 }
46 return minmax;
47}
48
49// Unmerged MTZ files always store in-asu hkl indices and symmetry operation
50// encoded in the M/ISYM column. Here is a helper for writing such files.
52 UnmergedHklMover(const SpaceGroup* spacegroup) : asu_(spacegroup) {
53 if (spacegroup)
54 group_ops_ = spacegroup->operations();
55 }
56
57 // Modifies hkl and returns ISYM value for M/ISYM
58 int move_to_asu(std::array<int, 3>& hkl) {
59 std::pair<Miller, int> hkl_isym = asu_.to_asu(hkl, group_ops_);
60 hkl = hkl_isym.first;
61 return hkl_isym.second;
62 }
63
64private:
65 ReciprocalAsu asu_;
66 GroupOps group_ops_;
67};
68
69
70struct GEMMI_DLL Mtz {
71 struct Dataset {
72 int id;
73 std::string project_name;
74 std::string crystal_name;
75 std::string dataset_name;
77 double wavelength; // 0 means not set
78 };
79
80 struct Column {
82 char type;
83 std::string label;
84 float min_value = NAN;
85 float max_value = NAN;
86 std::string source; // from COLSRC
88 std::size_t idx;
89
90 Dataset& dataset() { return parent->dataset(dataset_id); }
91 const Dataset& dataset() const { return parent->dataset(dataset_id); }
92 bool has_data() const { return parent->has_data(); }
93 int size() const { return has_data() ? parent->nreflections : 0; }
94 size_t stride() const { return parent->columns.size(); }
95 float& operator[](std::size_t n) { return parent->data[idx + n * stride()]; }
96 float operator[](std::size_t n) const { return parent->data[idx + n * stride()]; }
97 float& at(std::size_t n) { return parent->data.at(idx + n * stride()); }
98 float at(std::size_t n) const { return parent->data.at(idx + n * stride()); }
99 bool is_integer() const {
100 return type == 'H' || type == 'B' || type == 'Y' || type == 'I';
101 }
102
104 if (idx + 1 < parent->columns.size()) {
105 const Column& next_col = parent->columns[idx + 1];
106 if (next_col.dataset_id == dataset_id && next_col.type == next_type)
107 return &next_col;
108 }
109 return nullptr;
110 }
111
114 assert(parent);
115 assert(&parent->columns[idx] == this);
116 return iterator({parent->data.data(), idx, stride()});
117 }
119 return iterator({parent->data.data() + parent->data.size(), idx,
120 stride()});
121 }
123 const_iterator begin() const { return const_cast<Column*>(this)->begin(); }
124 const_iterator end() const { return const_cast<Column*>(this)->end(); }
125 };
126
127 struct Batch {
129 ints.resize(29, 0);
130 floats.resize(156, 0.);
131 // write the same values that are written by CCP4 progs such as COMBAT
132 ints[0] = 29 + 156;
133 ints[1] = 29;
134 ints[2] = 156;
135 // COMBAT sets BSCALE=1, but Pointless sets it to 0.
136 //floats[43] = 1.f; // batch scale
137 }
138 int number = 0;
139 std::string title;
140 std::vector<int> ints;
141 std::vector<float> floats;
142 std::vector<std::string> axes;
143
145 return UnitCell(floats[0], floats[1], floats[2],
146 floats[3], floats[4], floats[5]);
147 }
148 void set_cell(const UnitCell& uc) {
149 floats[0] = (float) uc.a;
150 floats[1] = (float) uc.b;
151 floats[2] = (float) uc.c;
152 floats[3] = (float) uc.alpha;
153 floats[4] = (float) uc.beta;
154 floats[5] = (float) uc.gamma;
155 }
156
157 int dataset_id() const { return ints[20]; }
158 void set_dataset_id(int id) { ints[20] = id; }
159 float wavelength() const { return floats[86]; }
160 void set_wavelength(float lambda) { floats[86] = lambda; }
161 float phi_start() const { return floats[36]; }
162 float phi_end() const { return floats[37]; }
163 Mat33 matrix_U() const {
164 return Mat33(floats[6], floats[9], floats[12],
165 floats[7], floats[10], floats[13],
166 floats[8], floats[11], floats[14]);
167 }
168 };
169
170 std::string source_path; // input file path, if known
171 bool same_byte_order = true;
172 bool indices_switched_to_original = false;
173 std::int64_t header_offset = 0;
174 std::string version_stamp;
175 std::string title;
176 int nreflections = 0;
177 std::array<int, 5> sort_order = {};
178 double min_1_d2 = NAN;
179 double max_1_d2 = NAN;
180 float valm = NAN;
181 int nsymop = 0;
183 int spacegroup_number = 0;
184 std::string spacegroup_name;
185 std::vector<Op> symops;
186 const SpaceGroup* spacegroup = nullptr;
187 std::vector<Dataset> datasets;
188 std::vector<Column> columns;
189 std::vector<Batch> batches;
190 std::vector<std::string> history;
191 std::string appended_text;
192 std::vector<float> data;
193
194 // stream used for warnings when reading mtz file (and also in mtz2cif)
195 std::ostream* warnings = nullptr;
196
197 explicit Mtz(bool with_base=false) {
198 if (with_base)
199 add_base();
200 }
201 Mtz(Mtz&& o) noexcept { *this = std::move(o); }
202 Mtz& operator=(Mtz&& o) noexcept {
203 same_byte_order = o.same_byte_order;
204 header_offset = o.header_offset;
205 version_stamp = std::move(o.version_stamp);
206 title = std::move(o.title);
207 nreflections = o.nreflections;
208 sort_order = o.sort_order;
209 min_1_d2 = o.min_1_d2;
210 max_1_d2 = o.max_1_d2;
211 valm = o.valm;
212 nsymop = o.nsymop;
213 cell = std::move(o.cell);
214 spacegroup_number = o.spacegroup_number;
215 spacegroup_name = std::move(o.spacegroup_name);
216 symops = std::move(o.symops);
217 spacegroup = o.spacegroup;
218 datasets = std::move(o.datasets);
219 columns = std::move(o.columns);
220 batches = std::move(o.batches);
221 history = std::move(o.history);
222 appended_text = std::move(o.appended_text);
223 data = std::move(o.data);
224 warnings = o.warnings;
225 for (Mtz::Column& col : columns)
226 col.parent = this;
227 return *this;
228 }
229 Mtz(Mtz const&) = delete;
230 Mtz& operator=(Mtz const&) = delete;
231
232 void add_base() {
233 datasets.push_back({0, "HKL_base", "HKL_base", "HKL_base", cell, 0.});
234 for (int i = 0; i != 3; ++i)
235 add_column(std::string(1, "HKL"[i]), 'H', 0, i, false);
236 }
237
238 // Functions to use after MTZ headers (and data) is read.
239
240 double resolution_high() const { return std::sqrt(1.0 / max_1_d2); }
241 double resolution_low() const { return std::sqrt(1.0 / min_1_d2); }
242
243 UnitCell& get_cell(int dataset=-1) {
244 for (Dataset& ds : datasets)
245 if (ds.id == dataset && ds.cell.is_crystal() && ds.cell.a > 0)
246 return ds.cell;
247 return cell;
248 }
249
250 const UnitCell& get_cell(int dataset=-1) const {
251 return const_cast<Mtz*>(this)->get_cell(dataset);
252 }
253
255 cell = new_cell;
256 cell.set_cell_images_from_spacegroup(spacegroup); // probably not needed
257 for (Dataset& ds : datasets)
258 ds.cell = cell;
259 }
260
262 if (rmsd)
263 for (int i = 0; i < 6; ++i)
264 rmsd[i] = 0.;
265 double avg[6] = {0., 0., 0., 0., 0., 0.};
266 for (const Batch& batch : batches)
267 for (int i = 0; i < 6; ++i) {
268 // if batch headers are not set correctly, return global cell
269 if (batch.floats[i] <= 0)
270 return cell;
271 avg[i] += batch.floats[i];
272 }
273 if (avg[0] <= 0 || avg[1] <= 0 || avg[2] <= 0 ||
274 avg[3] <= 0 || avg[4] <= 0 || avg[5] <= 0)
275 return UnitCell();
276 size_t n = batches.size();
277 for (int i = 0; i < 6; ++i)
278 avg[i] /= n;
279 if (rmsd) {
280 for (const Batch& batch : batches)
281 for (int i = 0; i < 6; ++i)
282 rmsd[i] += sq(avg[i] - batch.floats[i]);
283 for (int i = 0; i < 6; ++i)
284 rmsd[i] = std::sqrt(rmsd[i] / n);
285 }
286 return UnitCell(avg[0], avg[1], avg[2], avg[3], avg[4], avg[5]);
287 }
288
290 spacegroup = new_sg;
291 spacegroup_number = new_sg ? spacegroup->ccp4 : 0;
292 spacegroup_name = new_sg ? spacegroup->hm : "";
293 }
294
296 if (datasets.empty())
297 fail("MTZ dataset not found (missing DATASET header line?).");
298 return datasets.back();
299 }
300 Dataset& dataset(int id) {
301 if ((size_t)id < datasets.size() && datasets[id].id == id)
302 return datasets[id];
303 for (Dataset& d : datasets)
304 if (d.id == id)
305 return d;
306 fail("MTZ file has no dataset with ID " + std::to_string(id));
307 }
308 const Dataset& dataset(int id) const {
309 return const_cast<Mtz*>(this)->dataset(id);
310 }
311 Dataset* dataset_with_name(const std::string& name) {
312 for (Dataset& d : datasets)
313 if (d.dataset_name == name)
314 return &d;
315 return nullptr;
316 }
317 const Dataset* dataset_with_name(const std::string& label) const {
318 return const_cast<Mtz*>(this)->dataset_with_name(label);
319 }
320 int count(const std::string& label) const {
321 int n = 0;
322 for (const Column& col : columns)
323 if (col.label == label)
324 ++n;
325 return n;
326 }
327 int count_type(char type) const {
328 int n = 0;
329 for (const Column& col : columns)
330 if (col.type == type)
331 ++n;
332 return n;
333 }
334 Column* column_with_label(const std::string& label,
335 const Dataset* ds=nullptr) {
336 for (Column& col : columns)
337 if (col.label == label && (!ds || ds->id == col.dataset_id))
338 return &col;
339 return nullptr;
340 }
341 const Column* column_with_label(const std::string& label,
342 const Dataset* ds=nullptr) const {
343 return const_cast<Mtz*>(this)->column_with_label(label, ds);
344 }
345 const Column& get_column_with_label(const std::string& label,
346 const Dataset* ds=nullptr) const {
347 if (const Column* col = column_with_label(label, ds))
348 return *col;
349 fail("Column label not found: " + label);
350 }
351 std::vector<const Column*> columns_with_type(char type) const {
352 std::vector<const Column*> cols;
353 for (const Column& col : columns)
354 if (col.type == type)
355 cols.push_back(&col);
356 return cols;
357 }
358
359 std::vector<int> positions_of_columns_with_type(char col_type) const {
360 std::vector<int> cols;
361 for (int i = 0; i < (int) columns.size(); ++i)
362 if (columns[i].type == col_type)
363 cols.push_back(i);
364 return cols;
365 }
366
367 // F(+)/(-) pairs should have type G (and L for sigma),
368 // I(+)/(-) -- K (M for sigma), but E(+)/(-) has no special column type,
369 // so here we use column labels not types.
370 std::vector<std::pair<int,int>> positions_of_plus_minus_columns() const {
371 std::vector<std::pair<int,int>> r;
372 for (int i = 0; i < (int) columns.size(); ++i) {
373 const Column& col = columns[i];
374 size_t sign_pos = col.label.find("(+)");
375 if (sign_pos != std::string::npos) {
376 std::string minus_label = columns[i].label;
377 minus_label[sign_pos+1] = '-';
378 for (int j = 0; j < (int) columns.size(); ++j)
379 if (columns[j].label == minus_label &&
380 columns[j].type == col.type &&
381 columns[j].dataset_id == col.dataset_id) {
382 r.emplace_back(i, j);
383 break;
384 }
385 }
386 }
387 return r;
388 }
389
390 const Column* column_with_one_of_labels(std::initializer_list<const char*> labels) const {
391 for (const char* label : labels) {
392 if (const Column* col = column_with_label(label))
393 return col;
394 }
395 return nullptr;
396 }
397
399 std::initializer_list<const char*> labels) {
400 for (Column& col : columns)
401 if (col.type == type) {
402 for (const char* label : labels)
403 if (col.label == label)
404 return &col;
405 }
406 return nullptr;
407 }
408
410 // cf. MtzToCif::default_spec in mtz2cif.hpp
411 return column_with_type_and_one_of_labels('I',
412 {"FREE", "RFREE", "FREER", "FreeR_flag", "R-free-flags", "FreeRflag"});
413 }
414 const Column* rfree_column() const {
415 return const_cast<Mtz*>(this)->rfree_column();
416 }
417
419 return column_with_type_and_one_of_labels('J', {"IMEAN", "I", "IOBS", "I-obs"});
420 }
421 const Column* imean_column() const {
422 return const_cast<Mtz*>(this)->imean_column();
423 }
424
426 return column_with_type_and_one_of_labels('K', {"I(+)", "IOBS(+)", "I-obs(+)"});
427 }
428 const Column* iplus_column() const {
429 return const_cast<Mtz*>(this)->iplus_column();
430 }
431
433 return column_with_type_and_one_of_labels('K', {"I(-)", "IOBS(-)", "I-obs(-)"});
434 }
435 const Column* iminus_column() const {
436 return const_cast<Mtz*>(this)->iminus_column();
437 }
438
439 bool has_data() const {
440 return data.size() == columns.size() * nreflections;
441 }
442
443 bool is_merged() const { return batches.empty(); }
444
445 void extend_min_max_1_d2(const UnitCell& uc, double& min, double& max) const {
446 for (size_t i = 0; i < data.size(); i += columns.size()) {
447 double res = uc.calculate_1_d2_double(data[i+0], data[i+1], data[i+2]);
448 if (res < min)
449 min = res;
450 if (res > max)
451 max = res;
452 }
453 }
454
455 std::array<double,2> calculate_min_max_1_d2() const {
456 if (!has_data() || columns.size() < 3)
457 fail("No data.");
458 double min_value = INFINITY;
459 double max_value = 0.;
460 if (cell.is_crystal() && cell.a > 0)
461 extend_min_max_1_d2(cell, min_value, max_value);
462 const UnitCell* prev_cell = nullptr;
463 for (const Dataset& ds : datasets)
464 if (ds.cell.is_crystal() && ds.cell.a > 0 && ds.cell != cell &&
465 (!prev_cell || ds.cell != *prev_cell)) {
466 extend_min_max_1_d2(ds.cell, min_value, max_value);
467 prev_cell = &ds.cell;
468 }
469 if (min_value == INFINITY)
470 min_value = 0;
471 return {{min_value, max_value}};
472 }
473
474 void update_reso() {
475 std::array<double,2> reso = calculate_min_max_1_d2();
476 min_1_d2 = reso[0];
477 max_1_d2 = reso[1];
478 }
479
480 // Functions for reading MTZ headers and data.
481
483 same_byte_order = !same_byte_order;
484 swap_eight_bytes(&header_offset);
485 }
486
487 template<typename Stream>
488 void read_first_bytes(Stream& stream) {
489 char buf[20] = {0};
490
491 if (!stream.read(buf, 20))
492 fail("Could not read the MTZ file (is it empty?)");
493 if (buf[0] != 'M' || buf[1] != 'T' || buf[2] != 'Z' || buf[3] != ' ')
494 fail("Not an MTZ file - it does not start with 'MTZ '");
495
496 // Bytes 9-12 have so-called machine stamp:
497 // "The first 4 half-bytes represent the real, complex, integer and
498 // character formats".
499 // We don't try to handle all the combinations here, only the two most
500 // common: big endian (for all types) and little endian (for all types).
501 // BE is denoted by 1 and LE by 4.
502 // If we get a value different than 1 and 4 we assume the native byte order.
503 if ((buf[9] & 0xf0) == (is_little_endian() ? 0x10 : 0x40))
504 toggle_endianness();
505
506 std::int32_t tmp_header_offset;
507 std::memcpy(&tmp_header_offset, buf + 4, 4);
508 if (!same_byte_order)
510
511 if (tmp_header_offset == -1) {
512 std::memcpy(&header_offset, buf + 12, 8);
513 if (!same_byte_order) {
514 swap_eight_bytes(&header_offset);
515 }
516 } else {
517 header_offset = (int64_t) tmp_header_offset;
518 }
519 }
520
521 static const char* skip_word(const char* line) {
522 while (*line != '\0' && !std::isspace(*line))
523 ++line;
524 while (std::isspace(*line))
525 ++line;
526 return line;
527 }
528
529 static UnitCell read_cell_parameters(const char* line) {
530 double a = fast_atof(line, &line);
531 double b = fast_atof(line, &line);
532 double c = fast_atof(line, &line);
533 double alpha = fast_atof(line, &line);
534 double beta = fast_atof(line, &line);
535 double gamma = fast_atof(line, &line);
536 return UnitCell(a, b, c, alpha, beta, gamma);
537 }
538
539 template<typename T> void warn(const T& text) const {
540 if (warnings)
541 *warnings << text << std::endl;
542 }
543
544 template<typename Stream>
545 void seek_headers(Stream& stream) {
546 std::ptrdiff_t pos = 4 * std::ptrdiff_t(header_offset - 1);
547 if (!stream.seek(pos))
548 fail("Cannot rewind to the MTZ header at byte " + std::to_string(pos));
549 }
550
551 // read headers until END
552 template<typename Stream>
553 void read_main_headers(Stream& stream) {
554 char line[81] = {0};
555 seek_headers(stream);
556 int ncol = 0;
557 bool has_batch = false;
558 while (stream.read(line, 80) && ialpha3_id(line) != ialpha3_id("END")) {
559 const char* args = skip_word(line);
560 switch (ialpha4_id(line)) {
561 case ialpha4_id("VERS"):
562 version_stamp = rtrim_str(args);
563 break;
564 case ialpha4_id("TITL"):
565 title = rtrim_str(args);
566 break;
567 case ialpha4_id("NCOL"): {
569 nreflections = simple_atoi(args, &args);
571 if (nbatches < 0 || nbatches > 10000000) // sanity check
572 fail("Wrong NCOL header");
573 batches.resize(nbatches);
574 break;
575 }
576 case ialpha4_id("CELL"):
577 cell = read_cell_parameters(args);
578 break;
579 case ialpha4_id("SORT"):
580 for (int& n : sort_order)
581 n = simple_atoi(args, &args);
582 break;
583 case ialpha4_id("SYMI"): {
584 nsymop = simple_atoi(args, &args);
585 symops.reserve(nsymop);
586 simple_atoi(args, &args); // ignore number of primitive operations
587 args = skip_word(skip_blank(args)); // ignore lattice type
588 spacegroup_number = simple_atoi(args, &args);
590 if (*args != '\'')
591 spacegroup_name = read_word(args);
592 else if (const char* end = std::strchr(++args, '\''))
593 spacegroup_name.assign(args, end);
594 // ignore point group which is at the end of args
595 break;
596 }
597 case ialpha4_id("SYMM"):
598 symops.push_back(parse_triplet(args));
599 break;
600 case ialpha4_id("RESO"):
601 min_1_d2 = fast_atof(args, &args);
602 max_1_d2 = fast_atof(args, &args);
603 break;
604 case ialpha4_id("VALM"):
605 if (*args != 'N') {
606 const char* endptr;
607 float v = (float) fast_atof(args, &endptr);
608 if (*endptr == '\0' || is_space(*endptr))
609 valm = v;
610 else
611 warn("Unexpected VALM value: " + rtrim_str(args));
612 }
613 break;
614 case ialpha4_id("COLU"): {
615 columns.emplace_back();
616 Column& col = columns.back();
617 col.label = read_word(args, &args);
618 col.type = read_word(args, &args)[0];
619 col.min_value = (float) fast_atof(args, &args);
620 col.max_value = (float) fast_atof(args, &args);
622 col.parent = this;
623 col.idx = columns.size() - 1;
624 break;
625 }
626 case ialpha4_id("COLS"):
627 if (columns.empty())
628 fail("MTZ: COLSRC before COLUMN?");
630 columns.back().source = read_word(args);
631 break;
632 case ialpha4_id("COLG"):
633 // Column group - not used.
634 break;
635 case ialpha4_id("NDIF"):
636 datasets.reserve(simple_atoi(args));
637 break;
638 case ialpha4_id("PROJ"):
639 datasets.emplace_back();
640 datasets.back().id = simple_atoi(args, &args);
641 datasets.back().project_name = read_word(skip_word(args));
642 datasets.back().wavelength = 0.0;
643 break;
644 case ialpha4_id("CRYS"):
645 if (simple_atoi(args, &args) == last_dataset().id)
646 datasets.back().crystal_name = read_word(args);
647 else
648 warn("MTZ CRYSTAL line: unusual numbering.");
649 break;
650 case ialpha4_id("DATA"):
651 if (simple_atoi(args, &args) == last_dataset().id)
652 datasets.back().dataset_name = read_word(args);
653 else
654 warn("MTZ DATASET line: unusual numbering.");
655 break;
656 case ialpha4_id("DCEL"):
657 if (simple_atoi(args, &args) == last_dataset().id)
658 datasets.back().cell = read_cell_parameters(args);
659 else
660 warn("MTZ DCELL line: unusual numbering.");
661 break;
662 // case("DRES"): not in use yet
663 case ialpha4_id("DWAV"):
664 if (simple_atoi(args, &args) == last_dataset().id)
665 datasets.back().wavelength = fast_atof(args);
666 else
667 warn("MTZ DWAV line: unusual numbering.");
668 break;
669 case ialpha4_id("BATCH"):
670 // We take number of batches from the NCOL record and serial numbers
671 // from BH. This header could be used only to check consistency.
672 has_batch = true;
673 break;
674 default:
675 warn("Unknown header: " + rtrim_str(line));
676 }
677 }
678 if (ncol != (int) columns.size())
679 fail("Number of COLU records inconsistent with NCOL record.");
680 if (has_batch != !batches.empty())
681 fail("BATCH header inconsistent with NCOL record.");
682 }
683
684 // read the part between END and MTZENDOFHEADERS
685 template<typename Stream>
687 char buf[81] = {0};
688 int n_headers = 0;
689 while (stream.read(buf, 80) && ialpha4_id(buf) != ialpha4_id("MTZE")) {
690 if (n_headers != 0) {
691 const char* start = skip_blank(buf);
692 const char* end = rtrim_cstr(start, start+80);
693 history.emplace_back(start, end);
694 --n_headers;
695 } else if (ialpha4_id(buf) == ialpha4_id("MTZH")) {
698 warn("Wrong MTZ: number of headers should be between 0 and 30");
699 return;
700 }
701 history.reserve(n_headers);
702 } else if (ialpha4_id(buf) == ialpha4_id("MTZB")) {
703 for (Batch& batch : batches) {
704 stream.read(buf, 80);
705 if (ialpha3_id(buf) != ialpha3_id("BH "))
706 fail("Missing BH header");
707 const char* args = skip_word(buf);
708 batch.number = simple_atoi(args, &args);
712 if (total_words != int_words + float_words || total_words > 1000)
713 fail("Wrong BH header");
714 stream.read(buf, 80); // TITLE
715 const char* end = rtrim_cstr(buf + 6, buf+76);
716 batch.title.assign(buf, end - buf);
717 batch.ints.resize(int_words);
718 stream.read(batch.ints.data(), int_words * 4);
719 batch.floats.resize(float_words);
720 stream.read(batch.floats.data(), float_words * 4);
721 stream.read(buf, 80);
722 if (ialpha4_id(buf) != ialpha4_id("BHCH"))
723 fail("Missing BHCH header");
724 split_str_into_multi(buf + 5, " \t", batch.axes);
725 }
726 }
727 }
728 appended_text = stream.read_rest();
729 }
730
732 spacegroup = find_spacegroup_by_name(spacegroup_name,
733 cell.alpha, cell.gamma);
734 if (!spacegroup) {
735 warn("MTZ: unrecognized spacegroup name: " + spacegroup_name);
736 return;
737 }
738 if (spacegroup->ccp4 != spacegroup_number)
739 warn("MTZ: inconsistent spacegroup name and number");
740 cell.set_cell_images_from_spacegroup(spacegroup);
741 for (Dataset& d : datasets)
742 d.cell.set_cell_images_from_spacegroup(spacegroup);
743 }
744
745 template<typename Stream>
746 void read_raw_data(Stream& stream) {
747 size_t n = columns.size() * nreflections;
748 data.resize(n);
749 if (!stream.seek(80))
750 fail("Cannot rewind to the MTZ data.");
751 if (!stream.read(data.data(), 4 * n))
752 fail("Error when reading MTZ data");
753 if (!same_byte_order)
754 for (float& f : data)
755 swap_four_bytes(&f);
756 }
757
758 template<typename Stream>
759 void read_all_headers(Stream& stream) {
760 read_first_bytes(stream);
761 read_main_headers(stream);
762 read_history_and_batch_headers(stream);
763 setup_spacegroup();
764 if (datasets.empty())
765 datasets.push_back({0, "HKL_base", "HKL_base", "HKL_base", cell, 0.});
766 }
767
768 template<typename Stream>
769 void read_stream(Stream&& stream, bool with_data) {
770 read_all_headers(stream);
771 if (with_data)
772 read_raw_data(stream);
773 }
774
775 void read_file(const std::string& path) {
776 fileptr_t f = file_open(path.c_str(), "rb");
777 try {
778 source_path = path;
779 read_stream(FileStream{f.get()}, true);
780 } catch (std::runtime_error& e) {
781 fail(std::string(e.what()) + ": " + path);
782 }
783 }
784
785 template<typename Input>
787 source_path = input.path();
788 if (input.is_stdin()) {
789 read_stream(FileStream{stdin}, with_data);
790 } else if (CharArray mem = input.uncompress_into_buffer()) {
791 read_stream(mem.stream(), with_data);
792 } else {
793 fileptr_t f = file_open(input.path().c_str(), "rb");
794 read_stream(FileStream{f.get()}, true);
795 }
796 }
797
799 void read_file_gz(const std::string& path, bool with_data=true);
800
801 std::vector<int> sorted_row_indices(int use_first=3) const {
802 if (!has_data())
803 fail("No data.");
804 if (use_first <= 0 || use_first >= (int) columns.size())
805 fail("Wrong use_first arg in Mtz::sort.");
806 std::vector<int> indices(nreflections);
807 for (int i = 0; i != nreflections; ++i)
808 indices[i] = i;
809 std::stable_sort(indices.begin(), indices.end(), [&](int i, int j) {
810 int a = i * (int) columns.size();
811 int b = j * (int) columns.size();
812 for (int n = 0; n < use_first; ++n)
813 if (data[a+n] != data[b+n])
814 return data[a+n] < data[b+n];
815 return false;
816 });
817 return indices;
818 }
819
820 bool sort(int use_first=3) {
821 std::vector<int> indices = sorted_row_indices(use_first);
822 sort_order = {{0, 0, 0, 0, 0}};
823 for (int i = 0; i < use_first; ++i)
824 sort_order[i] = i + 1;
825 if (std::is_sorted(indices.begin(), indices.end()))
826 return false;
827 std::vector<float> new_data(data.size());
828 size_t w = columns.size();
829 for (size_t i = 0; i != indices.size(); ++i)
830 std::memcpy(&new_data[i * w], &data[indices[i] * w], w * sizeof(float));
831 data.swap(new_data);
832 return true;
833 }
834
835 Miller get_hkl(size_t offset) const {
836 return {{(int)data[offset], (int)data[offset+1], (int)data[offset+2]}};
837 }
838 void set_hkl(size_t offset, const Miller& hkl) {
839 for (int i = 0; i != 3; ++i)
840 data[offset + i] = static_cast<float>(hkl[i]);
841 }
842
844 size_t find_offset_of_hkl(const Miller& hkl, size_t start=0) const;
845
847 void ensure_asu(bool tnt_asu=false);
848
850 void reindex(const Op& op, std::ostream* out);
851
855
858
861
862 Dataset& add_dataset(const std::string& name) {
863 int id = 0;
864 for (const Dataset& d : datasets)
865 if (d.id >= id)
866 id = d.id + 1;
867 datasets.push_back({id, name, name, name, cell, 0.0});
868 return datasets.back();
869 }
870
871 Column& add_column(const std::string& label, char type,
872 int dataset_id, int pos, bool expand_data) {
873 if (datasets.empty())
874 fail("No datasets.");
875 if (dataset_id < 0)
876 dataset_id = datasets.back().id;
877 else
878 dataset(dataset_id); // check if such dataset exist
879 if (pos > (int) columns.size())
880 fail("Requested column position after the end.");
881 if (pos < 0)
882 pos = (int) columns.size();
883 auto col = columns.emplace(columns.begin() + pos);
884 for (auto i = col + 1; i != columns.end(); ++i)
885 i->idx++;
886 col->dataset_id = dataset_id;
887 col->type = type;
888 col->label = label;
889 col->parent = this;
890 col->idx = pos;
891 if (expand_data)
892 expand_data_rows(1, pos);
893 return *col;
894 }
895
896 // helper_functions
897 void check_column(size_t idx, const char* msg) const {
898 if (!has_data())
899 fail(msg, ": data not read yet");
900 if (idx >= columns.size())
901 fail(msg, ": no column with 0-based index ", std::to_string(idx));
902 }
904 const std::vector<std::string>& trailing_cols) const {
905 assert(src_col.parent == this);
906 if (!has_data())
907 fail("data in source mtz not read yet");
908 if (src_col.idx + trailing_cols.size() >= columns.size())
909 fail("Not enough columns after " + src_col.label);
910 for (size_t i = 0; i < trailing_cols.size(); ++i)
911 if (!trailing_cols[i].empty() &&
912 trailing_cols[i] != columns[src_col.idx + i + 1].label)
913 fail("expected trailing column ", trailing_cols[i], ", found ", src_col.label);
914 }
916 const std::vector<std::string>& trailing_cols) {
917 const Mtz* src_mtz = src_col.parent;
918 for (size_t i = 0; i <= trailing_cols.size(); ++i) {
919 Column& dst = columns[dest_idx + i];
920 const Column& src = src_mtz->columns[src_col.idx + i];
921 dst.type = src.type;
922 dst.label = src.label;
923 dst.min_value = src.min_value;
924 dst.max_value = src.max_value;
925 dst.source = src.source;
926 dst.dataset_id = src.dataset_id;
927 }
928 if (src_mtz == this) {
929 // internal copying
930 for (size_t n = 0; n < data.size(); n += columns.size())
931 for (size_t i = 0; i <= trailing_cols.size(); ++i)
932 data[n + dest_idx + i] = data[n + src_col.idx + i];
933 } else {
934 // external copying - need to match indices
935 std::vector<int> dst_indices = sorted_row_indices();
936 std::vector<int> src_indices = src_mtz->sorted_row_indices();
937 // cf. for_matching_reflections()
938 size_t dst_stride = columns.size();
939 size_t src_stride = src_mtz->columns.size();
940 auto dst = dst_indices.begin();
941 auto src = src_indices.begin();
942 while (dst != dst_indices.end() && src != src_indices.end()) {
943 Miller dst_hkl = get_hkl(*dst * dst_stride);
944 Miller src_hkl = src_mtz->get_hkl(*src * src_stride);
945 if (dst_hkl == src_hkl) {
946 // copy values
947 for (size_t i = 0; i <= trailing_cols.size(); ++i)
948 data[*dst * dst_stride + dest_idx + i] =
949 src_mtz->data[*src * src_stride + src_col.idx + i];
950 ++dst;
951 ++src;
952 } else if (dst_hkl < src_hkl) {
953 ++dst;
954 } else {
955 ++src;
956 }
957 }
958 }
959 }
960
961 // extra_col are columns right after src_col that are also copied.
963 const std::vector<std::string>& trailing_cols={}) {
964 src_col.parent->check_trailing_cols(src_col, trailing_cols);
965 check_column(dest_idx + trailing_cols.size(), "replace_column()");
966 do_replace_column(dest_idx, src_col, trailing_cols);
967 return columns[dest_idx];
968 }
969
970 // If dest_idx < 0 - columns are appended at the end
971 // append new column(s), otherwise overwrite existing ones.
973 const std::vector<std::string>& trailing_cols={}) {
974 // check input consistency
975 if (!has_data())
976 fail("copy_column(): data not read yet");
977 src_col.parent->check_trailing_cols(src_col, trailing_cols);
978 // add new columns
979 if (dest_idx < 0)
980 dest_idx = (int) columns.size();
981 // if src_col is from this Mtz it may get invalidated when adding columns
982 int col_idx = -1;
983 if (src_col.parent == this) {
984 col_idx = (int) src_col.idx;
985 if (col_idx >= dest_idx)
986 col_idx += 1 + (int)trailing_cols.size();
987 }
988 for (int i = 0; i <= (int) trailing_cols.size(); ++i)
989 add_column("", ' ', -1, dest_idx + i, false);
990 expand_data_rows(1 + trailing_cols.size(), dest_idx);
991 // copy the data
992 const Column& src_col_now = col_idx < 0 ? src_col : columns[col_idx];
993 // most of the work (hkl-based row matching and data copying) is done here:
994 do_replace_column(dest_idx, src_col_now, trailing_cols);
995 return columns[dest_idx];
996 }
997
998 void remove_column(size_t idx) {
999 check_column(idx, "remove_column()");
1000 columns.erase(columns.begin() + idx);
1001 for (size_t i = idx; i < columns.size(); ++i)
1002 --columns[i].idx;
1003 vector_remove_column(data, columns.size(), idx);
1004 assert(columns.size() * nreflections == data.size());
1005 }
1006
1007 template <typename Func>
1009 if (!has_data())
1010 fail("No data.");
1011 auto out = data.begin();
1012 size_t width = columns.size();
1013 for (auto r = data.begin(); r < data.end(); r += width)
1014 if (!condition(&*r)) {
1015 if (r != out)
1016 std::copy(r, r + width, out);
1017 out += width;
1018 }
1019 data.erase(out, data.end());
1020 nreflections = int(data.size() / width);
1021 }
1022
1023 void expand_data_rows(size_t added, int pos_=-1) {
1024 size_t old_row_size = columns.size() - added;
1025 if (data.size() != old_row_size * nreflections)
1026 fail("Internal error");
1027 size_t pos = pos_ == -1 ? old_row_size : (size_t) pos_;
1028 if (pos > old_row_size)
1029 fail("expand_data_rows(): pos out of range");
1030 vector_insert_columns(data, old_row_size, (size_t)nreflections, added, pos, NAN);
1031 }
1032
1033 void set_data(const float* new_data, size_t n) {
1034 size_t ncols = columns.size();
1035 if (n % ncols != 0)
1036 fail("Mtz.set_data(): expected " + std::to_string(ncols) + " columns.");
1037 nreflections = int(n / ncols);
1038 data.assign(new_data, new_data + n);
1039 }
1040
1041 // Function for writing MTZ file
1042 void write_to_cstream(std::FILE* stream) const;
1043 void write_to_string(std::string& str) const;
1044 void write_to_file(const std::string& path) const;
1045
1046private:
1047 template<typename Write> void write_to_stream(Write write) const;
1048};
1049
1050
1051inline Mtz read_mtz_file(const std::string& path) {
1052 Mtz mtz;
1053 mtz.read_file(path);
1054 return mtz;
1055}
1056
1057template<typename Input>
1059 Mtz mtz;
1060 mtz.read_input(std::forward<Input>(input), with_data);
1061 return mtz;
1062}
1063
1064// Abstraction of data source, cf. ReflnDataProxy.
1066 const Mtz& mtz_;
1067 size_t stride() const { return mtz_.columns.size(); }
1068 size_t size() const { return mtz_.data.size(); }
1070 float get_num(size_t n) const { return mtz_.data[n]; }
1071 const UnitCell& unit_cell() const { return mtz_.cell; }
1072 const SpaceGroup* spacegroup() const { return mtz_.spacegroup; }
1073 Miller get_hkl(size_t offset) const { return mtz_.get_hkl(offset); }
1074
1075 size_t column_index(const std::string& label) const {
1076 if (const Mtz::Column* col = mtz_.column_with_label(label))
1077 return col->idx;
1078 fail("MTZ file has no column with label: " + label);
1079 }
1080};
1081
1082// Like above, but here the data is stored outside of the Mtz class
1084 const float* data_;
1085 MtzExternalDataProxy(const Mtz& mtz, const float* data)
1086 : MtzDataProxy{mtz}, data_(data) {}
1087 size_t size() const { return mtz_.columns.size() * mtz_.nreflections; }
1088 float get_num(size_t n) const { return data_[n]; }
1089 Miller get_hkl(size_t offset) const {
1090 return {{(int)data_[offset + 0],
1091 (int)data_[offset + 1],
1092 (int)data_[offset + 2]}};
1093 }
1094};
1095
1096inline MtzDataProxy data_proxy(const Mtz& mtz) { return {mtz}; }
1097
1098} // namespace gemmi
1099
1100#endif
#define GEMMI_DLL
Definition fail.hpp:53
Op parse_triplet(const std::string &s)
Definition symmetry.hpp:302
void swap_eight_bytes(void *start)
Definition fileutil.hpp:89
void swap_four_bytes(void *start)
Definition fileutil.hpp:83
std::unique_ptr< std::FILE, decltype(&std::fclose)> fileptr_t
Definition fileutil.hpp:37
MtzDataProxy data_proxy(const Mtz &mtz)
Definition mtz.hpp:1096
const char * rtrim_cstr(const char *start, const char *end=nullptr)
Definition util.hpp:124
int simple_atoi(const char *p, const char **endptr=nullptr)
Definition atox.hpp:105
double fast_atof(const char *p, const char **endptr=nullptr)
Definition atof.hpp:32
const SpaceGroup * find_spacegroup_by_name(std::string name, double alpha=0., double gamma=0.) noexcept
constexpr int ialpha3_id(const char *s)
Definition util.hpp:309
std::array< int, 3 > Miller
A synonym for convenient passing of hkl.
Definition unitcell.hpp:128
std::string rtrim_str(const std::string &str)
Definition util.hpp:118
bool is_little_endian()
Definition fileutil.hpp:73
void vector_insert_columns(std::vector< T > &data, size_t old_width, size_t length, size_t n, size_t pos, T new_value)
Definition util.hpp:273
std::string read_word(const char *line)
Definition atox.hpp:61
fileptr_t file_open(const char *path, const char *mode)
Definition fileutil.hpp:39
void split_str_into_multi(const std::string &str, const char *seps, std::vector< std::string > &result)
Definition util.hpp:164
Mtz read_mtz_file(const std::string &path)
Definition mtz.hpp:1051
constexpr float sq(float x)
Definition math.hpp:34
std::array< FP, 2 > calculate_min_max_disregarding_nans(T begin, T end)
Definition mtz.hpp:32
void fail(const std::string &msg)
Definition fail.hpp:59
void vector_remove_column(std::vector< T > &data, size_t new_width, size_t pos)
Definition util.hpp:292
const char * skip_word(const char *p)
Definition atox.hpp:54
bool is_space(char c)
Definition atox.hpp:23
Mtz read_mtz(Input &&input, bool with_data)
Definition mtz.hpp:1058
constexpr int ialpha4_id(const char *s)
Definition util.hpp:305
const char * skip_blank(const char *p)
Definition atox.hpp:47
const SpaceGroup * spacegroup() const
Definition mtz.hpp:1072
size_t column_index(const std::string &label) const
Definition mtz.hpp:1075
const UnitCell & unit_cell() const
Definition mtz.hpp:1071
Miller get_hkl(size_t offset) const
Definition mtz.hpp:1073
size_t stride() const
Definition mtz.hpp:1067
float get_num(size_t n) const
Definition mtz.hpp:1070
size_t size() const
Definition mtz.hpp:1068
MtzExternalDataProxy(const Mtz &mtz, const float *data)
Definition mtz.hpp:1085
Miller get_hkl(size_t offset) const
Definition mtz.hpp:1089
size_t size() const
Definition mtz.hpp:1087
float get_num(size_t n) const
Definition mtz.hpp:1088
std::vector< int > ints
Definition mtz.hpp:140
std::vector< float > floats
Definition mtz.hpp:141
Mat33 matrix_U() const
Definition mtz.hpp:163
int dataset_id() const
Definition mtz.hpp:157
std::vector< std::string > axes
Definition mtz.hpp:142
std::string title
Definition mtz.hpp:139
float phi_end() const
Definition mtz.hpp:162
void set_wavelength(float lambda)
Definition mtz.hpp:160
UnitCell get_cell() const
Definition mtz.hpp:144
float phi_start() const
Definition mtz.hpp:161
void set_cell(const UnitCell &uc)
Definition mtz.hpp:148
float wavelength() const
Definition mtz.hpp:159
void set_dataset_id(int id)
Definition mtz.hpp:158
float max_value
Definition mtz.hpp:85
bool is_integer() const
Definition mtz.hpp:99
float & operator[](std::size_t n)
Definition mtz.hpp:95
float at(std::size_t n) const
Definition mtz.hpp:98
size_t stride() const
Definition mtz.hpp:94
Dataset & dataset()
Definition mtz.hpp:90
std::size_t idx
Definition mtz.hpp:88
float min_value
Definition mtz.hpp:84
const Column * get_next_column_if_type(char next_type) const
Definition mtz.hpp:103
int size() const
Definition mtz.hpp:93
float operator[](std::size_t n) const
Definition mtz.hpp:96
const_iterator begin() const
Definition mtz.hpp:123
float & at(std::size_t n)
Definition mtz.hpp:97
iterator begin()
Definition mtz.hpp:113
const_iterator end() const
Definition mtz.hpp:124
iterator end()
Definition mtz.hpp:118
const Dataset & dataset() const
Definition mtz.hpp:91
std::string source
Definition mtz.hpp:86
std::string label
Definition mtz.hpp:83
bool has_data() const
Definition mtz.hpp:92
std::string dataset_name
Definition mtz.hpp:75
std::string project_name
Definition mtz.hpp:73
std::string crystal_name
Definition mtz.hpp:74
UnitCell cell
Definition mtz.hpp:76
double wavelength
Definition mtz.hpp:77
const Column * column_with_one_of_labels(std::initializer_list< const char * > labels) const
Definition mtz.hpp:390
void check_trailing_cols(const Column &src_col, const std::vector< std::string > &trailing_cols) const
Definition mtz.hpp:903
Mtz & operator=(Mtz &&o) noexcept
Definition mtz.hpp:202
std::vector< Dataset > datasets
Definition mtz.hpp:187
void read_first_bytes(Stream &stream)
Definition mtz.hpp:488
const Column * iplus_column() const
Definition mtz.hpp:428
Column & add_column(const std::string &label, char type, int dataset_id, int pos, bool expand_data)
Definition mtz.hpp:871
int count_type(char type) const
Definition mtz.hpp:327
std::vector< Batch > batches
Definition mtz.hpp:189
const Column & get_column_with_label(const std::string &label, const Dataset *ds=nullptr) const
Definition mtz.hpp:345
void warn(const T &text) const
Definition mtz.hpp:539
void write_to_cstream(std::FILE *stream) const
void extend_min_max_1_d2(const UnitCell &uc, double &min, double &max) const
Definition mtz.hpp:445
void expand_to_p1()
Change symmetry to P1 and expand reflections.
std::vector< int > positions_of_columns_with_type(char col_type) const
Definition mtz.hpp:359
const Dataset * dataset_with_name(const std::string &label) const
Definition mtz.hpp:317
std::string appended_text
Definition mtz.hpp:191
bool sort(int use_first=3)
Definition mtz.hpp:820
const Column * column_with_label(const std::string &label, const Dataset *ds=nullptr) const
Definition mtz.hpp:341
bool has_data() const
Definition mtz.hpp:439
Dataset & add_dataset(const std::string &name)
Definition mtz.hpp:862
std::vector< Op > symops
Definition mtz.hpp:185
const UnitCell & get_cell(int dataset=-1) const
Definition mtz.hpp:250
const Column * iminus_column() const
Definition mtz.hpp:435
Column * column_with_label(const std::string &label, const Dataset *ds=nullptr)
Definition mtz.hpp:334
bool switch_to_asu_hkl()
(for unmerged MTZ only) change HKL to ASU equivalent and set ISYM
void seek_headers(Stream &stream)
Definition mtz.hpp:545
void write_to_file(const std::string &path) const
void ensure_asu(bool tnt_asu=false)
(for merged MTZ only) change HKL to ASU equivalent, adjust phases, etc
Column * column_with_type_and_one_of_labels(char type, std::initializer_list< const char * > labels)
Definition mtz.hpp:398
void set_spacegroup(const SpaceGroup *new_sg)
Definition mtz.hpp:289
std::string spacegroup_name
Definition mtz.hpp:184
double resolution_low() const
Definition mtz.hpp:241
Column * rfree_column()
Definition mtz.hpp:409
void read_file_gz(const std::string &path, bool with_data=true)
the same as read_input(MaybeGzipped(path), with_data)
Dataset & dataset(int id)
Definition mtz.hpp:300
void read_stream(Stream &&stream, bool with_data)
Definition mtz.hpp:769
std::vector< const Column * > columns_with_type(char type) const
Definition mtz.hpp:351
Column & copy_column(int dest_idx, const Column &src_col, const std::vector< std::string > &trailing_cols={})
Definition mtz.hpp:972
static UnitCell read_cell_parameters(const char *line)
Definition mtz.hpp:529
void read_raw_data(Stream &stream)
Definition mtz.hpp:746
std::vector< int > sorted_row_indices(int use_first=3) const
Definition mtz.hpp:801
void read_input(Input &&input, bool with_data)
Definition mtz.hpp:786
void reindex(const Op &op, std::ostream *out)
reindex data, usually followed by ensure_asu()
Dataset & last_dataset()
Definition mtz.hpp:295
int nreflections
Definition mtz.hpp:176
void read_main_headers(Stream &stream)
Definition mtz.hpp:553
std::array< double, 2 > calculate_min_max_1_d2() const
Definition mtz.hpp:455
std::vector< std::pair< int, int > > positions_of_plus_minus_columns() const
Definition mtz.hpp:370
const Column * rfree_column() const
Definition mtz.hpp:414
Column * imean_column()
Definition mtz.hpp:418
const Column * imean_column() const
Definition mtz.hpp:421
void set_hkl(size_t offset, const Miller &hkl)
Definition mtz.hpp:838
void toggle_endianness()
Definition mtz.hpp:482
Mtz(Mtz &&o) noexcept
Definition mtz.hpp:201
void do_replace_column(size_t dest_idx, const Column &src_col, const std::vector< std::string > &trailing_cols)
Definition mtz.hpp:915
std::vector< std::string > history
Definition mtz.hpp:190
UnitCell cell
Definition mtz.hpp:182
double resolution_high() const
Definition mtz.hpp:240
void set_cell_for_all(const UnitCell &new_cell)
Definition mtz.hpp:254
Dataset * dataset_with_name(const std::string &name)
Definition mtz.hpp:311
void read_file(const std::string &path)
Definition mtz.hpp:775
Mtz & operator=(Mtz const &)=delete
UnitCell get_average_cell_from_batch_headers(double *rmsd) const
Definition mtz.hpp:261
Mtz(Mtz const &)=delete
void read_history_and_batch_headers(Stream &stream)
Definition mtz.hpp:686
Column & replace_column(size_t dest_idx, const Column &src_col, const std::vector< std::string > &trailing_cols={})
Definition mtz.hpp:962
Column * iminus_column()
Definition mtz.hpp:432
bool switch_to_original_hkl()
(for unmerged MTZ only) change HKL according to M/ISYM
Column * iplus_column()
Definition mtz.hpp:425
void set_data(const float *new_data, size_t n)
Definition mtz.hpp:1033
std::string source_path
Definition mtz.hpp:170
static const char * skip_word(const char *line)
Definition mtz.hpp:521
const Dataset & dataset(int id) const
Definition mtz.hpp:308
std::vector< Column > columns
Definition mtz.hpp:188
void remove_rows_if(Func condition)
Definition mtz.hpp:1008
Mtz(bool with_base=false)
Definition mtz.hpp:197
size_t find_offset_of_hkl(const Miller &hkl, size_t start=0) const
Returns offset of the first hkl or (size_t)-1. Can be slow.
std::string title
Definition mtz.hpp:175
void write_to_string(std::string &str) const
bool is_merged() const
Definition mtz.hpp:443
void expand_data_rows(size_t added, int pos_=-1)
Definition mtz.hpp:1023
Miller get_hkl(size_t offset) const
Definition mtz.hpp:835
std::string version_stamp
Definition mtz.hpp:174
void check_column(size_t idx, const char *msg) const
Definition mtz.hpp:897
void read_all_headers(Stream &stream)
Definition mtz.hpp:759
void update_reso()
Definition mtz.hpp:474
const SpaceGroup * spacegroup
Definition mtz.hpp:186
void add_base()
Definition mtz.hpp:232
UnitCell & get_cell(int dataset=-1)
Definition mtz.hpp:243
int count(const std::string &label) const
Definition mtz.hpp:320
void setup_spacegroup()
Definition mtz.hpp:731
std::vector< float > data
Definition mtz.hpp:192
void remove_column(size_t idx)
Definition mtz.hpp:998
GroupOps operations() const
Unit cell.
Definition unitcell.hpp:139
bool is_crystal() const
Definition unitcell.hpp:164
void set_cell_images_from_spacegroup(const SpaceGroup *sg)
Definition unitcell.hpp:337
UnmergedHklMover(const SpaceGroup *spacegroup)
Definition mtz.hpp:52
int move_to_asu(std::array< int, 3 > &hkl)
Definition mtz.hpp:58