Framework for help export from wrapper binary.
[alexxy/gromacs.git] / src / gromacs / trajectoryanalysis / cmdlinerunner.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2011,2012,2013, by the GROMACS development team, led by
5  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6  * others, as listed in the AUTHORS file in the top-level source
7  * 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::TrajectoryAnalysisCommandLineRunner.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_trajectoryanalysis
41  */
42 #include "cmdlinerunner.h"
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include "gromacs/legacyheaders/pbc.h"
49 #include "gromacs/legacyheaders/rmpbc.h"
50 #include "gromacs/legacyheaders/statutil.h"
51
52 #include "gromacs/analysisdata/paralleloptions.h"
53 #include "gromacs/commandline/cmdlinehelpcontext.h"
54 #include "gromacs/commandline/cmdlinehelpwriter.h"
55 #include "gromacs/commandline/cmdlinemodule.h"
56 #include "gromacs/commandline/cmdlinemodulemanager.h"
57 #include "gromacs/commandline/cmdlineparser.h"
58 #include "gromacs/onlinehelp/helpwritercontext.h"
59 #include "gromacs/options/options.h"
60 #include "gromacs/selection/selectioncollection.h"
61 #include "gromacs/selection/selectionoptionmanager.h"
62 #include "gromacs/trajectoryanalysis/analysismodule.h"
63 #include "gromacs/trajectoryanalysis/analysissettings.h"
64 #include "gromacs/trajectoryanalysis/runnercommon.h"
65 #include "gromacs/utility/exceptions.h"
66 #include "gromacs/utility/file.h"
67 #include "gromacs/utility/gmxassert.h"
68 #include "gromacs/utility/programinfo.h"
69
70 namespace gmx
71 {
72
73 /********************************************************************
74  * TrajectoryAnalysisCommandLineRunner::Impl
75  */
76
77 class TrajectoryAnalysisCommandLineRunner::Impl
78 {
79     public:
80         class RunnerCommandLineModule;
81
82         Impl(TrajectoryAnalysisModule *module);
83         ~Impl();
84
85         void printHelp(const Options                        &options,
86                        const TrajectoryAnalysisSettings     &settings,
87                        const TrajectoryAnalysisRunnerCommon &common);
88         bool parseOptions(TrajectoryAnalysisSettings *settings,
89                           TrajectoryAnalysisRunnerCommon *common,
90                           SelectionCollection *selections,
91                           int *argc, char *argv[]);
92
93         TrajectoryAnalysisModule *module_;
94         int                       debugLevel_;
95 };
96
97
98 TrajectoryAnalysisCommandLineRunner::Impl::Impl(
99         TrajectoryAnalysisModule *module)
100     : module_(module), debugLevel_(0)
101 {
102 }
103
104
105 TrajectoryAnalysisCommandLineRunner::Impl::~Impl()
106 {
107 }
108
109
110 void
111 TrajectoryAnalysisCommandLineRunner::Impl::printHelp(
112         const Options                        &options,
113         const TrajectoryAnalysisSettings     &settings,
114         const TrajectoryAnalysisRunnerCommon &common)
115 {
116     TrajectoryAnalysisRunnerCommon::HelpFlags flags = common.helpFlags();
117     if (flags != 0)
118     {
119         CommandLineHelpContext context(&File::standardError(),
120                                        eHelpOutputFormat_Console);
121         CommandLineHelpWriter(options)
122             .setShowDescriptions(flags & TrajectoryAnalysisRunnerCommon::efHelpShowDescriptions)
123             .setShowHidden(flags & TrajectoryAnalysisRunnerCommon::efHelpShowHidden)
124             .setTimeUnitString(settings.timeUnitManager().timeUnitAsString())
125             .writeHelp(context);
126     }
127 }
128
129
130 bool
131 TrajectoryAnalysisCommandLineRunner::Impl::parseOptions(
132         TrajectoryAnalysisSettings *settings,
133         TrajectoryAnalysisRunnerCommon *common,
134         SelectionCollection *selections,
135         int *argc, char *argv[])
136 {
137     Options options(NULL, NULL);
138     Options moduleOptions(module_->name(), module_->description());
139     Options commonOptions("common", "Common analysis control");
140     Options selectionOptions("selection", "Common selection control");
141     module_->initOptions(&moduleOptions, settings);
142     common->initOptions(&commonOptions);
143     selections->initOptions(&selectionOptions);
144
145     options.addSubSection(&commonOptions);
146     options.addSubSection(&selectionOptions);
147     options.addSubSection(&moduleOptions);
148
149     SelectionOptionManager seloptManager(selections);
150     setManagerForSelectionOptions(&options, &seloptManager);
151
152     {
153         CommandLineParser  parser(&options);
154         try
155         {
156             parser.parse(argc, argv);
157         }
158         catch (const UserInputError &ex)
159         {
160             printHelp(options, *settings, *common);
161             throw;
162         }
163         printHelp(options, *settings, *common);
164         common->scaleTimeOptions(&options);
165         options.finish();
166     }
167
168     if (!common->optionsFinished(&commonOptions))
169     {
170         return false;
171     }
172     module_->optionsFinished(&moduleOptions, settings);
173
174     common->initIndexGroups(selections);
175
176     // TODO: Check whether the input is a pipe.
177     bool bInteractive = true;
178     seloptManager.parseRequestedFromStdin(bInteractive);
179     common->doneIndexGroups(selections);
180
181     return true;
182 }
183
184
185 /********************************************************************
186  * TrajectoryAnalysisCommandLineRunner
187  */
188
189 TrajectoryAnalysisCommandLineRunner::TrajectoryAnalysisCommandLineRunner(
190         TrajectoryAnalysisModule *module)
191     : impl_(new Impl(module))
192 {
193 }
194
195
196 TrajectoryAnalysisCommandLineRunner::~TrajectoryAnalysisCommandLineRunner()
197 {
198 }
199
200
201 void
202 TrajectoryAnalysisCommandLineRunner::setSelectionDebugLevel(int debuglevel)
203 {
204     impl_->debugLevel_ = 1;
205 }
206
207
208 int
209 TrajectoryAnalysisCommandLineRunner::run(int argc, char *argv[])
210 {
211     TrajectoryAnalysisModule *module = impl_->module_;
212
213     SelectionCollection       selections;
214     selections.setDebugLevel(impl_->debugLevel_);
215
216     TrajectoryAnalysisSettings      settings;
217     TrajectoryAnalysisRunnerCommon  common(&settings);
218
219     if (!impl_->parseOptions(&settings, &common, &selections, &argc, argv))
220     {
221         return 0;
222     }
223
224     common.initTopology(&selections);
225     selections.compile();
226
227     const TopologyInformation &topology = common.topologyInformation();
228     module->initAnalysis(settings, topology);
229
230     // Load first frame.
231     common.initFirstFrame();
232     module->initAfterFirstFrame(common.frame());
233
234     t_pbc  pbc;
235     t_pbc *ppbc = settings.hasPBC() ? &pbc : NULL;
236
237     int    nframes = 0;
238     AnalysisDataParallelOptions         dataOptions;
239     TrajectoryAnalysisModuleDataPointer pdata(
240             module->startFrames(dataOptions, selections));
241     do
242     {
243         common.initFrame();
244         t_trxframe &frame = common.frame();
245         if (ppbc != NULL)
246         {
247             set_pbc(ppbc, topology.ePBC(), frame.box);
248         }
249
250         selections.evaluate(&frame, ppbc);
251         module->analyzeFrame(nframes, frame, ppbc, pdata.get());
252
253         nframes++;
254     }
255     while (common.readNextFrame());
256     module->finishFrames(pdata.get());
257     if (pdata.get() != NULL)
258     {
259         pdata->finish();
260     }
261     pdata.reset();
262
263     if (common.hasTrajectory())
264     {
265         fprintf(stderr, "Analyzed %d frames, last time %.3f\n",
266                 nframes, common.frame().time);
267     }
268     else
269     {
270         fprintf(stderr, "Analyzed topology coordinates\n");
271     }
272
273     // Restore the maximal groups for dynamic selections.
274     selections.evaluateFinal(nframes);
275
276     module->finishAnalysis(nframes);
277     module->writeOutput();
278
279     return 0;
280 }
281
282
283 void
284 TrajectoryAnalysisCommandLineRunner::writeHelp(const CommandLineHelpContext &context)
285 {
286     // TODO: This method duplicates some code from run() and Impl::printHelp().
287     // See how to best refactor it to share the common code.
288     SelectionCollection             selections;
289     TrajectoryAnalysisSettings      settings;
290     TrajectoryAnalysisRunnerCommon  common(&settings);
291
292     Options options(NULL, NULL);
293     Options moduleOptions(impl_->module_->name(), impl_->module_->description());
294     Options commonOptions("common", "Common analysis control");
295     Options selectionOptions("selection", "Common selection control");
296
297     impl_->module_->initOptions(&moduleOptions, &settings);
298     common.initOptions(&commonOptions);
299     selections.initOptions(&selectionOptions);
300
301     options.addSubSection(&commonOptions);
302     options.addSubSection(&selectionOptions);
303     options.addSubSection(&moduleOptions);
304
305     SelectionOptionManager seloptManager(&selections);
306     setManagerForSelectionOptions(&options, &seloptManager);
307
308     CommandLineHelpWriter(options)
309         .setShowDescriptions(true)
310         .setTimeUnitString(settings.timeUnitManager().timeUnitAsString())
311         .writeHelp(context);
312 }
313
314
315 /*! \internal \brief
316  * Command line module for a trajectory analysis module.
317  *
318  * \ingroup module_trajectoryanalysis
319  */
320 class TrajectoryAnalysisCommandLineRunner::Impl::RunnerCommandLineModule
321     : public CommandLineModuleInterface
322 {
323     public:
324         /*! \brief
325          * Constructs a module.
326          *
327          * \param[in] name         Name for the module.
328          * \param[in] description  One-line description for the module.
329          * \param[in] factory      Factory method to create the analysis module.
330          *
331          * Does not throw.  This is important for correct implementation of
332          * runAsMain().
333          */
334         RunnerCommandLineModule(const char *name, const char *description,
335                                 ModuleFactoryMethod factory)
336             : name_(name), description_(description), factory_(factory)
337         {
338         }
339
340         virtual const char *name() const { return name_; }
341         virtual const char *shortDescription() const { return description_; };
342
343         virtual int run(int argc, char *argv[]);
344         virtual void writeHelp(const CommandLineHelpContext &context) const;
345
346     private:
347         const char             *name_;
348         const char             *description_;
349         ModuleFactoryMethod     factory_;
350
351         GMX_DISALLOW_COPY_AND_ASSIGN(RunnerCommandLineModule);
352 };
353
354 int TrajectoryAnalysisCommandLineRunner::Impl::RunnerCommandLineModule::run(
355         int argc, char *argv[])
356 {
357     TrajectoryAnalysisModulePointer     module(factory_());
358     TrajectoryAnalysisCommandLineRunner runner(module.get());
359     return runner.run(argc, argv);
360 }
361
362 void TrajectoryAnalysisCommandLineRunner::Impl::RunnerCommandLineModule::writeHelp(
363         const CommandLineHelpContext &context) const
364 {
365     // TODO: Implement #969.
366     if (context.writerContext().outputFormat() != eHelpOutputFormat_Console)
367     {
368         return;
369     }
370     TrajectoryAnalysisModulePointer     module(factory_());
371     TrajectoryAnalysisCommandLineRunner runner(module.get());
372     runner.writeHelp(context);
373 }
374
375 // static
376 int
377 TrajectoryAnalysisCommandLineRunner::runAsMain(
378         int argc, char *argv[], ModuleFactoryMethod factory)
379 {
380     Impl::RunnerCommandLineModule module(NULL, NULL, factory);
381     return CommandLineModuleManager::runAsMainSingleModule(argc, argv, &module);
382 }
383
384 // static
385 void
386 TrajectoryAnalysisCommandLineRunner::registerModule(
387         CommandLineModuleManager *manager, const char *name,
388         const char *description, ModuleFactoryMethod factory)
389 {
390     CommandLineModulePointer module(
391             new Impl::RunnerCommandLineModule(name, description, factory));
392     manager->addModule(move(module));
393 }
394
395 } // namespace gmx