Gemmi C++ API
Loading...
Searching...
No Matches
refln.hpp
Go to the documentation of this file.
1// Copyright 2019 Global Phasing Ltd.
2//
3// Reads reflection data from the mmCIF format.
4
5#ifndef GEMMI_REFLN_HPP_
6#define GEMMI_REFLN_HPP_
7
8#include <array>
9#include "cifdoc.hpp"
10#include "fail.hpp" // for fail
11#include "mmcif_impl.hpp" // for set_cell_from_mmcif, read_spacegroup_from_block
12#include "numb.hpp" // for as_number
13#include "symmetry.hpp" // for SpaceGroup
14#include "unitcell.hpp" // for UnitCell
15
16namespace gemmi {
17
18struct ReflnBlock {
20 std::string entry_id;
22 const SpaceGroup* spacegroup = nullptr;
23 double wavelength;
28
29 ReflnBlock() = default;
33 impl::set_cell_from_mmcif(block, cell);
34 if (const std::string* hm = impl::find_spacegroup_hm_value(block))
38 const char* wave_tag = "_diffrn_radiation_wavelength.wavelength";
40 wavelength_count = wave_col.length();
42 refln_loop = block.find_loop("_refln.index_h").get_loop();
43 diffrn_refln_loop = block.find_loop("_diffrn_refln.index_h").get_loop();
45 }
48 if (this == &o)
49 return *this;
50 block = o.block;
51 entry_id = o.entry_id;
52 cell = o.cell;
53 spacegroup = o.spacegroup;
54 wavelength = o.wavelength;
55 wavelength_count = o.wavelength_count;
56 if (o.refln_loop)
57 refln_loop = block.find_loop("_refln.index_h").get_loop();
58 if (o.diffrn_refln_loop)
59 diffrn_refln_loop = block.find_loop("_diffrn_refln.index_h").get_loop();
61 return *this;
62 }
63
64 bool ok() const { return default_loop != nullptr; }
65 void check_ok() const { if (!ok()) fail("Invalid ReflnBlock"); }
66
67 // position after "_refln." or "_diffrn_refln."
68 size_t tag_offset() const { return default_loop == refln_loop ? 7 : 14; }
69
73 bool is_merged() const { return ok() && default_loop == refln_loop; }
74 // deprecated
75 bool is_unmerged() const { return ok() && default_loop == diffrn_refln_loop; }
76
77 std::vector<std::string> column_labels() const {
78 check_ok();
79 std::vector<std::string> labels(default_loop->tags.size());
80 for (size_t i = 0; i != labels.size(); ++i)
81 labels[i].assign(default_loop->tags[i], tag_offset(), std::string::npos);
82 return labels;
83 }
84
85 int find_column_index(const std::string& tag) const {
86 if (!ok())
87 return -1;
88 size_t name_pos = tag_offset();
89 for (int i = 0; i != (int) default_loop->tags.size(); ++i)
90 if (default_loop->tags[i].compare(name_pos, std::string::npos, tag) == 0)
91 return i;
92 return -1;
93 }
94
95 size_t get_column_index(const std::string& tag) const {
96 int idx = find_column_index(tag);
97 if (idx == -1) {
98 if (!ok())
99 fail("No reflection data in block ", block.name);
100 const char* category = default_loop == refln_loop ? "_refln." : "_diffrn_refln.";
101 fail("Column not found in block ", block.name, ": ", category, tag);
102 }
103 return idx;
104 }
105
106 template<typename T>
107 std::vector<T> make_vector(const std::string& tag, T null) const {
108 size_t n = get_column_index(tag);
109 std::vector<T> v(default_loop->length());
110 for (size_t j = 0; j != v.size(); n += default_loop->width(), ++j)
112 return v;
113 }
114
115 std::array<size_t,3> get_hkl_column_indices() const {
116 return {{get_column_index("index_h"),
117 get_column_index("index_k"),
118 get_column_index("index_l")}};
119 }
120
121 std::vector<Miller> make_miller_vector() const {
123 std::vector<Miller> v(default_loop->length());
124 for (size_t j = 0, n = 0; j != v.size(); j++, n += default_loop->width())
125 for (int i = 0; i != 3; ++i)
126 v[j][i] = cif::as_int(default_loop->values[n + hkl_idx[i]]);
127 return v;
128 }
129
130 std::vector<double> make_1_d2_vector() const {
131 if (!cell.is_crystal() || cell.a <= 0)
132 fail("Unit cell is not known");
134 std::vector<double> r(default_loop->length());
135 for (size_t j = 0, n = 0; j != r.size(); j++, n += default_loop->width()) {
136 Miller hkl;
137 for (int i = 0; i != 3; ++i)
138 hkl[i] = cif::as_int(default_loop->values[n + hkl_idx[i]]);
139 r[j] = cell.calculate_1_d2(hkl);
140 }
141 return r;
142 }
143
144 std::vector<double> make_d_vector() const {
145 std::vector<double> vec = make_1_d2_vector();
146 for (double& d : vec)
147 d = 1.0 / std::sqrt(d);
148 return vec;
149 }
150};
151
152// moves blocks from the argument to the return value
153inline
154std::vector<ReflnBlock> as_refln_blocks(std::vector<cif::Block>&& blocks) {
155 std::vector<ReflnBlock> rvec;
156 rvec.reserve(blocks.size());
157 for (cif::Block& block : blocks)
158 rvec.emplace_back(std::move(block));
159 blocks.clear();
160 // Some blocks miss space group or unit cell, try to fill it in.
161 const SpaceGroup* first_sg = nullptr;
162 const UnitCell* first_cell = nullptr;
163 for (ReflnBlock& rblock : rvec) {
164 if (!first_sg)
165 first_sg = rblock.spacegroup;
166 else if (!rblock.spacegroup)
167 rblock.spacegroup = first_sg;
168 if (rblock.cell.is_crystal()) {
169 if (!first_cell)
170 first_cell = &rblock.cell;
171 } else if (first_cell) {
172 rblock.cell = *first_cell;
173 }
174 }
175 return rvec;
176}
177
178// Get the first (merged) block with required labels.
179// Optionally, block name can be specified.
180inline ReflnBlock get_refln_block(std::vector<cif::Block>&& blocks,
181 const std::vector<std::string>& labels,
182 const char* block_name=nullptr) {
183 const SpaceGroup* first_sg = nullptr;
184 bool has_block = false;
185 for (cif::Block& block : blocks) {
186 if (!first_sg)
187 if (const std::string* hm = impl::find_spacegroup_hm_value(block)) {
189 if (first_sg && first_sg->ext == 'H') {
190 UnitCell cell;
191 impl::set_cell_from_mmcif(block, cell);
193 }
194 }
195 if (!block_name || block.name == block_name) {
196 has_block = true;
197 if (cif::Loop* loop = block.find_loop("_refln.index_h").get_loop())
198 if (std::all_of(labels.begin(), labels.end(),
199 [&](const std::string& s) { return loop->has_tag("_refln."+s); })) {
200 ReflnBlock rblock(std::move(block));
201 if (!rblock.spacegroup && first_sg)
202 rblock.spacegroup = first_sg;
203 return rblock;
204 }
205 }
206 }
207 if (block_name && !has_block)
208 fail("Required block not found in SF-mmCIF file.");
209 fail("Tags not found in SF-mmCIF file: _refln.", join_str(labels, ", _refln."));
210}
211
214 rb.block.swap(block);
215 rb.entry_id = rb.block.name;
216 impl::set_cell_from_mmcif(rb.block, rb.cell, /*mmcif=*/false);
217 const char* hm_tag = "_symmetry_space_group_name_H-M";
218 if (const std::string* hm = rb.block.find_value(hm_tag))
219 rb.spacegroup = find_spacegroup_by_name(cif::as_string(*hm),
220 rb.cell.alpha, rb.cell.gamma);
221 rb.cell.set_cell_images_from_spacegroup(rb.spacegroup);
222 rb.refln_loop = rb.block.find_loop("_refln_index_h").get_loop();
223 rb.default_loop = rb.refln_loop;
224 return rb;
225}
226
227// Abstraction of data source, cf. MtzDataProxy.
229 const ReflnBlock& rb_;
230 std::array<size_t,3> hkl_cols_;
231 explicit ReflnDataProxy(const ReflnBlock& rb)
232 : rb_(rb), hkl_cols_(rb_.get_hkl_column_indices()) {}
233 size_t stride() const { return loop().tags.size(); }
234 size_t size() const { return loop().values.size(); }
236 double get_num(size_t n) const { return cif::as_number(loop().values[n]); }
237 const UnitCell& unit_cell() const { return rb_.cell; }
238 const SpaceGroup* spacegroup() const { return rb_.spacegroup; }
239 Miller get_hkl(size_t offset) const {
240 return {{get_int(offset + hkl_cols_[0]),
241 get_int(offset + hkl_cols_[1]),
242 get_int(offset + hkl_cols_[2])}};
243 }
244 size_t column_index(const std::string& label) const { return rb_.get_column_index(label); }
245private:
246 const cif::Loop& loop() const { rb_.check_ok(); return *rb_.default_loop; }
247 int get_int(size_t n) const { return cif::as_int(loop().values[n]); }
248};
249
251
252} // namespace gemmi
253#endif
struct Document that represents the CIF file (but can also be read from a different representation,...
Loop * get_loop() const
Definition cifdoc.hpp:681
fail(), unreachable() and __declspec/__attribute__ macros
Functions used in both mmcif. hpp and refln. hpp (for coordinate and reflection mmCIF files).
int as_any(const std::string &s, int null)
Definition cifdoc.hpp:116
double as_number(const std::string &s, double nan=NAN)
Definition numb.hpp:19
std::string as_string(const std::string &value)
Definition cifdoc.hpp:80
int as_int(const std::string &str)
Definition cifdoc.hpp:107
MtzDataProxy data_proxy(const Mtz &mtz)
Definition mtz.hpp:596
std::vector< ReflnBlock > as_refln_blocks(std::vector< cif::Block > &&blocks)
Definition refln.hpp:154
ReflnBlock hkl_cif_as_refln_block(cif::Block &block)
Definition refln.hpp:212
std::array< int, 3 > Miller
A synonym for convenient passing of hkl.
Definition unitcell.hpp:129
GEMMI_DLL const SpaceGroup * find_spacegroup_by_name(std::string name, double alpha=0., double gamma=0., const char *prefer=nullptr)
If angles alpha and gamma are provided, they are used to distinguish hexagonal and rhombohedral setti...
ReflnBlock get_refln_block(std::vector< cif::Block > &&blocks, const std::vector< std::string > &labels, const char *block_name=nullptr)
Definition refln.hpp:180
std::string join_str(T begin, T end, const S &sep, const F &getter)
Definition util.hpp:183
void fail(const std::string &msg)
Definition fail.hpp:59
Definition seqid.hpp:151
Utilities for parsing CIF numbers (the CIF spec calls them 'numb').
int find_column_index(const std::string &tag) const
Definition refln.hpp:85
size_t tag_offset() const
Definition refln.hpp:68
std::vector< T > make_vector(const std::string &tag, T null) const
Definition refln.hpp:107
UnitCell cell
Definition refln.hpp:21
void use_unmerged(bool unmerged)
Definition refln.hpp:70
cif::Loop * default_loop
Definition refln.hpp:27
std::string entry_id
Definition refln.hpp:20
bool ok() const
Definition refln.hpp:64
cif::Loop * refln_loop
Definition refln.hpp:25
double wavelength
Definition refln.hpp:23
void check_ok() const
Definition refln.hpp:65
ReflnBlock & operator=(const ReflnBlock &o)
Definition refln.hpp:47
std::vector< Miller > make_miller_vector() const
Definition refln.hpp:121
cif::Loop * diffrn_refln_loop
Definition refln.hpp:26
ReflnBlock & operator=(ReflnBlock &&)=default
const SpaceGroup * spacegroup
Definition refln.hpp:22
bool is_unmerged() const
Definition refln.hpp:75
size_t get_column_index(const std::string &tag) const
Definition refln.hpp:95
std::vector< double > make_d_vector() const
Definition refln.hpp:144
bool is_merged() const
Definition refln.hpp:73
ReflnBlock(cif::Block &&block_)
Definition refln.hpp:31
std::array< size_t, 3 > get_hkl_column_indices() const
Definition refln.hpp:115
ReflnBlock(ReflnBlock &&rblock_)=default
cif::Block block
Definition refln.hpp:19
ReflnBlock()=default
std::vector< double > make_1_d2_vector() const
Definition refln.hpp:130
std::vector< std::string > column_labels() const
Definition refln.hpp:77
ReflnDataProxy(const ReflnBlock &rb)
Definition refln.hpp:231
Miller get_hkl(size_t offset) const
Definition refln.hpp:239
size_t stride() const
Definition refln.hpp:233
size_t size() const
Definition refln.hpp:234
double get_num(size_t n) const
Definition refln.hpp:236
const UnitCell & unit_cell() const
Definition refln.hpp:237
const SpaceGroup * spacegroup() const
Definition refln.hpp:238
size_t column_index(const std::string &label) const
Definition refln.hpp:244
Unit cell.
Definition unitcell.hpp:165
bool is_crystal() const
Definition unitcell.hpp:187
double calculate_1_d2(const Miller &hkl) const
Definition unitcell.hpp:573
void set_cell_images_from_spacegroup(const SpaceGroup *sg)
Definition unitcell.hpp:363
Column find_values(const std::string &tag)
Definition cifdoc.hpp:855
Column find_loop(const std::string &tag)
Definition cifdoc.hpp:829
std::string name
Definition cifdoc.hpp:450
const std::string * find_value(const std::string &tag) const
Definition cifdoc.hpp:841
size_t width() const
Definition cifdoc.hpp:141
std::vector< std::string > tags
Definition cifdoc.hpp:128
std::vector< std::string > values
Definition cifdoc.hpp:129
size_t length() const
Definition cifdoc.hpp:142
Crystallographic Symmetry. Space Groups. Coordinate Triplets.
Unit cell.