- minor updates
authorAnatoly <Titov_AI@pnpi.nrcki.ru>
Fri, 31 Jan 2020 08:08:48 +0000 (11:08 +0300)
committerAnatoly <Titov_AI@pnpi.nrcki.ru>
Fri, 31 Jan 2020 08:08:48 +0000 (11:08 +0300)
removed unnecessary if clause
- added explanatory comments into code

src/domains.cpp

index 58321c818179fed78eeeeff3547281aa406d1529..7244ba0d2d2b0fc28ed3b0c8f7a5bfee20975e08 100644 (file)
@@ -61,12 +61,14 @@ using namespace gmx;
 
 using gmx::RVec;
 
+// вычисление модуля расстояния между двумя точками, с учётом геометрического преобразования
 double F (double aix, double aiy, double aiz, double bix_plus_x, double biy_plus_y, double biz_plus_z, double A, double B, double C) {
     return  sqrt(   pow(aix + biy_plus_y * (cos(A) * sin(C) - cos(C) * sin(A) * sin(B)) - biz_plus_z * (sin(A) * sin(C) + cos(A) * cos(C) * sin(B)) - cos(B) * cos(C) * bix_plus_x, 2) +
                     pow(aiy - biy_plus_y * (cos(A) * cos(C) + sin(A) * sin(B) * sin(C)) + biz_plus_z * (cos(C) * sin(A) - cos(A) * sin(B) * sin(C)) - cos(B) * sin(C) * bix_plus_x, 2) +
                     pow(aiz + sin(B) * bix_plus_x - cos(A) * cos(B) * biz_plus_z - cos(B) * sin(A) * biy_plus_y, 2)  );
 }
 
+// вычисление функции F и её частных производных
 void searchF0xyzabc (double &F, double &Fx, double &Fy, double &Fz, double &Fa, double &Fb, double &Fc, double aix, double aiy, double aiz, double bix_plus_x, double biy_plus_y, double biz_plus_z, double A, double B, double C) {
     double t01, t02, t03, t04, t05, t06, t07;
     t01 = pow(aix + biy_plus_y * (cos(A) * sin(C) - cos(C) * sin(A) * sin(B)) - biz_plus_z * (sin(A) * sin(C) + cos(A) * cos(C) * sin(B)) - cos(B) * cos(C) * bix_plus_x, 2);
@@ -90,6 +92,7 @@ void searchF0xyzabc (double &F, double &Fx, double &Fy, double &Fz, double &Fa,
             2 * (biz_plus_z * (sin(A) * sin(C) + cos(A) * cos(C) * sin(B)) - biy_plus_y * (cos(A) * sin(C) - cos(C) * sin(A) * sin(B)) + cos(B) * cos(C) * bix_plus_x) * t07) / (2 * t04);
 }
 
