1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2     Copyright (c) 2017 of Haochuan Chen (excluding colvar_UIestimator.h)
3     Copyright (c) 2017 of Haohao Fu (colvar_UIestimator.h)
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU Lesser General Public License as published
7     by the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
18 #ifdef __PLUMED_HAS_BOOST_SERIALIZATION
19 #include "cltools/CLTool.h"
20 #include "cltools/CLToolRegister.h"
21 #include "config/Config.h"
22 #include "core/ActionRegister.h"
23 #include "DRR.h"
24 #include "tools/Tools.h"
25 #include "tools/Units.h"
26 #include <boost/archive/binary_iarchive.hpp>
27 #include <boost/archive/binary_oarchive.hpp>
28 #include <boost/serialization/vector.hpp>
29 #include <cstdlib>
30 #include <fstream>
31 #include <iostream>
32 #include <string>
33 
34 using namespace PLMD;
35 using namespace cltools;
36 
37 namespace PLMD {
38 namespace drr {
39 
40 //+PLUMEDOC EABFMOD_TOOLS drr_tool
41 /*
42  - Extract .grad and .count files from the binary output .drrstate
43  - Merge windows
44 
45 \par Examples
46 
47 The following command will extract .grad and .count files.
48 \verbatim
49 plumed drr_tool --extract eabf.drrstate
50 \endverbatim
51 
52 The following command will merge windows of two .drrstate file, and output the
53 .grad and .count files.
54 \verbatim
55 plumed drr_tool --merge win1.drrstate,win2.drrstate
56 \endverbatim
57 
58 After getting the .grad and .count file, you can do numerical integration by
59 using abf_integrate tool from
60 https://github.com/Colvars/colvars/tree/master/colvartools
61 \verbatim
62 abf_integrate eabf.czar.grad
63 \endverbatim
64 \note
65 The abf_integrate in colvartools is in kcal/mol, so it may be better to use --units kcal/mol when running drr_tool
66 
67 */
68 //+ENDPLUMEDOC
69 
70 using std::vector;
71 using std::string;
72 
73 class drrtool : public CLTool {
74 public:
75   static void registerKeywords(Keywords &keys);
76   explicit drrtool(const CLToolOptions &co);
77   int main(FILE *in, FILE *out, Communicator &pc);
78   void extractdrr(const vector<string> &filename);
79   void mergewindows(const vector<string> &filename, string outputname);
80   void calcDivergence(const vector<string> &filename);
description() const81   string description() const { return "Extract or merge the drrstate files."; }
82 
83 private:
84   bool verbosity;
85   Units units;
86   const string suffix{".drrstate"};
87 };
88 
89 PLUMED_REGISTER_CLTOOL(drrtool, "drr_tool")
90 
registerKeywords(Keywords & keys)91 void drrtool::registerKeywords(Keywords &keys) {
92   CLTool::registerKeywords(keys);
93   keys.add("optional", "--extract", "Extract drrstate file(s)");
94   keys.add("optional", "--merge", "Merge eABF windows");
95   keys.add("optional", "--merge_output", "The output filename of the merged result");
96   keys.add("optional", "--divergence", "Calculate divergence of gradient field (experimental)");
97   keys.add("compulsory","--units","kj/mol","the units of energy can be kj/mol, kcal/mol, j/mol, eV or the conversion factor from kj/mol");
98   keys.addFlag("-v", false, "Verbose output");
99 }
100 
drrtool(const CLToolOptions & co)101 drrtool::drrtool(const CLToolOptions &co) : CLTool(co) {
102   inputdata = commandline;
103   verbosity = false;
104 }
105 
main(FILE * in,FILE * out,Communicator & pc)106 int drrtool::main(FILE *in, FILE *out, Communicator &pc) {
107   parseFlag("-v", verbosity);
108   vector<string> stateFilesToExtract;
109   string unitname;
110   parse("--units",unitname);
111   units.setEnergy( unitname );
112   bool doextract = parseVector("--extract", stateFilesToExtract);
113   if (doextract) {
114     extractdrr(stateFilesToExtract);
115   }
116   vector<string> stateFilesToMerge;
117   bool domerge = parseVector("--merge", stateFilesToMerge);
118   if (domerge) {
119     string merge_outputname;
120     parse("--merge_output", merge_outputname);
121     mergewindows(stateFilesToMerge, merge_outputname);
122   }
123   vector<string> stateFilesToDivergence;
124   bool dodivergence = parseVector("--divergence", stateFilesToDivergence);
125   if (dodivergence) {
126     calcDivergence(stateFilesToDivergence);
127   }
128   return 0;
129 }
130 
extractdrr(const vector<string> & filename)131 void drrtool::extractdrr(const vector<string> &filename) {
132   #pragma omp parallel for
133   for (size_t j = 0; j < filename.size(); ++j) {
134     std::ifstream in;
135     in.open(filename[j]);
136     boost::archive::binary_iarchive ia(in);
137     long long int step;
138     vector<double> fict;
139     vector<double> vfict;
140     vector<double> vfict_laststep;
141     vector<double> ffict;
142     ABF abfgrid;
143     CZAR czarestimator;
144     ia >> step >> fict >> vfict >> vfict_laststep >> ffict >> abfgrid >>
145        czarestimator;
146     in.close();
147     abfgrid.setOutputUnit(units.getEnergy());
148     czarestimator.setOutputUnit(units.getEnergy());
149     if (verbosity) {
150       std::cout << "Output units factor: " << units.getEnergy() << '\n';
151       std::cout << "Dumping information of extended variables..." << '\n';
152       std::cout << "Step: " << step << '\n';
153       for (size_t i = 0; i < fict.size(); ++i) {
154         std::cout << "Dimension[" << i + 1 << "]:\n"
155                   << "  Coordinate: " << fict[i] << '\n'
156                   << "  Velocity: " << vfict[i] << '\n'
157                   << "  Velocity(laststep): " << vfict_laststep[i] << '\n'
158                   << "  Force: " << ffict[i] << '\n';
159       }
160       std::cout << "Dumping counts and gradients from grids..." << '\n';
161     }
162     string outputname(filename[j]);
163     outputname = outputname.substr(0, outputname.length() - suffix.length());
164     if (verbosity)
165       std::cout << "Writing ABF(naive) estimator files..." << '\n';
166     abfgrid.writeAll(outputname);
167     if (verbosity)
168       std::cout << "Writing CZAR estimator files..." << '\n';
169     czarestimator.writeAll(outputname);
170     czarestimator.writeZCount(outputname);
171   }
172 }
173 
mergewindows(const vector<string> & filename,string outputname)174 void drrtool::mergewindows(const vector<string> &filename, string outputname) {
175   if (filename.size() < 2) {
176     std::cerr << "ERROR! You need at least two .drrstate file to merge windows!" << std::endl;
177     std::abort();
178   }
179   // Read grid into abfs and czars;
180   vector<ABF> abfs;
181   vector<CZAR> czars;
182   for (auto it_fn = filename.begin(); it_fn != filename.end(); ++it_fn) {
183     std::ifstream in;
184     in.open((*it_fn));
185     boost::archive::binary_iarchive ia(in);
186     long long int step;
187     vector<double> fict;
188     vector<double> vfict;
189     vector<double> vfict_laststep;
190     vector<double> ffict;
191     ABF abfgrid;
192     CZAR czarestimator;
193     ia >> step >> fict >> vfict >> vfict_laststep >> ffict >> abfgrid >>
194        czarestimator;
195     abfgrid.setOutputUnit(units.getEnergy());
196     czarestimator.setOutputUnit(units.getEnergy());
197     abfs.push_back(abfgrid);
198     czars.push_back(czarestimator);
199     in.close();
200   }
201   CZAR cmerged = CZAR::mergewindow(czars[0], czars[1]);
202   ABF amerged = ABF::mergewindow(abfs[0], abfs[1]);
203   for (size_t i = 2; i < czars.size(); ++i) {
204     cmerged = CZAR::mergewindow(cmerged, czars[i]);
205     amerged = ABF::mergewindow(amerged, abfs[i]);
206   }
207   if (outputname.empty()) {
208     // Generate new file name for merged grad and count
209     vector<string> tmp_name = filename;
210     std::transform(std::begin(tmp_name), std::end(tmp_name), std::begin(tmp_name),
211     [&](string s) {return s.substr(0, s.find(suffix));});
212     outputname = std::accumulate(std::begin(tmp_name), std::end(tmp_name), string(""),
213     [](const string & a, const string & b) {return a + b + "+";});
214     outputname = outputname.substr(0, outputname.size() - 1);
215     std::cerr << "You have not specified an output filename for the merged"
216               << " result, so the default name \"" + outputname
217               << "\" is used here, which may yield unexpected behavior.\n";
218   }
219   cmerged.writeAll(outputname);
220   cmerged.writeZCount(outputname);
221   amerged.writeAll(outputname);
222 }
223 
calcDivergence(const vector<string> & filename)224 void drrtool::calcDivergence(const vector<string> &filename) {
225   #pragma omp parallel for
226   for (size_t j = 0; j < filename.size(); ++j) {
227     std::ifstream in;
228     in.open(filename[j]);
229     boost::archive::binary_iarchive ia(in);
230     long long int step;
231     vector<double> fict;
232     vector<double> vfict;
233     vector<double> vfict_laststep;
234     vector<double> ffict;
235     ABF abfgrid;
236     CZAR czarestimator;
237     ia >> step >> fict >> vfict >> vfict_laststep >> ffict >> abfgrid >>
238        czarestimator;
239     in.close();
240     abfgrid.setOutputUnit(units.getEnergy());
241     czarestimator.setOutputUnit(units.getEnergy());
242     if (verbosity) {
243       std::cout << "Output units factor: " << units.getEnergy() << '\n';
244       std::cout << "Dumping information of extended variables..." << '\n';
245       std::cout << "Step: " << step << '\n';
246       for (size_t i = 0; i < fict.size(); ++i) {
247         std::cout << "Dimension[" << i + 1 << "]:\n"
248                   << "  Coordinate: " << fict[i] << '\n'
249                   << "  Velocity: " << vfict[i] << '\n'
250                   << "  Velocity(laststep): " << vfict_laststep[i] << '\n'
251                   << "  Force: " << ffict[i] << '\n';
252       }
253       std::cout << "Dumping counts and gradients from grids..." << '\n';
254     }
255     string outputname(filename[j]);
256     outputname = outputname.substr(0, outputname.length() - suffix.length());
257     abfgrid.writeDivergence(outputname);
258     czarestimator.writeDivergence(outputname);
259   }
260 }
261 
262 } // End of namespace
263 }
264 
265 #endif
266