e6f1007efa4d38b806b30b5a3d720329c0c74799
[alexxy/gromacs-colorvec.git] / src / colorvec.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2013,2014,2015, 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::Freevolume.
38  *
39  * \author Titov Anatoly <Wapuk-cobaka@yandex.ru>
40  * \ingroup module_trajectoryanalysis
41  */
42
43 #include <gromacs/trajectoryanalysis.h>
44 #include <gromacs/trajectoryanalysis/topologyinformation.h>
45 #include <gromacs/selection/nbsearch.h>
46
47 #include <iostream>
48 #include <fstream>
49 //#include <chrono>
50 #include <cfloat>
51 #include <omp.h>
52 #include <vector>
53 #include <cstdio>
54 #include <iomanip>
55
56 // структура углов для одной краски
57 struct colorLocalAngles {
58     gmx::RVec   a1, a2;
59     gmx::RVec   b1, b2;
60     gmx::RVec   n1, n2;
61     double      a12, b12, n12;
62     std::vector< double > betaAngles;
63 };
64
65 // хрен пойми почему, но захотелось рекурсивно сделать | можно сделать и через вайл
66 long long returnBetaEnd(const std::string &currentLine, long long pos) {
67     switch (currentLine[pos]) {
68         case 'B' :
69             returnBetaEnd(currentLine, pos + 1);
70             break;
71         case 'E' :
72             returnBetaEnd(currentLine, pos + 1);
73             break;
74         default :
75             return (pos - 1);
76             break;
77     }
78     return (pos - 1); // формально логически лишняя строчка, но Qt ругается
79 }
80
81 // функция парсинга одной строки
82 void parseBetaListDATLine(const std::string &currentLine, std::vector< std::vector< unsigned int > > &localInputBL) {
83     size_t                      equalCount = 0;
84     std::vector< unsigned int > a;
85     a.resize(0);
86     for (size_t i = 0; i < currentLine.size(); ++i) {
87         if (currentLine[i] == '=') { // подсчитываем число "пустых" символов
88             ++equalCount;
89         } else {
90             long long temp = returnBetaEnd(currentLine, i);
91             if (temp - static_cast< long long >(i) > 3) {
92                 localInputBL.push_back(a);
93                 for (size_t j = i; j <= temp; ++j) {
94                     localInputBL.back().push_back(j - equalCount);
95                 }
96                 i = temp;
97             }
98         }
99     }
100 }
101
102 // функция нахождения бета-листов в структуре по файлу ДССП
103 void betaListDigestion(const std::string &inputFile, std::vector< std::vector< std::vector< unsigned int > > > &inputBL) {
104     inputBL.resize(0);
105     std::ifstream   file(inputFile);
106     std::string     line;
107     getline(file, line); // считываем число в первой строке - кол-во осмысленных элементов в строках - нам не нужно
108     getline(file, line);
109     if (line.size() > 3) {
110         do {
111             inputBL.resize(inputBL.size() + 1);
112             parseBetaListDATLine(line, inputBL.back());
113             line = "";
114             getline(file, line);
115         } while (line.size() > 3);
116     } else {
117         throw "DSSP DAT FILE IS EMPTY";
118     }
119     file.close();
120 }
121
122 // функция выделения индексов для бэталистов
123 inline void aminoacidsIndexation(const std::vector< size_t > &inputIndex, const gmx::TopologyInformation &top, std::vector< std::vector< size_t > > &aminoacidsIndex) {
124     aminoacidsIndex.resize(0);
125     for (size_t i = 0; i < inputIndex.size(); ++i) {
126         aminoacidsIndex.resize(std::max(aminoacidsIndex.size(), static_cast< size_t >(top.atoms()->atom[inputIndex[i]].resind + 1)));
127         aminoacidsIndex[top.atoms()->atom[inputIndex[i]].resind].push_back(inputIndex[i]);
128     }
129 }
130
131 // функция поиска RVec в кадре по имени->индексу
132 gmx::RVec returnRVec(const std::vector< gmx::RVec > &frame, const std::vector< std::pair< std::string, size_t > > &colorsIndex, const std::string &toFind) {
133     for (auto &i : colorsIndex) {
134         if (i.first == toFind) {
135             return frame[i.second];
136         }
137     }
138     throw "WRONG COLOR ATOM NAME TO EVALUATE VECTORS";
139 }
140
141 // функция векторного произведения двух RVec'ов
142 inline void RVecVecMultiply(gmx::RVec &n, const gmx::RVec &a, const gmx::RVec &b) {
143     n[0] = a[1] * b[2] - a[2] * b[1];
144     n[1] = a[2] * b[0] - a[0] * b[2];
145     n[2] = a[0] * b[1] - a[2] * b[0];
146 }
147
148 // поиск угла между двумя RVec'ами
149 inline double RVecAngle(const gmx::RVec &a, const gmx::RVec &b) {
150     return std::acos((a[0] * b[0] + a[1] * b[1] + a[2] * b[2]) / (a.norm() * b.norm()));
151 }
152
153 // вычисление внутренних углов в краске
154 void colorsAnglesEvaluation(const std::vector< gmx::RVec > &frame, const std::vector< std::vector< std::pair< std::string, size_t > > > &colorsIndex,
155                             std::vector< colorLocalAngles > &colorStruct) {
156     colorStruct.resize(colorsIndex.size());
157     #pragma omp parallel for ordered schedule(dynamic)
158     for (size_t i = 0; i < colorsIndex.size(); ++i) {
159         colorStruct[i].betaAngles.resize(0);
160         // "левый" блок
161         colorStruct[i].a1 = returnRVec(frame, colorsIndex[i], "CAF") - returnRVec(frame, colorsIndex[i], "CAJ") + returnRVec(frame, colorsIndex[i], "CAK") - returnRVec(frame, colorsIndex[i], "CAO");
162         colorStruct[i].a1 /= colorStruct[i].a1.norm();
163         colorStruct[i].b1 = returnRVec(frame, colorsIndex[i], "CAO") - returnRVec(frame, colorsIndex[i], "CAJ") + returnRVec(frame, colorsIndex[i], "CAM") - returnRVec(frame, colorsIndex[i], "CAH") + returnRVec(frame, colorsIndex[i], "CAK") - returnRVec(frame, colorsIndex[i], "CAF");
164         colorStruct[i].b1 /= colorStruct[i].b1.norm();
165         RVecVecMultiply(colorStruct[i].n1, colorStruct[i].a1, colorStruct[i].b1);
166         colorStruct[i].n1 /= colorStruct[i].n1.norm();
167         // "правый" блок
168         colorStruct[i].a2 = returnRVec(frame, colorsIndex[i], "CAB") - returnRVec(frame, colorsIndex[i], "CBQ") + returnRVec(frame, colorsIndex[i], "CBP") - returnRVec(frame, colorsIndex[i], "CBL");
169         colorStruct[i].a2 /= colorStruct[i].a2.norm();
170         colorStruct[i].b2 = returnRVec(frame, colorsIndex[i], "CBL") - returnRVec(frame, colorsIndex[i], "CBQ") + returnRVec(frame, colorsIndex[i], "CBN") - returnRVec(frame, colorsIndex[i], "CBS") + returnRVec(frame, colorsIndex[i], "CBP") - returnRVec(frame, colorsIndex[i], "CAB");
171         colorStruct[i].b2 /= colorStruct[i].b2.norm();
172         RVecVecMultiply(colorStruct[i].n2, colorStruct[i].a2, colorStruct[i].b2);
173         colorStruct[i].n2 *= -1; // для "сонаправленности" векторов нормали
174         colorStruct[i].n2 /= colorStruct[i].n2.norm();
175         colorStruct[i].a12 = RVecAngle(colorStruct[i].a1, colorStruct[i].a2);
176         colorStruct[i].b12 = RVecAngle(colorStruct[i].b1, colorStruct[i].b2);
177         colorStruct[i].n12 = RVecAngle(colorStruct[i].n1, colorStruct[i].n2);
178     }
179     #pragma omp barrier
180 }
181
182 // вычисление направляющего вектора в бэта-листе
183 inline void betaListsRVecsEvaluation(const std::vector< gmx::RVec > &frame, const std::vector< std::vector< unsigned int > > &inputBetaLists,
184                                      std::vector< gmx::RVec > &temp, const std::vector< size_t > &inputCA) {
185     temp.resize(0);
186     gmx::RVec tempA;
187     for (const auto &i : inputBetaLists) {
188         tempA = frame[inputCA[i[i.size() - 1]]] + frame[inputCA[i[i.size() - 2]]] - frame[inputCA[i[1]]] - frame[inputCA[i[0]]];
189         tempA /= tempA.norm();
190         temp.push_back(tempA);
191     }
192 }
193
194 // определение близко ли к белку находится краска
195 bool isNearPeptide(const t_trxframe &fr, const t_pbc *pbc, const std::vector< gmx::RVec > &inputFrame,
196                           gmx::AnalysisNeighborhood &nbhood, const std::vector< size_t > &inputIndex,
197                           const std::vector< std::pair< std::string, size_t > > &inputColor) {
198     gmx::AnalysisNeighborhoodSearch     nbsearch = nbhood.initSearch(pbc, gmx::AnalysisNeighborhoodPositions(fr.x, fr.natoms));
199     gmx::AnalysisNeighborhoodPair       pair;
200     for (const auto &i : inputColor) {
201         gmx::AnalysisNeighborhoodPairSearch pairSearch = nbsearch.startPairSearch(inputFrame[i.second].as_vec());
202         std::cout << std::endl << i.first << std::endl;
203         int count1 {0};
204         while (pairSearch.findNextPair(&pair)) {
205             std::cout << " " << ++count1 << std::endl;
206             for (const auto &j : inputIndex) {
207                 if (j % 100 == 0) {
208                     std::cout << " " << j;
209                 }
210                 if (pair.refIndex() == j) {
211                     return true;
212                 }
213             }
214         }
215         std::cout << std::endl << i.first;
216     }
217     return false;
218 }
219
220 // поиск ближайших к краске бэта-листов
221 inline void searchNearBetaLists(const t_trxframe &fr, const t_pbc *pbc, const std::vector< gmx::RVec > &inputFrame,
222                                 gmx::AnalysisNeighborhood &nbhood,
223                                 const std::vector< std::vector< unsigned int > > &inputBLists,
224                                 const std::vector< std::pair< std::string, size_t > > &inputColor,
225                                 std::vector< bool > &outputList, const std::vector< std::vector< size_t > > &inputAminoacids) {
226     outputList.resize(0);
227     outputList.resize(inputBLists.size(), false);
228     gmx::AnalysisNeighborhoodSearch      nbsearch = nbhood.initSearch(pbc, gmx::AnalysisNeighborhoodPositions(fr.x, fr.natoms));
229     gmx::AnalysisNeighborhoodPair        pair;
230     for (const auto &i : inputColor) {
231         while (nbsearch.startPairSearch(inputFrame[i.second].as_vec()).findNextPair(&pair)) {
232             for (size_t j = 0; j < inputBLists.size(); ++j) {
233                 for (size_t k = 0; k < inputBLists[j].size(); ++k) {
234                     for (size_t m = 0; m < inputAminoacids[inputBLists[j][k]].size(); ++m) {
235                         if (pair.testIndex() == inputAminoacids[inputBLists[j][k]][m]) {
236                             outputList[j] = true;
237                         }
238                     }
239                 }
240             }
241         }
242     }
243
244 }
245
246 // определение углов между краской и направляющим вектором бэта-листа
247 inline void computeAnglesColorsVsBeta(const gmx::RVec &inputBetaRVec, colorLocalAngles &colorFormation) {
248     colorFormation.betaAngles.push_back(RVecAngle(inputBetaRVec, colorFormation.a1));
249     colorFormation.betaAngles.push_back(RVecAngle(inputBetaRVec, colorFormation.b1));
250     colorFormation.betaAngles.push_back(RVecAngle(inputBetaRVec, colorFormation.n1));
251     colorFormation.betaAngles.push_back(RVecAngle(inputBetaRVec, colorFormation.a2));
252     colorFormation.betaAngles.push_back(RVecAngle(inputBetaRVec, colorFormation.b2));
253     colorFormation.betaAngles.push_back(RVecAngle(inputBetaRVec, colorFormation.n2));
254 }
255
256 // функция записи в файл значений углов для кадра
257 void anglesFileDump(const int frameNum, const std::string &output, const std::vector< bool > &toPeptide, const std::vector< colorLocalAngles > &colorFormation) {
258     std::ofstream   file(output);
259     int temp = 0;
260     std::vector< double > betaTemp;
261     betaTemp.resize(0);
262     file << "frame =" << std::setw(8) << frameNum << std::endl;
263     for (size_t i = 0; i < colorFormation.size(); ++i) {
264         file << "color #" << std::setw(3) << i;
265         if (toPeptide[i]) {
266             file << std::setw(4) << "yes";
267         } else {
268             file << std::setw(4) << "no";
269         }
270         file << std::setw(7) << std::setprecision(2) << colorFormation[i].a12 << colorFormation[i].b12 << colorFormation[i].n12;
271         temp = colorFormation[i].betaAngles.size() / 6;
272         if (temp == 0) {
273             file << std::setw(4) << 0;
274         } else {
275             betaTemp.resize(6, 0.); // magic number, meh
276             for (size_t j = 0; j < colorFormation[i].betaAngles.size(); ++j) {
277                 betaTemp[j % 6] += colorFormation[i].betaAngles[j];
278             }
279             for (size_t j = 0; j < betaTemp.size(); ++j) {
280                 betaTemp[j] /= temp;
281             }
282             file << std::setw(4) << temp;
283             for (size_t j = 0; j < betaTemp.size(); ++j) {
284                 file << std::setw(7) << std::setprecision(2) << betaTemp[j];
285             }
286             for (size_t j = 0; j < colorFormation[i].betaAngles.size(); ++j) {
287                 file << std::setw(7) << std::setprecision(2) << colorFormation[i].betaAngles[j];
288             }
289         }
290     }
291     file.close();
292 }
293
294 /*! \brief
295  * \ingroup module_trajectoryanalysis
296  */
297 class colorVec : public gmx::TrajectoryAnalysisModule
298 {
299     public:
300
301         colorVec();
302         virtual ~colorVec();
303
304         //! Set the options and setting
305         virtual void initOptions(gmx::IOptionsContainer          *options,
306                                  gmx::TrajectoryAnalysisSettings *settings);
307
308         //! First routine called by the analysis framework
309         // virtual void initAnalysis(const t_trxframe &fr, t_pbc *pbc);
310         virtual void initAnalysis(const gmx::TrajectoryAnalysisSettings &settings,
311                                   const gmx::TopologyInformation        &top);
312
313         //! Call for each frame of the trajectory
314         // virtual void analyzeFrame(const t_trxframe &fr, t_pbc *pbc);
315         virtual void analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
316                                   gmx::TrajectoryAnalysisModuleData *pdata);
317
318         //! Last routine called by the analysis framework
319         // virtual void finishAnalysis(t_pbc *pbc);
320         virtual void finishAnalysis(int nframes);
321
322         //! Routine to write output, that is additional over the built-in
323         virtual void writeOutput();
324
325     private:
326
327         gmx::SelectionList                                              sel_;
328         std::string                                                     fnOut           {"name"};   // selectable
329         std::string                                                     fnBetaListsDat;             // selectable
330         float                                                           effRad          {0.8};      // selectable
331         std::vector< size_t >                                           index;
332         std::vector< size_t >                                           indexCA;
333         std::vector< std::vector< size_t > >                            aminoacidsIndex;
334         std::vector< std::vector< std::pair< std::string, size_t > > >  colorsNames;
335         std::vector< std::vector< std::vector< unsigned int > > >       betaLists;
336         gmx::AnalysisNeighborhood                                       nb_;
337
338         // Copy and assign disallowed by base.
339 };
340
341 colorVec::colorVec(): TrajectoryAnalysisModule()
342 {
343 }
344
345 colorVec::~colorVec()
346 {
347 }
348
349 /*
350  * ndx:
351  * [peptide]
352  * [CA]
353  * [color_{i}]
354  *
355  */
356
357 void
358 colorVec::initOptions(  gmx::IOptionsContainer          *options,
359                         gmx::TrajectoryAnalysisSettings *settings)
360 {
361     static const char *const desc[] = {
362         "[THISMODULE] to be done"
363     };
364     // Add the descriptive text (program help text) to the options
365     settings->setHelpText(desc);
366     // Add option for selection list
367     options->addOption(gmx::SelectionOption("sel")
368                             .storeVector(&sel_)
369                             .required().dynamicMask().multiValue()
370                             .description("select pepride and colors / -sf"));
371     // Add option for input file names
372     options->addOption(gmx::StringOption("dat")
373                             .store(&fnBetaListsDat)
374                             .description("a file to make dynamic beta lists"));
375     // Add option for output file name
376     options->addOption(gmx::StringOption("out")
377                             .store(&fnOut)
378                             .description("Index file for the algorithm output."));
379     // Add option for effRad constant
380     options->addOption(gmx::FloatOption("efRad")
381                             .store(&effRad)
382                             .description("max distance from colors to peptide in nm to consider to be \"near\""));
383     // Control input settings
384     settings->setFlags(gmx::TrajectoryAnalysisSettings::efNoUserPBC);
385     settings->setFlag(gmx::TrajectoryAnalysisSettings::efUseTopX);
386     //settings->setFlag(TrajectoryAnalysisSettings::efRequireTop);
387     settings->setPBC(true);
388 }
389
390 void
391 colorVec::initAnalysis( const gmx::TrajectoryAnalysisSettings   &settings,
392                         const gmx::TopologyInformation          &top)
393 {
394     // считывание индекса
395     index.resize(0);
396     for (gmx::ArrayRef< const int >::iterator ai {sel_.front().atomIndices().begin()}; (ai < sel_.front().atomIndices().end()); ai++) {
397         index.push_back(static_cast< size_t >(*ai));
398     }
399     // считывание индекса
400     indexCA.resize(0);
401     for (gmx::ArrayRef< const int >::iterator ai {sel_[1].atomIndices().begin()}; (ai < sel_[2].atomIndices().end()); ai++) {
402         index.push_back(static_cast< size_t >(*ai));
403     }
404     // считывание красок
405     colorsNames.resize(sel_.size() - 2);
406     for (size_t i = 2; i < sel_.size(); ++i) {
407         for (gmx::ArrayRef< const int >::iterator ai {sel_[i].atomIndices().begin()}; (ai < sel_[i].atomIndices().end()); ai++) {
408             colorsNames[i - 2].push_back(std::make_pair(*(top.atoms()->atomname[*ai]), static_cast< size_t >(*ai)));
409         }
410     }
411     // разбор dat файла для создания бэта листов
412     betaListDigestion(fnBetaListsDat, betaLists);
413     // разбор топологии для индексации бета листов
414     aminoacidsIndexation(index, top, aminoacidsIndex);
415     // задание радиуса рассматриваемых соседей
416     nb_.setCutoff(effRad);
417     /*
418      * формально можно сделать:
419      * найти соотношение между именами для углов и индексными номерами
420      * заполнить std::vector< std::vector< size_t > > nameToIndex;
421      * и в последствии считать:
422      * a1 = frame[nameToIndex[0][1] + ... - ... - ...
423      * b1 a2 b2 по аналогии только для [@<-[1, 2, 3]]
424      *
425      */
426 }
427
428 void
429 colorVec::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc, gmx::TrajectoryAnalysisModuleData *pdata)
430 {
431     std::cout << "\tFrame analisis start ..." << std::endl;
432     std::vector< gmx::RVec > trajectoryFrame;
433     trajectoryFrame.resize(0);
434     // считывания текущего фрейма траектории
435     for (size_t i {0}; i < index.size(); ++i) {
436         trajectoryFrame.push_back(fr.x[index[i]]);
437     }
438     // подсчёт углов в красках
439     std::vector< colorLocalAngles > colorFormation;
440     std::cout << "\t\tColors' angles evaluation." << std::endl;
441     colorsAnglesEvaluation(trajectoryFrame, colorsNames, colorFormation);
442     // рассчёт положения относительно белка
443     /*
444      * формально можно совместить определение близости с белком и определение ближайших бэта-листов
445      * для этого думаю нужно как-то соотнести или сделать соотношение между индексом и бэта-листами (т.е. хранить что бы за О(1) делать)
446      *
447      */
448
449     std::vector< bool >     colorsToPeptide;
450     colorsToPeptide.resize(0);
451     colorsToPeptide.resize(colorsNames.size(), false);
452     std::cout << "\t\tWhich colors are \"near\" the pepride mass." << std::endl;
453     for (size_t i = 0; i < colorsNames.size(); ++i) {
454         colorsToPeptide[i] = isNearPeptide(fr, pbc, trajectoryFrame, nb_, index, colorsNames[i]);
455     }
456     // расчёт угла и среднего угла с ближайшими бета листами
457     std::vector< std::vector< bool > > colorsToBeta;
458     colorsToBeta.resize(0);
459     colorsToBeta.resize(colorsNames.size());
460     std::vector< std::vector< double > > colorsToBetaAngles;
461     colorsToBetaAngles.resize(0);
462     std::vector< gmx::RVec > betaListsRVecs;
463     std::cout << "\t\tBeta-lists' RVecs search." << std::endl;
464     betaListsRVecsEvaluation(trajectoryFrame, betaLists[frnr], betaListsRVecs, indexCA);
465     std::cout << "\t\tSearching nearby beta-lists." << std::endl;
466     for (size_t i = 0; i < colorsToPeptide.size(); ++i) {
467         if (colorsToPeptide[i]) {
468             searchNearBetaLists(fr, pbc, trajectoryFrame, nb_, betaLists[frnr], colorsNames[i], colorsToBeta[i], aminoacidsIndex);
469         }
470     }
471     std::cout << "\t\tComputing angles colors vs betas." << std::endl;
472     for (size_t i = 0; i < colorsToBeta.size(); ++i) {
473         for (size_t j = 0; j < colorsToBeta[i].size(); ++j) {
474             if (colorsToBeta[i][j]) {
475                 computeAnglesColorsVsBeta(betaListsRVecs[j], colorFormation[i]);
476             }
477         }
478     }
479     // вывод в файл(ы) информацию для фрейма
480     std::cout << "\t\tDumping data." << std::endl;
481     anglesFileDump(frnr, fnOut, colorsToPeptide, colorFormation);
482     std::cout << "\tFrame analysed." << std::endl;
483 }
484
485 void
486 colorVec::finishAnalysis(int nframes)
487 {
488
489 }
490
491 void
492 colorVec::writeOutput()
493 {
494     /*
495      *
496      * frame #<current frame number>
497      * color #<color number> <yes/no for "close" to peptide> a12 b12 n12 <number of beta lists> <6 avg beta angles> [<6 angles for each beta list>]
498      *
499      */
500     std::cout << "\n\t colorAngles finished successfully" << std::endl;
501 }
502
503 /*! \brief
504  * The main function for the analysis template.
505  */
506 int
507 main(int argc, char *argv[])
508 {
509     return gmx::TrajectoryAnalysisCommandLineRunner::runAsMain<colorVec>(argc, argv);
510 }