Merge branch 'release-4-6'
[alexxy/gromacs.git] / src / gromacs / trajectoryanalysis / analysismodule.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 classes in analysismodule.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_trajectoryanalysis
41  */
42 #include "gromacs/trajectoryanalysis/analysismodule.h"
43
44 #include <utility>
45
46 #include "gromacs/analysisdata/analysisdata.h"
47 #include "gromacs/selection/selection.h"
48 #include "gromacs/utility/exceptions.h"
49 #include "gromacs/utility/gmxassert.h"
50
51 namespace gmx
52 {
53
54 /********************************************************************
55  * TrajectoryAnalysisModule::Impl
56  */
57
58 /*! \internal \brief
59  * Private implementation class for TrajectoryAnalysisModule.
60  *
61  * \ingroup module_trajectoryanalysis
62  */
63 class TrajectoryAnalysisModule::Impl
64 {
65     public:
66         //! Container that associates a data set with its name.
67         typedef std::map<std::string, AbstractAnalysisData *> DatasetContainer;
68         //! Container that associates a AnalysisData object with its name.
69         typedef std::map<std::string, AnalysisData *> AnalysisDatasetContainer;
70
71         //! Initializes analysis module data with given name and description.
72         Impl(const char *name, const char *description)
73             : name_(name), description_(description)
74         {
75         }
76
77         //! Name of the module.
78         std::string                     name_;
79         //! Description of the module.
80         std::string                     description_;
81         //! List of registered data set names.
82         std::vector<std::string>        datasetNames_;
83         /*! \brief
84          * Keeps all registered data sets.
85          *
86          * This container also includes datasets from \a analysisDatasets_.
87          */
88         DatasetContainer                datasets_;
89         //! Keeps registered AnalysisData objects.
90         AnalysisDatasetContainer        analysisDatasets_;
91 };
92
93 /********************************************************************
94  * TrajectoryAnalysisModuleData::Impl
95  */
96
97 /*! \internal \brief
98  * Private implementation class for TrajectoryAnalysisModuleData.
99  *
100  * \ingroup module_trajectoryanalysis
101  */
102 class TrajectoryAnalysisModuleData::Impl
103 {
104     public:
105         //! Container that associates a data handle to its AnalysisData object.
106         typedef std::map<const AnalysisData *, AnalysisDataHandle>
107             HandleContainer;
108
109         //! \copydoc TrajectoryAnalysisModuleData::TrajectoryAnalysisModuleData()
110         Impl(TrajectoryAnalysisModule          *module,
111              const AnalysisDataParallelOptions &opt,
112              const SelectionCollection         &selections);
113
114         //! Keeps a data handle for each AnalysisData object.
115         HandleContainer            handles_;
116         //! Stores thread-local selections.
117         const SelectionCollection &selections_;
118 };
119
120 TrajectoryAnalysisModuleData::Impl::Impl(
121         TrajectoryAnalysisModule          *module,
122         const AnalysisDataParallelOptions &opt,
123         const SelectionCollection         &selections)
124     : selections_(selections)
125 {
126     TrajectoryAnalysisModule::Impl::AnalysisDatasetContainer::const_iterator i;
127     for (i = module->impl_->analysisDatasets_.begin();
128          i != module->impl_->analysisDatasets_.end(); ++i)
129     {
130         handles_.insert(std::make_pair(i->second, i->second->startData(opt)));
131     }
132 }
133
134
135 /********************************************************************
136  * TrajectoryAnalysisModuleData
137  */
138
139 TrajectoryAnalysisModuleData::TrajectoryAnalysisModuleData(
140         TrajectoryAnalysisModule          *module,
141         const AnalysisDataParallelOptions &opt,
142         const SelectionCollection         &selections)
143     : impl_(new Impl(module, opt, selections))
144 {
145 }
146
147
148 TrajectoryAnalysisModuleData::~TrajectoryAnalysisModuleData()
149 {
150 }
151
152
153 void TrajectoryAnalysisModuleData::finishDataHandles()
154 {
155     // FIXME: Call finishData() for all handles even if one throws
156     Impl::HandleContainer::iterator i;
157     for (i = impl_->handles_.begin(); i != impl_->handles_.end(); ++i)
158     {
159         i->second.finishData();
160     }
161     impl_->handles_.clear();
162 }
163
164
165 AnalysisDataHandle
166 TrajectoryAnalysisModuleData::dataHandle(const AnalysisData &data)
167 {
168     Impl::HandleContainer::const_iterator i = impl_->handles_.find(&data);
169     GMX_RELEASE_ASSERT(i != impl_->handles_.end(),
170                        "Data handle requested on unknown dataset");
171     return i->second;
172 }
173
174
175 Selection TrajectoryAnalysisModuleData::parallelSelection(const Selection &selection)
176 {
177     // TODO: Implement properly.
178     return selection;
179 }
180
181
182 SelectionList
183 TrajectoryAnalysisModuleData::parallelSelections(const SelectionList &selections)
184 {
185     // TODO: Consider an implementation that does not allocate memory every time.
186     SelectionList                 newSelections;
187     newSelections.reserve(selections.size());
188     SelectionList::const_iterator i = selections.begin();
189     for (; i != selections.end(); ++i)
190     {
191         newSelections.push_back(parallelSelection(*i));
192     }
193     return newSelections;
194 }
195
196
197 /********************************************************************
198  * TrajectoryAnalysisModuleDataBasic
199  */
200
201 namespace
202 {
203
204 /*! \internal \brief
205  * Basic thread-local trajectory analysis data storage class.
206  *
207  * Most simple tools should only require data handles and selections to be
208  * thread-local, so this class implements just that.
209  *
210  * \ingroup module_trajectoryanalysis
211  */
212 class TrajectoryAnalysisModuleDataBasic : public TrajectoryAnalysisModuleData
213 {
214     public:
215         /*! \brief
216          * Initializes thread-local storage for data handles and selections.
217          *
218          * \param[in] module     Analysis module to use for data objects.
219          * \param[in] opt        Data parallelization options.
220          * \param[in] selections Thread-local selection collection.
221          */
222         TrajectoryAnalysisModuleDataBasic(TrajectoryAnalysisModule          *module,
223                                           const AnalysisDataParallelOptions &opt,
224                                           const SelectionCollection         &selections);
225
226         virtual void finish();
227 };
228
229 TrajectoryAnalysisModuleDataBasic::TrajectoryAnalysisModuleDataBasic(
230         TrajectoryAnalysisModule          *module,
231         const AnalysisDataParallelOptions &opt,
232         const SelectionCollection         &selections)
233     : TrajectoryAnalysisModuleData(module, opt, selections)
234 {
235 }
236
237
238 void
239 TrajectoryAnalysisModuleDataBasic::finish()
240 {
241     finishDataHandles();
242 }
243
244 }   // namespace
245
246
247 /********************************************************************
248  * TrajectoryAnalysisModule
249  */
250
251 TrajectoryAnalysisModule::TrajectoryAnalysisModule(const char *name,
252                                                    const char *description)
253     : impl_(new Impl(name, description))
254 {
255 }
256
257
258 TrajectoryAnalysisModule::~TrajectoryAnalysisModule()
259 {
260 }
261
262
263 void TrajectoryAnalysisModule::optionsFinished(
264         Options                    * /*options*/,
265         TrajectoryAnalysisSettings * /*settings*/)
266 {
267 }
268
269
270 void TrajectoryAnalysisModule::initAfterFirstFrame(const t_trxframe & /*fr*/)
271 {
272 }
273
274
275 TrajectoryAnalysisModuleDataPointer
276 TrajectoryAnalysisModule::startFrames(const AnalysisDataParallelOptions &opt,
277                                       const SelectionCollection         &selections)
278 {
279     return TrajectoryAnalysisModuleDataPointer(
280             new TrajectoryAnalysisModuleDataBasic(this, opt, selections));
281 }
282
283
284 void TrajectoryAnalysisModule::finishFrames(TrajectoryAnalysisModuleData * /*pdata*/)
285 {
286 }
287
288
289 const char *TrajectoryAnalysisModule::name() const
290 {
291     return impl_->name_.c_str();
292 }
293
294
295 const char *TrajectoryAnalysisModule::description() const
296 {
297     return impl_->description_.c_str();
298 }
299
300
301 int TrajectoryAnalysisModule::datasetCount() const
302 {
303     return impl_->datasetNames_.size();
304 }
305
306
307 const std::vector<std::string> &TrajectoryAnalysisModule::datasetNames() const
308 {
309     return impl_->datasetNames_;
310 }
311
312
313 AbstractAnalysisData &TrajectoryAnalysisModule::datasetFromIndex(int index) const
314 {
315     if (index < 0 || index >= datasetCount())
316     {
317         GMX_THROW(APIError("Out of range data set index"));
318     }
319     Impl::DatasetContainer::const_iterator item
320         = impl_->datasets_.find(impl_->datasetNames_[index]);
321     GMX_RELEASE_ASSERT(item != impl_->datasets_.end(),
322                        "Inconsistent data set names");
323     return *item->second;
324 }
325
326
327 AbstractAnalysisData &TrajectoryAnalysisModule::datasetFromName(const char *name) const
328 {
329     Impl::DatasetContainer::const_iterator item = impl_->datasets_.find(name);
330     if (item == impl_->datasets_.end())
331     {
332         GMX_THROW(APIError("Unknown data set name"));
333     }
334     return *item->second;
335 }
336
337
338 void TrajectoryAnalysisModule::registerBasicDataset(AbstractAnalysisData *data,
339                                                     const char           *name)
340 {
341     GMX_RELEASE_ASSERT(data != NULL, "Attempting to register NULL data");
342     // TODO: Strong exception safety should be possible to implement.
343     GMX_RELEASE_ASSERT(impl_->datasets_.find(name) == impl_->datasets_.end(),
344                        "Duplicate data set name registered");
345     impl_->datasets_[name] = data;
346     impl_->datasetNames_.push_back(name);
347 }
348
349
350 void TrajectoryAnalysisModule::registerAnalysisDataset(AnalysisData *data,
351                                                        const char   *name)
352 {
353     // TODO: Strong exception safety should be possible to implement.
354     registerBasicDataset(data, name);
355     impl_->analysisDatasets_[name] = data;
356 }
357
358 } // namespace gmx