Меняю типы данных. Авось поможет
[alexxy/gromacs-dssp.git] / src / dssptools.cpp
1 /*
2 * This file is part of the GROMACS molecular simulation package.
3 *
4 * Copyright (c) 2021, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
8 *
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
13 *
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23 *
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
31 *
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
34 */
35 /*! \internal \file
36 * \brief
37 * Implements gmx::analysismodules::Trajectory.
38 *
39 * \author Sergey Gorelov <Infinity2573@gmail.com>
40 * \author Anatoly Titov <titov_ai@pnpi.nrcki.ru>
41 * \author Alexey Shvetsov <alexxyum@gmail.com>
42 * \ingroup module_trajectoryanalysis
43 */
44
45 #include "dssptools.h"
46
47 #include <algorithm>
48 #include "gromacs/math/units.h"
49
50 #include "gromacs/pbcutil/pbc.h"
51 #include <gromacs/trajectoryanalysis.h>
52 #include "gromacs/trajectoryanalysis/topologyinformation.h"
53 #include <set>
54 #include <fstream>
55 #include <mutex>
56 #include <iostream>
57
58 namespace gmx
59 {
60
61 namespace analysismodules
62 {
63
64 //void ResInfo::setIndex(backboneAtomTypes atomTypeName, std::size_t atomIndex)
65 //{
66 //   _ResInfo.at(static_cast<std::size_t>(atomTypeName)) = atomIndex;
67 //}
68
69 //std::size_t ResInfo::getIndex(backboneAtomTypes atomTypeName) const
70 //{
71 //   return _ResInfo[static_cast<std::size_t>(atomTypeName)];
72 //}
73
74 std::size_t ResInfo::getIndex(backboneAtomTypes atomTypeName) const{
75     return _backboneIndices[static_cast<std::size_t>(atomTypeName)];
76 }
77
78 secondaryStructures::secondaryStructures(){
79 }
80 void secondaryStructures::initiateSearch(const std::vector<ResInfo> &ResInfoMatrix, const bool PiHelicesPreferencez, const int _pp_stretch){
81     SecondaryStructuresStatusMap.resize(0);
82     SecondaryStructuresStringLine.resize(0);
83     std::vector<std::size_t> temp; temp.resize(0),
84     PiHelixPreference = PiHelicesPreferencez;
85     ResInfoMap = &ResInfoMatrix;
86     SecondaryStructuresStatusMap.resize(ResInfoMatrix.size());
87     SecondaryStructuresStringLine.resize(ResInfoMatrix.size(), '~');
88 }
89
90 void secondaryStructures::secondaryStructuresData::setStatus(const secondaryStructureTypes secondaryStructureTypeName, bool status){
91     SecondaryStructuresStatusArray[static_cast<std::size_t>(secondaryStructureTypeName)] = status;
92     if (status){
93         SecondaryStructuresStatus = secondaryStructureTypeName;
94     }
95     else{
96         SecondaryStructuresStatus = secondaryStructureTypes::Loop;
97     }
98 }
99
100 void secondaryStructures::secondaryStructuresData::setStatus(const HelixPositions helixPosition, const turnsTypes turn){
101     TurnsStatusArray[static_cast<std::size_t>(turn)] = helixPosition;
102 }
103
104 bool secondaryStructures::secondaryStructuresData::getStatus(const secondaryStructureTypes secondaryStructureTypeName) const{
105     return SecondaryStructuresStatusArray[static_cast<std::size_t>(secondaryStructureTypeName)];
106 }
107
108 bool secondaryStructures::secondaryStructuresData::isBreakPartnerWith(const secondaryStructuresData *partner) const{
109     return breakPartners[0] == partner || breakPartners[1] == partner;
110 }
111
112 HelixPositions secondaryStructures::secondaryStructuresData::getStatus(const turnsTypes turn) const{
113     return TurnsStatusArray[static_cast<std::size_t>(turn)];
114 }
115
116 secondaryStructureTypes secondaryStructures::secondaryStructuresData::getStatus() const{
117     return  SecondaryStructuresStatus;
118 }
119
120 void secondaryStructures::secondaryStructuresData::setBreak(secondaryStructuresData *breakPartner){
121     if (breakPartners[0] == nullptr){
122         breakPartners[0] = breakPartner;
123     }
124     else{
125         breakPartners[1] = breakPartner;
126     }
127     setStatus(secondaryStructureTypes::Break);
128 }
129
130 void secondaryStructures::secondaryStructuresData::setBridge(secondaryStructuresData *bridgePartner, std::size_t bridgePartnerIndex, bridgeTypes bridgeType){
131     if(bridgeType == bridgeTypes::ParallelBridge){
132         bridgePartners[0] = bridgePartner;
133         bridgePartnersIndexes[0] = bridgePartnerIndex;
134     }
135     else if (bridgeType == bridgeTypes::AntiParallelBridge){
136         bridgePartners[1] = bridgePartner;
137         bridgePartnersIndexes[1] = bridgePartnerIndex;
138     }
139 }
140
141 bool secondaryStructures::secondaryStructuresData::hasBridges() const{
142     return bridgePartners[0] || bridgePartners[1];
143
144 }
145
146 bool secondaryStructures::secondaryStructuresData::hasBridges(bridgeTypes bridgeType) const{
147     if(bridgeType == bridgeTypes::ParallelBridge){
148         return bridgePartners[0] != nullptr;
149     }
150     else if (bridgeType == bridgeTypes::AntiParallelBridge){
151         return bridgePartners[1] != nullptr;
152     }
153
154     return false;
155
156 }
157
158 bool secondaryStructures::secondaryStructuresData::isBridgePartnerWith(secondaryStructuresData *bridgePartner, bridgeTypes bridgeType) const{
159     if(bridgeType == bridgeTypes::ParallelBridge){
160         return bridgePartners[0] == bridgePartner;
161     }
162     else if (bridgeType == bridgeTypes::AntiParallelBridge){
163         return bridgePartners[1] == bridgePartner;
164     }
165     return false;
166 }
167
168 std::size_t secondaryStructures::secondaryStructuresData::getBridgePartnerIndex(bridgeTypes bridgeType) const{
169     if (bridgeType == bridgeTypes::ParallelBridge){
170         return bridgePartnersIndexes[0];
171     }
172     return bridgePartnersIndexes[1];
173 }
174
175 secondaryStructures::secondaryStructuresData secondaryStructures::secondaryStructuresData::getBridgePartner(bridgeTypes bridgeType) const{
176     if(bridgeType == bridgeTypes::ParallelBridge){
177         return *(bridgePartners[0]);
178     }
179     return *(bridgePartners[1]);
180 }
181
182 bool secondaryStructures::hasHBondBetween(std::size_t Donor, std::size_t Acceptor) const{
183 //    if( (*ResInfoMap)[Donor].acceptor[0] == nullptr ||
184 //        (*ResInfoMap)[Donor].acceptor[1] == nullptr ||
185 //        (*ResInfoMap)[Acceptor].info == nullptr ){
186 //        return false;
187 //    }
188 //    else if (!( (*ResInfoMap)[Acceptor].donor[0] == nullptr ||
189 //              (*ResInfoMap)[Acceptor].donor[1] == nullptr ||
190 //              (*ResInfoMap)[Donor].info == nullptr )) {
191 //        std::cout << "Comparing DONOR №" << (*ResInfoMap)[Donor].info->nr << " And ACCEPTOR №" << (*ResInfoMap)[Acceptor].info->nr << ": " << std::endl;
192 //        std::cout << "Donor's acceptors' nr are = " << (*ResInfoMap)[Donor].acceptor[0]->nr << " (chain " << (*ResInfoMap)[Donor].acceptor[0]->chainid << ") , " << (*ResInfoMap)[Donor].acceptor[1]->nr << " (chain " << (*ResInfoMap)[Donor].acceptor[1]->chainid << ")" << std::endl;
193 //        std::cout << "Donor's acceptors' energy are = " << (*ResInfoMap)[Donor].acceptorEnergy[0] << ", " << (*ResInfoMap)[Donor].acceptorEnergy[1] << std::endl;
194 //        std::cout << "Acceptors's donors' nr are = " << (*ResInfoMap)[Acceptor].donor[0]->nr << " (chain " << (*ResInfoMap)[Acceptor].donor[0]->chainid << ") , " << (*ResInfoMap)[Acceptor].donor[1]->nr << " (chain " << (*ResInfoMap)[Acceptor].donor[1]->chainid << ")" << std::endl;
195 //        std::cout << "Acceptors's donors' energy are = " << (*ResInfoMap)[Acceptor].donorEnergy[0] << ", " << (*ResInfoMap)[Acceptor].donorEnergy[1] << std::endl;
196 //        if( ( (*ResInfoMap)[Donor].acceptor[0] == (*ResInfoMap)[Acceptor].info && (*ResInfoMap)[Donor].acceptorEnergy[0] < HBondEnergyCutOff ) ||
197 //                ( (*ResInfoMap)[Donor].acceptor[1] == (*ResInfoMap)[Acceptor].info && (*ResInfoMap)[Donor].acceptorEnergy[1] < HBondEnergyCutOff ) ){
198 //            std::cout << "HBond Exist" << std::endl;
199 //        }
200 //    }
201 //    else {
202 //        std::cout << "Bad hbond check. Reason(s): " ;
203 //        if ( (*ResInfoMap)[Acceptor].donor[0] == nullptr ){
204 //            std::cout << "Acceptor has no donor[0]; ";
205 //        }
206 //        if ( (*ResInfoMap)[Acceptor].donor[1] == nullptr ){
207 //            std::cout << "Acceptor has no donor[1]; ";
208 //        }
209 //        if ( (*ResInfoMap)[Donor].info == nullptr ){
210 //            std::cout << "No info about donor; ";
211 //        }
212 //        std::cout << std::endl;
213 //    }
214
215     return (( (*ResInfoMap)[Donor].acceptor[0] == (*ResInfoMap)[Acceptor].info && (*ResInfoMap)[Donor].acceptorEnergy[0] < HBondEnergyCutOff ) ||
216            ( (*ResInfoMap)[Donor].acceptor[1] == (*ResInfoMap)[Acceptor].info && (*ResInfoMap)[Donor].acceptorEnergy[1] < HBondEnergyCutOff ));
217
218
219 }
220
221 bool secondaryStructures::NoChainBreaksBetween(std::size_t Resi1, std::size_t Resi2) const{
222     std::size_t i{Resi1}, j{Resi2}; // From i to j → i <= j
223     if ( i > j ){
224         std::swap(i, j);
225     }
226
227     for (; i != j; ++i){
228         if ( SecondaryStructuresStatusMap[i].isBreakPartnerWith(&SecondaryStructuresStatusMap[i + 1]) && SecondaryStructuresStatusMap[i + 1].isBreakPartnerWith(&SecondaryStructuresStatusMap[i]) ){
229 //            std::cout << "Patternsearch has detected a CHAINBREAK between " << Resi1 << " and " << Resi2 << std::endl;
230             return false;
231         }
232     }
233     return true;
234 }
235
236 bridgeTypes secondaryStructures::calculateBridge(std::size_t i, std::size_t j) const{
237     if( i < 1 || j < 1 || i + 1 >= ResInfoMap->size() || j + 1 >= ResInfoMap->size() ){ // Protection from idiotz, не обязательно нужен
238         return bridgeTypes::None;
239     }
240
241     ResInfo a{(*ResInfoMap)[i]}, b{(*ResInfoMap)[j]};
242
243     if(NoChainBreaksBetween(i - 1, i + 1) && NoChainBreaksBetween(j - 1, j + 1) && a.prevResi && a.nextResi && b.prevResi && b.nextResi){
244         if((hasHBondBetween(i + 1, j) && hasHBondBetween(j, i - 1)) || (hasHBondBetween(j + 1, i) && hasHBondBetween(i, j - 1)) ){
245             return bridgeTypes::ParallelBridge;
246         }
247         else if((hasHBondBetween(i + 1, j - 1) && hasHBondBetween(j + 1, i - 1)) || (hasHBondBetween(j, i) && hasHBondBetween(i, j)) ){
248             return bridgeTypes::AntiParallelBridge;
249         }
250     }
251     return bridgeTypes::None;
252 }
253
254 void secondaryStructures::analyzeBridgesAndStrandsPatterns(){
255 //  Calculate Bridgez
256     for(std::size_t i {1}; i + 4 < SecondaryStructuresStatusMap.size(); ++i){
257         for(std::size_t j {i + 3}; j + 1 < SecondaryStructuresStatusMap.size(); ++j ){
258             switch(calculateBridge(i, j)){
259             case bridgeTypes::ParallelBridge : {
260                 SecondaryStructuresStatusMap[i].setBridge(&(SecondaryStructuresStatusMap[j]), j, bridgeTypes::ParallelBridge);
261                 SecondaryStructuresStatusMap[i].setStatus(secondaryStructureTypes::Bridge);
262                 SecondaryStructuresStatusMap[j].setBridge(&(SecondaryStructuresStatusMap[i]), i, bridgeTypes::ParallelBridge);
263                 SecondaryStructuresStatusMap[j].setStatus(secondaryStructureTypes::Bridge);
264                 break;
265             }
266             case bridgeTypes::AntiParallelBridge : {
267                 SecondaryStructuresStatusMap[i].setBridge(&(SecondaryStructuresStatusMap[j]), j, bridgeTypes::AntiParallelBridge);
268                 SecondaryStructuresStatusMap[i].setStatus(secondaryStructureTypes::Bridge);
269                 SecondaryStructuresStatusMap[j].setBridge(&(SecondaryStructuresStatusMap[i]), i, bridgeTypes::AntiParallelBridge);
270                 SecondaryStructuresStatusMap[j].setStatus(secondaryStructureTypes::Bridge);
271                 break;
272             }
273             default :
274                 continue;
275             }
276         }
277     }
278 //  Calculate Extended Strandz
279     for(std::size_t i {1}; i + 1 < SecondaryStructuresStatusMap.size(); ++i){
280         bool is_Estrand {false};
281         for(std::size_t j {2}; j != 0; --j){
282             for(const bridgeTypes &bridgeType : {bridgeTypes::ParallelBridge, bridgeTypes::AntiParallelBridge}){
283                 if (SecondaryStructuresStatusMap[i].hasBridges(bridgeType) && SecondaryStructuresStatusMap[i + j].hasBridges(bridgeType) ){
284                     std::size_t i_partner{SecondaryStructuresStatusMap[i].getBridgePartnerIndex(bridgeType)}, j_partner{SecondaryStructuresStatusMap[i + j].getBridgePartnerIndex(bridgeType)}, second_strand{};
285                     if ( abs(i_partner - j_partner) < 6){
286                         if (i_partner < j_partner){
287                             second_strand = i_partner;
288                         }
289                         else{
290                             second_strand = j_partner;
291                         }
292                         for(int k{abs(i_partner - j_partner)}; k >= 0; --k){
293                             if (SecondaryStructuresStatusMap[second_strand + k].getStatus(secondaryStructureTypes::Bridge)){
294                                 SecondaryStructuresStatusMap[second_strand + k].setStatus(secondaryStructureTypes::Bridge, false);
295                             }
296
297                             SecondaryStructuresStatusMap[second_strand + k].setStatus(secondaryStructureTypes::Strand);
298                         }
299                         is_Estrand = true;
300                     }
301                 }
302             }
303             if (is_Estrand){
304                 for(std::size_t k{0}; k <= j; ++k){
305                     if (SecondaryStructuresStatusMap[i + k].getStatus(secondaryStructureTypes::Bridge)){
306                         SecondaryStructuresStatusMap[i + k].setStatus(secondaryStructureTypes::Bridge, false);
307                     }
308                     SecondaryStructuresStatusMap[i + k].setStatus(secondaryStructureTypes::Strand);
309                 }
310                 break;
311             }
312         }
313     }
314
315
316
317
318
319
320
321
322
323
324
325
326 //    for (std::size_t i{ 1 }; i < HBondsMap.front().size() - 1; ++i){
327 //        for (std::size_t j{ 1 }; j < HBondsMap.front().size() - 1; ++j){
328 //            if (std::abs(static_cast<int>(i) - static_cast<int>(j)) > 2){
329 //                if ((HBondsMap[i - 1][j] && HBondsMap[j][i + 1])    ||
330 //                    (HBondsMap[j - 1][i] && HBondsMap[i][j + 1])){
331 //                    Bridge[i].push_back(j);
332 //                }
333 //                if ((HBondsMap[i][j] && HBondsMap[j][i])    ||
334 //                    (HBondsMap[i - 1][j + 1] && HBondsMap[j - 1][i + 1])){
335 //                    AntiBridge[i].push_back(j);
336 //                }
337 //            }
338 //        }
339 //    }
340 //    for (std::size_t i{ 0 }; i < HBondsMap.front().size(); ++i){
341 //        if ((!Bridge[i].empty() || !AntiBridge[i].empty())){
342 //            setStatus(i, secondaryStructureTypes::Bulge);
343 //        }
344 //    }
345 //    for (std::size_t i{ 2 }; i + 2 < HBondsMap.front().size(); ++i){
346 //        for (std::size_t j { i - 2 }; j <= (i + 2); ++j){
347 //            if (j == i){
348 //                continue;
349 //            }
350 //            else {
351 //                for (std::vector<bridgeTypes>::const_iterator bridge {Bridges.begin()}; bridge != Bridges.end(); ++bridge ){
352 //                    if (!getBridge(*bridge)[i].empty() || !getBridge(*bridge)[j].empty()){
353 //                        for (std::size_t i_resi{ 0 }; i_resi < getBridge(*bridge)[i].size(); ++i_resi){
354 //                            for (std::size_t j_resi{ 0 }; j_resi < getBridge(*bridge)[j].size(); ++j_resi){
355 //                                if (abs(static_cast<int>(getBridge(*bridge)[i][i_resi])
356 //                                        - static_cast<int>(getBridge(*bridge)[j][j_resi]))
357 //                                        && (abs(static_cast<int>(getBridge(*bridge)[i][i_resi])
358 //                                        - static_cast<int>(getBridge(*bridge)[j][j_resi]))
359 //                                        < 5)){
360 //                                    if (j < i){
361 //                                        for (std::size_t k{ 0 }; k <= i - j; ++k){
362 //                                            setStatus(i + k, secondaryStructureTypes::Ladder);
363 //                                        }
364 //                                    }
365 //                                    else{
366 //                                        for (std::size_t k{ 0 }; k <= j - i; ++k){
367 //                                            setStatus(i + k, secondaryStructureTypes::Ladder);
368 //                                        }
369 //                                    }
370 //                                }
371 //                            }
372 //                        }
373 //                    }
374 //                }
375 //            }
376 //        }
377 //    }
378 }
379
380 void secondaryStructures::analyzeTurnsAndHelicesPatterns(){
381     for(const turnsTypes &i : { turnsTypes::Turn_4, turnsTypes::Turn_3, turnsTypes::Turn_5 }){
382         std::size_t stride {static_cast<std::size_t>(i) + 3};
383         for(std::size_t j {0}; j + stride < SecondaryStructuresStatusMap.size(); ++j){
384             if (hasHBondBetween(j + stride, j)){
385                             std::cout << "Bond between " << j << " and " << j + stride << " exists" << std::endl;
386             }
387             if ( hasHBondBetween(j + stride, j) && NoChainBreaksBetween(j, j + stride) ){
388 //                std::cout << "Resi " << j << " is Helix_" << stride << " start" << std::endl;
389                 SecondaryStructuresStatusMap[j + stride].setStatus(HelixPositions::End, i);
390
391                 for (std::size_t k {1}; k < stride; ++k){
392                     if( SecondaryStructuresStatusMap[j + k].getStatus(i) == HelixPositions::None ){
393                         SecondaryStructuresStatusMap[j + k].setStatus(HelixPositions::Middle, i);
394 //                        SecondaryStructuresStatusMap[j + k].setStatus(secondaryStructureTypes::Turn);
395                     }
396                 }
397
398                 if( SecondaryStructuresStatusMap[j].getStatus(i) == HelixPositions::End ){
399                     SecondaryStructuresStatusMap[j].setStatus(HelixPositions::Start_AND_End, i);
400                 }
401                 else {
402                     SecondaryStructuresStatusMap[j].setStatus(HelixPositions::Start, i);
403                 }
404             }
405         }
406     }
407
408     for(const turnsTypes &i : { turnsTypes::Turn_4, turnsTypes::Turn_3, turnsTypes::Turn_5 }){
409         std::size_t stride {static_cast<std::size_t>(i) + 3};
410         for(std::size_t j {1}; j + stride < SecondaryStructuresStatusMap.size(); ++j){
411             if ( (SecondaryStructuresStatusMap[j - 1].getStatus(i) == HelixPositions::Start || SecondaryStructuresStatusMap[j - 1].getStatus(i) == HelixPositions::Start_AND_End ) &&
412                  (SecondaryStructuresStatusMap[j].getStatus(i) == HelixPositions::Start || SecondaryStructuresStatusMap[j].getStatus(i) == HelixPositions::Start_AND_End ) ){
413                 bool empty = true;
414                 secondaryStructureTypes Helix;
415                 switch(i){
416                 case turnsTypes::Turn_3:
417                     for (std::size_t k {0}; empty && k < stride; ++k){
418                         empty = SecondaryStructuresStatusMap[j + k].getStatus(secondaryStructureTypes::Loop ) || SecondaryStructuresStatusMap[j + k].getStatus(secondaryStructureTypes::Helix_3);
419                     }
420                     Helix = secondaryStructureTypes::Helix_3;
421                     break;
422                 case turnsTypes::Turn_5:
423                     for (std::size_t k {0}; empty && k < stride; ++k){
424                         empty = SecondaryStructuresStatusMap[j + k].getStatus(secondaryStructureTypes::Loop ) || SecondaryStructuresStatusMap[j + k].getStatus(secondaryStructureTypes::Helix_5) || (PiHelixPreference && SecondaryStructuresStatusMap[j + k].getStatus(secondaryStructureTypes::Helix_4)); //TODO
425                     }
426                     Helix = secondaryStructureTypes::Helix_5;
427                     break;
428                 default:
429                     Helix = secondaryStructureTypes::Helix_4;
430                     break;
431                 }
432                 if ( empty || Helix == secondaryStructureTypes::Helix_4 ){
433                     for(std::size_t k {0}; k < stride; ++k ){
434 //                        std::cout << "Resi " << j << " is Helix_" << static_cast<std::size_t>(Helix) - 5 << std::endl;
435                         SecondaryStructuresStatusMap[j + k].setStatus(Helix);
436                     }
437                 }
438             }
439         }
440     }
441
442     /* Не знаю зач они в дссп так сделали, этож полное говно */
443
444     for(std::size_t i {1}; i + 1 < SecondaryStructuresStatusMap.size(); ++i){
445         if (static_cast<int>(SecondaryStructuresStatusMap[i].getStatus()) <= static_cast<int>(secondaryStructureTypes::Turn)){
446             bool isTurn = false;
447             for(const turnsTypes &j : {turnsTypes::Turn_3, turnsTypes::Turn_4, turnsTypes::Turn_5}){
448                 std::size_t stride {static_cast<std::size_t>(j) + 3};
449                 for(std::size_t k {1}; k < stride and !isTurn; ++k){
450                     isTurn = (i >= k) && (SecondaryStructuresStatusMap[i - k].getStatus(j) == HelixPositions::Start || SecondaryStructuresStatusMap[i - k].getStatus(j) == HelixPositions::Start_AND_End) ;
451                 }
452             }
453             if (isTurn){
454 //                std::cout << "Resi " << i << " is Turn" << std::endl;
455                 SecondaryStructuresStatusMap[i].setStatus(secondaryStructureTypes::Turn);
456             }
457         }
458     }
459
460 }
461
462 std::string secondaryStructures::patternSearch(){
463
464
465     analyzeBridgesAndStrandsPatterns();
466     analyzeTurnsAndHelicesPatterns();
467
468 //    for(std::size_t i {0}; i < ResInfoMap->size(); ++i){
469 //        std::cout << (*ResInfoMap)[i].info->nr << " " << *((*ResInfoMap)[i].info->name) << std::endl;
470 //    }
471
472     std::cout.precision(5);
473     for(std::size_t i{0}; i < ResInfoMap->size(); ++i, std::cout << std::endl << std::endl){
474         std::cout << (*ResInfoMap)[i].info->nr << " " << *((*ResInfoMap)[i].info->name) ;
475         if ( (*ResInfoMap)[i].donor[0] != nullptr ){
476             std::cout << " has donor[0] = " << (*ResInfoMap)[i].donor[0]->nr << " " << *((*ResInfoMap)[i].donor[0]->name) << " with E = " << (*ResInfoMap)[i].donorEnergy[0] << " and" ;
477         }
478         else {
479             std::cout << " has no donor[0] and" ;
480         }
481         if ( (*ResInfoMap)[i].acceptor[0] != nullptr ){
482             std::cout << " has acceptor[0] = " << (*ResInfoMap)[i].acceptor[0]->nr << " " << *((*ResInfoMap)[i].acceptor[0]->name) << " with E = " << (*ResInfoMap)[i].acceptorEnergy[0] ;
483         }
484         else {
485             std::cout << " has no acceptor[0]" ;
486         }
487         std::cout << std::endl << "Also, " << (*ResInfoMap)[i].info->nr << " " << *((*ResInfoMap)[i].info->name);
488         if ( (*ResInfoMap)[i].donor[1] != nullptr ){
489             std::cout << " has donor[1] = " << (*ResInfoMap)[i].donor[1]->nr << " " << *((*ResInfoMap)[i].donor[1]->name) << " with E = " << (*ResInfoMap)[i].donorEnergy[1] << " and" ;
490         }
491         else {
492             std::cout << " has no donor[1] and" ;
493         }
494         if ( (*ResInfoMap)[i].acceptor[1] != nullptr ){
495             std::cout << " has acceptor[1] = " << (*ResInfoMap)[i].acceptor[1]->nr << " " << *((*ResInfoMap)[i].acceptor[1]->name) << " with E = " << (*ResInfoMap)[i].acceptorEnergy[1] ;
496         }
497         else {
498             std::cout << " has no acceptor[1]" ;
499         }
500     }
501
502     /*Write Data*/
503
504     for(std::size_t i {static_cast<std::size_t>(secondaryStructureTypes::Bend)}; i != static_cast<std::size_t>(secondaryStructureTypes::Count); ++i){
505         for(std::size_t j {0}; j < SecondaryStructuresStatusMap.size(); ++j){
506             if (SecondaryStructuresStatusMap[j].getStatus(static_cast<secondaryStructureTypes>(i))){
507                 SecondaryStructuresStringLine[j] = secondaryStructureTypeNames[i] ;
508             }
509         }
510     }
511
512     /*Add breaks*/
513
514     if(SecondaryStructuresStatusMap.size() > 1){
515         for(std::size_t i {0}, linefactor{1}; i + 1 < SecondaryStructuresStatusMap.size(); ++i){
516             if( SecondaryStructuresStatusMap[i].getStatus(secondaryStructureTypes::Break) && SecondaryStructuresStatusMap[i + 1].getStatus(secondaryStructureTypes::Break) ){
517                 if(SecondaryStructuresStatusMap[i].isBreakPartnerWith(&SecondaryStructuresStatusMap[i + 1]) && SecondaryStructuresStatusMap[i + 1].isBreakPartnerWith(&SecondaryStructuresStatusMap[i]) ){
518                     SecondaryStructuresStringLine.insert(SecondaryStructuresStringLine.begin() + i + linefactor, secondaryStructureTypeNames[secondaryStructureTypes::Break]);
519                     ++linefactor;
520                 }
521             }
522         }
523     }
524     return SecondaryStructuresStringLine;
525 }
526
527 secondaryStructures::~secondaryStructures(){
528     SecondaryStructuresStatusMap.resize(0);
529     SecondaryStructuresStringLine.resize(0);
530 }
531
532 DsspTool::DsspStorage::DsspStorage(){
533     storaged_data.resize(0);
534 }
535
536 void DsspTool::DsspStorage::clearAll(){
537     storaged_data.resize(0);
538 }
539
540 std::mutex DsspTool::DsspStorage::mx;
541
542 void DsspTool::DsspStorage::storageData(int frnr, std::string data){
543     std::lock_guard<std::mutex> guardian(mx);
544     std::pair<int, std::string> datapair(frnr, data);
545     storaged_data.push_back(datapair);
546 }
547
548 std::vector<std::pair<int, std::string>> DsspTool::DsspStorage::returnData(){
549     std::sort(storaged_data.begin(), storaged_data.end());
550     return storaged_data;
551 }
552
553 void alternateNeighborhoodSearch::setCutoff(const real &cutoff_init){
554     cutoff = cutoff_init;
555 }
556
557 void alternateNeighborhoodSearch::FixAtomCoordinates(real &coordinate, const real vector_length){
558     while (coordinate < 0) {
559         coordinate += vector_length;
560     }
561     while (coordinate >= vector_length) {
562         coordinate -= vector_length;
563     }
564 }
565
566 void alternateNeighborhoodSearch::ReCalculatePBC(int &x, const int &x_max) {
567     if (x < 0) {
568         x += x_max;
569     }
570     if (x >= x_max) {
571         x -= x_max;
572     }
573 }
574
575 void alternateNeighborhoodSearch::GetMiniBoxesMap(const t_trxframe &fr, const std::vector<ResInfo> &IndexMap){
576     rvec coordinates, box_vector_length;
577     num_of_miniboxes.resize(0);
578     num_of_miniboxes.resize(3);
579     for (std::size_t i{XX}; i <= ZZ; ++i) {
580         box_vector_length[i] = std::sqrt(
581                     std::pow(fr.box[i][XX], 2) + std::pow(fr.box[i][YY], 2) + std::pow(fr.box[i][ZZ], 2));
582         num_of_miniboxes[i] = std::floor((box_vector_length[i] / cutoff)) + 1;
583     }
584     MiniBoxesMap.resize(0);
585     MiniBoxesReverseMap.resize(0);
586     MiniBoxesMap.resize(num_of_miniboxes[XX], std::vector<std::vector<std::vector<std::size_t> > >(
587                              num_of_miniboxes[YY], std::vector<std::vector<std::size_t> >(
588                              num_of_miniboxes[ZZ], std::vector<std::size_t>(
589                              0))));
590     MiniBoxesReverseMap.resize(IndexMap.size(), std::vector<std::size_t>(3));
591     for (std::vector<ResInfo>::const_iterator i {IndexMap.begin()}; i != IndexMap.end(); ++i) {
592         for (std::size_t j{XX}; j <= ZZ; ++j) {
593             coordinates[j] = fr.x[i->getIndex(backboneAtomTypes::AtomCA)][j];
594             FixAtomCoordinates(coordinates[j], box_vector_length[j]);
595         }
596         MiniBoxesMap[std::floor(coordinates[XX] / cutoff)][std::floor(coordinates[YY] / cutoff)][std::floor(
597                           coordinates[ZZ] / cutoff)].push_back(i - IndexMap.begin());
598         for (std::size_t j{XX}; j <= ZZ; ++j){
599             MiniBoxesReverseMap[i - IndexMap.begin()][j] = std::floor(coordinates[j] / cutoff);
600         }
601     }
602 }
603
604 void alternateNeighborhoodSearch::AltPairSearch(const t_trxframe &fr, const std::vector<ResInfo> &IndexMap){
605     GetMiniBoxesMap(fr, IndexMap);
606     MiniBoxSize[XX] = MiniBoxesMap.size();
607     MiniBoxSize[YY] = MiniBoxesMap.front().size();
608     MiniBoxSize[ZZ] = MiniBoxesMap.front().front().size();
609     PairMap.resize(0);
610     PairMap.resize(IndexMap.size(), std::vector<bool>(IndexMap.size(), false));
611     ResiI = PairMap.begin();
612     ResiJ = ResiI->begin();
613
614     for (std::vector<ResInfo>::const_iterator i = IndexMap.begin(); i != IndexMap.end(); ++i){
615         for (offset[XX] = -1; offset[XX] <= 1; ++offset[XX]) {
616             for (offset[YY] = -1; offset[YY] <= 1; ++offset[YY]) {
617                 for (offset[ZZ] = -1; offset[ZZ] <= 1; ++offset[ZZ]) {
618                     for (std::size_t k{XX}; k <= ZZ; ++k) {
619                         fixBox[k] = MiniBoxesReverseMap[i - IndexMap.begin()][k] + offset[k];
620                         ReCalculatePBC(fixBox[k], MiniBoxSize[k]);
621                     }
622                     for (std::size_t j{0}; j < MiniBoxesMap[fixBox[XX]][fixBox[YY]][fixBox[ZZ]].size(); ++j) {
623                         if ( (i - IndexMap.begin()) != MiniBoxesMap[fixBox[XX]][fixBox[YY]][fixBox[ZZ]][j]){
624                             PairMap[i - IndexMap.begin()][MiniBoxesMap[fixBox[XX]][fixBox[YY]][fixBox[ZZ]][j]] = true;
625                             PairMap[MiniBoxesMap[fixBox[XX]][fixBox[YY]][fixBox[ZZ]][j]][i - IndexMap.begin()] = true;
626                         }
627                     }
628                 }
629             }
630         }
631     }
632 }
633
634 bool alternateNeighborhoodSearch::findNextPair(){
635
636     if(!PairMap.size()){
637         return false;
638     }
639
640     for(; ResiI != PairMap.end(); ++ResiI, ResiJ = ResiI->begin() ){
641         for(; ResiJ != ResiI->end(); ++ResiJ){
642             if(*ResiJ){
643                 resiIpos = ResiI - PairMap.begin();
644                 resiJpos = ResiJ - ResiI->begin();
645                 if ( ResiJ != ResiI->end() ){
646                     ++ResiJ;
647                 }
648                 else if (ResiI != PairMap.end()) {
649                     ++ResiI;
650                     ResiJ = ResiI->begin();
651                 }
652                 else {
653                     return false; // ???
654                 }
655                 return true;
656             }
657         }
658     }
659
660     return false;
661 }
662
663 std::size_t alternateNeighborhoodSearch::getResiI() const {
664     return resiIpos;
665 }
666
667 std::size_t alternateNeighborhoodSearch::getResiJ() const {
668     return resiJpos;
669 }
670
671
672 DsspTool::DsspStorage DsspTool::Storage;
673
674 DsspTool::DsspTool(){
675 }
676
677 void DsspTool::calculateBends(const t_trxframe &fr, const t_pbc *pbc)
678 {
679    const float benddegree{ 70.0 }, maxdist{ 2.5 };
680    float       degree{ 0 }, vdist{ 0 }, vprod{ 0 };
681    gmx::RVec   a{ 0, 0, 0 }, b{ 0, 0, 0 };
682    for (std::size_t i{ 0 }; i + 1 < IndexMap.size(); ++i)
683    {
684        if (CalculateAtomicDistances(static_cast<int>(IndexMap[i].getIndex(backboneAtomTypes::AtomC)),
685                                     static_cast<int>(IndexMap[i + 1].getIndex(backboneAtomTypes::AtomN)),
686                                     fr,
687                                     pbc)
688            > maxdist)
689        {
690            PatternSearch.SecondaryStructuresStatusMap[i].setBreak(&PatternSearch.SecondaryStructuresStatusMap[i + 1]);
691            PatternSearch.SecondaryStructuresStatusMap[i + 1].setBreak(&PatternSearch.SecondaryStructuresStatusMap[i]);
692
693 //           std::cout << "Break between " << i + 1 << " and " << i + 2 << std::endl;
694        }
695    }
696    for (std::size_t i{ 2 }; i + 2 < IndexMap.size() ; ++i)
697    {
698        if (PatternSearch.SecondaryStructuresStatusMap[i - 2].getStatus(secondaryStructureTypes::Break) ||
699            PatternSearch.SecondaryStructuresStatusMap[i - 1].getStatus(secondaryStructureTypes::Break) ||
700            PatternSearch.SecondaryStructuresStatusMap[i].getStatus(secondaryStructureTypes::Break) ||
701            PatternSearch.SecondaryStructuresStatusMap[i + 1].getStatus(secondaryStructureTypes::Break)
702           )
703        {
704            continue;
705        }
706        for (int j{ 0 }; j < 3; ++j)
707        {
708            a[j] = fr.x[IndexMap[i].getIndex(backboneAtomTypes::AtomCA)][j]
709                   - fr.x[IndexMap[i - 2].getIndex(backboneAtomTypes::AtomCA)][j];
710            b[j] = fr.x[IndexMap[i + 2].getIndex(backboneAtomTypes::AtomCA)][j]
711                   - fr.x[IndexMap[i].getIndex(backboneAtomTypes::AtomCA)][j];
712        }
713        vdist = (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
714        vprod = CalculateAtomicDistances(IndexMap[i - 2].getIndex(backboneAtomTypes::AtomCA),
715                                         IndexMap[i].getIndex(backboneAtomTypes::AtomCA),
716                                         fr,
717                                         pbc)
718                * gmx::c_angstrom / gmx::c_nano
719                * CalculateAtomicDistances(IndexMap[i].getIndex(backboneAtomTypes::AtomCA),
720                                           IndexMap[i + 2].getIndex(backboneAtomTypes::AtomCA),
721                                           fr,
722                                           pbc)
723                * gmx::c_angstrom / gmx::c_nano;
724        degree = std::acos(vdist / vprod) * gmx::c_rad2Deg;
725        if (degree > benddegree)
726        {
727            PatternSearch.SecondaryStructuresStatusMap[i].setStatus(secondaryStructureTypes::Bend);
728        }
729    }
730 }
731
732 float DsspTool::CalculateDihedralAngle(const int &A, const int &B, const int &C, const int &D, const t_trxframe &fr, const t_pbc *pbc){
733     float result{360}, u{}, v{};
734     gmx::RVec v12{}, v43{}, z{}, p{}, x{}, y{};
735     pbc_dx(pbc, fr.x[A], fr.x[B], v12.as_vec());
736     pbc_dx(pbc, fr.x[D], fr.x[C], v43.as_vec());
737     pbc_dx(pbc, fr.x[B], fr.x[C], z.as_vec());
738
739     for(std::size_t j {XX}; j <= ZZ; ++j){
740         v12[j] *= gmx::c_nm2A;
741         v43[j] *= gmx::c_nm2A;
742         z[j] *= gmx::c_nm2A;
743     }
744     for(std::size_t i{XX}, j{i + 1}, k{i + 2}; i <= ZZ; ++i, ++j, ++k){
745         if (j > 2){
746             j -= 3;
747         }
748         if (k > 2){
749             k -= 3;
750         }
751         p[i] = (z[j] * v12[k]) - (z[k] * v12[j]);
752         x[i] = (z[j] * v43[k]) - (z[k] * v43[j]);
753
754     }
755     for(std::size_t i{XX}, j{i + 1}, k{i + 2}; i <= ZZ; ++i, ++j, ++k){
756         if (j > 2){
757             j -= 3;
758         }
759         if (k > 2){
760             k -= 3;
761         }
762         y[i] = (z[j] * x[k]) - (z[k] * x[j]);
763     }
764
765 //    std::cout << "v12 = " << v12[0] << ", " << v12[1] << ", " << v12[2] << std::endl;
766 //    std::cout << "v43 = " << v43[0] << ", " << v43[1] << ", " << v43[2] << std::endl;
767 //    std::cout << "z = " << z[0] << ", " << z[1] << ", " << z[2] << std::endl;
768 //    std::cout << "p = " << p[0] << ", " << p[1] << ", " << p[2] << std::endl;
769 //    std::cout << "x = " << x[0] << ", " << x[1] << ", " << x[2] << std::endl;
770 //    std::cout << "y = " << y[0] << ", " << y[1] << ", " << y[2] << std::endl;
771
772     u = (x[XX] * x[XX]) + (x[YY] * x[YY]) + (x[ZZ] * x[ZZ]);
773     v = (y[XX] * y[XX]) + (y[YY] * y[YY]) + (y[ZZ] * y[ZZ]);
774
775 //    std::cout << "u = " << u << std::endl;
776 //    std::cout << "v = " << v << std::endl;
777
778     if (u > 0 and v > 0){
779         u = ((p[XX] * x[XX]) + (p[YY] * x[YY]) + (p[ZZ] * x[ZZ])) / std::sqrt(u);
780         v = ((p[XX] * y[XX]) + (p[YY] * y[YY]) + (p[ZZ] * y[ZZ])) / std::sqrt(v);
781 //        std::cout << "new u = " << u << std::endl;
782 //        std::cout << "new v = " << v << std::endl;
783         if (u != 0 or v != 0){
784             result = std::atan2(v, u) * gmx::c_rad2Deg;
785 //            std::cout << "result = " << result << std::endl;
786         }
787     }
788     return result;
789 }
790
791 void DsspTool::calculateDihedrals(const t_trxframe &fr, const t_pbc *pbc){
792     const float epsilon = 29;
793     const float phi_min = -75 - epsilon; // -104
794     const float phi_max = -75 + epsilon; // -46
795     const float psi_min = 145 - epsilon; // 116
796     const float psi_max = 145 + epsilon; // 176
797     std::vector<float>          phi(IndexMap.size(), 360), psi(IndexMap.size(), 360);
798 //    phi.resize(0);
799 //    psi.resize(0);
800 //    phi.resize(IndexMap.size(), 360);
801 //    psi.resize(IndexMap.size(), 360);
802
803     for (std::size_t i = 1; i + 1 < IndexMap.size(); ++i){ // TODO add index verifictaion (check if those atom indexes exist)
804 //        std::cout << "For resi " << i << " :" << std::endl;
805         phi[i] = CalculateDihedralAngle(static_cast<int>(IndexMap[i - 1].getIndex(backboneAtomTypes::AtomC)),
806                                         static_cast<int>(IndexMap[i].getIndex(backboneAtomTypes::AtomN)),
807                                         static_cast<int>(IndexMap[i].getIndex(backboneAtomTypes::AtomCA)),
808                                         static_cast<int>(IndexMap[i].getIndex(backboneAtomTypes::AtomC)),
809                                         fr,
810                                         pbc);
811         psi[i] = CalculateDihedralAngle(static_cast<int>(IndexMap[i].getIndex(backboneAtomTypes::AtomN)),
812                                         static_cast<int>(IndexMap[i].getIndex(backboneAtomTypes::AtomCA)),
813                                         static_cast<int>(IndexMap[i].getIndex(backboneAtomTypes::AtomC)),
814                                         static_cast<int>(IndexMap[i + 1].getIndex(backboneAtomTypes::AtomN)),
815                                         fr,
816                                         pbc);
817 //        std::cout << "For " << i << " phi = " << phi[i] << ", psi = " << psi[i] << std::endl;
818 //        std::cout << "phi[" << i << "] = " << phi[i] << std::endl;
819 //        std::cout << "psi[" << i << "] = " << psi[i] << std::endl;
820     }
821
822     for (std::size_t i = 1; i + 3 < IndexMap.size(); ++i){
823         switch (initParams.pp_stretch){
824         case 2: {
825             if (phi_min > phi[i] or phi[i] > phi_max or
826                 phi_min > phi[i + 1] or phi[i + 1]> phi_max){
827                 continue;
828             }
829
830             if (psi_min > psi[i] or psi[i] > psi_max or
831                 psi_min > psi[i + 1] or psi[i + 1] > psi_max){
832                 continue;
833             }
834
835             switch (PatternSearch.SecondaryStructuresStatusMap[i].getStatus(turnsTypes::Turn_PP)){
836                 case HelixPositions::None:
837                     PatternSearch.SecondaryStructuresStatusMap[i].setStatus(HelixPositions::Start, turnsTypes::Turn_PP);
838                     break;
839
840                 case HelixPositions::End:
841                     PatternSearch.SecondaryStructuresStatusMap[i].setStatus(HelixPositions::Start_AND_End, turnsTypes::Turn_PP);
842                     break;
843
844                 default:
845                     break;
846             }
847
848             PatternSearch.SecondaryStructuresStatusMap[i + 1].setStatus(HelixPositions::End, turnsTypes::Turn_PP);
849             /* Пропустил проверку того, что заменяемая ак - петля */
850             PatternSearch.SecondaryStructuresStatusMap[i].setStatus(secondaryStructureTypes::Helix_PP);
851             PatternSearch.SecondaryStructuresStatusMap[i + 1].setStatus(secondaryStructureTypes::Helix_PP);
852             break;
853         }
854         case 3:{
855             if (phi_min > phi[i] or phi[i] > phi_max or
856                 phi_min > phi[i + 1] or phi[i + 1]> phi_max or
857                 phi_min > phi[i + 2] or phi[i + 2]> phi_max){
858                 continue;
859             }
860
861             if (psi_min > psi[i] or psi[i] > psi_max or
862                 psi_min > psi[i + 1] or psi[i + 1] > psi_max or
863                 psi_min > psi[i + 2] or psi[i + 2] > psi_max){
864                 continue;
865             }
866
867             switch (PatternSearch.SecondaryStructuresStatusMap[i].getStatus(turnsTypes::Turn_PP)){
868                 case HelixPositions::None:
869                     PatternSearch.SecondaryStructuresStatusMap[i].setStatus(HelixPositions::Start, turnsTypes::Turn_PP);
870                     break;
871
872                 case HelixPositions::End:
873                     PatternSearch.SecondaryStructuresStatusMap[i].setStatus(HelixPositions::Start_AND_End, turnsTypes::Turn_PP);
874                     break;
875
876                 default:
877                     break;
878             }
879
880             PatternSearch.SecondaryStructuresStatusMap[i + 1].setStatus(HelixPositions::Middle, turnsTypes::Turn_PP);
881             PatternSearch.SecondaryStructuresStatusMap[i + 2].setStatus(HelixPositions::End, turnsTypes::Turn_PP);
882             /* Пропустил проверку того, что заменяемая ак - петля */
883             PatternSearch.SecondaryStructuresStatusMap[i].setStatus(secondaryStructureTypes::Helix_PP);
884             PatternSearch.SecondaryStructuresStatusMap[i + 1].setStatus(secondaryStructureTypes::Helix_PP);
885             PatternSearch.SecondaryStructuresStatusMap[i + 2].setStatus(secondaryStructureTypes::Helix_PP);
886
887             break;
888         }
889         default:
890             throw std::runtime_error("Unsupported stretch length");
891         }
892     }
893
894 }
895
896 void DsspTool::calculateHBondEnergy(ResInfo& Donor,
897                        ResInfo& Acceptor,
898                        const t_trxframe&          fr,
899                        const t_pbc*               pbc)
900 {
901    /*
902     * DSSP uses eq from dssp 2.x
903     * kCouplingConstant = 27.888,  //  = 332 * 0.42 * 0.2
904     * E = k * (1/rON + 1/rCH - 1/rOH - 1/rCN) where CO comes from one AA and NH from another
905     * if R is in A
906     * Hbond if E < -0.5
907     *
908     * For the note, H-Bond Donor is N-H («Donor of H») and H-Bond Acceptor is C=O («Acceptor of H»)
909     *
910     */
911
912     if (CalculateAtomicDistances(
913                 Donor.getIndex(backboneAtomTypes::AtomCA), Acceptor.getIndex(backboneAtomTypes::AtomCA), fr, pbc)
914         >= minimalCAdistance)
915     {
916         return void();
917     }
918
919     const double kCouplingConstant = 27.888f;
920     const double minimalAtomDistance{ 0.5f },
921             minEnergy{ -9.9f };
922     double HbondEnergy{ 0 };
923     double distanceNO{ 0 }, distanceHC{ 0 }, distanceHO{ 0 }, distanceNC{ 0 };
924
925 //    std::cout << "For Donor №" << Donor.info->nr - 1 << " and Accpetor №" << Acceptor.info->nr - 1 << std::endl;
926
927     if( !(Donor.is_proline) && (Acceptor.getIndex(backboneAtomTypes::AtomC) && Acceptor.getIndex(backboneAtomTypes::AtomO)
928                                 && Donor.getIndex(backboneAtomTypes::AtomN) && ( Donor.getIndex(backboneAtomTypes::AtomH) || initParams.addHydrogens ) ) ){ // TODO
929         distanceNO = CalculateAtomicDistances(
930                Donor.getIndex(backboneAtomTypes::AtomN), Acceptor.getIndex(backboneAtomTypes::AtomO), fr, pbc);
931         distanceNC = CalculateAtomicDistances(
932                Donor.getIndex(backboneAtomTypes::AtomN), Acceptor.getIndex(backboneAtomTypes::AtomC), fr, pbc);
933         if (initParams.addHydrogens){
934             if (Donor.prevResi != nullptr && Donor.prevResi->getIndex(backboneAtomTypes::AtomC) && Donor.prevResi->getIndex(backboneAtomTypes::AtomO)){
935                rvec atomH{};
936                float prevCODist {CalculateAtomicDistances(Donor.prevResi->getIndex(backboneAtomTypes::AtomC), Donor.prevResi->getIndex(backboneAtomTypes::AtomO), fr, pbc)};
937                for (int i{XX}; i <= ZZ; ++i){
938                    float prevCO = fr.x[Donor.prevResi->getIndex(backboneAtomTypes::AtomC)][i] - fr.x[Donor.prevResi->getIndex(backboneAtomTypes::AtomO)][i];
939                    atomH[i] = fr.x[Donor.getIndex(backboneAtomTypes::AtomH)][i]; // Но на самом деле берутся координаты N
940                    atomH[i] += prevCO / prevCODist;
941                }
942                distanceHO = CalculateAtomicDistances(atomH, Acceptor.getIndex(backboneAtomTypes::AtomO), fr, pbc);
943                distanceHC = CalculateAtomicDistances(atomH, Acceptor.getIndex(backboneAtomTypes::AtomC), fr, pbc);
944             }
945             else{
946                 distanceHO = distanceNO;
947                 distanceHC = distanceNC;
948             }
949        }
950        else {
951            distanceHO = CalculateAtomicDistances(
952                    Donor.getIndex(backboneAtomTypes::AtomH), Acceptor.getIndex(backboneAtomTypes::AtomO), fr, pbc);
953            distanceHC = CalculateAtomicDistances(
954                    Donor.getIndex(backboneAtomTypes::AtomH), Acceptor.getIndex(backboneAtomTypes::AtomC), fr, pbc);
955        }
956        if ((distanceNO < minimalAtomDistance) || (distanceHC < minimalAtomDistance)
957         || (distanceHO < minimalAtomDistance) || (distanceNC < minimalAtomDistance))
958        {
959             HbondEnergy = minEnergy;
960        }
961        else{
962            HbondEnergy =
963                    kCouplingConstant
964                    * ((1 / distanceNO) + (1 / distanceHC) - (1 / distanceHO) - (1 / distanceNC));
965        }
966
967 //       std::cout << "CA-CA distance: " << CalculateAtomicDistances(
968 //                        Donor.getIndex(backboneAtomTypes::AtomCA), Acceptor.getIndex(backboneAtomTypes::AtomCA), fr, pbc) << std::endl;
969 //       std::cout << "N-O distance: " << distanceNO << std::endl;
970 //       std::cout << "N-C distance: " << distanceNC << std::endl;
971 //       std::cout << "H-O distance: " << distanceHO << std::endl;
972 //       std::cout << "H-C distance: " << distanceHC << std::endl;
973
974        HbondEnergy = std::round(HbondEnergy * 1000) / 1000;
975
976        if ( HbondEnergy < minEnergy ){
977             HbondEnergy = minEnergy;
978        }
979
980 //       std::cout << "Calculated energy = " << HbondEnergy << std::endl;
981     }
982 //    else{
983 //        std::cout << "Donor Is Proline" << std::endl;
984 //    }
985
986     if (HbondEnergy < Donor.acceptorEnergy[0]){
987            Donor.acceptor[1] = Donor.acceptor[0];
988            Donor.acceptor[0] = Acceptor.info;
989            Donor.acceptorEnergy[0] = HbondEnergy;
990     }
991     else if (HbondEnergy < Donor.acceptorEnergy[1]){
992            Donor.acceptor[1] = Acceptor.info;
993            Donor.acceptorEnergy[1] = HbondEnergy;
994     }
995
996
997     if (HbondEnergy < Acceptor.donorEnergy[0]){
998            Acceptor.donor[1] = Acceptor.donor[0];
999            Acceptor.donor[0] = Donor.info;
1000            Acceptor.donorEnergy[0] = HbondEnergy;
1001     }
1002     else if (HbondEnergy < Acceptor.donorEnergy[1]){
1003            Acceptor.donor[1] = Donor.info;
1004            Acceptor.donorEnergy[1] = HbondEnergy;
1005     }
1006 }
1007
1008
1009 /* Calculate Distance From B to A */
1010 float DsspTool::CalculateAtomicDistances(const int &A, const int &B, const t_trxframe &fr, const t_pbc *pbc)
1011 {
1012    gmx::RVec r{ 0, 0, 0 };
1013    pbc_dx(pbc, fr.x[A], fr.x[B], r.as_vec());
1014    return r.norm() * gmx::c_nm2A; // НЕ ТРОГАТЬ
1015 }
1016
1017 /* Calculate Distance From B to A, where A is only fake coordinates */
1018 float DsspTool::CalculateAtomicDistances(const rvec &A, const int &B, const t_trxframe &fr, const t_pbc *pbc)
1019 {
1020    gmx::RVec r{ 0, 0, 0 };
1021    pbc_dx(pbc, A, fr.x[B], r.as_vec());
1022    return r.norm() * gmx::c_nm2A; // НЕ ТРОГАТЬ
1023 }
1024
1025 void DsspTool::initAnalysis(/*const TrajectoryAnalysisSettings &settings,*/const TopologyInformation& top, const initParameters &initParamz)
1026 {
1027    initParams = initParamz;
1028    ResInfo _backboneAtoms;
1029    std::size_t                 i{ 0 };
1030    std::string proLINE;
1031    int resicompare{ top.atoms()->atom[static_cast<std::size_t>(*(initParams.sel_.atomIndices().begin()))].resind };
1032    IndexMap.resize(0);
1033    IndexMap.push_back(_backboneAtoms);
1034    IndexMap[i].info = &(top.atoms()->resinfo[resicompare]);
1035    proLINE = *(IndexMap[i].info->name);
1036    if( proLINE.compare("PRO") == 0 ){
1037        IndexMap[i].is_proline = true;
1038    }
1039
1040    for (gmx::ArrayRef<const int>::iterator ai{ initParams.sel_.atomIndices().begin() }; (ai != initParams.sel_.atomIndices().end()); ++ai){
1041        if (resicompare != top.atoms()->atom[static_cast<std::size_t>(*ai)].resind)
1042        {
1043            ++i;
1044            resicompare = top.atoms()->atom[static_cast<std::size_t>(*ai)].resind;
1045            IndexMap.emplace_back(_backboneAtoms);
1046            IndexMap[i].info = &(top.atoms()->resinfo[resicompare]);
1047            proLINE = *(IndexMap[i].info->name);
1048            if( proLINE.compare("PRO") == 0 ){
1049                IndexMap[i].is_proline = true;
1050            }
1051
1052        }
1053        std::string atomname(*(top.atoms()->atomname[static_cast<std::size_t>(*ai)]));
1054        if (atomname == backboneAtomTypeNames[backboneAtomTypes::AtomCA])
1055        {
1056            IndexMap[i]._backboneIndices[static_cast<std::size_t>(backboneAtomTypes::AtomCA)] = *ai;
1057        }
1058        else if (atomname == backboneAtomTypeNames[backboneAtomTypes::AtomC])
1059        {
1060            IndexMap[i]._backboneIndices[static_cast<std::size_t>(backboneAtomTypes::AtomC)] = *ai;
1061        }
1062        else if (atomname == backboneAtomTypeNames[backboneAtomTypes::AtomO])
1063        {
1064            IndexMap[i]._backboneIndices[static_cast<std::size_t>(backboneAtomTypes::AtomO)] = *ai;
1065        }
1066        else if (atomname == backboneAtomTypeNames[backboneAtomTypes::AtomN])
1067        {
1068            IndexMap[i]._backboneIndices[static_cast<std::size_t>(backboneAtomTypes::AtomN)] = *ai;
1069            if (initParamz.addHydrogens == true){
1070                IndexMap[i]._backboneIndices[static_cast<std::size_t>(backboneAtomTypes::AtomH)] = *ai;
1071            }
1072        }
1073        else if (atomname == backboneAtomTypeNames[backboneAtomTypes::AtomH] && initParamz.addHydrogens == false) // Юзать водород в структуре
1074        {
1075            IndexMap[i]._backboneIndices[static_cast<std::size_t>(backboneAtomTypes::AtomH)] = *ai;
1076        }
1077
1078
1079
1080 //       if( atomname == backboneAtomTypeNames[backboneAtomTypes::AtomCA] || atomname == backboneAtomTypeNames[backboneAtomTypes::AtomC] || atomname == backboneAtomTypeNames[backboneAtomTypes::AtomO]
1081 //       || atomname == backboneAtomTypeNames[backboneAtomTypes::AtomN] || atomname == backboneAtomTypeNames[backboneAtomTypes::AtomH]){
1082 //           std::cout << "Atom " << atomname << " №" << *ai << " From Resi " << *(top.atoms()->resinfo[i].name) << " №" << resicompare << std::endl;
1083 //       }
1084    }
1085
1086    for (std::size_t j {1}; j < IndexMap.size(); ++j){
1087        IndexMap[j].prevResi = &(IndexMap[j - 1]);
1088
1089        IndexMap[j - 1].nextResi = &(IndexMap[j]);
1090
1091 //           std::cout << "Resi " << IndexMap[i].info->nr << *(IndexMap[i].info->name) << std::endl;
1092 //           std::cout << "Prev resi is " << IndexMap[i].prevResi->info->nr << *(IndexMap[i].prevResi->info->name) << std::endl;
1093 //           std::cout << "Prev resi's next resi is " << IndexMap[i - 1].nextResi->info->nr << *(IndexMap[i - 1].nextResi->info->name) << std::endl;
1094 //         std::cout << IndexMap[j].prevResi->info->nr;
1095 //         std::cout << *(IndexMap[j].prevResi->info->name) ;
1096 //         std::cout << " have CA = " << IndexMap[j].prevResi->getIndex(backboneAtomTypes::AtomCA) ;
1097 //         std::cout << " C = " << IndexMap[j].prevResi->getIndex(backboneAtomTypes::AtomC);
1098 //         std::cout << " O = " << IndexMap[j].prevResi->getIndex(backboneAtomTypes::AtomO);
1099 //         std::cout << " N = " << IndexMap[j].prevResi->getIndex(backboneAtomTypes::AtomN);
1100 //         std::cout << " H = " << IndexMap[j].prevResi->getIndex(backboneAtomTypes::AtomH) << std::endl;
1101    }
1102
1103    nres = i + 1;
1104 }
1105
1106 void DsspTool::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc)
1107 {
1108
1109     switch(initParams.NBS){
1110     case (NBSearchMethod::Classique): {
1111
1112         // store positions of CA atoms to use them for nbSearch
1113         std::vector<gmx::RVec> positionsCA_;
1114         for (std::size_t i{ 0 }; i < IndexMap.size(); ++i)
1115         {
1116             positionsCA_.emplace_back(fr.x[IndexMap[i].getIndex(backboneAtomTypes::AtomCA)]);
1117         }
1118
1119         AnalysisNeighborhood nb_;
1120         nb_.setCutoff(initParams.cutoff_);
1121         AnalysisNeighborhoodPositions       nbPos_(positionsCA_);
1122         gmx::AnalysisNeighborhoodSearch     start      = nb_.initSearch(pbc, nbPos_);
1123         gmx::AnalysisNeighborhoodPairSearch pairSearch = start.startPairSearch(nbPos_);
1124         gmx::AnalysisNeighborhoodPair       pair;
1125         while (pairSearch.findNextPair(&pair))
1126         {
1127             if(CalculateAtomicDistances(
1128                         IndexMap[pair.refIndex()].getIndex(backboneAtomTypes::AtomCA), IndexMap[pair.testIndex()].getIndex(backboneAtomTypes::AtomCA), fr, pbc)
1129                 < minimalCAdistance){
1130                 calculateHBondEnergy(IndexMap[pair.refIndex()], IndexMap[pair.testIndex()], fr, pbc);
1131                 if (IndexMap[pair.testIndex()].info != IndexMap[pair.refIndex() + 1].info){
1132                     calculateHBondEnergy(IndexMap[pair.testIndex()], IndexMap[pair.refIndex()], fr, pbc);
1133                 }
1134             }
1135         }
1136
1137         break;
1138     }
1139     case (NBSearchMethod::Experimental): { // TODO FIX
1140
1141         alternateNeighborhoodSearch as_;
1142
1143         as_.setCutoff(initParams.cutoff_);
1144
1145         as_.AltPairSearch(fr, IndexMap);
1146
1147         while (as_.findNextPair()){
1148             if(CalculateAtomicDistances(
1149                         IndexMap[as_.getResiI()].getIndex(backboneAtomTypes::AtomCA), IndexMap[as_.getResiJ()].getIndex(backboneAtomTypes::AtomCA), fr, pbc)
1150                 < minimalCAdistance){
1151                 calculateHBondEnergy(IndexMap[as_.getResiI()], IndexMap[as_.getResiJ()], fr, pbc);
1152                 if (IndexMap[as_.getResiJ()].info != IndexMap[as_.getResiI() + 1].info){
1153                     calculateHBondEnergy(IndexMap[as_.getResiJ()], IndexMap[as_.getResiI()], fr, pbc);
1154                 }
1155             }
1156         }
1157
1158         break;
1159     }
1160     default: {
1161
1162         for(std::vector<ResInfo>::iterator Donor {IndexMap.begin()}; Donor != IndexMap.end() ; ++Donor){
1163             for(std::vector<ResInfo>::iterator Acceptor {Donor + 1} ; Acceptor != IndexMap.end() ; ++Acceptor){
1164                 if(CalculateAtomicDistances(
1165                             Donor->getIndex(backboneAtomTypes::AtomCA), Acceptor->getIndex(backboneAtomTypes::AtomCA), fr, pbc)
1166                     < minimalCAdistance){
1167                     calculateHBondEnergy(*Donor, *Acceptor, fr, pbc);
1168                     if (Acceptor != Donor + 1){
1169                         calculateHBondEnergy(*Acceptor, *Donor, fr, pbc);
1170                     }
1171                 }
1172             }
1173         }
1174         break;
1175     }
1176     }
1177
1178
1179 //    for(std::size_t i {0}; i < IndexMap.size(); ++i){
1180 //        std::cout << IndexMap[i].info->nr << " " << *(IndexMap[i].info->name) << std::endl;
1181 //    }
1182
1183    PatternSearch.initiateSearch(IndexMap, initParams.PPHelices, initParams.pp_stretch);
1184    calculateBends(fr, pbc);
1185    calculateDihedrals(fr, pbc);
1186    Storage.storageData(frnr, PatternSearch.patternSearch());
1187
1188 }
1189
1190 std::vector<std::pair<int, std::string>> DsspTool::getData(){
1191     return Storage.returnData();
1192 }
1193
1194 } // namespace analysismodules
1195
1196 } // namespace gmx