Add coolquotes
[gromacs.git] / src / gromacs / trajectoryanalysis / modules / select.cpp
blobde253b201a0fada8f2e213a4db5267974cf95abf
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2009,2010,2011,2012,2013,2014,2015,2016,2017,2018, 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.
35 /*! \internal \file
36 * \brief
37 * Implements gmx::analysismodules::Select.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_trajectoryanalysis
42 #include "gmxpre.h"
44 #include "select.h"
46 #include <cstdio>
47 #include <cstring>
49 #include <algorithm>
50 #include <set>
51 #include <string>
52 #include <vector>
54 #include "gromacs/analysisdata/analysisdata.h"
55 #include "gromacs/analysisdata/dataframe.h"
56 #include "gromacs/analysisdata/datamodule.h"
57 #include "gromacs/analysisdata/modules/average.h"
58 #include "gromacs/analysisdata/modules/lifetime.h"
59 #include "gromacs/analysisdata/modules/plot.h"
60 #include "gromacs/fileio/gmxfio.h"
61 #include "gromacs/fileio/trxio.h"
62 #include "gromacs/options/basicoptions.h"
63 #include "gromacs/options/filenameoption.h"
64 #include "gromacs/options/ioptionscontainer.h"
65 #include "gromacs/selection/selection.h"
66 #include "gromacs/selection/selectionoption.h"
67 #include "gromacs/topology/topology.h"
68 #include "gromacs/trajectory/trajectoryframe.h"
69 #include "gromacs/trajectoryanalysis/analysissettings.h"
70 #include "gromacs/trajectoryanalysis/topologyinformation.h"
71 #include "gromacs/utility/arrayref.h"
72 #include "gromacs/utility/exceptions.h"
73 #include "gromacs/utility/gmxassert.h"
74 #include "gromacs/utility/smalloc.h"
75 #include "gromacs/utility/stringutil.h"
76 #include "gromacs/utility/unique_cptr.h"
78 namespace gmx
81 namespace analysismodules
84 namespace
87 /*! \internal \brief
88 * Data module for writing index files.
90 * \ingroup module_analysisdata
92 class IndexFileWriterModule : public AnalysisDataModuleSerial
94 public:
95 IndexFileWriterModule();
96 ~IndexFileWriterModule() override;
98 //! Sets the file name to write the index file to.
99 void setFileName(const std::string &fnm);
100 /*! \brief
101 * Adds information about a group to be printed.
103 * Must be called for each group present in the input data.
105 void addGroup(const std::string &name, bool bDynamic);
107 int flags() const override;
109 void dataStarted(AbstractAnalysisData *data) override;
110 void frameStarted(const AnalysisDataFrameHeader &header) override;
111 void pointsAdded(const AnalysisDataPointSetRef &points) override;
112 void frameFinished(const AnalysisDataFrameHeader &header) override;
113 void dataFinished() override;
115 private:
116 void closeFile();
118 struct GroupInfo
120 GroupInfo(const std::string &name, bool bDynamic)
121 : name(name), bDynamic(bDynamic)
124 std::string name;
125 bool bDynamic;
128 std::string fnm_;
129 std::vector<GroupInfo> groups_;
130 FILE *fp_;
131 int currentGroup_;
132 int currentSize_;
133 bool bAnyWritten_;
136 /********************************************************************
137 * IndexFileWriterModule
140 IndexFileWriterModule::IndexFileWriterModule()
141 : fp_(nullptr), currentGroup_(-1), currentSize_(0), bAnyWritten_(false)
146 IndexFileWriterModule::~IndexFileWriterModule()
148 closeFile();
152 void IndexFileWriterModule::closeFile()
154 if (fp_ != nullptr)
156 gmx_fio_fclose(fp_);
157 fp_ = nullptr;
162 void IndexFileWriterModule::setFileName(const std::string &fnm)
164 fnm_ = fnm;
168 void IndexFileWriterModule::addGroup(const std::string &name, bool bDynamic)
170 std::string newName(name);
171 std::replace(newName.begin(), newName.end(), ' ', '_');
172 groups_.emplace_back(newName, bDynamic);
176 int IndexFileWriterModule::flags() const
178 return efAllowMulticolumn | efAllowMultipoint;
182 void IndexFileWriterModule::dataStarted(AbstractAnalysisData * /*data*/)
184 if (!fnm_.empty())
186 fp_ = gmx_fio_fopen(fnm_.c_str(), "w");
191 void IndexFileWriterModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
193 bAnyWritten_ = false;
194 currentGroup_ = -1;
198 void
199 IndexFileWriterModule::pointsAdded(const AnalysisDataPointSetRef &points)
201 if (fp_ == nullptr)
203 return;
205 bool bFirstFrame = (points.frameIndex() == 0);
206 if (points.firstColumn() == 0)
208 ++currentGroup_;
209 GMX_RELEASE_ASSERT(currentGroup_ < static_cast<int>(groups_.size()),
210 "Too few groups initialized");
211 if (bFirstFrame || groups_[currentGroup_].bDynamic)
213 if (!bFirstFrame || currentGroup_ > 0)
215 std::fprintf(fp_, "\n\n");
217 std::string name = groups_[currentGroup_].name;
218 if (groups_[currentGroup_].bDynamic)
220 name += formatString("_f%d_t%.3f", points.frameIndex(), points.x());
222 std::fprintf(fp_, "[ %s ]", name.c_str());
223 bAnyWritten_ = true;
224 currentSize_ = 0;
227 else
229 if (bFirstFrame || groups_[currentGroup_].bDynamic)
231 if (currentSize_ % 15 == 0)
233 std::fprintf(fp_, "\n");
235 std::fprintf(fp_, "%4d ", static_cast<int>(points.y(0)));
236 ++currentSize_;
242 void IndexFileWriterModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
247 void IndexFileWriterModule::dataFinished()
249 if (fp_ != nullptr)
251 std::fprintf(fp_, "\n");
253 closeFile();
256 /********************************************************************
257 * Select
260 //! How to identify residues in output files.
261 enum ResidueNumbering
263 ResidueNumbering_ByNumber,
264 ResidueNumbering_ByIndex
266 //! Which atoms to write out to PDB files.
267 enum PdbAtomsSelection
269 PdbAtomsSelection_All,
270 PdbAtomsSelection_MaxSelection,
271 PdbAtomsSelection_Selected
273 //! String values corresponding to ResidueNumbering.
274 const char *const cResNumberEnum[] = { "number", "index" };
275 //! String values corresponding to PdbAtomsSelection.
276 const char *const cPDBAtomsEnum[] = { "all", "maxsel", "selected" };
278 class Select : public TrajectoryAnalysisModule
280 public:
281 Select();
283 void initOptions(IOptionsContainer *options,
284 TrajectoryAnalysisSettings *settings) override;
285 void optionsFinished(TrajectoryAnalysisSettings *settings) override;
286 void initAnalysis(const TrajectoryAnalysisSettings &settings,
287 const TopologyInformation &top) override;
289 void analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
290 TrajectoryAnalysisModuleData *pdata) override;
292 void finishAnalysis(int nframes) override;
293 void writeOutput() override;
295 private:
296 SelectionList sel_;
298 std::string fnSize_;
299 std::string fnFrac_;
300 std::string fnIndex_;
301 std::string fnNdx_;
302 std::string fnMask_;
303 std::string fnOccupancy_;
304 std::string fnPDB_;
305 std::string fnLifetime_;
306 bool bTotNorm_;
307 bool bFracNorm_;
308 bool bResInd_;
309 bool bCumulativeLifetimes_;
310 ResidueNumbering resNumberType_;
311 PdbAtomsSelection pdbAtoms_;
313 //! The input topology.
314 const TopologyInformation *top_;
315 std::vector<int> totsize_;
316 AnalysisData sdata_;
317 AnalysisData cdata_;
318 AnalysisData idata_;
319 AnalysisData mdata_;
320 AnalysisDataAverageModulePointer occupancyModule_;
321 AnalysisDataLifetimeModulePointer lifetimeModule_;
324 Select::Select()
325 : bTotNorm_(false), bFracNorm_(false), bResInd_(false),
326 bCumulativeLifetimes_(true), resNumberType_(ResidueNumbering_ByNumber),
327 pdbAtoms_(PdbAtomsSelection_All), top_(nullptr),
328 occupancyModule_(new AnalysisDataAverageModule()),
329 lifetimeModule_(new AnalysisDataLifetimeModule())
331 mdata_.addModule(occupancyModule_);
332 mdata_.addModule(lifetimeModule_);
334 registerAnalysisDataset(&sdata_, "size");
335 registerAnalysisDataset(&cdata_, "cfrac");
336 idata_.setColumnCount(0, 2);
337 idata_.setMultipoint(true);
338 registerAnalysisDataset(&idata_, "index");
339 registerAnalysisDataset(&mdata_, "mask");
340 occupancyModule_->setXAxis(1.0, 1.0);
341 registerBasicDataset(occupancyModule_.get(), "occupancy");
342 registerBasicDataset(lifetimeModule_.get(), "lifetime");
346 void
347 Select::initOptions(IOptionsContainer *options, TrajectoryAnalysisSettings *settings)
349 static const char *const desc[] = {
350 "[THISMODULE] writes out basic data about dynamic selections.",
351 "It can be used for some simple analyses, or the output can",
352 "be combined with output from other programs and/or external",
353 "analysis programs to calculate more complex things.",
354 "For detailed help on the selection syntax, please use",
355 "[TT]gmx help selections[tt].",
357 "Any combination of the output options is possible, but note",
358 "that [TT]-om[tt] only operates on the first selection.",
359 "Also note that if you provide no output options, no output is",
360 "produced.",
362 "With [TT]-os[tt], calculates the number of positions in each",
363 "selection for each frame. With [TT]-norm[tt], the output is",
364 "between 0 and 1 and describes the fraction from the maximum",
365 "number of positions (e.g., for selection 'resname RA and x < 5'",
366 "the maximum number of positions is the number of atoms in",
367 "RA residues). With [TT]-cfnorm[tt], the output is divided",
368 "by the fraction covered by the selection.",
369 "[TT]-norm[tt] and [TT]-cfnorm[tt] can be specified independently",
370 "of one another.",
372 "With [TT]-oc[tt], the fraction covered by each selection is",
373 "written out as a function of time.",
375 "With [TT]-oi[tt], the selected atoms/residues/molecules are",
376 "written out as a function of time. In the output, the first",
377 "column contains the frame time, the second contains the number",
378 "of positions, followed by the atom/residue/molecule numbers.",
379 "If more than one selection is specified, the size of the second",
380 "group immediately follows the last number of the first group",
381 "and so on.",
383 "With [TT]-on[tt], the selected atoms are written as a index file",
384 "compatible with [TT]make_ndx[tt] and the analyzing tools. Each selection",
385 "is written as a selection group and for dynamic selections a",
386 "group is written for each frame.",
388 "For residue numbers, the output of [TT]-oi[tt] can be controlled",
389 "with [TT]-resnr[tt]: [TT]number[tt] (default) prints the residue",
390 "numbers as they appear in the input file, while [TT]index[tt] prints",
391 "unique numbers assigned to the residues in the order they appear",
392 "in the input file, starting with 1. The former is more intuitive,",
393 "but if the input contains multiple residues with the same number,",
394 "the output can be less useful.",
396 "With [TT]-om[tt], a mask is printed for the first selection",
397 "as a function of time. Each line in the output corresponds to",
398 "one frame, and contains either 0/1 for each atom/residue/molecule",
399 "possibly selected. 1 stands for the atom/residue/molecule being",
400 "selected for the current frame, 0 for not selected.",
402 "With [TT]-of[tt], the occupancy fraction of each position (i.e.,",
403 "the fraction of frames where the position is selected) is",
404 "printed.",
406 "With [TT]-ofpdb[tt], a PDB file is written out where the occupancy",
407 "column is filled with the occupancy fraction of each atom in the",
408 "selection. The coordinates in the PDB file will be those from the",
409 "input topology. [TT]-pdbatoms[tt] can be used to control which atoms",
410 "appear in the output PDB file: with [TT]all[tt] all atoms are",
411 "present, with [TT]maxsel[tt] all atoms possibly selected by the",
412 "selection are present, and with [TT]selected[tt] only atoms that are",
413 "selected at least in one frame are present.",
415 "With [TT]-olt[tt], a histogram is produced that shows the number of",
416 "selected positions as a function of the time the position was",
417 "continuously selected. [TT]-cumlt[tt] can be used to control whether",
418 "subintervals of longer intervals are included in the histogram.[PAR]",
419 "[TT]-om[tt], [TT]-of[tt], and [TT]-olt[tt] only make sense with",
420 "dynamic selections.",
422 "To plot coordinates for selections, use [gmx-trajectory]."
425 settings->setHelpText(desc);
427 options->addOption(FileNameOption("os").filetype(eftPlot).outputFile()
428 .store(&fnSize_).defaultBasename("size")
429 .description("Number of positions in each selection"));
430 options->addOption(FileNameOption("oc").filetype(eftPlot).outputFile()
431 .store(&fnFrac_).defaultBasename("cfrac")
432 .description("Covered fraction for each selection"));
433 options->addOption(FileNameOption("oi").filetype(eftGenericData).outputFile()
434 .store(&fnIndex_).defaultBasename("index")
435 .description("Indices selected by each selection"));
436 options->addOption(FileNameOption("on").filetype(eftIndex).outputFile()
437 .store(&fnNdx_).defaultBasename("index")
438 .description("Index file from the selection"));
439 options->addOption(FileNameOption("om").filetype(eftPlot).outputFile()
440 .store(&fnMask_).defaultBasename("mask")
441 .description("Mask for selected positions"));
442 options->addOption(FileNameOption("of").filetype(eftPlot).outputFile()
443 .store(&fnOccupancy_).defaultBasename("occupancy")
444 .description("Occupied fraction for selected positions"));
445 options->addOption(FileNameOption("ofpdb").filetype(eftPDB).outputFile()
446 .store(&fnPDB_).defaultBasename("occupancy")
447 .description("PDB file with occupied fraction for selected positions"));
448 options->addOption(FileNameOption("olt").filetype(eftPlot).outputFile()
449 .store(&fnLifetime_).defaultBasename("lifetime")
450 .description("Lifetime histogram"));
452 options->addOption(SelectionOption("select").storeVector(&sel_)
453 .required().multiValue()
454 .description("Selections to analyze"));
456 options->addOption(BooleanOption("norm").store(&bTotNorm_)
457 .description("Normalize by total number of positions with -os"));
458 options->addOption(BooleanOption("cfnorm").store(&bFracNorm_)
459 .description("Normalize by covered fraction with -os"));
460 options->addOption(EnumOption<ResidueNumbering>("resnr").store(&resNumberType_)
461 .enumValue(cResNumberEnum)
462 .description("Residue number output type with -oi and -on"));
463 options->addOption(EnumOption<PdbAtomsSelection>("pdbatoms").store(&pdbAtoms_)
464 .enumValue(cPDBAtomsEnum)
465 .description("Atoms to write with -ofpdb"));
466 options->addOption(BooleanOption("cumlt").store(&bCumulativeLifetimes_)
467 .description("Cumulate subintervals of longer intervals in -olt"));
470 void
471 Select::optionsFinished(TrajectoryAnalysisSettings *settings)
473 if (!fnPDB_.empty())
475 settings->setFlag(TrajectoryAnalysisSettings::efRequireTop);
476 settings->setFlag(TrajectoryAnalysisSettings::efUseTopX);
480 void
481 Select::initAnalysis(const TrajectoryAnalysisSettings &settings,
482 const TopologyInformation &top)
484 bResInd_ = (resNumberType_ == ResidueNumbering_ByIndex);
486 for (SelectionList::iterator i = sel_.begin(); i != sel_.end(); ++i)
488 i->initCoveredFraction(CFRAC_SOLIDANGLE);
491 // TODO: For large systems, a float may not have enough precision
492 sdata_.setColumnCount(0, sel_.size());
493 totsize_.reserve(sel_.size());
494 for (size_t g = 0; g < sel_.size(); ++g)
496 totsize_.push_back(sel_[g].posCount());
498 if (!fnSize_.empty())
500 AnalysisDataPlotModulePointer plot(
501 new AnalysisDataPlotModule(settings.plotSettings()));
502 plot->setFileName(fnSize_);
503 plot->setTitle("Selection size");
504 plot->setXAxisIsTime();
505 plot->setYLabel("Number");
506 for (size_t g = 0; g < sel_.size(); ++g)
508 plot->appendLegend(sel_[g].name());
510 sdata_.addModule(plot);
513 cdata_.setColumnCount(0, sel_.size());
514 if (!fnFrac_.empty())
516 AnalysisDataPlotModulePointer plot(
517 new AnalysisDataPlotModule(settings.plotSettings()));
518 plot->setFileName(fnFrac_);
519 plot->setTitle("Covered fraction");
520 plot->setXAxisIsTime();
521 plot->setYLabel("Fraction");
522 plot->setYFormat(6, 4);
523 for (size_t g = 0; g < sel_.size(); ++g)
525 plot->appendLegend(sel_[g].name());
527 cdata_.addModule(plot);
530 // TODO: For large systems, a float may not have enough precision
531 if (!fnIndex_.empty())
533 AnalysisDataPlotModulePointer plot(
534 new AnalysisDataPlotModule(settings.plotSettings()));
535 plot->setFileName(fnIndex_);
536 plot->setPlainOutput(true);
537 plot->setYFormat(4, 0);
538 idata_.addModule(plot);
540 if (!fnNdx_.empty())
542 std::shared_ptr<IndexFileWriterModule> writer(new IndexFileWriterModule());
543 writer->setFileName(fnNdx_);
544 for (size_t g = 0; g < sel_.size(); ++g)
546 writer->addGroup(sel_[g].name(), sel_[g].isDynamic());
548 idata_.addModule(writer);
551 mdata_.setDataSetCount(sel_.size());
552 for (size_t g = 0; g < sel_.size(); ++g)
554 mdata_.setColumnCount(g, sel_[g].posCount());
556 lifetimeModule_->setCumulative(bCumulativeLifetimes_);
557 if (!fnMask_.empty())
559 AnalysisDataPlotModulePointer plot(
560 new AnalysisDataPlotModule(settings.plotSettings()));
561 plot->setFileName(fnMask_);
562 plot->setTitle("Selection mask");
563 plot->setXAxisIsTime();
564 plot->setYLabel("Occupancy");
565 plot->setYFormat(1, 0);
566 // TODO: Add legend? (there can be massive amount of columns)
567 mdata_.addModule(plot);
569 if (!fnOccupancy_.empty())
571 AnalysisDataPlotModulePointer plot(
572 new AnalysisDataPlotModule(settings.plotSettings()));
573 plot->setFileName(fnOccupancy_);
574 plot->setTitle("Fraction of time selection matches");
575 plot->setXLabel("Selected position");
576 plot->setYLabel("Occupied fraction");
577 for (size_t g = 0; g < sel_.size(); ++g)
579 plot->appendLegend(sel_[g].name());
581 occupancyModule_->addModule(plot);
583 if (!fnLifetime_.empty())
585 AnalysisDataPlotModulePointer plot(
586 new AnalysisDataPlotModule(settings.plotSettings()));
587 plot->setFileName(fnLifetime_);
588 plot->setTitle("Lifetime histogram");
589 plot->setXAxisIsTime();
590 plot->setYLabel("Number of occurrences");
591 for (size_t g = 0; g < sel_.size(); ++g)
593 plot->appendLegend(sel_[g].name());
595 lifetimeModule_->addModule(plot);
598 top_ = &top;
602 void
603 Select::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc * /* pbc */,
604 TrajectoryAnalysisModuleData *pdata)
606 AnalysisDataHandle sdh = pdata->dataHandle(sdata_);
607 AnalysisDataHandle cdh = pdata->dataHandle(cdata_);
608 AnalysisDataHandle idh = pdata->dataHandle(idata_);
609 AnalysisDataHandle mdh = pdata->dataHandle(mdata_);
610 const SelectionList &sel = pdata->parallelSelections(sel_);
612 sdh.startFrame(frnr, fr.time);
613 for (size_t g = 0; g < sel.size(); ++g)
615 real normfac = bFracNorm_ ? 1.0 / sel[g].coveredFraction() : 1.0;
616 if (bTotNorm_)
618 normfac /= totsize_[g];
620 sdh.setPoint(g, sel[g].posCount() * normfac);
622 sdh.finishFrame();
624 cdh.startFrame(frnr, fr.time);
625 for (size_t g = 0; g < sel.size(); ++g)
627 cdh.setPoint(g, sel[g].coveredFraction());
629 cdh.finishFrame();
631 idh.startFrame(frnr, fr.time);
632 for (size_t g = 0; g < sel.size(); ++g)
634 idh.setPoint(0, sel[g].posCount());
635 idh.finishPointSet();
636 for (int i = 0; i < sel[g].posCount(); ++i)
638 const SelectionPosition &p = sel[g].position(i);
639 if (sel[g].type() == INDEX_RES && !bResInd_)
641 idh.setPoint(1, top_->atoms()->resinfo[p.mappedId()].nr);
643 else
645 idh.setPoint(1, p.mappedId() + 1);
647 idh.finishPointSet();
650 idh.finishFrame();
652 mdh.startFrame(frnr, fr.time);
653 for (size_t g = 0; g < sel.size(); ++g)
655 mdh.selectDataSet(g);
656 for (int i = 0; i < totsize_[g]; ++i)
658 mdh.setPoint(i, 0);
660 for (int i = 0; i < sel[g].posCount(); ++i)
662 mdh.setPoint(sel[g].position(i).refId(), 1);
665 mdh.finishFrame();
669 void
670 Select::finishAnalysis(int /*nframes*/)
675 void
676 Select::writeOutput()
678 if (!fnPDB_.empty())
680 GMX_RELEASE_ASSERT(top_->hasTopology(),
681 "Topology should have been loaded or an error given earlier");
682 auto atoms = top_->copyAtoms();
683 if (!atoms->havePdbInfo)
685 snew(atoms->pdbinfo, atoms->nr);
686 atoms->havePdbInfo = TRUE;
688 for (int i = 0; i < atoms->nr; ++i)
690 atoms->pdbinfo[i].occup = 0.0;
692 for (size_t g = 0; g < sel_.size(); ++g)
694 for (int i = 0; i < sel_[g].posCount(); ++i)
696 ArrayRef<const int> atomIndices
697 = sel_[g].position(i).atomIndices();
698 ArrayRef<const int>::const_iterator ai;
699 for (ai = atomIndices.begin(); ai != atomIndices.end(); ++ai)
701 atoms->pdbinfo[*ai].occup += occupancyModule_->average(g, i);
706 std::vector<RVec> x = copyOf(top_->x());
707 t_trxframe fr;
708 clear_trxframe(&fr, TRUE);
709 fr.bAtoms = TRUE;
710 fr.atoms = atoms.get();
711 fr.bX = TRUE;
712 fr.bBox = TRUE;
713 fr.x = as_rvec_array(x.data());
714 top_->getBox(fr.box);
716 switch (pdbAtoms_)
718 case PdbAtomsSelection_All:
720 t_trxstatus *status = open_trx(fnPDB_.c_str(), "w");
721 write_trxframe(status, &fr, nullptr);
722 close_trx(status);
723 break;
725 case PdbAtomsSelection_MaxSelection:
727 std::set<int> atomIndicesSet;
728 for (size_t g = 0; g < sel_.size(); ++g)
730 ArrayRef<const int> atomIndices = sel_[g].atomIndices();
731 atomIndicesSet.insert(atomIndices.begin(), atomIndices.end());
733 std::vector<int> allAtomIndices(atomIndicesSet.begin(),
734 atomIndicesSet.end());
735 t_trxstatus *status = open_trx(fnPDB_.c_str(), "w");
736 write_trxframe_indexed(status, &fr, allAtomIndices.size(),
737 allAtomIndices.data(), nullptr);
738 close_trx(status);
739 break;
741 case PdbAtomsSelection_Selected:
743 std::vector<int> indices;
744 for (int i = 0; i < atoms->nr; ++i)
746 if (atoms->pdbinfo[i].occup > 0.0)
748 indices.push_back(i);
751 t_trxstatus *status = open_trx(fnPDB_.c_str(), "w");
752 write_trxframe_indexed(status, &fr, indices.size(), indices.data(), nullptr);
753 close_trx(status);
754 break;
756 default:
757 GMX_RELEASE_ASSERT(false,
758 "Mismatch between -pdbatoms enum values and implementation");
763 } // namespace
765 const char SelectInfo::name[] = "select";
766 const char SelectInfo::shortDescription[] =
767 "Print general information about selections";
769 TrajectoryAnalysisModulePointer SelectInfo::create()
771 return TrajectoryAnalysisModulePointer(new Select);
774 } // namespace analysismodules
776 } // namespace gmx