void HelpManager::enterTopic(const char *name) { const HelpTopicInterface &topic = impl_->currentTopic(); if (!topic.hasSubTopics()) { GMX_THROW(InvalidInputError( formatString("Help topic '%s' has no subtopics", impl_->currentTopicAsString().c_str()))); } const HelpTopicInterface *newTopic = topic.findSubTopic(name); if (newTopic == NULL) { if (impl_->isAtRootTopic()) { GMX_THROW(InvalidInputError( formatString("No help available for '%s'", name))); } else { GMX_THROW(InvalidInputError( formatString("Help topic '%s' has no subtopic '%s'", impl_->currentTopicAsString().c_str(), name))); } } impl_->topicStack_.push_back(newTopic); }
std::string FileNameOptionManager::completeDefaultFileName( const std::string &prefix, const FileNameOptionInfo &option) { if (option.isDirectoryOption()) { return std::string(); } const bool bInput = option.isInputFile() || option.isInputOutputFile(); const std::string realPrefix = !impl_->defaultFileName_.empty() ? impl_->defaultFileName_ : prefix; if (bInput && !impl_->bInputCheckingDisabled_) { const std::string completedName = findExistingExtension(realPrefix, option, impl_->redirector_); if (!completedName.empty()) { return completedName; } if (option.allowMissing()) { return realPrefix + option.defaultExtension(); } else if (option.isLibraryFile()) { // TODO: Treat also library files here. return realPrefix + option.defaultExtension(); } else if (option.isSet()) { std::string message = formatString("No file name was provided, and the default file " "'%s' does not exist or is not accessible.\n" "The following extensions were tried to complete the file name:\n %s", prefix.c_str(), joinStrings(option.extensions(), ", ").c_str()); GMX_THROW(InvalidInputError(message)); } else if (option.isRequired()) { std::string message = formatString("Required option was not provided, and the default file " "'%s' does not exist or is not accessible.\n" "The following extensions were tried to complete the file name:\n %s", prefix.c_str(), joinStrings(option.extensions(), ", ").c_str()); GMX_THROW(InvalidInputError(message)); } // We get here with the legacy optional behavior. } return realPrefix + option.defaultExtension(); }
void OptionsAssigner::finishOption() { AbstractOptionStorage *option = _impl->_currentOption; GMX_RELEASE_ASSERT(option != NULL, "startOption() not called"); bool bBoolReverseValue = false; if (option->isBoolean()) { if (_impl->_currentValueCount == 0) { // Should not throw, otherwise something is wrong. // TODO: Get rid of the hard-coded values. option->appendValue(_impl->_reverseBoolean ? "0" : "1"); } else if (_impl->_reverseBoolean) { bBoolReverseValue = true; } } _impl->_currentOption = NULL; _impl->_reverseBoolean = false; option->finishSet(); if (bBoolReverseValue) { GMX_THROW(InvalidInputError("Cannot specify a value together with 'no' prefix")); } }
void OptionsAssigner::startOption(const char *name) { if (!tryStartOption(name)) { GMX_THROW(InvalidInputError("Unknown option " + std::string(name))); } }
void OptionsAssigner::finishOption() { AbstractOptionStorage *option = impl_->currentOption_; GMX_RELEASE_ASSERT(option != nullptr, "startOption() not called"); bool bBoolReverseValue = false; if (option->isBoolean()) { if (impl_->currentValueCount_ == 0) { // Should not throw, otherwise something is wrong. option->appendValue(Variant::create<bool>(!impl_->reverseBoolean_)); } else if (impl_->reverseBoolean_) { bBoolReverseValue = true; } } impl_->currentOption_ = nullptr; impl_->reverseBoolean_ = false; option->finishSet(); if (bBoolReverseValue) { GMX_THROW(InvalidInputError("Cannot specify a value together with 'no' prefix")); } }
void File::throwOnNotFound(const NotFoundInfo &info) { throwOnError(info); const std::string message = formatString("File '%s' does not exist or is not accessible.\n%s", info.filename, info.message); GMX_THROW_WITH_ERRNO(InvalidInputError(message), info.call, info.err); }
inline Mutation::Mutation(MutationType type, int start, int end, std::string newBases) : type_(type), start_(start), end_(end), newBases_(newBases) { if (!CheckInvariants()) throw InvalidInputError(); }
void AbstractOptionStorage::finish() { GMX_RELEASE_ASSERT(!bInSet_, "finishSet() not called"); processAll(); if (isRequired() && !(isSet() || hasFlag(efOption_ExplicitDefaultValue))) { GMX_THROW(InvalidInputError("Option is required, but not set")); } }
void OptionsAssigner::startSubSection(const char *name) { Options *section = _impl->currentSection()._impl->findSubSection(name); if (section == NULL) { GMX_THROW(InvalidInputError("Unknown subsection")); } _impl->_sectionStack.push_back(section); }
std::vector<int> parseUserGpuIds(const std::string &gpuIdString) { // An optional comma is used to separate GPU IDs assigned to the // same type of task, which will be useful for any nodes that have // more than ten GPUs. std::vector<int> digits; auto foundCommaDelimiters = gpuIdString.find(',') != std::string::npos; if (!foundCommaDelimiters) { for (const auto &c : gpuIdString) { if (std::isdigit(c) == 0) { GMX_THROW(InvalidInputError(formatString("Invalid character in GPU ID string: \"%c\"\n", c))); } // Convert each character in the token to an integer digits.push_back(c - '0'); } } else { if (gpuIdString[0] == ',') { GMX_THROW(InvalidInputError("Invalid use of leading comma in GPU ID string")); } std::istringstream ss(gpuIdString); std::string token; digits.reserve(gpuIdString.length()); token.reserve(gpuIdString.length()); while (std::getline(ss, token, ',')) { // Convert the whole token to an integer if (token.empty()) { GMX_THROW(InvalidInputError("Invalid use of comma in GPU ID string")); } digits.push_back(std::stoi(token)); } } return digits; }
explicit Impl(const std::string &value) try : regex_(value, std::regex::nosubs | std::regex::extended) { } catch (const std::regex_error &) { // TODO: Better error messages. GMX_THROW(InvalidInputError(formatString( "Error in regular expression \"%s\"", value))); }
void OptionsAssigner::startSection(const char *name) { Impl::Section *section = impl_->currentSection().findSection(name); if (section == nullptr) { GMX_THROW(InvalidInputError("Unknown subsection")); } impl_->sectionStack_.push_back(section); section->start(); }
void compile(const char *value) { std::string buf(formatString("^%s$", value)); int rc = regcomp(®ex_, buf.c_str(), REG_EXTENDED | REG_NOSUB); if (rc != 0) { // TODO: Better error messages. GMX_THROW(InvalidInputError(formatString( "Error in regular expression \"%s\"", value))); } }
void AbstractOptionStorage::setMaxValueCount(int count) { GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes), "setMaxValueCount() not supported with efOption_MultipleTimes"); GMX_RELEASE_ASSERT(count >= -1, "Invalid value count"); maxValueCount_ = count; if (isSet() && maxValueCount_ >= 0 && valueCount() > maxValueCount_) { GMX_THROW(InvalidInputError("Too many values")); } }
inline Mutation::Mutation(MutationType type, int position, char base) : type_(type), start_(position) { if (type == INSERTION) { end_ = position; } else { end_ = position + 1; } newBases_ = (type == DELETION ? "" : std::string(1, base)); if (!CheckInvariants()) throw InvalidInputError(); }
void OptionsAssigner::startOption(const char *name) { GMX_RELEASE_ASSERT(_impl->_currentOption == NULL, "finishOption() not called"); AbstractOptionStorage *option = _impl->findOption(name); if (option == NULL) { GMX_THROW(InvalidInputError("Unknown option")); } option->startSet(); _impl->_currentOption = option; _impl->_currentValueCount = 0; }
void AbstractOptionStorage::setMinValueCount(int count) { GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes), "setMinValueCount() not supported with efOption_MultipleTimes"); GMX_RELEASE_ASSERT(count >= 0, "Invalid value count"); minValueCount_ = count; if (isSet() && !hasFlag(efOption_DontCheckMinimumCount) && valueCount() < minValueCount_) { GMX_THROW(InvalidInputError("Too few values")); } }
void Distance::initAnalysis(const TrajectoryAnalysisSettings &settings, const TopologyInformation & /*top*/) { if (sel_[0].posCount() != 1) { GMX_THROW(InvalidInputError("The first selection does not define a single position")); } if (sel_[1].posCount() != 1) { GMX_THROW(InvalidInputError("The second selection does not define a single position")); } data_.addModule(avem_); AnalysisDataPlotModulePointer plotm_(new AnalysisDataPlotModule()); plotm_->setSettings(settings.plotSettings()); plotm_->setFileName(fnDist_); plotm_->setTitle("Distance"); plotm_->setXAxisIsTime(); plotm_->setYLabel("Distance (nm)"); data_.addModule(plotm_); }
void SelectionCollection::parseRequestedFromString(const std::string &str) { Impl::RequestsClearer clearRequestsOnExit(&_impl->_requests); std::vector<Selection *> selections; parseFromString(str, &selections); std::vector<Selection *>::const_iterator first = selections.begin(); std::vector<Selection *>::const_iterator last = first; Impl::RequestList::const_iterator i; for (i = _impl->_requests.begin(); i != _impl->_requests.end(); ++i) { const Impl::SelectionRequest &request = *i; if (request.count() > 0) { if (selections.end() - first < request.count()) { GMX_THROW(InvalidInputError("Too few selections provided")); } last = first + request.count(); } else { if (i != _impl->_requests.end() - 1) { GMX_THROW(APIError("Request for all selections not the last option")); } last = selections.end(); } std::vector<Selection *> curr(first, last); request.storage->addSelections(curr, true); first = last; } if (last != selections.end()) { GMX_THROW(InvalidInputError("Too many selections provided")); } }
void AbstractOptionStorage::startSet() { GMX_RELEASE_ASSERT(!bInSet_, "finishSet() not called"); // The last condition takes care of the situation where multiple // sources are used, and a later source should be able to reassign // the value even though the option is already set. if (isSet() && !hasFlag(efOption_MultipleTimes) && !hasFlag(efOption_ClearOnNextSet)) { GMX_THROW(InvalidInputError("Option specified multiple times")); } clearSet(); bInSet_ = true; bSetValuesHadErrors_ = false; }
const ArrowConfig& ArrowConfigTable::At(const std::string& name) const throw(InvalidInputError) { const_iterator it; // If we find a direct match for the chemistry, use it for (it = table.begin(); it != table.end(); it++) if (it->first.compare(name) == 0) return it->second; // Fallback is "*" for (it = table.begin(); it != table.end(); it++) if (it->first.compare("*") == 0) return it->second; throw InvalidInputError("Chemistry not found in ArrowConfigTable"); }
void SelectionCollection::setIndexGroups(gmx_ana_indexgrps_t *grps) { GMX_RELEASE_ASSERT(grps == NULL || !_impl->hasFlag(Impl::efExternalGroupsSet), "Can only set external groups once or clear them afterwards"); _impl->_grps = grps; _impl->_flags.set(Impl::efExternalGroupsSet); MessageStringCollector errors; t_selelem *root = _impl->_sc.root; while (root != NULL) { _impl->resolveExternalGroups(root, &errors); root = root->next; } if (!errors.isEmpty()) { GMX_THROW(InvalidInputError(errors.toString())); } }
void TimeUnitBehavior::setTimeUnitFromEnvironment() { const char *const value = std::getenv("GMXTIMEUNIT"); if (value != NULL) { ConstArrayRef<const char *> timeUnits(g_timeUnits); ConstArrayRef<const char *>::const_iterator i = std::find(timeUnits.begin(), timeUnits.end(), std::string(value)); if (i == timeUnits.end()) { std::string message = formatString( "Time unit provided with environment variable GMXTIMEUNIT=%s " "is not recognized as a valid time unit.\n" "Possible values are: %s", value, joinStrings(timeUnits, ", ").c_str()); GMX_THROW(InvalidInputError(message)); } setTimeUnit(static_cast<TimeUnit>(i - timeUnits.begin())); } }
void Options::finish() { // TODO: Consider how to customize these error messages based on context. ExceptionInitializer errors("Invalid input values"); Impl::OptionList::const_iterator i; for (i = impl_->options_.begin(); i != impl_->options_.end(); ++i) { AbstractOptionStorage &option = **i; try { option.finish(); } catch (UserInputError &ex) { ex.prependContext("In option " + option.name()); errors.addCurrentExceptionAsNested(); } } Impl::SubSectionList::const_iterator j; for (j = impl_->subSections_.begin(); j != impl_->subSections_.end(); ++j) { Options §ion = **j; try { section.finish(); } catch (const UserInputError &) { errors.addCurrentExceptionAsNested(); } } if (errors.hasNestedExceptions()) { // TODO: This exception type may not always be appropriate. GMX_THROW(InvalidInputError(errors)); } }
void SelectionCollection::Impl::runParser(yyscan_t scanner, int maxnr, std::vector<Selection *> *output) { gmx_ana_selcollection_t *sc = &_sc; GMX_ASSERT(sc == _gmx_sel_lexer_selcollection(scanner), "Incorrectly initialized lexer"); MessageStringCollector errors; _gmx_sel_set_lexer_error_reporter(scanner, &errors); int oldCount = sc->sel.size(); int bOk = !_gmx_sel_yybparse(scanner); _gmx_sel_free_lexer(scanner); int nr = sc->sel.size() - oldCount; if (maxnr > 0 && nr != maxnr) { bOk = false; errors.append("Too few selections provided"); } if (bOk) { SelectionList::const_iterator i; for (i = _sc.sel.begin() + oldCount; i != _sc.sel.end(); ++i) { output->push_back(*i); } } if (!bOk || !errors.isEmpty()) { GMX_ASSERT(!bOk && !errors.isEmpty(), "Inconsistent error reporting"); GMX_THROW(InvalidInputError(errors.toString())); } }
void mapGridToDataGrid(std::vector<int> *gridpointToDatapoint, const double* const *data, int numDataPoints, const std::string &dataFilename, const Grid &grid, const std::string &correctFormatMessage) { /* Transform the data into a grid in order to map each grid point to a data point using the grid functions. */ std::vector<GridAxis> axis_; /* Count the number of points for each dimension. Each dimension has its own stride. */ int stride = 1; int numPointsCounted = 0; std::vector<int> numPoints(grid.numDimensions()); for (int d = grid.numDimensions() - 1; d >= 0; d--) { int numPointsInDim = 0; int pointIndex = 0; double firstValue = data[d][pointIndex]; do { numPointsInDim++; pointIndex += stride; } while (pointIndex < numDataPoints && !gmx_within_tol(firstValue, data[d][pointIndex], GMX_REAL_EPS)); /* The stride in dimension dimension d - 1 equals the number of points dimension d. */ stride = numPointsInDim; numPointsCounted = (numPointsCounted == 0) ? numPointsInDim : numPointsCounted*numPointsInDim; numPoints[d] = numPointsInDim; } if (numPointsCounted != numDataPoints) { std::string mesg = gmx::formatString("Could not extract data properly from %s. Wrong data format?" "\n\n%s", dataFilename.c_str(), correctFormatMessage.c_str()); GMX_THROW(InvalidInputError(mesg)); } /* The data grid has the data that was read and the properties of the AWH grid */ for (int d = 0; d < grid.numDimensions(); d++) { axis_.push_back(GridAxis(data[d][0], data[d][numDataPoints - 1], grid.axis(d).period(), numPoints[d])); } /* Map each grid point to a data point. No interpolation, just pick the nearest one. * It is assumed that the given data is uniformly spaced for each dimension. */ for (size_t m = 0; m < grid.numPoints(); m++) { /* We only define what we need for the datagrid since it's not needed here which is a bit ugly */ if (!valueIsInGrid(grid.point(m).coordValue, axis_)) { std::string mesg = gmx::formatString("%s does not contain data for all coordinate values. " "Make sure your input data covers the whole sampling domain " "and is correctly formatted. \n\n%s", dataFilename.c_str(), correctFormatMessage.c_str()); GMX_THROW(InvalidInputError(mesg)); } (*gridpointToDatapoint)[m] = getNearestIndexInGrid(grid.point(m).coordValue, axis_); } }
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); } }
CommandLineModuleInterface * CommandLineModuleManager::Impl::processCommonOptions( CommandLineCommonOptionsHolder *optionsHolder, int *argc, char ***argv) { // Check if we are directly invoking a certain module. CommandLineModuleInterface *module = singleModule_; // TODO: It would be nice to propagate at least the -quiet option to // the modules so that they can also be quiet in response to this. if (module == NULL) { // If not in single-module mode, process options to the wrapper binary. // TODO: Ideally, this could be done by CommandLineParser. int argcForWrapper = 1; while (argcForWrapper < *argc && (*argv)[argcForWrapper][0] == '-') { ++argcForWrapper; } if (argcForWrapper > 1) { CommandLineParser(optionsHolder->options()) .parse(&argcForWrapper, *argv); } // If no action requested and there is a module specified, process it. if (argcForWrapper < *argc && !optionsHolder->shouldIgnoreActualModule()) { const char *moduleName = (*argv)[argcForWrapper]; CommandLineModuleMap::const_iterator moduleIter = findModuleByName(moduleName); if (moduleIter == modules_.end()) { std::string message = formatString("'%s' is not a GROMACS command.", moduleName); GMX_THROW(InvalidInputError(message)); } module = moduleIter->second.get(); *argc -= argcForWrapper; *argv += argcForWrapper; // After this point, argc and argv are the same independent of // which path is taken: (*argv)[0] is the module name. } } if (module != NULL) { if (singleModule_ == NULL) { programContext_.setDisplayName(binaryName_ + " " + module->name()); } // Recognize the common options also after the module name. // TODO: It could be nicer to only recognize -h/-hidden if module is not // null. CommandLineParser(optionsHolder->options()) .skipUnknown(true).parse(argc, *argv); } if (!optionsHolder->finishOptions()) { return NULL; } // If no module specified and no other action, show the help. // Also explicitly specifying -h for the wrapper binary goes here. if (module == NULL || optionsHolder->shouldShowHelp()) { ensureHelpModuleExists(); if (module != NULL) { helpModule_->setModuleOverride(*module); } *argc = 1; module = helpModule_; } if (module == helpModule_) { helpModule_->setShowHidden(optionsHolder->shouldShowHidden()); } return module; }
void CommandLineParser::parse(int *argc, char *argv[]) { ExceptionInitializer errors("Invalid command-line options"); std::string currentContext; bool bInOption = false; impl_->assigner_.start(); int newi = 1; for (int i = 1; i != *argc; ++i) { const char *const arg = argv[i]; const char *const optionName = impl_->toOptionName(arg); if (optionName != NULL) { if (bInOption) { try { impl_->assigner_.finishOption(); } catch (UserInputError &ex) { ex.prependContext(currentContext); errors.addCurrentExceptionAsNested(); } } currentContext = "In command-line option " + std::string(arg); try { bInOption = impl_->assigner_.tryStartOption(optionName); if (!bInOption) { currentContext.clear(); if (!impl_->bSkipUnknown_) { std::string message = "Unknown command-line option " + std::string(arg); GMX_THROW(InvalidInputError(message)); } } } catch (UserInputError &ex) { // If tryStartOption() throws, make sure that the rest gets // ignored. // TODO: Consider whether we should remove the option from the // command line nonetheless, as it is recognized, but just // invalid. bInOption = false; ex.prependContext(currentContext); errors.addCurrentExceptionAsNested(); currentContext.clear(); } } else if (bInOption) { try { impl_->assigner_.appendValue(arg); } // TODO: Consider if some types of exceptions would be better left // unhandled. catch (GromacsException &ex) { ex.prependContext(currentContext); errors.addCurrentExceptionAsNested(); } } // Remove recognized options if applicable. if (!bInOption && impl_->bSkipUnknown_) { argv[newi] = argv[i]; ++newi; } } // Update the argc count if argv was modified. if (impl_->bSkipUnknown_) { *argc = newi; argv[newi] = NULL; } // Finish the last option. if (bInOption) { try { impl_->assigner_.finishOption(); } catch (UserInputError &ex) { ex.prependContext(currentContext); errors.addCurrentExceptionAsNested(); } } impl_->assigner_.finish(); if (errors.hasNestedExceptions()) { // TODO: This exception type may not always be appropriate. GMX_THROW(InvalidInputError(errors)); } }
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); } }