+// применения геометрического преобразования: смещение на вектор (x, y, z) и повороты на градусы A, B, C относительно осей (x, y, z)
 void ApplyFit (std::vector< RVec > &b, double x, double y, double z, double A, double B, double C) {
     double t0 = 0, t1 = 0, t2 = 0;
     for (unsigned int i = 0; i < b.size(); i++) {
@@ -102,6 +105,7 @@ void ApplyFit (std::vector< RVec > &b, double x, double y, double z, double A, d
     }
 }
 
+// подсчёт геометрических центров множеств a и b на основе пар pairs
 void CalcMid (std::vector< RVec > a, std::vector< RVec > b, RVec &midA, RVec &midB, std::vector< std::pair< unsigned int, unsigned int > > pairs) {
     midA[0] = 0;
     midA[1] = 0;
@@ -124,12 +128,14 @@ void CalcMid (std::vector< RVec > a, std::vector< RVec > b, RVec &midA, RVec &mi
     midB[2] /= pairs.size();
 }
 
+// функция фитирования фрейма b на фрейм a на основе пар pairs с "точностью" FtCnst
 void MyFitNew (std::vector< RVec > a, std::vector< RVec > &b, std::vector< std::pair< unsigned int, unsigned int > > pairs, double FtCnst) {
     double f1 = 0, f2 = 0, fx = 0, fy = 0, fz = 0, fa = 0, fb = 0, fc = 0, l = 1;
     RVec ma, mb;
     CalcMid(a, b, ma, mb, pairs);
     ma -= mb;
     double x = static_cast< double >(ma[0]), y = static_cast< double >(ma[1]), z = static_cast< double >(ma[2]), A = 0, B = 0, C = 0;
+    // поиск стартового отклонения множеств
     for (unsigned int i = 0; i < pairs.size(); i++) {
         f1 += F(static_cast< double >(a[pairs[i].first][0]), static_cast< double >(a[pairs[i].first][1]), static_cast< double >(a[pairs[i].first][2]),
                 static_cast< double >(b[pairs[i].second][0]) + x, static_cast< double >(b[pairs[i].second][1]) + y, static_cast< double >(b[pairs[i].second][2]) + z, A, B, C);
@@ -140,8 +146,10 @@ void MyFitNew (std::vector< RVec > a, std::vector< RVec > &b, std::vector< std::
     if (f1 == 0) {
         return;
     } else {
+        // поиск оптимального геометрического преобразования методом градиентного спуска
         while (f1 - f2 < 0 || f1 - f2 > FtCnst) {
             f1 = 0; fx = 0; fy = 0; fz = 0; fa = 0; fb = 0; fc = 0; l = 1;
+            // поиск производных и отклонения при заданных параметрах
             for (unsigned int i = 0; i < pairs.size(); i++) {
                 searchF0xyzabc(f1, fx, fy, fz, fa, fb, fc,
                                static_cast< double >(a[pairs[i].first][0]), static_cast< double >(a[pairs[i].first][1]), static_cast< double >(a[pairs[i].first][2]),
@@ -150,6 +158,7 @@ void MyFitNew (std::vector< RVec > a, std::vector< RVec > &b, std::vector< std::
             }
             while (f2 != f1) {
                 f2 = 0;
+                // поиск отклонения при новых параметрах
                 for (unsigned int i = 0; i < pairs.size(); i++) {
                     f2 += F(static_cast< double >(a[pairs[i].first][0]), static_cast< double >(a[pairs[i].first][1]), static_cast< double >(a[pairs[i].first][2]),
                             static_cast< double >(b[pairs[i].second][0]) + (x - l * fx), static_cast< double >(b[pairs[i].second][1]) + (y - l * fy),
@@ -160,10 +169,13 @@ void MyFitNew (std::vector< RVec > a, std::vector< RVec > &b, std::vector< std::
                     fx = 0; fy = 0; fz = 0; fa = 0; fb = 0; fc = 0;
                     break;
                 } else {
-                    l *= 0.50;
+                    // по факту существует минимальное значение переменной типа double
+                    // в случае его достижения дважды останавливаем цикл т.к. упёрлись в предел допустимой точности
+                    // таким образом гарантируем выход из цикла
                     if (l == DBL_MIN) { //DBL_TRUE_MIN
                         break;
                     }
+                    l *= 0.50;
                 }
             }
         }
@@ -174,10 +186,13 @@ void MyFitNew (std::vector< RVec > a, std::vector< RVec > &b, std::vector< std::
 class domainsType {
     public:
 
+        // деструктор класса
         ~domainsType() {}
 
+        // конструктор класса для инициализации
         domainsType() {}
 
+        // конструктор класса для полноценной инициализации данных
         domainsType(std::vector< int > index, const std::vector< RVec > reference,
                     const int windowSize, const int domainMinimumSize,
                     const int domainSearchAlgorythm, const int timeStepBetweenWindowStarts,
@@ -187,6 +202,7 @@ class domainsType {
         }
 
         // set numeric values to "-1" / string value to "" - if you want default settings
+        // функция заполнения необходимыми данными для вычисления структурных доменов
         void setDefaults(std::vector< int > index, const std::vector< RVec > reference,
                         const int windowSize, const int domainMinimumSize,
                         const int domainSearchAlgorythm, const int timeStepBetweenWindows,
@@ -206,7 +222,9 @@ class domainsType {
             domsizes.resize(sliceNum);
         }
 
+        // фукнция обновления данных для выделения структурных доменов
         void update(const std::vector< std::vector< RVec > > frame, const int frameNumber) {
+            // громакс считает с нуля, проверял; инициализируем новое "окно"
             if (frameNumber % ts == 0) {
                 graph.resize(graph.size() + 1);
                 graph.back().resize(structIndex.size() - static_cast< unsigned long >(dms) + 1);
@@ -214,6 +232,7 @@ class domainsType {
                     setGraph(graph.back()[i], ref);
                 }
             }
+            // заполняем структуру данных для структурных доменов
             for (unsigned int i = 0; i < graph.size(); i++) {
                 #pragma omp parallel for
                 for (unsigned long j = 0; j < graph.front().size(); j++) {
@@ -232,9 +251,11 @@ class domainsType {
                 }
                 #pragma omp barrier
             }
+            // считаем число эффективных обновлений
             if (graph.size() > 0) {
                 updateCount++;
             }
+            // в случае, если число обновлений равно размеру окна, выделяем на нём домены
             if (updateCount == window) {
                 getDomains();
                 print(frameNumber);
@@ -242,25 +263,42 @@ class domainsType {
         }
 
     private:
+        // узел матрицы связности: число вхождений в один домен, вектор между элементами в референсной структуре, флаг для проверки
+        // последние два пункта технически можно перевычеслять при каждом обращении, что сократит размер ячейки с 20 байт до 4
+        // но замедлит скорость работы программы, возможно стоит проверить на больших структурах
         struct triple {
             int num;
             RVec radius;
             bool check;
         };
+        // референстная структура
         std::vector< RVec >                                                     ref;                            // must be presented
+        // индекс структуры
         std::vector< int >                                                      structIndex;                    // must be presented
+        // рабочие окна -> рассматриваемые основные последовательности -> матрица соотношений в структуре всё на всё
         std::vector< std::vector< std::vector< std::vector< triple > > > >      graph;
+        // списки доменов
         std::vector< std::vector< unsigned int > >                              domains;
+        // размеры доменов для каждой основной последовательности
         std::vector< std::vector< int > >                                       domsizes;
+        // размер рассматриваемого окна в последовательных фреймах траектории
         int                                                                     window      = 1000;             // selectable
+        // счётчик эффективных последовательных обновлений структуры graph
         int                                                                     updateCount = 0;
+        // минимальный рассматриваемый размер домена - осмысленно брать 4+
         int                                                                     dms         = 4;                // selectable
+        // какой из алгоритмов выделения использовать 0 - максимальный домен / 1 - минимальный домен
         int                                                                     dsa         = 0;                // selectable
+        // константа допустимых тепловых колебаний  относительно центра домена, находящегося в конкретном атоме структуры
         double                                                                  eps         = 0.2;              // selectable
+        // константа допустимой входимости атома в выделяемый домен, призвана сгладить резкую границу константы eps
         double                                                                  dlt         = 0.95;             // selectable
+        // шаг между началами рассматриваемых окон на траектории в фреймах
         int                                                                     ts          = window / 10;      // selectable
+        // название выходного файла для записи доменов, так же происходит создание selectionList для выделенных доменов
         std::string                                                             outPut      = "default.ndx";    // selectable
 
+        // инициализация матриц соотношений в структуре
         void setGraph(std::vector< std::vector< triple > > &smallGraph, const std::vector< RVec > reference) {
             smallGraph.resize(reference.size());
             for (unsigned i = 0; i < reference.size(); i++) {
@@ -273,6 +311,7 @@ class domainsType {
             }
         }
 
+        // "зануление" элементов матриц вошедших в домен
         void deleteDomainFromGraph(std::vector< unsigned int > domain) {
             for (unsigned int i = 0; i < graph.front().size(); i++) {
                 for (unsigned int j = 0; j < domain.size(); j++) {
@@ -284,6 +323,7 @@ class domainsType {
             }
         }
 
+        // подсчёт размеров всех потенциально возможных доменов и проверка на наличие домена для выделения
         bool searchDomainSizes() {
             bool flag = false;
             for (unsigned int i = 0; i < graph.front().size(); i++) {
@@ -305,7 +345,9 @@ class domainsType {
             return flag;
         }
 
+        // функция выделения доменов
         void getDomains() {
+            // проверка элементов матриц на создание на их основе доменов
             for (unsigned int i = 0; i < graph.front().size(); i++) {
                 for (unsigned int j = 0; j < graph.front()[i].size(); j++) {
                     for (unsigned int k = 0; k < graph.front()[i].size(); k++) {
@@ -316,12 +358,16 @@ class domainsType {
                 }
             }
             domains.resize(0);
+            // итеративное выделение доменов одним из двух(пока что) способов
+            // в случае если цикл запустился, то гарантированно имеется домен для выделения
             while (searchDomainSizes()) {
                 unsigned int t1 = 0, t2 = 0;
                 for (unsigned int i = 0; i < domsizes.size(); i++) {
                     for (unsigned int j = 0; j < domsizes[i].size(); j++) {
                         if ((dsa == 0) && (domsizes[i][j] > domsizes[t1][t2])) {
-                            // подумать как понять какой домен лучше при одинаковом размере
+                            // из-за физических ограничений по памяти в общем случае нельзя хранить всю подноготную данных на
+                            // основе которых было полученно "вхождение" атомов в домен, потому мы только знаем, что размер
+                            // совпадает, а сказать который из двух стабильнее нельзя, либо нужно придумать что-то новое
                             t1 = i;
                             t2 = j;
                         }
@@ -331,45 +377,48 @@ class domainsType {
                         }
                     }
                 }
-                if (domsizes[t1][t2] >= dms) {
-                    domains.resize(domains.size() + 1);
-                    for (unsigned int i = 0; i < graph.front()[t1][t2].size(); i++) {
-                        if (graph.front()[t1][t2][i].check) {
-                            domains.back().push_back(i);
-                        }
+                // выделяем найдённый домен
+                domains.resize(domains.size() + 1);
+                for (unsigned int i = 0; i < graph.front()[t1][t2].size(); i++) {
+                    if (graph.front()[t1][t2][i].check) {
+                        domains.back().push_back(i);
                     }
-                    deleteDomainFromGraph(domains.back());
-                } else {
-                    break;
                 }
+                // удаляем его из матриц
+                deleteDomainFromGraph(domains.back());
             }
+            // удаляем рассматриваемое окно из вектора
             graph.erase(graph.begin());
+            // смещаем счётчик обновлений для следующего окна, std::max для случая если окна не пересекаются
             updateCount = std::max(0, window - ts);
         }
 
+        // функция печати ndx и selectionList файлов
         void print(int currentFrame) {
             if (domains.size() == 0) {
                 return;
             }
             FILE    *ndxFile, *slFile;
             ndxFile = std::fopen(outPut.c_str(), "a+");
-            slFile  = std::fopen(("SelectionList-" + outPut.substr(0, outPut.size() - 4)).c_str(), "a+");
+            slFile  = std::fopen(("selectionList-" + outPut.substr(0, outPut.size() - 4)).c_str(), "a+");
             int writeCount;
             for (unsigned int i = 0; i < domains.size(); i++) {
-                    std::fprintf(ndxFile, "[domain-stPos-%06d-num-%03d-dms-%03d-epsi-%04.3f-delta-%04.3f]\n", currentFrame - window, i + 1, dms, eps, dlt);
-                    std::fprintf(slFile, "group %cdomain-stPos-%06d-num-%03d-dms-%03d-epsi-%04.3f-delta-%04.3f%c;\n", '"', currentFrame - window, i + 1, dms, eps, dlt, '"');
-                    writeCount = 0;
-                    for (unsigned int j = 0; j < domains[i].size(); j++) {
-                        writeCount++;
-                        if (writeCount > 20) {
-                            writeCount -= 20;
-                            std::fprintf(ndxFile, "\n");
-                        }
-                        std::fprintf(ndxFile, "%5d ", structIndex[domains[i][j]] + 1);
-                        std::printf("%5d ", structIndex[domains[i][j]] + 1);
+                // domain - стартовая позиция в фреймах - номер домена - минимальный размер домена -
+                // константа тепловых колебаний (отклонения) - константа входимости (отклонения)
+                std::fprintf(ndxFile, "[domain-stPos-%06d-num-%03d-dms-%03d-epsi-%04.3f-delta-%04.3f]\n", currentFrame - window, i + 1, dms, eps, dlt);
+                std::fprintf(slFile, "group %cdomain-stPos-%06d-num-%03d-dms-%03d-epsi-%04.3f-delta-%04.3f%c;\n", '"', currentFrame - window, i + 1, dms, eps, dlt, '"');
+                writeCount = 0;
+                for (unsigned int j = 0; j < domains[i].size(); j++) {
+                    writeCount++;
+                    if (writeCount > 20) {
+                        writeCount -= 20;
+                        std::fprintf(ndxFile, "\n");
                     }
-                    std::fprintf(ndxFile,"\n\n");
-                    std::printf("\n\n");
+                    std::fprintf(ndxFile, "%5d ", structIndex[domains[i][j]] + 1);
+                    std::printf("%5d ", structIndex[domains[i][j]] + 1);
+                }
+                std::fprintf(ndxFile,"\n\n");
+                std::printf("\n\n");
             }
             std::fprintf(ndxFile,"\n");
             std::fclose(ndxFile);
@@ -486,19 +535,25 @@ void
 Domains::initAnalysis(const TrajectoryAnalysisSettings &settings,
                       const TopologyInformation        &top)
 {
+    // считывание индекса
     index.resize(0);
     for (ArrayRef< const int >::iterator ai = selec.atomIndices().begin(); (ai < selec.atomIndices().end()); ai++) {
         index.push_back(*ai);
     }
 
+    // считывание референсной структуры
     reference.resize(0);
     if (top.hasFullTopology()) {
         for (unsigned int i = 0; i < index.size(); i++) {
             reference.push_back(top.x().at(index[i]));
         }
     }
+
+    // вычисление числа основных (от основаб основание) последовательностей
+    // в идеале нужно брать все сочетания, но ограничиваемся последовательными наборами
     bone = static_cast< unsigned int >(index.size() - static_cast< unsigned int >(domain_min_size) + 1);
 
+    // создание пар для фитирования структур
     fitPairs.resize(bone);
     for (unsigned int i = 0; i < bone; i++) {
         fitPairs[i].resize(0);
@@ -509,26 +564,31 @@ Domains::initAnalysis(const TrajectoryAnalysisSettings &settings,
 
     trajectory.resize(index.size());
 
+    // задание необходимых параметров для вычисления доменов
     testSubject.setDefaults(index, reference, window, domain_min_size, DomainSearchingAlgorythm, twStep, bone, epsi, delta, fnNdx_);
 }
 
 void
 Domains::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc, TrajectoryAnalysisModuleData *pdata)
 {
+    // считывания текущего фрейма траектории
     for (unsigned int i = 0; i < index.size(); i++) {
         trajectory[i] = fr.x[index[i]];
     }
 
+    // создание копий фрейма для каждой основной последовательности
     std::vector< std::vector< RVec > > tsTemp;
     tsTemp.resize(0);
     tsTemp.resize(bone, trajectory);
 
-    #pragma omp parallel for ordered schedule(dynamic) shared(fitPairs) firstprivate(reference)
+    // фитирование каждой копии
+    #pragma omp parallel for ordered schedule(dynamic) firstprivate(reference)
     for (unsigned int i = 0; i < bone; i++) {
         MyFitNew(reference, tsTemp[i], fitPairs[i], 0);
     }
     #pragma omp barrier
 
+    // (обновление/потенциальное выделение) доменов
     testSubject.update(tsTemp, frnr);
 }