From: Teemu Murtola Date: Fri, 16 Jan 2015 20:26:44 +0000 (+0200) Subject: Add input file options that accept missing files X-Git-Url: http://biod.pnpi.spb.ru/gitweb/?a=commitdiff_plain;h=63e5fa07ca77bd8b67d57311deec1c89c4a0077c;p=alexxy%2Fgromacs.git Add input file options that accept missing files Add a flag to t_filenm and to FileNameOption that makes input options not fail when the user-provided file does not exist. Add tests for the functionality. Use the flag for -cpi option to support using the same command line for initial and continuation runs. Fixes #1672. Change-Id: I62945266ff15449fb153d5153cd550b3a257df69 --- diff --git a/src/gromacs/commandline/pargs.cpp b/src/gromacs/commandline/pargs.cpp index 83180178c5..0b3538f395 100644 --- a/src/gromacs/commandline/pargs.cpp +++ b/src/gromacs/commandline/pargs.cpp @@ -3,7 +3,7 @@ * * Copyright (c) 1991-2000, University of Groningen, The Netherlands. * Copyright (c) 2001-2004, The GROMACS development team. - * Copyright (c) 2013,2014, by the GROMACS development team, led by + * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -328,6 +328,7 @@ void OptionsAdapter::filenmToOptions(Options *options, t_filenm *fnm) const bool bOptional = ((fnm->flag & ffOPT) != 0); const bool bLibrary = ((fnm->flag & ffLIB) != 0); const bool bMultiple = ((fnm->flag & ffMULT) != 0); + const bool bMissing = ((fnm->flag & ffALLOW_MISSING) != 0); const char *const name = &fnm->opt[1]; const char * defName = fnm->fn; int defType = -1; @@ -349,6 +350,7 @@ void OptionsAdapter::filenmToOptions(Options *options, t_filenm *fnm) .legacyType(fnm->ftp).legacyOptionalBehavior() .readWriteFlags(bRead, bWrite).required(!bOptional) .libraryFile(bLibrary).multiValue(bMultiple) + .allowMissing(bMissing) .description(ftp2desc(fnm->ftp))); } diff --git a/src/gromacs/commandline/tests/pargs.cpp b/src/gromacs/commandline/tests/pargs.cpp index 55dc8b0c36..d74f12f987 100644 --- a/src/gromacs/commandline/tests/pargs.cpp +++ b/src/gromacs/commandline/tests/pargs.cpp @@ -1,7 +1,7 @@ /* * This file is part of the GROMACS molecular simulation package. * - * Copyright (c) 2013,2014, by the GROMACS development team, led by + * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -439,6 +439,27 @@ TEST_F(ParseCommonArgsTest, HandlesNonExistentOptionalInputFiles) done_filenms(nfile(), fnm); } +TEST_F(ParseCommonArgsTest, AcceptsNonExistentInputFilesIfSpecified) +{ + t_filenm fnm[] = { + { efCPT, "-c", "file1", ffOPTRD | ffALLOW_MISSING }, + { efCPT, "-c2", "file2", ffOPTRD | ffALLOW_MISSING }, + { efCPT, "-c3", "file3", ffOPTRD | ffALLOW_MISSING }, + { efCPT, "-c4", "file4", ffOPTRD | ffALLOW_MISSING }, + { efTRX, "-f", "trj", ffOPTRD | ffALLOW_MISSING } + }; + const char *const cmdline[] = { + "test", "-c2", "-c3", "nonexistent", "-c4", "nonexistent.cpt", "-f", "nonexistent" + }; + parseFromArray(cmdline, 0, fnm, gmx::EmptyArrayRef()); + EXPECT_STREQ("file1.cpt", opt2fn("-c", nfile(), fnm)); + EXPECT_STREQ("file2.cpt", opt2fn("-c2", nfile(), fnm)); + EXPECT_STREQ("nonexistent.cpt", opt2fn("-c3", nfile(), fnm)); + EXPECT_STREQ("nonexistent.cpt", opt2fn("-c4", nfile(), fnm)); + EXPECT_STREQ("nonexistent.xtc", opt2fn("-f", nfile(), fnm)); + done_filenms(nfile(), fnm); +} + TEST_F(ParseCommonArgsTest, HandlesCompressedFiles) { t_filenm fnm[] = { diff --git a/src/gromacs/fileio/filenm.h b/src/gromacs/fileio/filenm.h index 0dcfd73b9d..dbd2bf730b 100644 --- a/src/gromacs/fileio/filenm.h +++ b/src/gromacs/fileio/filenm.h @@ -3,7 +3,7 @@ * * Copyright (c) 1991-2000, University of Groningen, The Netherlands. * Copyright (c) 2001-2004, The GROMACS development team. - * Copyright (c) 2013,2014, by the GROMACS development team, led by + * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -82,6 +82,7 @@ typedef struct { #define ffOPT 1<<3 #define ffLIB 1<<4 #define ffMULT 1<<5 +#define ffALLOW_MISSING 1<<6 #define ffRW (ffREAD | ffWRITE) #define ffOPTRD (ffREAD | ffOPT) #define ffOPTWR (ffWRITE| ffOPT) diff --git a/src/gromacs/options/filenameoption.cpp b/src/gromacs/options/filenameoption.cpp index 1f13641786..6884368653 100644 --- a/src/gromacs/options/filenameoption.cpp +++ b/src/gromacs/options/filenameoption.cpp @@ -1,7 +1,7 @@ /* * This file is part of the GROMACS molecular simulation package. * - * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by + * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -204,7 +204,7 @@ FileNameOptionStorage::FileNameOptionStorage(const FileNameOption &settings, FileNameOptionManager *manager) : MyBase(settings), info_(this), manager_(manager), fileType_(-1), defaultExtension_(""), bRead_(settings.bRead_), bWrite_(settings.bWrite_), - bLibrary_(settings.bLibrary_) + bLibrary_(settings.bLibrary_), bAllowMissing_(settings.bAllowMissing_) { GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes), "allowMultiple() is not supported for file name options"); @@ -479,6 +479,11 @@ bool FileNameOptionInfo::isLibraryFile() const return option().isLibraryFile(); } +bool FileNameOptionInfo::allowMissing() const +{ + return option().allowMissing(); +} + bool FileNameOptionInfo::isDirectoryOption() const { return option().isDirectoryOption(); diff --git a/src/gromacs/options/filenameoption.h b/src/gromacs/options/filenameoption.h index 2c1536fc8c..07fefeb3c8 100644 --- a/src/gromacs/options/filenameoption.h +++ b/src/gromacs/options/filenameoption.h @@ -1,7 +1,7 @@ /* * This file is part of the GROMACS molecular simulation package. * - * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by + * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -76,7 +76,8 @@ class FileNameOption : public OptionTemplate : MyBase(name), optionType_(eftUnknown), legacyType_(-1), defaultBasename_(NULL), defaultType_(-1), bLegacyOptionalBehavior_(false), - bRead_(false), bWrite_(false), bLibrary_(false) + bRead_(false), bWrite_(false), bLibrary_(false), + bAllowMissing_(false) { } @@ -134,6 +135,20 @@ class FileNameOption : public OptionTemplate */ MyClass &libraryFile(bool bLibrary = true) { bLibrary_ = bLibrary; return me(); } + /*! \brief + * Tells that missing file names explicitly provided by the user are + * valid for this input option. + * + * If this method is not called, an error will be raised if the user + * explicitly provides a file name that does not name an existing file, + * or if the default value does not resolve to a valid file name for a + * required option that the user has not set. + * + * This method only has effect with input files, and only if a + * FileNameOptionManager is being used. + */ + MyClass &allowMissing(bool bAllow = true) + { bAllowMissing_ = bAllow; return me(); } /*! \brief * Sets a default basename for the file option. * @@ -194,6 +209,7 @@ class FileNameOption : public OptionTemplate bool bRead_; bool bWrite_; bool bLibrary_; + bool bAllowMissing_; /*! \brief * Needed to initialize FileNameOptionStorage from this class without @@ -229,6 +245,8 @@ class FileNameOptionInfo : public OptionInfo * \see FileNameOption::libraryFile() */ bool isLibraryFile() const; + //! Whether the (input) option allows missing files to be provided. + bool allowMissing() const; //! Whether the option specifies directories. bool isDirectoryOption() const; diff --git a/src/gromacs/options/filenameoptionmanager.cpp b/src/gromacs/options/filenameoptionmanager.cpp index 834ec2cc78..fc630dfa25 100644 --- a/src/gromacs/options/filenameoptionmanager.cpp +++ b/src/gromacs/options/filenameoptionmanager.cpp @@ -1,7 +1,7 @@ /* * This file is part of the GROMACS molecular simulation package. * - * Copyright (c) 2014, by the GROMACS development team, led by + * Copyright (c) 2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -146,13 +146,16 @@ void FileNameOptionManager::addDefaultFileNameOption( std::string FileNameOptionManager::completeFileName( const std::string &value, const FileNameOptionInfo &option) { - const bool bInput = option.isInputFile() || option.isInputOutputFile(); + const bool bAllowMissing = option.allowMissing(); + const bool bInput + = option.isInputFile() || option.isInputOutputFile(); // Currently, directory options are simple, and don't need any // special processing. // TODO: Consider splitting them into a separate DirectoryOption. if (option.isDirectoryOption()) { - if (!impl_->bInputCheckingDisabled_ && bInput && !Directory::exists(value)) + if (!impl_->bInputCheckingDisabled_ && bInput && !bAllowMissing + && !Directory::exists(value)) { std::string message = formatString("Directory '%s' does not exist or is not accessible.", @@ -198,7 +201,11 @@ std::string FileNameOptionManager::completeFileName( { return processedValue; } - if (option.isLibraryFile()) + if (bAllowMissing) + { + return value + option.defaultExtension(); + } + else if (option.isLibraryFile()) { // TODO: Treat also library files here. return value + option.defaultExtension(); @@ -218,7 +225,7 @@ std::string FileNameOptionManager::completeFileName( { // TODO: Treat also library files. } - else if (!File::exists(value)) + else if (!bAllowMissing && !File::exists(value)) { std::string message = formatString("File '%s' does not exist or is not accessible.", @@ -254,6 +261,7 @@ std::string FileNameOptionManager::completeDefaultFileName( const bool bInput = option.isInputFile() || option.isInputOutputFile(); const std::string realPrefix = !impl_->defaultFileName_.empty() ? impl_->defaultFileName_ : prefix; + const bool bAllowMissing = option.allowMissing(); if (bInput) { std::string completedName = findExistingExtension(realPrefix, option); @@ -261,7 +269,11 @@ std::string FileNameOptionManager::completeDefaultFileName( { return completedName; } - if (option.isLibraryFile()) + if (bAllowMissing) + { + return realPrefix + option.defaultExtension(); + } + else if (option.isLibraryFile()) { // TODO: Treat also library files here. return realPrefix + option.defaultExtension(); diff --git a/src/gromacs/options/filenameoptionstorage.h b/src/gromacs/options/filenameoptionstorage.h index 7628a379d1..8e799687dd 100644 --- a/src/gromacs/options/filenameoptionstorage.h +++ b/src/gromacs/options/filenameoptionstorage.h @@ -1,7 +1,7 @@ /* * This file is part of the GROMACS molecular simulation package. * - * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by + * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -83,6 +83,8 @@ class FileNameOptionStorage : public OptionStorageTemplate bool isInputOutputFile() const { return bRead_ && bWrite_; } //! \copydoc FileNameOptionInfo::isLibraryFile() bool isLibraryFile() const { return bLibrary_; } + //! \copydoc FileNameOptionInfo::allowMissing() + bool allowMissing() const { return bAllowMissing_; } //! \copydoc FileNameOptionInfo::isDirectoryOption() bool isDirectoryOption() const; @@ -108,6 +110,7 @@ class FileNameOptionStorage : public OptionStorageTemplate bool bRead_; bool bWrite_; bool bLibrary_; + bool bAllowMissing_; }; } // namespace gmx diff --git a/src/gromacs/options/tests/filenameoptionmanager.cpp b/src/gromacs/options/tests/filenameoptionmanager.cpp index 8e2e523883..bb01302e86 100644 --- a/src/gromacs/options/tests/filenameoptionmanager.cpp +++ b/src/gromacs/options/tests/filenameoptionmanager.cpp @@ -1,7 +1,7 @@ /* * This file is part of the GROMACS molecular simulation package. * - * Copyright (c) 2014, by the GROMACS development team, led by + * Copyright (c) 2014,2015, by the GROMACS development team, led by * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl, * and including many others, as listed in the AUTHORS file in the * top-level source directory and at http://www.gromacs.org. @@ -192,6 +192,63 @@ TEST_F(FileNameOptionManagerTest, GivesErrorOnMissingRequiredInputFile) EXPECT_THROW_GMX(options_.finish(), gmx::InvalidInputError); } +TEST_F(FileNameOptionManagerTest, AcceptsMissingInputFileIfSpecified) +{ + std::string value; + ASSERT_NO_THROW_GMX(options_.addOption( + FileNameOption("f").store(&value) + .filetype(gmx::eftIndex).inputFile() + .allowMissing())); + EXPECT_TRUE(value.empty()); + + gmx::OptionsAssigner assigner(&options_); + EXPECT_NO_THROW_GMX(assigner.start()); + EXPECT_NO_THROW_GMX(assigner.startOption("f")); + EXPECT_NO_THROW_GMX(assigner.appendValue("missing.ndx")); + EXPECT_NO_THROW_GMX(assigner.finishOption()); + EXPECT_NO_THROW_GMX(assigner.finish()); + EXPECT_NO_THROW_GMX(options_.finish()); + + EXPECT_EQ("missing.ndx", value); +} + +TEST_F(FileNameOptionManagerTest, AcceptsMissingDefaultInputFileIfSpecified) +{ + std::string value; + ASSERT_NO_THROW_GMX(options_.addOption( + FileNameOption("f").store(&value) + .filetype(gmx::eftIndex).inputFile() + .defaultBasename("missing") + .allowMissing())); + + gmx::OptionsAssigner assigner(&options_); + EXPECT_NO_THROW_GMX(assigner.start()); + EXPECT_NO_THROW_GMX(assigner.startOption("f")); + EXPECT_NO_THROW_GMX(assigner.finishOption()); + EXPECT_NO_THROW_GMX(assigner.finish()); + EXPECT_NO_THROW_GMX(options_.finish()); + + EXPECT_EQ("missing.ndx", value); +} + +TEST_F(FileNameOptionManagerTest, AcceptsMissingRequiredInputFileIfSpecified) +{ + std::string value; + ASSERT_NO_THROW_GMX(options_.addOption( + FileNameOption("f").store(&value).required() + .filetype(gmx::eftIndex).inputFile() + .defaultBasename("missing") + .allowMissing())); + EXPECT_EQ("missing.ndx", value); + + gmx::OptionsAssigner assigner(&options_); + EXPECT_NO_THROW_GMX(assigner.start()); + EXPECT_NO_THROW_GMX(assigner.finish()); + EXPECT_NO_THROW_GMX(options_.finish()); + + EXPECT_EQ("missing.ndx", value); +} + TEST_F(FileNameOptionManagerTest, AddsMissingExtensionBasedOnExistingFile) { std::string filename(createDummyFile(".trr")); diff --git a/src/programs/mdrun/mdrun.cpp b/src/programs/mdrun/mdrun.cpp index 6f39815721..fa91f52506 100644 --- a/src/programs/mdrun/mdrun.cpp +++ b/src/programs/mdrun/mdrun.cpp @@ -408,7 +408,7 @@ int gmx_mdrun(int argc, char *argv[]) { efTPR, NULL, NULL, ffREAD }, { efTRN, "-o", NULL, ffWRITE }, { efCOMPRESSED, "-x", NULL, ffOPTWR }, - { efCPT, "-cpi", NULL, ffOPTRD }, + { efCPT, "-cpi", NULL, ffOPTRD | ffALLOW_MISSING }, { efCPT, "-cpo", NULL, ffOPTWR }, { efSTO, "-c", "confout", ffWRITE }, { efEDR, "-e", "ener", ffWRITE },