Gemmi C++ API
Loading...
Searching...
No Matches
smcif.hpp
Go to the documentation of this file.
1// Copyright 2018 Global Phasing Ltd.
2//
3// Read small molecule CIF file into SmallStructure (from small.hpp).
4
5#ifndef GEMMI_SMCIF_HPP_
6#define GEMMI_SMCIF_HPP_
7
8#include "small.hpp" // for SmallStructure
9#include "cifdoc.hpp"
10#include "numb.hpp" // for as_number
11#include "sprintf.hpp" // for to_str
12
13namespace gemmi {
14
15inline
17 using cif::as_number;
18 cif::Block& block = const_cast<cif::Block&>(block_);
20 st.name = block.name;
21
22 // unit cell and symmetry
23 cif::Table cell = block.find("_cell_",
24 {"length_a", "length_b", "length_c",
25 "angle_alpha", "angle_beta", "angle_gamma"});
26 if (cell.ok()) {
27 auto c = cell.one();
28 if (!cif::is_null(c[0]) && !cif::is_null(c[1]) && !cif::is_null(c[2]))
29 st.cell.set(as_number(c[0]), as_number(c[1]), as_number(c[2]),
30 as_number(c[3]), as_number(c[4]), as_number(c[5]));
31 }
32 for (const char* tag : {"_space_group_name_H-M_alt",
33 "_symmetry_space_group_name_H-M"})
34 if (const std::string* val = block.find_value(tag)) {
35 st.spacegroup_hm = cif::as_string(*val);
36 break;
37 }
38 for (const char* tag : {"_space_group_symop_operation_xyz",
39 "_symmetry_equiv_pos_as_xyz"}) {
40 if (const cif::Column col = block.find_values(tag)) {
41 st.symops.reserve(col.length());
42 for (const std::string& value : col)
43 st.symops.push_back(cif::as_string(value));
44 break;
45 }
46 }
47 for (const char* tag : {"_space_group_name_Hall", "_symmetry_space_group_name_Hall"})
48 if (const std::string* val = block.find_value(tag))
49 st.spacegroup_hall = cif::as_string(*val);
50 for (const char* tag : {"_space_group_IT_number", "_symmetry_Int_Tables_number"})
51 if (const std::string* val = block.find_value(tag)) {
52 st.spacegroup_number = cif::as_int(*val, 0);
53 break;
54 }
55 st.determine_and_set_spacegroup("S.H2");
56
58 cif::Table atom_table = block.find("_atom_site_",
59 {"label",
60 "?type_symbol",
61 "?fract_x",
62 "?fract_y",
63 "?fract_z",
64 "?U_iso_or_equiv",
65 "?B_iso_or_equiv",
66 "?occupancy",
67 "?disorder_group"});
68 for (auto row : atom_table) {
70 site.label = cif::as_string(row[kLabel]);
71 if (row.has(kSymbol))
72 site.type_symbol = cif::as_string(row[kSymbol]);
73 else
74 site.type_symbol = site.label;
75 if (row.has(kX))
76 site.fract.x = as_number(row[kX]);
77 if (row.has(kY))
78 site.fract.y = as_number(row[kY]);
79 if (row.has(kZ))
80 site.fract.z = as_number(row[kZ]);
81 if (row.has(kUiso))
82 site.u_iso = as_number(row[kUiso], 0.0);
83 else if (row.has(kBiso))
84 site.u_iso = as_number(row[kBiso], 0.0) / u_to_b();
85 if (row.has(kOcc))
86 site.occ = as_number(row[kOcc], 1.0);
87 if (row.has2(kDisorderGroup))
88 // ignore non-integer _atom_site_disorder_group
89 site.disorder_group = string_to_int(row[kDisorderGroup], false);
90 split_element_and_charge(site.type_symbol, &site);
91 st.sites.push_back(site);
92 }
93
94 std::vector<SmallStructure::Site>::iterator aniso_site = st.sites.begin();
95 for (auto row : block.find("_atom_site_aniso_",
96 {"label", "U_11", "U_22", "U_33",
97 "U_12", "U_13", "U_23"})) {
98 std::string aniso_label = row.str(0);
99 if (aniso_site == st.sites.end() || aniso_site->label != aniso_label) {
100 aniso_site = std::find_if(st.sites.begin(), st.sites.end(),
101 [&](SmallStructure::Site& x) { return x.label == aniso_label; });
102 if (aniso_site == st.sites.end())
103 continue;
104 }
105 aniso_site->aniso.u11 = as_number(row[1], 0.0);
106 aniso_site->aniso.u22 = as_number(row[2], 0.0);
107 aniso_site->aniso.u33 = as_number(row[3], 0.0);
108 aniso_site->aniso.u12 = as_number(row[4], 0.0);
109 aniso_site->aniso.u13 = as_number(row[5], 0.0);
110 aniso_site->aniso.u23 = as_number(row[6], 0.0);
111 ++aniso_site;
112 }
113
114 for (auto row : block.find("_atom_type_",
115 {"symbol",
116 "scat_dispersion_real",
117 "scat_dispersion_imag"})) {
118 SmallStructure::AtomType atom_type;
119 atom_type.symbol = row.str(0);
120 atom_type.dispersion_real = cif::as_number(row[1]);
121 atom_type.dispersion_imag = cif::as_number(row[2]);
122 split_element_and_charge(atom_type.symbol, &atom_type);
123 st.atom_types.push_back(atom_type);
124 }
125 if (cif::Column w_col = block.find_values("_diffrn_radiation_wavelength"))
126 st.wavelength = cif::as_number(w_col.at(0));
127 return st;
128}
129
131 cif::Block block;
132 block.name = st.name;
133 if (st.cell.is_crystal()) {
134 block.set_pair("_cell_length_a", to_str(st.cell.a));
135 block.set_pair("_cell_length_b", to_str(st.cell.b));
136 block.set_pair("_cell_length_c", to_str(st.cell.c));
137 block.set_pair("_cell_angle_alpha", to_str(st.cell.alpha));
138 block.set_pair("_cell_angle_beta", to_str(st.cell.beta));
139 block.set_pair("_cell_angle_gamma", to_str(st.cell.gamma));
140 }
141 if (!st.spacegroup_hm.empty())
142 block.set_pair("_symmetry_space_group_name_H-M", cif::quote(st.spacegroup_hm));
143 if (st.wavelength != 0)
144 block.set_pair("_diffrn_radiation_wavelength", to_str(st.wavelength));
145
146 cif::Loop& atom_loop = block.init_loop("_atom_site_", {"label",
147 "type_symbol",
148 "fract_x",
149 "fract_y",
150 "fract_z",
151 "U_iso_or_equiv",
152 "occupancy",
153 "disorder_group"});
154 for (const SmallStructure::Site& site: st.sites) {
155 atom_loop.add_row({
156 cif::quote(site.label),
157 site.type_symbol.empty() ? site.element_and_charge_symbol()
158 : cif::quote(site.type_symbol),
159 to_str(site.fract.x),
160 to_str(site.fract.y),
161 to_str(site.fract.z),
162 to_str(site.u_iso),
163 to_str(site.occ),
164 site.disorder_group == 0 ? "." : std::to_string(site.disorder_group)
165 });
166 }
167
168 bool has_aniso = false;
169 for (const SmallStructure::Site& site: st.sites)
170 if (site.aniso.nonzero()) {
171 has_aniso = true;
172 break;
173 }
174 if (has_aniso) {
175 cif::Loop& aniso_loop = block.init_loop("_atom_site_aniso_", {
176 "label", "U_11", "U_22", "U_33", "U_12", "U_13", "U_23"});
177 for (const SmallStructure::Site& site: st.sites)
178 if (site.aniso.nonzero())
179 aniso_loop.add_row({
180 cif::quote(site.label),
181 to_str(site.aniso.u11), to_str(site.aniso.u22), to_str(site.aniso.u33),
182 to_str(site.aniso.u12), to_str(site.aniso.u13), to_str(site.aniso.u23)
183 });
184 }
185
186 return block;
187}
188
189} // namespace gemmi
190#endif
struct Document that represents the CIF file (but can also be read from a different representation,...
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
bool is_null(const std::string &value)
Definition cifdoc.hpp:76
std::string quote(std::string v)
Definition cifdoc.hpp:1180
int as_int(const std::string &str)
Definition cifdoc.hpp:107
int string_to_int(const char *p, bool checked, size_t length=0)
Definition atox.hpp:73
void split_element_and_charge(const std::string &label, T *dest)
Definition small.hpp:214
SmallStructure make_small_structure_from_block(const cif::Block &block_)
Definition smcif.hpp:16
cif::Block make_cif_block_from_small_structure(const SmallStructure &st)
Definition smcif.hpp:130
GEMMI_DLL int GEMMI_DLL int std::string to_str(double d)
Definition sprintf.hpp:36
constexpr double u_to_b()
Definition math.hpp:29
Utilities for parsing CIF numbers (the CIF spec calls them 'numb').
Representation of a small molecule or inorganic crystal. Flat list of atom sites. Minimal functionali...
interface to stb_sprintf: snprintf_z, to_str(float|double)
Column find_values(const std::string &tag)
Definition cifdoc.hpp:855
Table find(const std::string &prefix, const std::vector< std::string > &tags)
Definition cifdoc.hpp:968
void set_pair(const std::string &tag, const std::string &value)
Definition cifdoc.hpp:897
Loop & init_loop(const std::string &prefix, std::vector< std::string > tags)
Definition cifdoc.hpp:494
std::string name
Definition cifdoc.hpp:450
const std::string * find_value(const std::string &tag) const
Definition cifdoc.hpp:841
bool ok() const
Definition cifdoc.hpp:357