Uncrustify
[alexxy/gromacs-sans.git] / src / sans.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2011,2012,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 #include <iostream>
36
37 #include <gromacs/trajectoryanalysis.h>
38 #include <gromacs/selection/nbsearch.h>
39 #include <gromacs/math/vec.h>
40 #include <gromacs/math/units.h>
41 #include <gromacs/topology/atomprop.h>
42
43
44 using namespace gmx;
45
46 /*! \brief
47  * Template class to serve as a basis for user analysis tools.
48  */
49 class SANS : public TrajectoryAnalysisModule
50 {
51     public:
52         SANS();
53
54         virtual void initOptions(IOptionsContainer          *options,
55                                  TrajectoryAnalysisSettings *settings);
56         virtual void initAnalysis(const TrajectoryAnalysisSettings &settings,
57                                   const TopologyInformation        &top);
58         virtual void initAfterFirstFrame(const TrajectoryAnalysisSettings &settings,
59                                          const t_trxframe                 &fr);
60
61
62         virtual void analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
63                                   TrajectoryAnalysisModuleData *pdata);
64
65         virtual void finishAnalysis(int nframes);
66         virtual void writeOutput();
67
68     private:
69         class ModuleData;
70
71         double Gaussian(double value, double sigma, RVec Rpos, RVec Rgrid, RVec GridSpacing);
72
73         double                           cutoff_;
74         double                           grid_;
75         double                           boxScale_;
76
77         IVec gridPoints_;
78         RVec gridSpacing_;
79
80         AnalysisNeighborhood              nb_;
81         const TopologyInformation        *top_;
82         std::vector < std::vector < std::vector<double>>> gausGrid_;
83         std::vector<double>               vdw_radius_;
84 };
85
86 SANS::SANS()
87     : cutoff_(1.0), grid_(0.05), boxScale_(1.0)
88 {
89 }
90
91 double SANS::Gaussian(double value, double sigma, RVec Rpos, RVec Rgrid, RVec GridSpacing)
92 {
93     //return value*M_PI*M_PI*GridSpacing[XX]*GridSpacing[YY]*GridSpacing[ZZ]*exp(-distance2(Rpos, Rgrid)/(2*sigma*sigma))/(std::sqrt(2.0)*sigma*sigma*sigma*108.);
94     //return value*std::exp(-distance2(Rpos, Rgrid)/(2*sigma*sigma))/(2*M_PI*std::sqrt(2.0*M_PI)*sigma*sigma*sigma);
95     return value*std::exp(-distance2(Rpos, Rgrid)/(2*sigma*sigma))/(2*M_PI*std::sqrt(2.0*M_PI)*sigma*sigma*sigma)*GridSpacing[XX]*GridSpacing[YY]*GridSpacing[ZZ];
96     //return value*std::exp(-distance2(Rpos, Rgrid)/(sigma*sigma))/(2*M_PI*std::sqrt(2.0*M_PI)*sigma*sigma*sigma)*GridSpacing[XX]*GridSpacing[YY]*GridSpacing[ZZ];
97 }
98
99 void
100 SANS::initOptions(IOptionsContainer          *options,
101                   TrajectoryAnalysisSettings *settings)
102 {
103     static const char *const desc[] = {
104         "Analysis tool for finding molecular core."
105     };
106
107     // Add the descriptive text (program help text) to the options
108     settings->setHelpText(desc);
109     // Add option for cutoff constant
110     options->addOption(DoubleOption("cutoff")
111                            .store(&cutoff_)
112                            .description("cutoff for neighbour search"));
113     options->addOption(DoubleOption("grid")
114                            .store(&grid_)
115                            .description("grid spacing for gaus grid"));
116     options->addOption(DoubleOption("boxscale")
117                            .store(&boxScale_)
118                            .description("box scaling for gaus grid"));
119 }
120
121 void
122 SANS::initAnalysis(const TrajectoryAnalysisSettings  &settings,
123                    const TopologyInformation         &top)
124 {
125
126     gmx_atomprop_t aps    = gmx_atomprop_init();
127     t_atoms       *atoms  = &(top.topology()->atoms);
128     real           value;
129
130     nb_.setCutoff(cutoff_);
131     top_ = &top;
132
133     for (int i = 0; i < top.topology()->atoms.nr; i++)
134     {
135         // Lookup the Van der Waals radius of this atom
136         int resnr = atoms->atom[i].resind;
137         if (gmx_atomprop_query(aps, epropVDW,
138                                *(atoms->resinfo[resnr].name),
139                                *(atoms->atomname[i]),
140                                &value))
141         {
142             vdw_radius_.push_back(value);
143         }
144         else
145         {
146             fprintf(stderr, "Could not determine VDW radius for %s-%s. Set to zero.\n",
147                     *(atoms->resinfo[resnr].name),
148                     *(atoms->atomname[i]));
149             vdw_radius_.push_back(0.0);
150         }
151
152     }
153
154 }
155
156 void
157 SANS::initAfterFirstFrame(const TrajectoryAnalysisSettings &settings,
158                           const t_trxframe                 &fr)
159 {
160     // set gridpoints and grid spacing for orthogonal boxes only....
161     for (int i = 0; i < DIM; i++)
162     {
163         gridSpacing_[i] = grid_;
164         gridPoints_[i]  = static_cast<int>(std::ceil(fr.box[i][i]*boxScale_/grid_));
165     }
166     // prepare gausGrid
167     gausGrid_.resize(gridPoints_[XX], std::vector < std::vector < double>>(gridPoints_[YY], std::vector<double>(gridPoints_[ZZ])));
168 }
169
170 void
171 SANS::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
172                    TrajectoryAnalysisModuleData *pdata)
173 {
174     RVec GridSpacing(0.1, 0.1, 0.1);
175     AnalysisNeighborhoodSearch nbsearch = nb_.initSearch(pbc, AnalysisNeighborhoodPositions(fr.x, fr.natoms));
176
177     t_topology                *top = top_->topology();
178
179     fprintf(stderr, "Box dimensions:\n");
180     for (int i = 0; i < DIM; i++)
181     {
182         fprintf(stderr, "[ ");
183         for (int j = 0; j < DIM; j++)
184         {
185             fprintf(stderr, " %f ", fr.box[i][j]);
186         }
187         fprintf(stderr, " ]\n");
188     }
189     // main loop over grid points
190     for (int i = 0; i < gridPoints_[XX]; i++)
191     {
192         for (int j = 0; j < gridPoints_[YY]; j++)
193         {
194             for (int k = 0; k < gridPoints_[ZZ]; k++)
195             {
196                 RVec                           point(i*gridSpacing_[XX], j*gridSpacing_[YY], k*gridSpacing_[ZZ]);
197                 AnalysisNeighborhoodPairSearch pairSearch = nbsearch.startPairSearch(point.as_vec());
198                 AnalysisNeighborhoodPair       pair;
199                 while (pairSearch.findNextPair(&pair))
200                 {
201                     //fprintf(stderr,"point = [ %f %f %f ]\n", point[XX],point[YY],point[ZZ]);
202                     // fprintf(stderr,"Index %d\n", pair.refIndex());
203                     // fprintf(stderr,"dx =  (%f, %f, %f)\n", pair.dx()[XX], pair.dx()[YY], pair.dx()[ZZ] );
204                     // fprintf(stderr,"ref =  (%f, %f, %f)\n", fr.x[pair.refIndex()][XX], fr.x[pair.refIndex()][YY], fr.x[pair.refIndex()][ZZ]);
205                     // fprintf(stderr,"ref_dx =  (%f, %f, %f)\n", GridSpacing[XX]+pair.dx()[XX], GridSpacing[YY]+pair.dx()[YY], GridSpacing[ZZ]+pair.dx()[ZZ] );
206                     RVec refPos(point[XX]+pair.dx()[XX], point[YY]+pair.dx()[YY], point[ZZ]+pair.dx()[ZZ]);
207                     //fprintf(stderr,"refPos = [ %f %f %f ]\n", refPos[XX], refPos[YY], refPos[ZZ]);
208                     //fprintf(stderr, "Mass = %f, Radius = %f\n", top->atoms.atom[pair.refIndex()].m, top->atomtypes.radius[top->atoms.atom[pair.refIndex()].type]);
209                     //fprintf(stderr, "Distance^2 = %3.8f\n", pair.distance2());
210                     //fprintf(stderr, "Gausian = %3.8f\n",Gaussian(top->atoms.atom[pair.refIndex()].m, 0.2, refPos, point, gridSpacing_)*AMU/((NANO*NANO*NANO)*(gridSpacing_[XX]*gridSpacing_[YY]*gridSpacing_[ZZ])));
211                     //gausGrid_[i][j][k] += Gaussian(top->atoms.atom[pair.refIndex()].m, 0.1, refPos, point, gridSpacing_)*AMU/((NANO*NANO*NANO)*(gridSpacing_[XX]*gridSpacing_[YY]*gridSpacing_[ZZ]));
212                     gausGrid_[i][j][k] += Gaussian(top->atoms.atom[pair.refIndex()].m, vdw_radius_[pair.refIndex()], refPos, point, gridSpacing_)*AMU/((NANO*NANO*NANO)*(gridSpacing_[XX]*gridSpacing_[YY]*gridSpacing_[ZZ]));
213                 }
214                 fprintf(stderr, "GausGrid[%d, %d, %d] = %f\n", i, j, k, gausGrid_[i][j][k]);
215             }
216         }
217     }
218     // only for orthogonal boxes...
219     fprintf(stderr, "NX = %d, NY = %d, NZ = %d\n", gridPoints_[XX], gridPoints_[YY], gridPoints_[ZZ]);
220 }
221
222 void
223 SANS::finishAnalysis(int nframes)
224 {
225 }
226
227 void
228 SANS::writeOutput()
229 {
230     FILE *fo;
231     // Construct opendx grid
232     fo = fopen("data.dx", "w");
233     //object 1 class gridpositions counts  140 140 140
234     //origin 0.000000 0.000000 0.000000
235     //delta  0.500000 0.000000 0.000000
236     //delta  0.000000 0.500000 0.000000
237     //delta  0.000000 0.000000 0.500000
238     //object 2 class gridconnections counts  140 140 140
239     //object 3 class array type "double" rank 0 items 2744000 data follows
240     fprintf(fo, "object 1 class gridpositions counts %d %d %d\n", gridPoints_[XX], gridPoints_[YY], gridPoints_[ZZ]);
241     fprintf(fo, "origin 0.000000 0.000000 0.000000\n");
242     fprintf(fo, "delta %3.6f %3.6f %3.6f\n", gridSpacing_[XX]*NM2A, 0.0, 0.0);
243     fprintf(fo, "delta %3.6f %3.6f %3.6f\n", 0.0, gridSpacing_[YY]*NM2A, 0.0);
244     fprintf(fo, "delta %3.6f %3.6f %3.6f\n", 0.0, 0.0, gridSpacing_[ZZ]*NM2A);
245     fprintf(fo, "object 2 class gridconnections counts  %d %d %d\n", gridPoints_[XX], gridPoints_[YY], gridPoints_[ZZ]);
246     fprintf(fo, "object 3 class array type \"double\" rank 0 items %d data follows\n", gridPoints_[XX]*gridPoints_[YY]*gridPoints_[ZZ]);
247     // now dump data in ordered mode
248     //    u(0,0,0) u(0,0,1) u(0,0,2)
249     //    ...
250     //    u(0,0,nz-3) u(0,0,nz-2) u(0,0,nz-1)
251     //    u(0,1,0) u(0,1,1) u(0,1,2)
252     //    ...
253     //    u(0,1,nz-3) u(0,1,nz-2) u(0,1,nz-1)
254     //    ...
255     //    u(0,ny-1,nz-3) u(0,ny-1,nz-2) u(0,ny-1,nz-1)
256     //    u(1,0,0) u(1,0,1) u(1,0,2)
257     //    ...
258     int NR = 3;
259     int n  = 0;
260     for (int i = 0; i < gridPoints_[XX]; i++)
261     {
262         for (int j = 0; j < gridPoints_[YY]; j++)
263         {
264             for (int k = 0; k < gridPoints_[ZZ]; k++)
265             {
266                 fprintf(fo, "%3.8f ", gausGrid_[i][j][k]);
267                 n++;
268                 if (n == NR)
269                 {
270                     fprintf(fo, "\n");
271                     n = 0;
272                 }
273             }
274         }
275     }
276     if (n != NR)
277     {
278         fprintf(fo, "\n");
279     }
280     //attribute "dep" string "positions"
281     //object "density" class field
282     //component "positions" value 1
283     //component "connections" value 2
284     //component "data" value 3
285     fprintf(fo, "attribute \"dep\" string \"positions\"\n");
286     fprintf(fo, "object \"density\" class field\n");
287     fprintf(fo, "component \"positions\" value 1\n");
288     fprintf(fo, "component \"connections\" value 2\n");
289     fprintf(fo, "component \"data\" value 3\n");
290     fclose(fo);
291 }
292
293 /*! \brief
294  * The main function for the analysis template.
295  */
296 int
297 main(int argc, char *argv[])
298 {
299     return gmx::TrajectoryAnalysisCommandLineRunner::runAsMain<SANS>(argc, argv);
300 }