Ticket #1024: rota.cpp

File rota.cpp, 7.7 KB (added by Tristan Croll, 8 years ago)
Line 
1#define PYINSTANCE_EXPORT
2
3#include "rota.h"
4#include <sstream> //DELETEME
5#include <pyinstance/PythonInstance.instantiate.h>
6
7template class pyinstance::PythonInstance<isolde::Rotamer>;
8template class pyinstance::PythonInstance<isolde::Rota_Mgr>;
9
10namespace isolde
11{
12
13/**********************************************************
14 *
15 * Rotamer
16 *
17 **********************************************************/
18
19Rotamer::Rotamer(Residue *res, Rota_Mgr *mgr): _residue(res), _mgr(mgr)
20{
21 auto rname = res->name();
22 _def = mgr->get_rotamer_def(rname);
23 auto n_chi = _def->n_chi;
24 auto dmgr = mgr->dihedral_mgr();
25 static const std::string basename("chi");
26 for (size_t i=1; i<=n_chi; ++i) {
27 //~ std::string chi_name = basename+std::to_string(i);
28 auto d = dmgr->get_dihedral(res, basename+std::to_string(i), true);
29 if (d==nullptr) {
30 std::cerr << "Missing dihedral " << basename + std::to_string(i) << + " for residue " << res->name() <<std::endl; //DELETEME
31 throw std::out_of_range("Rotamer is missing a dihedral!");
32 }
33 _chi_dihedrals.push_back(d);
34 }
35}
36
37void Rotamer::angles(std::vector<double> &a) const
38{
39 angles(a.data());
40}
41
42std::vector<double> Rotamer::angles() const
43{
44 std::vector<double> _angles(_def->n_chi);
45 angles(_angles);
46 return _angles;
47}
48
49void Rotamer::angles(double *a) const
50{
51 for (size_t i=0; i<n_chi(); ++i) {
52 auto aa = _chi_dihedrals[i]->angle();
53 *a++ = aa;
54 }
55 if (is_symmetric()) {
56 a--;
57 if (*a < 0) {
58 *a += M_PI;
59 }
60 }
61
62}
63
64float32_t Rotamer::score() const
65{
66 auto interpolator = _mgr->get_interpolator(_residue->name());
67 std::vector<double> cur_angles(_def->n_chi);
68 angles(cur_angles);
69 return interpolator->interpolate(cur_angles.data());
70}
71
72/************************************************************
73 *
74 * Rota_Mgr
75 *
76 ************************************************************/
77
78Rota_Mgr::~Rota_Mgr()
79{
80 auto du = DestructionUser(this);
81 for (auto &it: _residue_to_rotamer)
82 delete it.second;
83}
84
85void Rota_Mgr::add_rotamer_def(const std::string &resname, size_t n_chi, bool symmetric)
86{
87 if (_resname_to_rota_def.find(resname) == _resname_to_rota_def.end()) {
88 Rota_Def rdef(n_chi, symmetric);
89 _resname_to_rota_def[resname] = rdef;
90 } else {
91 throw std::runtime_error("Rotamer definition alread exists!");
92 }
93}
94
95void Rota_Mgr::set_colors(uint8_t *max, uint8_t *mid, uint8_t *min)
96{
97 colors::color thecolors[3];
98 for (size_t i=0; i<4; ++i)
99 {
100 thecolors[0][i] = ((double) *min++) / 255.0;
101 thecolors[1][i] = ((double) *mid++) / 255.0;
102 thecolors[2][i] = ((double) *max++) / 255.0;
103 }
104 auto cuts = get_cutoffs();
105 double these_cutoffs[3];
106 these_cutoffs[0] = cuts->log_outlier;
107 these_cutoffs[1] = cuts->log_allowed;
108 these_cutoffs[2] = 0;
109 _colors = colors::colormap(these_cutoffs, thecolors, 3);
110}
111
112Rota_Def* Rota_Mgr::get_rotamer_def(const std::string &resname)
113{
114 return &(_resname_to_rota_def.at(resname));
115}
116
117Rota_Def* Rota_Mgr::get_rotamer_def(const ResName &resname)
118{
119 return &(_resname_to_rota_def.at(std::string(resname)));
120}
121
122void Rota_Mgr::add_interpolator(const std::string &resname, const size_t &dim,
123 uint32_t *n, double *min, double *max, double *data)
124{
125 _interpolators[resname] = RegularGridInterpolator<double>(dim, n, min, max, data);
126}
127
128Rotamer* Rota_Mgr::new_rotamer(Residue* residue)
129{
130 try {
131 auto r = new Rotamer(residue, this);
132 _residue_to_rotamer[residue] = r;
133 return r;
134 } catch (...) {
135 return nullptr;
136 }
137}
138
139//! Fetch the rotamer for the current residue
140/*!
141 * If the desired rotamer is not found, an attempt will be made to
142 * create it. NOTE: if the attempt fails, nullptr will be returned.
143 */
144Rotamer* Rota_Mgr::get_rotamer(Residue* residue)
145{
146 auto iter = _residue_to_rotamer.find(residue);
147 if (iter != _residue_to_rotamer.end()) {
148 return iter->second;
149 } else {
150 return new_rotamer(residue);
151 }
152
153
154 //~ try {
155 //~ return _residue_to_rotamer.at(residue);
156 //~ } catch (std::out_of_range) {
157 //~ return new_rotamer(residue);
158 //~ }
159}
160
161//! Fast validation of pre-defined rotamers
162void Rota_Mgr::validate(Rotamer** rotamers, size_t n, double* scores)
163{
164 std::map<ResName, std::vector<size_t>> case_indices;
165 for (size_t i=0; i<n; ++i) {
166 case_indices[rotamers[i]->residue()->name()].push_back(i);
167 }
168 for (auto &it: case_indices) {
169 std::string name = std::string(it.first);
170 auto &indices = it.second;
171 size_t n_chi = get_rotamer_def(name)->n_chi;
172 size_t n_rot = indices.size();
173 size_t n_angles = n_rot*n_chi;
174 std::vector<double> chi_angles(n_angles);
175 for (size_t i=0; i<n_rot; i++) {
176 rotamers[indices[i]]->angles(chi_angles.data()+i*n_chi);
177 }
178 auto &interpolator = _interpolators.at(name);
179 std::vector<double> cur_scores(n_rot);
180 interpolator.interpolate(chi_angles.data(), n_rot, cur_scores.data());
181 for (size_t i=0; i<n_rot; ++i) {
182 scores[indices[i]] = cur_scores[i];
183 }
184 }
185}
186
187//! Slower, but more robust validation that allows non-rotameric residues.
188/*! Residues for which no valid rotamer is available will get a score of -1.
189 */
190void Rota_Mgr::validate(Residue** residues, size_t n, double* scores)
191{
192 for (size_t i=0; i<n; ++i) {
193 auto res = residues[i];
194 auto rot = get_rotamer(res);
195 if (rot == nullptr) {
196 scores[i] = -1.0;
197 continue;
198 }
199 auto &interpolator = _interpolators.at(std::string(res->name()));
200 scores[i] = interpolator.interpolate((rot->angles()));
201 }
202}
203
204/**********TESTING***********/
205void Rota_Mgr::_validate_from_thread(Rotamer **rotamers, size_t n, double* scores)
206{
207 _thread_running = true;
208 _thread_done = false;
209 validate(rotamers, n, scores);
210 _thread_done = true;
211}
212void Rota_Mgr::validate_threaded(Rotamer **rotamers, size_t n, double* scores)
213{
214 _validation_thread = std::thread(&Rota_Mgr::_validate_from_thread, this, rotamers, n, scores);
215}
216/******END TESTING***********/
217
218
219void Rota_Mgr::color_by_score(double *score, size_t n, uint8_t *out)
220{
221 colors::color this_color;
222 auto cmap = get_colors();
223 for (size_t i=0; i<n; ++i) {
224 cmap->interpolate(log(*score++), this_color);
225 for(size_t j=0; j<4; ++j) {
226 *out++ = (uint8_t)(this_color[j]*255.0);
227 }
228 }
229}
230
231int32_t Rota_Mgr::bin_score(const double &score)
232{
233 if (score >= _cutoffs.allowed)
234 return FAVORED;
235 if (score < _cutoffs.outlier) {
236 if (score>0)
237 return OUTLIER;
238 return BIN_NA;
239 }
240 return ALLOWED;
241} //bin_score
242
243
244void Rota_Mgr::destructors_done(const std::set<void*>& destroyed)
245{
246 auto db = DestructionBatcher(this);
247 std::set<Rotamer*> to_delete;
248 bool del;
249 for (auto it=_residue_to_rotamer.begin(); it!=_residue_to_rotamer.end();) {
250 auto rot = it->second;
251 del = false;
252 // If a residue is deleted then any associated dihedrals will be
253 // deleted by the Dihedral_Mgr, so we only need to worry about
254 // checking for deleted dihedrals and rotamers.
255 if (destroyed.find(static_cast<void *>(rot)) != destroyed.end()) {
256 del=true;
257 } else {
258 for (auto d: rot->dihedrals()) {
259 if (destroyed.find(static_cast<void *>(d)) != destroyed.end()) {
260 del = true;
261 break;
262 }
263 }
264 }
265 if (del) {
266 to_delete.insert(rot);
267 it = _residue_to_rotamer.erase(it);
268 } else {
269 ++it;
270 }
271 }
272 for (auto r: to_delete)
273 delete r;
274}
275
276
277
278} //namespace isolde