2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
37 * Implements gmx::analysismodules::Freevolume.
39 * \author Titov Anatoly <Wapuk-cobaka@yandex.ru>
40 * \ingroup module_trajectoryanalysis
49 #include <gromacs/trajectoryanalysis.h>
50 #include <gromacs/pbcutil/pbc.h>
51 #include <gromacs/utility/smalloc.h>
52 #include <gromacs/math/do_fit.h>
54 #include <gromacs/trajectoryanalysis/topologyinformation.h>
55 #include "gromacs/topology/topology.h"
56 #include "gromacs/topology/index.h"
59 #define MAX_NTRICVEC 12
65 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) {
66 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) +
67 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) +
68 pow(aiz + sin(B) * bix_plus_x - cos(A) * cos(B) * biz_plus_z - cos(B) * sin(A) * biy_plus_y, 2) );
71 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) {
72 double t01, t02, t03, t04, t05, t06, t07;
73 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);
74 t02 = 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);
75 t03 = pow(aiz + sin(B) * bix_plus_x - cos(A) * cos(B) * biz_plus_z - cos(B) * sin(A) * biy_plus_y, 2);
76 t04 = sqrt(t01 + t02 + t03);
77 t05 = (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);
78 t06 = (aiz + sin(B) * bix_plus_x - cos(A) * cos(B) * biz_plus_z - cos(B) * sin(A) * biy_plus_y);
79 t07 = (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);
81 Fx += -(2 * cos(B) * cos(C) * t05 - 2 * sin(B) * t06 + 2 * cos(B) * sin(C) * t07) / (2 * t04);
82 Fy += -(2 * (cos(A) * cos(C) + sin(A) * sin(B) * sin(C)) * t07 - 2 * (cos(A) * sin(C) - cos(C) * sin(A) * sin(B)) * t05 + 2 * cos(B) * sin(A) * t06) / (2 * t04);
83 Fz += -(2 * (sin(A) * sin(C) + cos(A) * cos(C) * sin(B)) * t05 - 2 * (cos(C) * sin(A) - cos(A) * sin(B) * sin(C)) * t07 + 2 * cos(A) * cos(B) * t06) / (2 * t04);
84 Fa += -(2 * (cos(A) * cos(B) * biy_plus_y - cos(B) * sin(A) * biz_plus_z) * t06 -
85 2 * (biy_plus_y * (cos(C) * sin(A) - cos(A) * sin(B) * sin(C)) + biz_plus_z * (cos(A) * cos(C) + sin(A) * sin(B) * sin(C))) * t07 +
86 2 * (biy_plus_y * (sin(A) * sin(C) + cos(A) * cos(C) * sin(B)) + biz_plus_z * (cos(A) * sin(C) - cos(C) * sin(A) * sin(B))) * t05) / (2 * t04);
87 Fb += -(2 * (cos(A) * cos(B) * sin(C) * biz_plus_z - sin(B) * sin(C) * bix_plus_x + cos(B) * sin(A) * sin(C) * biy_plus_y) * t07 +
88 2 * (cos(A) * cos(B) * cos(C) * biz_plus_z - cos(C) * sin(B) * bix_plus_x + cos(B) * cos(C) * sin(A) * biy_plus_y) * t05 -
89 2 * (cos(B) * bix_plus_x + sin(A) * sin(B) * biy_plus_y + cos(A) * sin(B) * biz_plus_z) * t06) / (2 * t04);
90 Fc += (2 * (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) * t05 -
91 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);
94 void ApplyFit (std::vector< RVec > &b, double x, double y, double z, double A, double B, double C) {
95 double t0 = 0, t1 = 0, t2 = 0;
96 for (unsigned int i = 0; i < b.size(); i++) {
97 t0 = static_cast< double >(b[i][0]);
98 t1 = static_cast< double >(b[i][1]);
99 t2 = static_cast< double >(b[i][2]);
100 b[i][0] = static_cast< float >((t2 + z) * (sin(A) * sin(C) + cos(A) * cos(C) * sin(B)) - (t1 + y) * (cos(A) * sin(C) - cos(C) * sin(A) * sin(B)) + cos(B) * cos(C) * (t0 + x));
101 b[i][1] = static_cast< float >((t1 + y) * (cos(A) * cos(C) + sin(A) * sin(B) * sin(C)) - (t2 + z) * (cos(C) * sin(A) - cos(A) * sin(B) * sin(C)) + cos(B) * sin(C) * (t0 + x));
102 b[i][2] = static_cast< float >(cos(A) * cos(B) * (t2 + z) - sin(B) * (t0 + x) + cos(B) * sin(A) * (t1 + y));
106 void CalcMid (std::vector< RVec > a, std::vector< RVec > b, RVec &midA, RVec &midB, std::vector< std::pair< unsigned int, unsigned int > > pairs) {
115 for (unsigned int i = 0; i < pairs.size(); i++) {
116 rvec_inc(midA, a[pairs[i].first]);
117 rvec_inc(midB, b[pairs[i].second]);
119 midA[0] /= pairs.size();
120 midA[1] /= pairs.size();
121 midA[2] /= pairs.size();
123 midB[0] /= pairs.size();
124 midB[1] /= pairs.size();
125 midB[2] /= pairs.size();
128 void MyFitNew (std::vector< RVec > a, std::vector< RVec > &b, std::vector< std::pair< unsigned int, unsigned int > > pairs, double FtCnst) {
129 double f1 = 0, f2 = 0, fx = 0, fy = 0, fz = 0, fa = 0, fb = 0, fc = 0, l = 1;
131 CalcMid(a, b, ma, mb, pairs);
133 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;
134 for (unsigned int i = 0; i < pairs.size(); i++) {
135 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]),
136 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);
145 while (f1 - f2 < 0 || f1 - f2 > FtCnst) {
146 f1 = 0; fx = 0; fy = 0; fz = 0; fa = 0; fb = 0; fc = 0; l = 1;
147 for (unsigned int i = 0; i < pairs.size(); i++) {
148 searchF0xyzabc(f1, fx, fy, fz, fa, fb, fc,
149 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 static_cast< double >(b[pairs[i].second][0]) + x, static_cast< double >(b[pairs[i].second][1]) + y,
151 static_cast< double >(b[pairs[i].second][2]) + z, A, B, C);
155 for (unsigned int i = 0; i < pairs.size(); i++) {
156 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]),
157 static_cast< double >(b[pairs[i].second][0]) + (x - l * fx), static_cast< double >(b[pairs[i].second][1]) + (y - l * fy),
158 static_cast< double >(b[pairs[i].second][2]) + (z - l * fz), A - l * fa, B - l * fb, C - l * fc);
162 x -= l * fx; y -= l * fy; z -= l * fz; A -= l * fa; B -= l * fb; C -= l * fc;
163 fx = 0; fy = 0; fz = 0; fa = 0; fb = 0; fc = 0;
169 std::cout << count << " " << l << "\n";
171 if (l == DBL_MIN) { /*DBL_TRUE_MIN*/
177 if (count % 100000 == 0) {
178 std::cout << "+100k\n";
181 ApplyFit(b, x, y, z, A, B, C);
191 void make_graph(unsigned long mgwi_natoms, std::vector < RVec > mgwi_x, std::vector< std::vector< node > > &mgwi_graph)
193 mgwi_graph.resize(mgwi_natoms);
194 for (unsigned int i = 0; i < mgwi_natoms; i++) {
195 mgwi_graph[i].resize(mgwi_natoms);
197 for (unsigned int i = 0; i < mgwi_natoms; i++) {
198 for (unsigned int j = 0; j < mgwi_natoms; j++) {
199 rvec_sub(mgwi_x[i].as_vec(), mgwi_x[j].as_vec(), mgwi_graph[i][j].r.as_vec());
200 mgwi_graph[i][j].n = 0;
205 void update_graph(std::vector< std::vector< node > > &ugwi_graph, std::vector < RVec > ugwi_x, /*long*/ double ugwi_epsi) {
207 for (unsigned int i = 0; i < ugwi_graph.size(); i++) {
208 for (unsigned int j = i; j < ugwi_graph.size(); j++) {
209 rvec_sub(ugwi_x[i].as_vec(), ugwi_x[j].as_vec(), ugwi_temp.as_vec());
210 rvec_dec(ugwi_temp.as_vec(), ugwi_graph[i][j].r.as_vec());
211 if (static_cast< double >(norm(ugwi_temp)) <= ugwi_epsi) {
213 ugwi_graph[i][j].n++;
216 ugwi_graph[i][j].n++;
217 ugwi_graph[j][i].n++;
224 void check_domains(double cd_delta, int cd_frames, std::vector< std::vector< std::vector< node > > > &cd_graph) {
225 for (unsigned int k = 0; k < cd_graph.size(); k++) {
226 for (unsigned int i = 0; i < cd_graph[1].size(); i++) {
227 for (unsigned int j = 0; j < cd_graph[1].size(); j++) {
228 if (cd_graph[k][i][j].n >= cd_frames * cd_delta) {
229 cd_graph[k][i][j].yep = true;
232 cd_graph[k][i][j].yep = false;
239 void find_domain_sizes(std::vector< std::vector< std::vector< node > > > fds_graph, std::vector< std::vector< int > > &fds_domsizes) {
240 fds_domsizes.resize(fds_graph.size());
241 for (unsigned int i = 0; i < fds_graph.size(); i++) {
242 fds_domsizes[i].resize(fds_graph[1].size(), 0);
243 for (unsigned int j = 0; j < fds_graph[1].size(); j++) {
244 for (unsigned int k = 0; k < fds_graph[1].size(); k++) {
245 if (fds_graph[i][j][k].yep) {
246 fds_domsizes[i][j]++;
253 void get_maxsized_domain(std::vector< unsigned int > &gmd_max_d, std::vector< std::vector< std::vector< node > > > gmd_graph, std::vector< std::vector< int > > gmd_domsizes) {
254 unsigned int gmd_number1 = 0, gmd_number2 = 0;
255 for (unsigned int i = 0; i < gmd_domsizes.size(); i++) {
256 for (unsigned int j = 0; j < gmd_domsizes[0].size(); j++) {
257 if (gmd_domsizes[i][j] >= gmd_domsizes[gmd_number1][gmd_number2]) {
264 for (unsigned int i = 0; i < gmd_graph[gmd_number1][gmd_number2].size(); i++) {
265 if (gmd_graph[gmd_number1][gmd_number2][i].yep) {
266 gmd_max_d.push_back(i);
271 void get_min_domain(std::vector< unsigned int > &gmd_min_d, std::vector< std::vector< std::vector< node > > > gmd_graph, std::vector< std::vector< int > > gmd_domsizes, int gmd_min_dom_size) {
272 unsigned int gmd_number1 = 0, gmd_number2 = 0;
273 for (unsigned int i = 0; i < gmd_domsizes.size(); i++) {
274 for (unsigned int j = 0; j < gmd_domsizes[0].size(); j++) {
275 if (gmd_domsizes[gmd_number1][gmd_number2] < gmd_min_dom_size && gmd_domsizes[i][j] >= gmd_min_dom_size) {
279 if (gmd_domsizes[i][j] <= gmd_domsizes[gmd_number1][gmd_number2] && gmd_domsizes[i][j] >= gmd_min_dom_size) {
286 for (unsigned int i = 0; i < gmd_graph[gmd_number1][gmd_number2].size(); i++) {
287 if (gmd_graph[gmd_number1][gmd_number2][i].yep) {
288 gmd_min_d.push_back(i);
293 void delete_domain_from_graph(std::vector< std::vector< std::vector< node > > > &ddf_graph, std::vector< unsigned int > ddf_domain) {
294 for (unsigned int i = 0; i < ddf_domain.size(); i++) {
295 for (unsigned int k = 0; k < ddf_graph.size(); k++) {
296 for (unsigned int j = 0; j < ddf_graph[1].size(); j++) {
297 if (ddf_graph[k][ddf_domain[i]][j].yep) {
298 ddf_graph[k][ddf_domain[i]][j].yep = false;
300 if (ddf_graph[k][j][ddf_domain[i]].yep) {
301 ddf_graph[k][j][ddf_domain[i]].yep = false;
308 bool check_domsizes(std::vector< std::vector< int > > cd_domsizes, int cd_domain_min_size) {
309 for (unsigned int i = 0; i < cd_domsizes.size(); i++) {
310 for (unsigned int j = 0; j < cd_domsizes[0].size(); j++) {
311 if (cd_domsizes[i][j] >= cd_domain_min_size) {
319 void print_domains(std::vector< std::vector< unsigned int > > pd_domains, std::vector< int > index, std::string fnNdx_, int dms, double epsi, double delta) {
321 fpNdx_ = std::fopen(fnNdx_.c_str(), "w+");
323 for (unsigned int i = 0; i < pd_domains.size(); i++) {
324 std::fprintf(fpNdx_, "[domain_№_%3d_%3d_%4.3f_%4.3f]\n", i + 1, dms, epsi, delta);
326 for (unsigned int j = 0; j < pd_domains[i].size(); j++) {
328 if (write_count > 20) {
330 std::fprintf(fpNdx_, "\n");
332 std::fprintf(fpNdx_, "%5d ", index[pd_domains[i][j]] + 1);
333 std::printf("%5d ", index[pd_domains[i][j]] + 1);
336 std::fprintf(fpNdx_,"\n\n");
338 std::fprintf(fpNdx_,"\n");
343 * \ingroup module_trajectoryanalysis
345 class Domains : public TrajectoryAnalysisModule
352 //! Set the options and setting
353 virtual void initOptions(IOptionsContainer *options,
354 TrajectoryAnalysisSettings *settings);
356 //! First routine called by the analysis framework
357 // virtual void initAnalysis(const t_trxframe &fr, t_pbc *pbc);
358 virtual void initAnalysis(const TrajectoryAnalysisSettings &settings,
359 const TopologyInformation &top);
361 //! Call for each frame of the trajectory
362 // virtual void analyzeFrame(const t_trxframe &fr, t_pbc *pbc);
363 virtual void analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
364 TrajectoryAnalysisModuleData *pdata);
366 //! Last routine called by the analysis framework
367 // virtual void finishAnalysis(t_pbc *pbc);
368 virtual void finishAnalysis(int nframes);
370 //! Routine to write output, that is additional over the built-in
371 virtual void writeOutput();
377 //std::vector< std::vector< std::vector< node > > > graph;
378 std::vector< std::vector< std::vector< std::vector< node > > > > graph;
381 std::vector< std::vector< unsigned int > > domains;
382 std::vector< std::vector< int > > domsizes;
384 std::vector< int > index;
385 std::vector< int > numbers;
386 std::vector< RVec > trajectory;
387 std::vector< RVec > reference;
390 int domain_min_size = 4; // selectable
392 std::vector< std::vector< std::pair< unsigned int, unsigned int > > > w_rls2;
394 double delta = 0.95; // selectable
395 double epsi = 0.10; // selectable
397 int DomainSearchingAlgorythm = 0; // selectable
398 // Copy and assign disallowed by base.
401 Domains::Domains(): TrajectoryAnalysisModule()
410 Domains::initOptions(IOptionsContainer *options,
411 TrajectoryAnalysisSettings *settings)
413 static const char *const desc[] = {
414 "[THISMODULE] to be done"
416 // Add the descriptive text (program help text) to the options
417 settings->setHelpText(desc);
418 // Add option for selecting a subset of atoms
419 options->addOption(SelectionOption("select")
420 .store(&selec).required()
421 .description("Atoms that are considered as part of the excluded volume"));
422 // Add option for output file name
423 options->addOption(FileNameOption("on").filetype(eftIndex).outputFile()
424 .store(&fnNdx_).defaultBasename("domains")
425 .description("Index file from the domains"));
426 // Add option for domain min size constant
427 options->addOption(gmx::IntegerOption("dms")
428 .store(&domain_min_size)
429 .description("minimum domain size, should be >= 4"));
430 // Add option for Domain's Searching Algorythm
431 options->addOption(gmx::IntegerOption("DSA")
432 .store(&DomainSearchingAlgorythm)
433 .description("Domain's Searching Algorythm: 0 == default (from bigger to smaller) | 1 == (from smaller to bigger)"));
434 // Add option for epsi constant
435 options->addOption(DoubleOption("epsilon")
437 .description("thermal vibrations' constant"));
438 // Add option for delta constant
439 options->addOption(DoubleOption("delta")
441 .description("domain membership probability"));
442 // Control input settings
443 settings->setFlags(TrajectoryAnalysisSettings::efNoUserPBC);
444 settings->setFlag(TrajectoryAnalysisSettings::efUseTopX);
445 settings->setPBC(true);
449 Domains::initAnalysis(const TrajectoryAnalysisSettings &settings,
450 const TopologyInformation &top)
453 for (ArrayRef< const int >::iterator ai = selec.atomIndices().begin(); (ai < selec.atomIndices().end()); ai++) {
454 index.push_back(*ai);
458 if (top.hasFullTopology()) {
459 for (unsigned int i = 0; i < index.size(); i++) {
460 reference.push_back(top.x().at(index[i]));
466 bone = static_cast< unsigned int >(index.size() - static_cast< unsigned int >(domain_min_size) + 1);
467 graph[0].resize(bone);
469 for (unsigned int i = 0; i < bone; i++) {
471 for (unsigned int j = 0; j < static_cast< unsigned int >(domain_min_size); j++) {
472 w_rls2[i].push_back(std::make_pair(j + i, j + i));
474 make_graph(index.size(), reference, graph[0][i]);
477 trajectory.resize(index.size());
481 Domains::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc, TrajectoryAnalysisModuleData *pdata)
483 for (unsigned int i = 0; i < index.size(); i++) {
484 trajectory[i] = fr.x[index[i]];
488 #pragma omp parallel for ordered schedule(dynamic) shared(w_rls2, graph) firstprivate(trajectory, reference, epsi)
489 for (unsigned int j = 0; j < bone; j++) {
490 std::vector < RVec > temp = trajectory;
491 MyFitNew(reference, temp, w_rls2[j], 0);
492 update_graph(graph[0][j], temp, epsi);
495 std::cout << "frame: " << frames << " analyzed\n";
499 Domains::finishAnalysis(int nframes)
503 std::cout << "final cheking\n";
504 check_domains(delta, frames, graph[0]);
506 std::cout << "finding domains' sizes\n";
507 find_domain_sizes(graph[0], domsizes);
509 std::cout << "finding domains\n";
510 std::vector< unsigned int > a;
512 while (check_domsizes(domsizes, domain_min_size)) {
513 domains.push_back(a);
514 if (DomainSearchingAlgorythm == 0) {
515 get_maxsized_domain(domains.back(), graph[0], domsizes);
516 } else if (DomainSearchingAlgorythm == 1) {
517 get_min_domain(domains.back(), graph[0], domsizes, domain_min_size);
519 std::cout << "new domain: " << domains.back().size() << " atoms\n";
520 delete_domain_from_graph(graph[0], domains.back());
522 find_domain_sizes(graph[0], domsizes);
527 Domains::writeOutput()
529 std::cout << "making output file\n";
530 print_domains(domains, index, fnNdx_, domain_min_size, epsi, delta); // see function for details | numbers from index
531 std::cout << "\n END \n";
535 * The main function for the analysis template.
538 main(int argc, char *argv[])
540 return gmx::TrajectoryAnalysisCommandLineRunner::runAsMain<Domains>(argc, argv);