void TrajectoryAnalysisRunnerCommon::optionsFinished() { if (impl_->trjfile_.empty() && impl_->topfile_.empty()) { GMX_THROW(InconsistentInputError("No trajectory or topology provided, nothing to do!")); } if (impl_->trajectoryGroup_.isValid() && impl_->trjfile_.empty()) { GMX_THROW(InconsistentInputError("-fgroup only makes sense together with a trajectory (-f)")); } impl_->settings_.impl_->plotSettings.setTimeUnit(impl_->settings_.timeUnit()); if (impl_->bStartTimeSet_) { setTimeValue(TBEGIN, impl_->startTime_); } if (impl_->bEndTimeSet_) { setTimeValue(TEND, impl_->endTime_); } if (impl_->bDeltaTimeSet_) { setTimeValue(TDELTA, impl_->deltaTime_); } }
void SelectionTreeElement::resolveIndexGroupReference( gmx_ana_indexgrps_t *grps, int natoms) { GMX_RELEASE_ASSERT(type == SEL_GROUPREF, "Should only be called for index group reference elements"); if (grps == NULL) { std::string message = formatString( "Cannot match '%s', because index groups are not available.", name().c_str()); GMX_THROW(InconsistentInputError(message)); } gmx_ana_index_t foundGroup; std::string foundName; if (u.gref.name != NULL) { if (!gmx_ana_indexgrps_find(&foundGroup, &foundName, grps, u.gref.name)) { std::string message = formatString( "Cannot match '%s', because no such index group can be found.", name().c_str()); GMX_THROW(InconsistentInputError(message)); } } else { if (!gmx_ana_indexgrps_extract(&foundGroup, &foundName, grps, u.gref.id)) { std::string message = formatString( "Cannot match '%s', because no such index group can be found.", name().c_str()); GMX_THROW(InconsistentInputError(message)); } } if (!gmx_ana_index_check_sorted(&foundGroup)) { flags |= SEL_UNSORTED; } sfree(u.gref.name); type = SEL_CONST; gmx_ana_index_set(&u.cgrp, foundGroup.isize, foundGroup.index, foundGroup.nalloc_index); setName(foundName); if (natoms > 0) { checkIndexGroup(natoms); } }
void SelectionCollection::setTopology(t_topology *top, int natoms) { GMX_RELEASE_ASSERT(natoms > 0 || top != NULL, "The number of atoms must be given if there is no topology"); // Get the number of atoms from the topology if it is not given. if (natoms <= 0) { natoms = top->atoms.nr; } if (impl_->bExternalGroupsSet_) { ExceptionInitializer errors("Invalid index group references encountered"); SelectionTreeElementPointer root = impl_->sc_.root; while (root) { checkExternalGroups(root, natoms, &errors); root = root->next; } if (errors.hasNestedExceptions()) { GMX_THROW(InconsistentInputError(errors)); } } gmx_ana_selcollection_t *sc = &impl_->sc_; // Do this first, as it allocates memory, while the others don't throw. gmx_ana_index_init_simple(&sc->gall, natoms); sc->pcc.setTopology(top); sc->top = top; }
void TrajectoryAnalysisRunnerCommon::Impl::initTopology(bool required) { // Return immediately if the topology has already been loaded. if (topInfo_.hasTopology()) { return; } if (required && topfile_.empty()) { GMX_THROW(InconsistentInputError("No topology provided, but one is required for analysis")); } // Load the topology if requested. if (!topfile_.empty()) { snew(topInfo_.top_, 1); topInfo_.bTop_ = read_tps_conf(topfile_.c_str(), topInfo_.top_, &topInfo_.ePBC_, &topInfo_.xtop_, NULL, topInfo_.boxtop_, TRUE); if (hasTrajectory() && !settings_.hasFlag(TrajectoryAnalysisSettings::efUseTopX)) { sfree(topInfo_.xtop_); topInfo_.xtop_ = NULL; } } }
bool TrajectoryAnalysisRunnerCommon::optionsFinished(Options *options) { if (impl_->bHelp_) { return false; } impl_->settings_.impl_->plotSettings.setTimeUnit( impl_->settings_.impl_->timeUnitManager.timeUnit()); if (impl_->trjfile_.empty() && impl_->topfile_.empty()) { GMX_THROW(InconsistentInputError("No trajectory or topology provided, nothing to do!")); } if (options->isSet("b")) { setTimeValue(TBEGIN, impl_->startTime_); } if (options->isSet("e")) { setTimeValue(TEND, impl_->endTime_); } if (options->isSet("dt")) { setTimeValue(TDELTA, impl_->deltaTime_); } return true; }
void SelectionCollection::setIndexGroups(gmx_ana_indexgrps_t *grps) { GMX_RELEASE_ASSERT(grps == NULL || !impl_->bExternalGroupsSet_, "Can only set external groups once or clear them afterwards"); impl_->grps_ = grps; impl_->bExternalGroupsSet_ = true; ExceptionInitializer errors("Invalid index group reference(s)"); SelectionTreeElementPointer root = impl_->sc_.root; while (root) { impl_->resolveExternalGroups(root, &errors); root->checkUnsortedAtoms(true, &errors); root = root->next; } if (errors.hasNestedExceptions()) { GMX_THROW(InconsistentInputError(errors)); } for (size_t i = 0; i < impl_->sc_.sel.size(); ++i) { impl_->sc_.sel[i]->refreshName(); } }
void Angle::optionsFinished(Options *options, TrajectoryAnalysisSettings *settings) { bool bSingle = (g1type_[0] == 'a' || g1type_[0] == 'd'); if (bSingle && g2type_[0] != 'n') { GMX_THROW(InconsistentInputError("Cannot use a second group (-g2) with " "-g1 angle or dihedral")); } if (bSingle && options->isSet("group2")) { GMX_THROW(InconsistentInputError("Cannot provide a second selection " "(-group2) with -g1 angle or dihedral")); } if (!bSingle && g2type_[0] == 'n') { GMX_THROW(InconsistentInputError("Should specify a second group (-g2) " "if the first group is not an angle or a dihedral")); } // Set up the number of positions per angle. switch (g1type_[0]) { case 'a': natoms1_ = 3; break; case 'd': natoms1_ = 4; break; case 'v': natoms1_ = 2; break; case 'p': natoms1_ = 3; break; default: GMX_THROW(InternalError("invalid -g1 value")); } switch (g2type_[0]) { case 'n': natoms2_ = 0; break; case 'v': natoms2_ = 2; break; case 'p': natoms2_ = 3; break; case 't': natoms2_ = 0; break; case 'z': natoms2_ = 0; break; case 's': natoms2_ = 1; break; default: GMX_THROW(InternalError("invalid -g2 value")); } if (natoms2_ == 0 && options->isSet("group2")) { GMX_THROW(InconsistentInputError("Cannot provide a second selection (-group2) with -g2 t0 or z")); } }
void TrajectoryAnalysisRunnerCommon::initTopology(SelectionCollection *selections) { // Return immediately if the topology has already been loaded. if (impl_->topInfo_.hasTopology()) { return; } const TrajectoryAnalysisSettings &settings = impl_->settings_; const bool bRequireTop = settings.hasFlag(TrajectoryAnalysisSettings::efRequireTop) || selections->requiresTopology(); if (bRequireTop && impl_->topfile_.empty()) { GMX_THROW(InconsistentInputError("No topology provided, but one is required for analysis")); } // Load the topology if requested. if (!impl_->topfile_.empty()) { char title[STRLEN]; snew(impl_->topInfo_.top_, 1); impl_->topInfo_.bTop_ = read_tps_conf(impl_->topfile_.c_str(), title, impl_->topInfo_.top_, &impl_->topInfo_.ePBC_, &impl_->topInfo_.xtop_, NULL, impl_->topInfo_.boxtop_, TRUE); if (hasTrajectory() && !settings.hasFlag(TrajectoryAnalysisSettings::efUseTopX)) { sfree(impl_->topInfo_.xtop_); impl_->topInfo_.xtop_ = NULL; } } // Read the first frame if we don't know the maximum number of atoms // otherwise. int natoms = -1; if (!impl_->topInfo_.hasTopology()) { initFirstFrame(); natoms = impl_->fr->natoms; } selections->setTopology(impl_->topInfo_.topology(), natoms); /* if (impl_->bSelDump) { gmx_ana_poscalc_coll_print_tree(stderr, impl_->pcc); fprintf(stderr, "\n"); } */ }
void Angle::checkSelections(const SelectionList &sel1, const SelectionList &sel2) const { if (natoms2_ > 0 && sel1.size() != sel2.size()) { GMX_THROW(InconsistentInputError( "-group1 and -group2 should specify the same number of selections")); } for (size_t g = 0; g < sel1.size(); ++g) { int na1 = sel1[g].posCount(); int na2 = (natoms2_ > 0) ? sel2[g].posCount() : 0; if (natoms1_ > 1 && na1 % natoms1_ != 0) { GMX_THROW(InconsistentInputError(formatString( "Number of positions in selection %d in the first group not divisible by %d", static_cast<int>(g + 1), natoms1_))); } if (natoms2_ > 1 && na2 % natoms2_ != 0) { GMX_THROW(InconsistentInputError(formatString( "Number of positions in selection %d in the second group not divisible by %d", static_cast<int>(g + 1), natoms2_))); } if (natoms1_ > 0 && natoms2_ > 1 && na1 / natoms1_ != na2 / natoms2_) { GMX_THROW(InconsistentInputError( "Number of vectors defined by the two groups are not the same")); } if (g2type_[0] == 's' && sel2[g].posCount() != 1) { GMX_THROW(InconsistentInputError( "The second group should contain a single position with -g2 sphnorm")); } } }
void SelectionTreeElement::checkIndexGroup(int natoms) { GMX_RELEASE_ASSERT(type == SEL_CONST && v.type == GROUP_VALUE, "Should only be called for index group elements"); if (!gmx_ana_index_check_range(&u.cgrp, natoms)) { std::string message = formatString( "Group '%s' cannot be used in selections, because it " "contains negative atom indices and/or references atoms " "not present (largest allowed atom index is %d).", name().c_str(), natoms); GMX_THROW(InconsistentInputError(message)); } }
virtual int getAtomCount() { if (!topInfo_.hasTopology()) { if (trajectoryGroup_.isValid()) { GMX_THROW(InconsistentInputError("-fgroup is only supported when -s is also specified")); } // Read the first frame if we don't know the maximum number of // atoms otherwise. initFirstFrame(); return fr->natoms; } return -1; }
void SelectionCollection::evaluate(t_trxframe *fr, t_pbc *pbc) { if (fr->natoms <= impl_->maxAtomIndex_) { std::string message = formatString( "Trajectory has less atoms (%d) than what is required for " "evaluating the provided selections (atoms up to index %d " "are required).", fr->natoms, impl_->maxAtomIndex_ + 1); GMX_THROW(InconsistentInputError(message)); } impl_->sc_.pcc.initFrame(); SelectionEvaluator evaluator; evaluator.evaluate(this, fr, pbc); if (impl_->debugLevel_ >= 3) { std::fprintf(stderr, "\n"); printTree(stderr, true); } }
void checkUserGpuIds(const gmx_gpu_info_t &gpu_info, const std::vector<int> &compatibleGpus, const std::vector<int> &gpuIds) { bool foundIncompatibleGpuIds = false; std::string message = "Some of the requested GPUs do not exist, behave strangely, or are not compatible:\n"; for (const auto &gpuId : gpuIds) { if (std::find(compatibleGpus.begin(), compatibleGpus.end(), gpuId) == compatibleGpus.end()) { foundIncompatibleGpuIds = true; message += gmx::formatString(" GPU #%d: %s\n", gpuId, getGpuCompatibilityDescription(gpu_info, gpuId)); } } if (foundIncompatibleGpuIds) { GMX_THROW(InconsistentInputError(message)); } }
void TrajectoryAnalysisRunnerCommon::Impl::initFrameIndexGroup() { if (!trajectoryGroup_.isValid()) { return; } GMX_RELEASE_ASSERT(bTrajOpen_, "Trajectory index only makes sense with a real trajectory"); if (trajectoryGroup_.atomCount() != fr->natoms) { const std::string message = formatString( "Selection specified with -fgroup has %d atoms, but " "the trajectory (-f) has %d atoms.", trajectoryGroup_.atomCount(), fr->natoms); GMX_THROW(InconsistentInputError(message)); } fr->bIndex = TRUE; snew(fr->index, trajectoryGroup_.atomCount()); std::copy(trajectoryGroup_.atomIndices().begin(), trajectoryGroup_.atomIndices().end(), fr->index); }
void SelectionCollection::compile() { if (_impl->_sc.top == NULL && requiresTopology()) { GMX_THROW(InconsistentInputError("Selection requires topology information, but none provided")); } if (!_impl->hasFlag(Impl::efExternalGroupsSet)) { setIndexGroups(NULL); } if (_impl->_debugLevel >= 1) { printTree(stderr, false); } SelectionCompiler compiler; compiler.compile(this); if (_impl->hasFlag(Impl::efOwnPositionCollection)) { if (_impl->_debugLevel >= 1) { std::fprintf(stderr, "\n"); printTree(stderr, false); std::fprintf(stderr, "\n"); gmx_ana_poscalc_coll_print_tree(stderr, _impl->_sc.pcc); std::fprintf(stderr, "\n"); } gmx_ana_poscalc_init_eval(_impl->_sc.pcc); if (_impl->_debugLevel >= 1) { gmx_ana_poscalc_coll_print_tree(stderr, _impl->_sc.pcc); std::fprintf(stderr, "\n"); } } }
void SelectionTreeElement::checkUnsortedAtoms( bool bUnsortedAllowed, ExceptionInitializer *errors) const { const bool bUnsortedSupported = (type == SEL_CONST && v.type == GROUP_VALUE) || type == SEL_ROOT || type == SEL_SUBEXPR || type == SEL_SUBEXPRREF // TODO: Consolidate. || type == SEL_MODIFIER || (type == SEL_EXPRESSION && (u.expr.method->flags & SMETH_ALLOW_UNSORTED)); // TODO: For some complicated selections, this may result in the same // index group reference being flagged as an error multiple times for the // same selection. SelectionTreeElementPointer child = this->child; while (child) { child->checkUnsortedAtoms(bUnsortedAllowed && bUnsortedSupported, errors); child = child->next; } // The logic here is simplified by the fact that only constant groups can // currently be the root cause of SEL_UNSORTED being set, so only those // need to be considered in triggering the error. if (!bUnsortedAllowed && (flags & SEL_UNSORTED) && type == SEL_CONST && v.type == GROUP_VALUE) { std::string message = formatString( "Group '%s' cannot be used in selections except " "as a full value of the selection, " "because atom indices in it are not sorted and/or " "it contains duplicate atoms.", name().c_str()); errors->addNested(InconsistentInputError(message)); } }
void TrajectoryAnalysisRunnerCommon::optionsFinished() { impl_->settings_.impl_->plotSettings.setTimeUnit( impl_->settings_.impl_->timeUnitManager.timeUnit()); if (impl_->trjfile_.empty() && impl_->topfile_.empty()) { GMX_THROW(InconsistentInputError("No trajectory or topology provided, nothing to do!")); } if (impl_->bStartTimeSet_) { setTimeValue(TBEGIN, impl_->startTime_); } if (impl_->bEndTimeSet_) { setTimeValue(TEND, impl_->endTime_); } if (impl_->bDeltaTimeSet_) { setTimeValue(TDELTA, impl_->deltaTime_); } }
void TrajectoryAnalysisRunnerCommon::initFirstFrame() { // Return if we have already initialized the trajectory. if (impl_->fr) { return; } time_unit_t time_unit = static_cast<time_unit_t>(impl_->settings_.timeUnit() + 1); output_env_init(&impl_->oenv_, 0, NULL, time_unit, FALSE, exvgNONE, 0, 0); int frflags = impl_->settings_.frflags(); frflags |= TRX_NEED_X; snew(impl_->fr, 1); const TopologyInformation &top = impl_->topInfo_; if (hasTrajectory()) { if (!read_first_frame(impl_->oenv_, &impl_->status_, impl_->trjfile_.c_str(), impl_->fr, frflags)) { GMX_THROW(FileIOError("Could not read coordinates from trajectory")); } impl_->bTrajOpen_ = true; if (top.hasTopology() && impl_->fr->natoms > top.topology()->atoms.nr) { GMX_THROW(InconsistentInputError(formatString( "Trajectory (%d atoms) does not match topology (%d atoms)", impl_->fr->natoms, top.topology()->atoms.nr))); } // Check index groups if they have been initialized based on the topology. /* if (top) { for (int i = 0; i < impl_->sel->nr(); ++i) { gmx_ana_index_check(impl_->sel->sel(i)->indexGroup(), impl_->fr->natoms); } } */ } else { // Prepare a frame from topology information. // TODO: Initialize more of the fields. if (frflags & (TRX_NEED_V)) { GMX_THROW(NotImplementedError("Velocity reading from a topology not implemented")); } if (frflags & (TRX_NEED_F)) { GMX_THROW(InvalidInputError("Forces cannot be read from a topology")); } impl_->fr->flags = frflags; impl_->fr->natoms = top.topology()->atoms.nr; impl_->fr->bX = TRUE; snew(impl_->fr->x, impl_->fr->natoms); memcpy(impl_->fr->x, top.xtop_, sizeof(*impl_->fr->x) * impl_->fr->natoms); impl_->fr->bBox = TRUE; copy_mat(const_cast<rvec *>(top.boxtop_), impl_->fr->box); } set_trxframe_ePBC(impl_->fr, top.ePBC()); if (top.hasTopology() && impl_->settings_.hasRmPBC()) { impl_->gpbc_ = gmx_rmpbc_init(&top.topology()->idef, top.ePBC(), impl_->fr->natoms, impl_->fr->box); } }
void Angle::initOptionsDone(TrajectoryAnalysisSettings *settings) { // Validity checks. bool bSingle = (_g1type[0] == 'a' || _g1type[0] == 'd'); if (bSingle && _g2type[0] != 'n') { GMX_THROW(InconsistentInputError("Cannot use a second group (-g2) with " "-g1 angle or dihedral")); } if (bSingle && _options.isSet("group2")) { GMX_THROW(InconsistentInputError("Cannot provide a second selection " "(-group2) with -g1 angle or dihedral")); } if (!bSingle && _g2type[0] == 'n') { GMX_THROW(InconsistentInputError("Should specify a second group (-g2) " "if the first group is not an angle or a dihedral")); } if (bSingle && _bDumpDist) { GMX_THROW(InconsistentInputError("Cannot calculate distances with -g1 angle or dihedral")); // _bDumpDist = false; } if (_bMulti && !bSingle) { GMX_THROW(InconsistentInputError("-mult can only be combined with -g1 angle or dihedral")); } if (_bMulti && _bSplit1) { GMX_THROW(InconsistentInputError("-mult can not be combined with -split1")); } if (_bMulti && _bAll) { GMX_THROW(InconsistentInputError("-mult and -all are mutually exclusive options")); } if (_bAll) { _sel1Adj->setOnlyStatic(true); } // Set up the number of positions per angle. switch (_g1type[0]) { case 'a': _natoms1 = 3; break; case 'd': _natoms1 = 4; break; case 'v': _natoms1 = 2; break; case 'p': _natoms1 = 3; break; default: GMX_THROW(InternalError("invalid -g1 value")); } switch (_g2type[0]) { case 'n': _natoms2 = 0; break; case 'v': _natoms2 = 2; break; case 'p': _natoms2 = 3; break; case 't': _natoms2 = 0; break; case 'z': _natoms2 = 0; break; case 's': _natoms2 = 1; break; default: GMX_THROW(InternalError("invalid -g2 value")); } if (_natoms2 == 0 && _options.isSet("group2")) { GMX_THROW(InconsistentInputError("Cannot provide a second selection (-group2) with -g2 t0 or z")); } if (!_bMulti) { _sel1Adj->setValueCount(_bSplit1 ? _natoms1 : 1); } if (_natoms2 > 0) { _sel2Adj->setValueCount(_bSplit2 ? _natoms2 : 1); } }
void Angle::checkSelections(const std::vector<Selection *> &sel1, const std::vector<Selection *> &sel2) const { if (_bMulti) { for (size_t g = 0; g < sel1.size(); ++g) { if (sel1[g]->posCount() % _natoms1 != 0) { GMX_THROW(InconsistentInputError(formatString( "Number of positions in selection %d not divisible by %d", static_cast<int>(g + 1), _natoms1))); } } return; } int na1 = sel1[0]->posCount(); int na2 = (_natoms2 > 0) ? sel2[0]->posCount() : 0; if (!_bSplit1 && _natoms1 > 1 && na1 % _natoms1 != 0) { GMX_THROW(InconsistentInputError(formatString( "Number of positions in the first group not divisible by %d", _natoms1))); } if (!_bSplit2 && _natoms2 > 1 && na2 % _natoms2 != 0) { GMX_THROW(InconsistentInputError(formatString( "Number of positions in the second group not divisible by %d", _natoms2))); } if (_bSplit1) { for (int g = 1; g < _natoms1; ++g) { if (sel1[g]->posCount() != na1) { GMX_THROW(InconsistentInputError( "All selections in the first group should contain " "the same number of positions")); } } } else { na1 /= _natoms1; } if (_natoms2 > 1) { if (_bSplit2) { for (int g = 1; g < _natoms2; ++g) { if (sel2[g]->posCount() != na2) { GMX_THROW(InconsistentInputError( "All selections in the second group should contain " "the same number of positions")); } } } else { na2 /= _natoms2; } } if (_natoms1 > 0 && _natoms2 > 1 && na1 != na2) { GMX_THROW(InconsistentInputError( "Number of vectors defined by the two groups are not the same")); } if (_g2type[0] == 's' && sel2[0]->posCount() != 1) { GMX_THROW(InconsistentInputError( "The second group should contain a single position with -g2 sphnorm")); } }
void SelectionCollection::compile() { if (impl_->sc_.top == NULL && requiresTopology()) { GMX_THROW(InconsistentInputError("Selection requires topology information, but none provided")); } if (!impl_->bExternalGroupsSet_) { setIndexGroups(NULL); } if (impl_->debugLevel_ >= 1) { printTree(stderr, false); } SelectionCompiler compiler; compiler.compile(this); if (impl_->debugLevel_ >= 1) { std::fprintf(stderr, "\n"); printTree(stderr, false); std::fprintf(stderr, "\n"); impl_->sc_.pcc.printTree(stderr); std::fprintf(stderr, "\n"); } impl_->sc_.pcc.initEvaluation(); if (impl_->debugLevel_ >= 1) { impl_->sc_.pcc.printTree(stderr); std::fprintf(stderr, "\n"); } // TODO: It would be nicer to associate the name of the selection option // (if available) to the error message. SelectionDataList::const_iterator iter; for (iter = impl_->sc_.sel.begin(); iter != impl_->sc_.sel.end(); ++iter) { const internal::SelectionData &sel = **iter; if (sel.hasFlag(efSelection_OnlyAtoms)) { if (!sel.hasOnlyAtoms()) { std::string message = formatString( "Selection '%s' does not evaluate to individual atoms. " "This is not allowed in this context.", sel.selectionText()); GMX_THROW(InvalidInputError(message)); } } if (sel.hasFlag(efSelection_DisallowEmpty)) { if (sel.posCount() == 0) { std::string message = formatString( "Selection '%s' never matches any atoms.", sel.selectionText()); GMX_THROW(InvalidInputError(message)); } } } }
void TrajectoryAnalysisRunnerCommon::Impl::initFirstFrame() { // Return if we have already initialized the trajectory. if (fr != NULL) { return; } time_unit_t time_unit = static_cast<time_unit_t>(settings_.timeUnit() + 1); output_env_init(&oenv_, getProgramContext(), time_unit, FALSE, exvgNONE, 0); int frflags = settings_.frflags(); frflags |= TRX_NEED_X; snew(fr, 1); if (hasTrajectory()) { if (!read_first_frame(oenv_, &status_, trjfile_.c_str(), fr, frflags)) { GMX_THROW(FileIOError("Could not read coordinates from trajectory")); } bTrajOpen_ = true; if (topInfo_.hasTopology()) { const int topologyAtomCount = topInfo_.topology()->atoms.nr; if (fr->natoms > topologyAtomCount) { const std::string message = formatString("Trajectory (%d atoms) does not match topology (%d atoms)", fr->natoms, topologyAtomCount); GMX_THROW(InconsistentInputError(message)); } } } else { // Prepare a frame from topology information. // TODO: Initialize more of the fields. if (frflags & (TRX_NEED_V)) { GMX_THROW(NotImplementedError("Velocity reading from a topology not implemented")); } if (frflags & (TRX_NEED_F)) { GMX_THROW(InvalidInputError("Forces cannot be read from a topology")); } fr->natoms = topInfo_.topology()->atoms.nr; fr->bX = TRUE; snew(fr->x, fr->natoms); memcpy(fr->x, topInfo_.xtop_, sizeof(*fr->x) * fr->natoms); fr->bBox = TRUE; copy_mat(topInfo_.boxtop_, fr->box); } set_trxframe_ePBC(fr, topInfo_.ePBC()); if (topInfo_.hasTopology() && settings_.hasRmPBC()) { gpbc_ = gmx_rmpbc_init(&topInfo_.topology()->idef, topInfo_.ePBC(), fr->natoms); } }