Gemmi C++ API
Loading...
Searching...
No Matches
modify.hpp
Go to the documentation of this file.
1// Copyright 2017-2021 Global Phasing Ltd.
2//
3// Modify various properties of the model.
4
5// For modifications that depend on entities or connectivity see polyheur.hpp.
6
7#ifndef GEMMI_MODIFY_HPP_
8#define GEMMI_MODIFY_HPP_
9
10#include "model.hpp"
11#include "util.hpp" // for vector_remove_if
12#include <set>
13
14namespace gemmi {
15
17template<class T> void remove_alternative_conformations(T& obj) {
18 for (auto& child : obj.children())
20}
21template<> inline void remove_alternative_conformations(Chain& chain) {
22 std::set<SeqId> seqids;
23 for (size_t i = 0; i < chain.residues.size(); ) {
24 if (seqids.insert(chain.residues[i].seqid).second)
25 ++i;
26 else
27 chain.residues.erase(chain.residues.begin() + i);
28 }
29 for (Residue& residue : chain.residues) {
30 std::set<std::string> names;
31 for (size_t i = 0; i < residue.atoms.size(); ) {
32 Atom& atom = residue.atoms[i];
33 atom.altloc = '\0';
34 if (names.insert(atom.name).second)
35 ++i;
36 else
37 residue.atoms.erase(residue.atoms.begin() + i);
38 }
39 }
40}
41
43template<class T> void remove_hydrogens(T& obj) {
44 for (auto& child : obj.children())
46}
47template<> inline void remove_hydrogens(Residue& res) {
48 vector_remove_if(res.atoms, [](const Atom& a) {
49 return a.element == El::H || a.element == El::D;
50 });
51}
52
56template<class T> void assign_b_iso(T& obj, float b_min, float b_max) {
57 for (auto& child : obj.children())
59}
60template<> inline void assign_b_iso(Atom& atom, float b_min, float b_max) {
61 atom.b_iso = clamp(atom.b_iso, b_min, b_max);
62}
63
65template<class T> void remove_anisou(T& obj) {
66 for (auto& child : obj.children())
68}
69template<> inline void remove_anisou(Atom& atom) {
70 atom.aniso = {0, 0, 0, 0, 0, 0};
71}
72
74template<class T> void ensure_anisou(T& obj) {
75 for (auto& child : obj.children())
77}
78template<> inline void ensure_anisou(Atom& atom) {
79 if (!atom.aniso.nonzero()) {
80 float u = float(1. / gemmi::u_to_b() * atom.b_iso);
81 atom.aniso = {u, u, u, 0.f, 0.f, 0.f};
82 }
83}
84
86template<class T> void transform_pos_and_adp(T& obj, const Transform& tr) {
87 for (auto& child : obj.children())
89}
90template<> inline void transform_pos_and_adp(Atom& atom, const Transform& tr) {
91 atom.pos = Position(tr.apply(atom.pos));
92 if (atom.aniso.nonzero())
93 atom.aniso = atom.aniso.transformed_by<float>(tr.mat);
94}
95
97inline void assign_serial_numbers(Model& model, bool numbered_ter=false) {
98 int serial = 0;
99 for (Chain& chain : model.chains)
100 for (Residue& res : chain.residues) {
101 for (Atom& atom : res.atoms)
102 atom.serial = ++serial;
103 if (numbered_ter && res.entity_type == EntityType::Polymer &&
104 (&res == &chain.residues.back() || (&res + 1)->entity_type != EntityType::Polymer))
105 ++serial;
106 }
107}
108inline void assign_serial_numbers(Structure& st, bool numbered_ter=false) {
109 for (Model& model : st.models)
110 assign_serial_numbers(model, numbered_ter);
111}
112
113
119template<typename Func>
121 for (Connection& con : st.connections) {
122 func(con.partner1);
123 func(con.partner2);
124 }
125 for (CisPep& cispep : st.cispeps) {
126 func(cispep.partner_c);
127 func(cispep.partner_n);
128 }
129 for (Helix& helix : st.helices) {
130 func(helix.start);
131 func(helix.end);
132 }
133 for (Sheet& sheet : st.sheets)
134 for (Sheet::Strand& strand : sheet.strands) {
135 func(strand.start);
136 func(strand.end);
137 func(strand.hbond_atom2);
138 func(strand.hbond_atom1);
139 }
140}
141
145template<typename Func>
147 process_addresses(st, [&](AtomAddress& aa) { func(aa.chain_name, aa.res_id.seqid); });
148 for (ModRes& modres : st.mod_residues)
149 func(modres.chain_name, modres.res_id.seqid);
150 for (RefinementInfo& ri : st.meta.refinement)
151 for (TlsGroup& tls : ri.tls_groups)
152 for (TlsGroup::Selection& sel : tls.selections) {
153 func(sel.chain, sel.res_begin);
154 func(sel.chain, sel.res_end);
155 }
156}
157
158inline void rename_chain(Structure& st, const std::string& old_name,
159 const std::string& new_name) {
160 auto update = [&](std::string& name) {
161 if (name == old_name)
162 name = new_name;
163 };
164 process_addresses(st, [&](AtomAddress& aa) { update(aa.chain_name); });
165 for (ModRes& modres : st.mod_residues)
166 update(modres.chain_name);
167 for (RefinementInfo& ri : st.meta.refinement)
168 for (TlsGroup& tls : ri.tls_groups)
169 for (TlsGroup::Selection& sel : tls.selections)
170 update(sel.chain);
171 for (Model& model : st.models)
172 for (Chain& chain : model.chains)
173 update(chain.name);
174}
175
176inline void rename_residues(Structure& st, const std::string& old_name,
177 const std::string& new_name) {
178 auto update = [&](ResidueId& rid) {
179 if (rid.name == old_name)
180 rid.name = new_name;
181 };
182 process_addresses(st, [&](AtomAddress& aa) { update(aa.res_id); });
183 for (ModRes& modres : st.mod_residues)
184 update(modres.res_id);
185 for (Entity& ent : st.entities)
186 for (std::string& mon_ids : ent.full_sequence)
187 for (size_t start = 0;;) {
188 size_t end = mon_ids.find(',', start);
189 if (mon_ids.compare(start, end-start, old_name) == 0) {
190 mon_ids.replace(start, end-start, new_name);
191 if (end != std::string::npos)
192 end = start + new_name.size();
193 }
194 if (end == std::string::npos)
195 break;
196 start = end + 1;
197 }
198 for (Model& model : st.models)
199 for (Chain& chain : model.chains)
200 for (Residue& res : chain.residues)
201 update(res);
202}
203
204
205inline void rename_atom_names(Structure& st, const std::string& res_name,
206 const std::map<std::string, std::string>& old_new) {
207 auto update = [&old_new](std::string& name) {
208 auto it = old_new.find(name);
209 if (it != old_new.end())
210 name = it->second;
211 };
213 if (aa.res_id.name == res_name)
214 update(aa.atom_name);
215 });
216 for (Model& model : st.models)
217 for (Chain& chain : model.chains)
218 for (Residue& res : chain.residues)
219 if (res.name == res_name) {
220 for (Atom& atom : res.atoms)
221 update(atom.name);
222 }
223}
224
225
227 for (size_t i = res.atoms.size(); i-- != 0; ) {
228 Atom& atom = res.atoms[i];
229 float d_fraction = atom.fraction;
230 if (atom.element == El::H && d_fraction > 0) {
231 if (d_fraction >= 1) {
232 atom.element = El::D;
233 if (atom.name[0] == 'H')
234 atom.name[0] = 'D';
235 } else {
236 int alt_offset = atom.altloc;
237 if (alt_offset) {
238 alt_offset -= 'A';
239 // we don't expect 4+ altlocs - ignore such cases
241 continue;
242 }
243 atom.altloc = 'A' + alt_offset;
244 float d_occ = atom.occ * d_fraction;
245 atom.occ *= (1 - d_fraction);
246 auto deut = res.atoms.insert(res.atoms.begin() + i + 1, atom);
247 deut->altloc = 'D' + alt_offset;
248 deut->element = El::D;
249 deut->occ = d_occ;
250 if (deut->name[0] == 'H')
251 deut->name[0] = 'D';
252 }
253 }
254 }
255}
256
258 bool found = false;
259 for (auto d = res.atoms.end(); d-- != res.atoms.begin(); )
260 if (d->element == El::D) {
261 found = true;
262 auto h = res.atoms.begin();
263 for (; h != res.atoms.end(); ++h)
264 if (h->element == El::H && h->pos.approx(d->pos, 1e-9))
265 break;
266 if (h != res.atoms.end()) {
267 h->occ += d->occ;
268 h->fraction = h->occ > 0.f ? d->occ / h->occ : 0.f;
269 if (h->altloc) {
270 bool keep_altloc = false;
271 for (auto i = res.atoms.begin(); i != res.atoms.end(); ++i)
272 if (i != d && i != h && (i->name == h->name || i->name == d->name))
273 keep_altloc = true;
274 if (!keep_altloc)
275 h->altloc = '\0';
276 }
277 res.atoms.erase(d);
278 } else {
279 d->element = El::H;
280 d->fraction = 1;
281 // Atom name is left unchanged. prepare_topology() first calls this
282 // function and then conditionally changes the name (Dxx -> Hxx).
283 }
284 }
285 return found;
286}
287
294 if (st.has_d_fraction == store_fraction)
295 return;
296 st.has_d_fraction = false;
297 for (Model& model : st.models)
298 for (Chain& chain : model.chains)
299 for (Residue& res : chain.residues)
300 if (store_fraction) {
302 st.has_d_fraction = true;
303 } else {
305 }
306}
307
310 if (!st.cell.explicit_matrices || !st.cell.is_crystal())
311 return;
312 Transform orig_frac = st.cell.frac;
313 st.cell.explicit_matrices = false;
314 st.cell.calculate_properties();
315 Transform tr = st.cell.orth.combine(orig_frac);
316 Transform tr_inv = tr.inverse();
317 st.has_origx = true;
318 st.origx = tr_inv.combine(st.origx);
319 for (NcsOp& ncsop : st.ncs)
320 ncsop.tr = tr.combine(ncsop.tr).combine(tr_inv);
322}
323
324} // namespace gemmi
325#endif
Data structures to store macromolecular structure models.
void assign_serial_numbers(Model &model, bool numbered_ter=false)
set atom site serial numbers to 1, 2, ..., optionally leaving gaps for TERs
Definition modify.hpp:97
void remove_anisou(T &obj)
Remove anisotropic ADP.
Definition modify.hpp:65
void remove_alternative_conformations(T &obj)
Remove alternative conformations.
Definition modify.hpp:17
void replace_d_fraction_with_altlocs(Residue &res)
Definition modify.hpp:226
void vector_remove_if(std::vector< T > &v, F &&condition)
Definition util.hpp:267
bool replace_deuterium_with_fraction(Residue &res)
Definition modify.hpp:257
constexpr T clamp(T v, T lo, T hi)
Definition math.hpp:54
void process_addresses(Structure &st, Func func)
Helper function for processing (usually: changing) names and numbers in AtomAddress instances in meta...
Definition modify.hpp:120
void rename_chain(Structure &st, const std::string &old_name, const std::string &new_name)
Definition modify.hpp:158
void rename_residues(Structure &st, const std::string &old_name, const std::string &new_name)
Definition modify.hpp:176
void transform_pos_and_adp(T &obj, const Transform &tr)
apply Transform to both atom's position and ADP
Definition modify.hpp:86
void remove_hydrogens(T &obj)
Remove hydrogens.
Definition modify.hpp:43
void store_deuterium_as_fraction(Structure &st, bool store_fraction)
Hydrogens modelled as H/D mixture (altlocs H and D with the same position and ADP,...
Definition modify.hpp:293
void rename_atom_names(Structure &st, const std::string &res_name, const std::map< std::string, std::string > &old_new)
Definition modify.hpp:205
void standardize_crystal_frame(Structure &st)
Convert coordinates to the standard coordinate system for the unit cell.
Definition modify.hpp:309
void assign_b_iso(T &obj, float b_min, float b_max)
Set isotropic ADP to the range (b_min, b_max).
Definition modify.hpp:56
void process_sequence_ids(Structure &st, Func func)
Takes func(const std::string& chain_name, gemmi::SeqId& seqid).
Definition modify.hpp:146
void ensure_anisou(T &obj)
Set absent ANISOU to value from B_iso.
Definition modify.hpp:74
constexpr double u_to_b()
Definition math.hpp:29
Represents atom site in macromolecular structure (~100 bytes).
Definition model.hpp:120
SMat33< float > aniso
Definition model.hpp:135
char altloc
Definition model.hpp:123
float b_iso
Definition model.hpp:134
Element element
Definition model.hpp:125
float fraction
Definition model.hpp:130
float occ
Definition model.hpp:132
Position pos
Definition model.hpp:131
std::string name
Definition model.hpp:122
std::vector< Residue > residues
Definition model.hpp:486
std::vector< Chain > chains
Definition model.hpp:722
Non-crystallographic symmetry operation (such as in the MTRIXn record)
Definition unitcell.hpp:121
Coordinates in Angstroms - orthogonal (Cartesian) coordinates.
Definition unitcell.hpp:32
std::vector< Atom > atoms
Definition model.hpp:196
bool nonzero() const
Definition math.hpp:292
SMat33< Real > transformed_by(const Mat33 &m) const
Definition math.hpp:338
Vec3 apply(const Vec3 &x) const
Definition math.hpp:402
Transform combine(const Transform &b) const
Definition math.hpp:404
Transform inverse() const
Definition math.hpp:397
Utilities. Mostly for working with strings and vectors.