From 8c120cd79b11b0bd23f830e7a22c1184e3ca0ad0 Mon Sep 17 00:00:00 2001 From: ggutierrez-sunbright Date: Fri, 3 May 2024 20:19:01 +0000 Subject: [PATCH 01/13] replace popt in rbdock --- src/exe/rbdock.cxx | 844 +++++++++++++++++++++------------------------ 1 file changed, 401 insertions(+), 443 deletions(-) diff --git a/src/exe/rbdock.cxx b/src/exe/rbdock.cxx index 6cd0445..7c95f40 100644 --- a/src/exe/rbdock.cxx +++ b/src/exe/rbdock.cxx @@ -11,12 +11,13 @@ ***********************************************************************/ // Main docking application -#include -using std::setw; - #include #include // for command-line parsing +//#include +#include + +#include "RbtArgParser.h" #include "RbtBiMolWorkSpace.h" #include "RbtCrdFileSink.h" #include "RbtDockingError.h" @@ -28,6 +29,7 @@ using std::setw; #include "RbtModelError.h" #include "RbtPRMFactory.h" #include "RbtParameterFileSource.h" +#include "RbtPlatformCompatibility.h" #include "RbtRand.h" #include "RbtSFFactory.h" #include "RbtSFRequest.h" @@ -40,30 +42,396 @@ const RbtString _ROOT_SF = "SCORE"; const RbtString _RESTRAINT_SF = "RESTR"; const RbtString _ROOT_TRANSFORM = "DOCK"; -void PrintUsage(void) { - cout << endl << "Usage:" << endl; - cout << "rbdock -i -o -r -p [-n ] [-ap] [-an] [-allH]" - << endl; - cout << " [-t ] [-c] [-T ] [-s ]" << endl; - cout << endl << "Options:\t-i - input ligand SD file" << endl; - cout << "\t\t-o - root name for output file(s)" << endl; - cout << "\t\t-r - receptor parameter file " << endl; - cout << "\t\t-p - docking protocol parameter file" << endl; - cout << "\t\t-n - number of runs/ligand (default=1)" << endl; - cout << "\t\t-ap - protonate all neutral amines, guanidines, imidazoles (default=disabled)" << endl; - cout << "\t\t-an - deprotonate all carboxylic, sulphur and phosphorous acid groups (default=disabled)" << endl; - cout << "\t\t-allH - read all hydrogens present (default=polar hydrogens only)" << endl; - cout << "\t\t-t - score threshold OR filter file name" << endl; - cout << "\t\t-c - continue if score threshold is met (use with -t , default=terminate ligand)" - << endl; - cout << "\t\t-T - controls output level for debugging (0 = minimal, >0 = more verbose)" << endl; - cout << "\t\t-s - random number seed (default=from sys clock)" << endl; +RbtArgParser::RbtArgParser get_arguments_parser() { + using std::string; + + RbtArgParser::RbtArgParser parser("rbdock", "Docking application"); + parser.add("i,input", "input ligand SD file (mandatory)"); + parser.add("o,output-root", "root name for output file(s)", ""); + parser.add("r,receptor", "receptor parameter file (mandatory)"); + parser.add("p,protocol", "docking protocol parameter file", "dock.prm"); + parser.add("n,runs", "number of runs/ligand", "1"); + parser.add_flag("P,ap", "protonate all neutral amines, guanidines, imidazoles"); + parser.add_flag("D,an", "deprotonate all carboxylic, sulphur and phosphorous acid groups"); + parser.add_flag("H,allH", "read all hydrogens present. If disabled, read polar hydrogens only"); + parser.add("t,target", "score threshold OR filter file name"); + parser.add_flag("C,cont", "if enabled, continue if score threshold is met (use with -t )"); + parser.add("T,trace", "controls output level for debugging (0 = minimal, >0 = more verbose)", "0"); + parser.add("s,seed", "random number seed (default=from sys clock)"); + + return parser; +} + +struct RBDockConfig { + RbtString strLigandMdlFile; + RbtBool bOutput = false; + RbtString strRunName; + RbtString strReceptorPrmFile; + RbtString strParamFile; + RbtString strFilterFile; + RbtInt nDockingRuns = 1; + RbtBool bTarget = false; + RbtBool bContinue = false; + RbtBool bDockingRuns = false; + RbtDouble dTargetScore; + RbtBool bFilter = false; + RbtBool bPosIonise = false; + RbtBool bNegIonise = false; + RbtBool bAllH = false; + RbtBool bSeed = false; + RbtInt nSeed = 0; + RbtBool bTrace = false; + RbtInt iTrace = 0; + + friend std::ostream &operator<<(std::ostream &os, const RBDockConfig &config); + + void validate() { + using RbtArgParser::ValidationError; + if (strLigandMdlFile.empty()) throw ValidationError("input ligand SD file is mandatory"); + if (strReceptorPrmFile.empty()) throw ValidationError("receptor parameter file is mandatory"); + if (nDockingRuns < 1) throw ValidationError("number of runs must be greater than 0"); + } +}; + +std::ostream &operator<<(std::ostream &os, const RBDockConfig &config) { + os << "Command line args:" << std::endl; + os << " -i " << config.strLigandMdlFile << std::endl; + os << " -r " << config.strReceptorPrmFile << std::endl; + os << " -p " << config.strParamFile << std::endl; + if (config.bOutput) { + os << " -o " << config.strRunName << std::endl; + } else { + os << "WARNING: output file name is missing." << std::endl; + } + auto def_aux = config.bDockingRuns ? " (default) " : ""; + os << " -n " << config.nDockingRuns << def_aux << std::endl; + if (config.bSeed) os << " -s " << config.nSeed << std::endl; + if (config.bTrace) os << " -T " << config.iTrace << std::endl; + if (config.bPosIonise) os << " -ap " << std::endl; + if (config.bNegIonise) os << " -an " << std::endl; + if (!config.bAllH) os << " -allH " << std::endl; + if (config.bTarget) os << " -t " << config.dTargetScore << std::endl; + if (config.bContinue) os << " -cont " << std::endl; + + return os; +} + +RBDockConfig parse_args(int argc, const char *argv[]) { + auto parser = get_arguments_parser(); + try { + auto parser_result = RbtArgParser::RbtParseResult(parser.parse(argc, argv)); + RBDockConfig config; + parser_result["input"] >> config.strLigandMdlFile; + parser_result["receptor"] >> config.strReceptorPrmFile; + parser_result["protocol"] >> config.strParamFile; + config.bOutput = parser_result["output-root"].is_present(); + parser_result["output-root"] >> config.strRunName; + parser_result["runs"] >> config.nDockingRuns; + parser_result["ap"] >> config.bPosIonise; + parser_result["an"] >> config.bNegIonise; + parser_result["allH"] >> config.bAllH; + config.bSeed = parser_result["seed"].is_present(); + parser_result["seed"] >> config.nSeed; + config.bTrace = parser_result["trace"].is_present(); + parser_result["trace"] >> config.iTrace; + if (parser_result["target"].is_present()) { + std::string target; + parser_result["target"] >> target; + if (target.find(".prm") != string::npos) { + config.bFilter = true; + config.strFilterFile = target; + } else { + config.bTarget = true; + config.dTargetScore = std::stod(target); + } + } + parser_result["cont"] >> config.bContinue; + + config.validate(); + return config; + } catch (RbtArgParser::ParsingError &e) { + std::cerr << "Error parsing options: " << e.what() << std::endl; + } catch (RbtArgParser::ValidationError &e) { + std::cerr << "Invalid configuration: " << e.what() << std::endl; + } + std::cerr << parser.help() << std::endl; + exit(1); } ///////////////////////////////////////////////////////////////////// // MAIN PROGRAM STARTS HERE ///////////////////////////////////////////////////////////////////// +std::string get_filter_string(const RBDockConfig &config) { + ostringstream strFilter; + if (!config.bFilter) { + if (config.bTarget) { // -t + if (!config.bDockingRuns) { // -t only + strFilter << "0 1 - SCORE.INTER " << config.dTargetScore << endl; + } else // -t -n need to check if -cont present + // for all other cases it doesn't matter + if (config.bContinue) { // -t -n -cont + strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " + << config.dTargetScore << endl; + } else { // -t -n + strFilter << "1 if - " << config.dTargetScore << " SCORE.INTER 0.0 " + << "if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " + << config.dTargetScore << endl; + } + } // no target score, no filter + else if (config.bDockingRuns) { // -n + strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n0"; + } else { // no -t no -n + strFilter << "0 0\n"; + } + } + return strFilter.str(); +} + +void RBDock(const RBDockConfig &config, const RbtString &strExeName) { + // Create a bimolecular workspace + RbtBiMolWorkSpacePtr spWS(new RbtBiMolWorkSpace()); + // Set the workspace name to the root of the receptor .prm filename + RbtStringList componentList = Rbt::ConvertDelimitedStringToList(config.strReceptorPrmFile, "."); + RbtString wsName = componentList.front(); + spWS->SetName(wsName); + + // Read the docking protocol parameter file + RbtParameterFileSourcePtr spParamSource( + new RbtParameterFileSource(Rbt::GetRbtFileName("data/scripts", config.strParamFile)) + ); + // Read the receptor parameter file + RbtParameterFileSourcePtr spRecepPrmSource( + new RbtParameterFileSource(Rbt::GetRbtFileName("data/receptors", config.strReceptorPrmFile)) + ); + cout << endl + << "DOCKING PROTOCOL:" << endl + << spParamSource->GetFileName() << endl + << spParamSource->GetTitle() << endl; + cout << endl + << "RECEPTOR:" << endl + << spRecepPrmSource->GetFileName() << endl + << spRecepPrmSource->GetTitle() << endl; + + // Create the scoring function from the SCORE section of the docking protocol prm file + // Format is: + // SECTION SCORE + // INTER RbtInterSF.prm + // INTRA RbtIntraSF.prm + // END_SECTION + // + // Notes: + // Section name must be SCORE. This is also the name of the root SF aggregate + // An aggregate is created for each parameter in the section. + // Parameter name becomes the name of the subaggregate (e.g. SCORE.INTER) + // Parameter value is the file name for the subaggregate definition + // Default directory is $RBT_ROOT/data/sf + RbtSFFactoryPtr spSFFactory(new RbtSFFactory()); // Factory class for scoring functions + RbtSFAggPtr spSF(new RbtSFAgg(_ROOT_SF)); // Root SF aggregate + spParamSource->SetSection(_ROOT_SF); + RbtStringList sfList(spParamSource->GetParameterList()); + // Loop over all parameters in the SCORE section + for (RbtStringListConstIter sfIter = sfList.begin(); sfIter != sfList.end(); sfIter++) { + // sfFile = file name for scoring function subaggregate + RbtString sfFile(Rbt::GetRbtFileName("data/sf", spParamSource->GetParameterValueAsString(*sfIter))); + RbtParameterFileSourcePtr spSFSource(new RbtParameterFileSource(sfFile)); + // Create and add the subaggregate + spSF->Add(spSFFactory->CreateAggFromFile(spSFSource, *sfIter)); + } + + // Add the RESTRAINT subaggregate scoring function from any SF definitions in the receptor prm file + spSF->Add(spSFFactory->CreateAggFromFile(spRecepPrmSource, _RESTRAINT_SF)); + + // Create the docking transform aggregate from the transform definitions in the docking prm file + RbtTransformFactoryPtr spTransformFactory(new RbtTransformFactory()); + spParamSource->SetSection(); + RbtTransformAggPtr spTransform(spTransformFactory->CreateAggFromFile(spParamSource, _ROOT_TRANSFORM)); + + // Override the TRACE levels for the scoring function and transform + // Dump details to cout + // Register the scoring function and the transform with the workspace + if (config.bTrace) { + RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace)); + spSF->HandleRequest(spTraceReq); + spTransform->HandleRequest(spTraceReq); + } + if (config.iTrace > 0) { + cout << endl << "SCORING FUNCTION DETAILS:" << endl << *spSF << endl; + cout << endl << "SEARCH DETAILS:" << endl << *spTransform << endl; + } + spWS->SetSF(spSF); + spWS->SetTransform(spTransform); + + // DM 18 May 1999 + // Variants describing the library version, exe version, parameter file, and current directory + // Will be stored in the ligand SD files + RbtVariant vLib(Rbt::GetProduct() + " (" + Rbt::GetVersion() + ", Build" + Rbt::GetBuild() + ")"); + RbtVariant vExe(strExeName + " - " + EXEVERSION); + RbtVariant vRecep(spRecepPrmSource->GetFileName()); + RbtVariant vPrm(spParamSource->GetFileName()); + RbtVariant vDir(Rbt::GetCurrentDirectory()); + + spRecepPrmSource->SetSection(); + // Read docking site from file and register with workspace + RbtString strASFile = spWS->GetName() + ".as"; + RbtString strInputFile = Rbt::GetRbtFileName("data/grids", strASFile); + // DM 26 Sep 2000 - ios_base::binary is invalid with IRIX CC + ifstream istr(strInputFile.c_str(), Rbt::inputMode); + // DM 14 June 2006 - bug fix to one of the longest standing rDock issues + //(the cryptic "Error reading from input stream" message, if cavity file was missing) + if (!istr) { + RbtString message = "Cavity file (" + strASFile + ") not found in current directory or $RBT_HOME"; + message += " - run rbcavity first"; + throw RbtFileReadError(_WHERE_, message); + } + RbtDockingSitePtr spDS(new RbtDockingSite(istr)); + istr.close(); + spWS->SetDockingSite(spDS); + cout << endl << "DOCKING SITE" << endl << (*spDS) << endl; + + // Prepare the SD file sink for saving the docked conformations for each ligand + // DM 3 Dec 1999 - replaced ostringstream with RbtString in determining SD file name + // SRC 2014 moved here this block to allow WRITE_ERROR TRUE + if (config.bOutput) { + RbtMolecularFileSinkPtr spMdlFileSink(new RbtMdlFileSink(config.strRunName + ".sd", RbtModelPtr())); + spWS->SetSink(spMdlFileSink); + } + + RbtPRMFactory prmFactory(spRecepPrmSource, spDS); + prmFactory.SetTrace(config.iTrace); + // Create the receptor model from the file names in the receptor parameter file + RbtModelPtr spReceptor = prmFactory.CreateReceptor(); + spWS->SetReceptor(spReceptor); + + // Register any solvent + RbtModelList solventList = prmFactory.CreateSolvent(); + spWS->SetSolvent(solventList); + if (spWS->hasSolvent()) { + RbtInt nSolvent = spWS->GetSolvent().size(); + cout << endl << nSolvent << " solvent molecules registered" << endl; + } else { + cout << endl << "No solvent" << endl; + } + + // SRC 2014 removed sector bOutput from here to some blocks above, for WRITEERRORS TRUE + + // Seed the random number generator + RbtRand &theRand = Rbt::GetRbtRand(); // ref to random number generator + if (config.bSeed) { + theRand.Seed(config.nSeed); + } + + // Create the filter object for controlling early termination of protocol + RbtFilterPtr spfilter; + if (config.bFilter) { + spfilter = new RbtFilter(config.strFilterFile); + if (config.bDockingRuns) { + spfilter->SetMaxNRuns(config.nDockingRuns); + } + } else { + spfilter = new RbtFilter(get_filter_string(config), true); + } + if (config.bTrace) { + RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace)); + spfilter->HandleRequest(spTraceReq); + } + + // Register the Filter with the workspace + spWS->SetFilter(spfilter); + + // MAIN LOOP OVER LIGAND RECORDS + // DM 20 Apr 1999 - add explicit bPosIonise and bNegIonise flags to MdlFileSource constructor + RbtMolecularFileSourcePtr spMdlFileSource( + new RbtMdlFileSource(config.strLigandMdlFile, config.bPosIonise, config.bNegIonise, !config.bAllH) + ); + for (RbtInt nRec = 1; spMdlFileSource->FileStatusOK(); spMdlFileSource->NextRecord(), nRec++) { + cout.setf(ios_base::left, ios_base::adjustfield); + cout << endl << "**************************************************" << endl << "RECORD #" << nRec << endl; + RbtError molStatus = spMdlFileSource->Status(); + if (!molStatus.isOK()) { + cout << endl << molStatus << endl << "************************************************" << endl; + continue; + } + + // DM 26 Jul 1999 - only read the largest segment (guaranteed to be called H) + // BGD 07 Oct 2002 - catching errors created by the ligands, + // so rbdock continues with the next one, instead of + // completely stopping + try { + spMdlFileSource->SetSegmentFilterMap(Rbt::ConvertStringToSegmentMap("H")); + + if (spMdlFileSource->isDataFieldPresent("Name")) + cout << "NAME: " << spMdlFileSource->GetDataValue("Name") << endl; + if (spMdlFileSource->isDataFieldPresent("REG_Number")) + cout << "REG_Num:" << spMdlFileSource->GetDataValue("REG_Number") << endl; + cout << std::setw(30) << "RANDOM_NUMBER_SEED:" << theRand.GetSeed() << endl; + + // Create and register the ligand model + RbtModelPtr spLigand = prmFactory.CreateLigand(spMdlFileSource); + RbtString strMolName = spLigand->GetName(); + spWS->SetLigand(spLigand); + // Update any model coords from embedded chromosomes in the ligand file + spWS->UpdateModelCoordsFromChromRecords(spMdlFileSource, config.iTrace); + + // DM 18 May 1999 - store run info in model data + // Clear any previous Rbt.* data fields + spLigand->ClearAllDataFields("Rbt."); + spLigand->SetDataValue("Rbt.Library", vLib); + spLigand->SetDataValue("Rbt.Executable", vExe); + spLigand->SetDataValue("Rbt.Receptor", vRecep); + spLigand->SetDataValue("Rbt.Parameter_File", vPrm); + spLigand->SetDataValue("Rbt.Current_Directory", vDir); + + // DM 10 Dec 1999 - if in target mode, loop until target score is reached + RbtBool bTargetMet = false; + + //////////////////////////////////////////////////// + // MAIN LOOP OVER EACH SIMULATED ANNEALING RUN + // Create a history file sink, just in case it's needed by any + // of the transforms + RbtInt iRun = 1; + // need to check this here. The termination + // filter is only run once at least + // one docking run has been done. + if (config.nDockingRuns < 1) bTargetMet = true; + while (!bTargetMet) { + // Catching errors with this specific run + try { + if (config.bOutput) { + ostringstream histr; + histr << config.strRunName << "_" << strMolName << nRec << "_his_" << iRun << ".sd" << ends; + RbtMolecularFileSinkPtr spHistoryFileSink(new RbtMdlFileSink(histr.str(), spLigand)); + spWS->SetHistorySink(spHistoryFileSink); + } + spWS->Run(); // Dock! + RbtBool bterm = spfilter->Terminate(); + RbtBool bwrite = spfilter->Write(); + if (bterm) bTargetMet = true; + if (config.bOutput && bwrite) { + spWS->Save(); + } + iRun++; + } catch (RbtDockingError &e) { + cout << e << endl; + } + } + // END OF MAIN LOOP OVER EACH SIMULATED ANNEALING RUN + //////////////////////////////////////////////////// + } + // END OF TRY + catch (RbtLigandError &e) { + cout << e << endl; + } + } + // END OF MAIN LOOP OVER LIGAND RECORDS + //////////////////////////////////////////////////// + cout << endl << "END OF RUN" << endl; + // if (bOutput && flexRec) { + // RbtMolecularFileSinkPtr spRecepSink(new RbtCrdFileSink(strRunName+".crd",spReceptor)); + // spRecepSink->Render(); + // } +} + int main(int argc, const char *argv[]) { cout.setf(ios_base::left, ios_base::adjustfield); @@ -75,448 +443,38 @@ int main(int argc, const char *argv[]) { // Print a standard header Rbt::PrintStdHeader(cout, strExeName + " - " + EXEVERSION); - // Command line arguments and default values - RbtString strLigandMdlFile; - RbtBool bOutput(false); - RbtString strRunName; - RbtString strReceptorPrmFile; // Receptor param file - RbtString strParamFile; // Docking run param file - RbtString strFilterFile; // Filter file - RbtInt nDockingRuns(0); // Init to zero, so can detect later whether user explictly typed -n - - // Params for target score - RbtBool bTarget(false); - RbtBool bStop(true); // DM 25 May 2001 - if true, stop once target is met - RbtBool bDockingRuns(false); // is argument -n present? - RbtDouble dTargetScore(0.0); - RbtBool bFilter(false); - - RbtBool bPosIonise(false); - RbtBool bNegIonise(false); - RbtBool bImplH(true); // if true, read only polar hydrogens from SD file, else read all H's present - RbtBool bSeed(false); // Random number seed (default = from system clock) - RbtInt nSeed(0); - RbtBool bTrace(false); - RbtInt iTrace(0); // Trace level, for debugging - - // variables for popt command-line parsing - char c; // for argument parsing - poptContext optCon; // ditto - - char *inputFile = NULL; // will be 'strLigandMdlFile' - char *outputFile = NULL; // will be 'strRunName' - char *receptorFile = NULL; // will be 'strReceptorPrmFile' - char *protocolFile = NULL; // will be 'strParamFile' - char *strTargetScr = NULL; // will be 'dTargetScore' - struct poptOption optionsTable[] = { - // command line options - {"input", 'i', POPT_ARG_STRING | POPT_ARGFLAG_ONEDASH, &inputFile, 'i', "input file"}, - {"output", 'o', POPT_ARG_STRING | POPT_ARGFLAG_ONEDASH, &outputFile, 'o', "output file"}, - {"receptor", 'r', POPT_ARG_STRING | POPT_ARGFLAG_ONEDASH, &receptorFile, 'r', "receptor file"}, - {"protocol", 'p', POPT_ARG_STRING | POPT_ARGFLAG_ONEDASH, &protocolFile, 'p', "protocol file"}, - {"runs", 'n', POPT_ARG_INT | POPT_ARGFLAG_ONEDASH, &nDockingRuns, 'n', "number of runs"}, - {"trace", 'T', POPT_ARG_INT | POPT_ARGFLAG_ONEDASH, &iTrace, 'T', "trace level for debugging"}, - {"seed", 's', POPT_ARG_INT | POPT_ARGFLAG_ONEDASH, &nSeed, 's', "random seed"}, - {"ap", 'P', POPT_ARG_NONE | POPT_ARGFLAG_ONEDASH, 0, 'P', "protonate groups"}, - {"an", 'D', POPT_ARG_NONE | POPT_ARGFLAG_ONEDASH, 0, 'D', "DEprotonate groups"}, - {"allH", 'H', POPT_ARG_NONE | POPT_ARGFLAG_ONEDASH, 0, 'H', "read all Hs"}, - {"target", 't', POPT_ARG_STRING | POPT_ARGFLAG_ONEDASH, &strTargetScr, 't', "target score"}, - {"cont", 'C', POPT_ARG_NONE | POPT_ARGFLAG_ONEDASH, 0, 'C', "continue even if target met"}, - POPT_AUTOHELP{NULL, 0, 0, NULL, 0}}; - - optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); - poptSetOtherOptionHelp(optCon, "-r -p -i -o [options]"); - // Brief help message - if (argc < 2) { - PrintUsage(); - return 1; - } - RbtDouble val(0.0); - while ((c = poptGetNextOpt(optCon)) >= 0) { - switch (c) { - case 'P': // protonate - bPosIonise = true; - break; - case 'D': // deprotonate - bNegIonise = true; - break; - case 'H': // all-H model - bImplH = false; - break; - case 'C': - bStop = false; - break; - case 't': - // If str can be translated to an integer, I assume is a - // threshold. Otherwise, I assume is the filter file name - char *error; - errno = 0; - val = strtod(strTargetScr, &error); - if (!errno && !*error) // Is it a number? - { - dTargetScore = val; - bTarget = true; - } else // Assume is the filter file name - { - bFilter = true; - strFilterFile = strTargetScr; - } - break; - case 's': - bSeed = true; - break; - case 'T': - bTrace = true; - break; - default: - break; - } - } - cout << endl; - poptFreeContext(optCon); - - // print out arguments - // input ligand file, receptor and parameter is compulsory - cout << endl << "Command line args:" << endl; - if (!inputFile || !receptorFile || !protocolFile) { // if any of them is missing - // SRC poptPrintUsage(optCon, stderr, 0); - PrintUsage(); - exit(1); - } else { - strLigandMdlFile = inputFile; - strReceptorPrmFile = receptorFile; - strParamFile = protocolFile; - cout << " -i " << strLigandMdlFile << endl; - cout << " -r " << strReceptorPrmFile << endl; - cout << " -p " << strParamFile << endl; - } - // output is not that important but good to have - if (outputFile) { - strRunName = outputFile; - bOutput = true; - cout << " -o " << strRunName << endl; - } else { - cout << "WARNING: output file name is missing." << endl; - } - // docking runs - if (nDockingRuns >= 1) { // User typed -n explicitly, so set bDockingRuns to true - bDockingRuns = true; - cout << " -n " << nDockingRuns << endl; - } else { - nDockingRuns = 1; // User didn't type -n explicitly, so fall back to the default of n=1 - cout << " -n " << nDockingRuns << " (default) " << endl; - } - if (bSeed) // random seed (if provided) - cout << " -s " << nSeed << endl; - if (bTrace) // random seed (if provided) - cout << " -T " << iTrace << endl; - if (bPosIonise) // protonate - cout << " -ap " << endl; - if (bNegIonise) // deprotonate - cout << " -an " << endl; - if (!bImplH) // all-H - cout << " -allH " << endl; - if (!bStop) // stop after target - cout << " -cont " << endl; - if (bTarget) cout << " -t " << dTargetScore << endl; + // Parse command line arguments + RBDockConfig config = parse_args(argc, argv); + std::cout << "Command line args:\n"; + std::cout << config << std::endl; // BGD 26 Feb 2003 - Create filters to simulate old rbdock // behaviour - ostringstream strFilter; - if (!bFilter) { - if (bTarget) // -t - { - if (!bDockingRuns) // -t only - { - strFilter << "0 1 - SCORE.INTER " << dTargetScore << endl; - } else // -t -n need to check if -cont present - // for all other cases it doesn't matter - if (!bStop) // -t -n -cont - { - strFilter << "1 if - SCORE.NRUNS " << (nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " - << dTargetScore << endl; - } else // -t -n - { - strFilter << "1 if - " << dTargetScore << " SCORE.INTER 0.0 " - << "if - SCORE.NRUNS " << (nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " - << dTargetScore << endl; - } - } // no target score, no filter - else if (bDockingRuns) // -n - { - strFilter << "1 if - SCORE.NRUNS " << (nDockingRuns - 1) << " 0.0 -1.0,\n0"; - } else // no -t no -n - { - strFilter << "0 0\n"; - } - } // DM 20 Apr 1999 - set the auto-ionise flags - if (bPosIonise) + if (config.bPosIonise) cout << "Automatically protonating positive ionisable groups (amines, imidazoles, guanidines)" << endl; - if (bNegIonise) + if (config.bNegIonise) cout << "Automatically deprotonating negative ionisable groups (carboxylic acids, phosphates, sulphates, " "sulphonates)" << endl; - if (bImplH) + if (!config.bAllH) cout << "Reading polar hydrogens only from ligand SD file" << endl; else cout << "Reading all hydrogens from ligand SD file" << endl; - if (bTarget) { - cout << endl << "Lower target intermolecular score = " << dTargetScore << endl; + if (config.bTarget) { + cout << endl << "Lower target intermolecular score = " << config.dTargetScore << endl; } try { - // Create a bimolecular workspace - RbtBiMolWorkSpacePtr spWS(new RbtBiMolWorkSpace()); - // Set the workspace name to the root of the receptor .prm filename - RbtStringList componentList = Rbt::ConvertDelimitedStringToList(strReceptorPrmFile, "."); - RbtString wsName = componentList.front(); - spWS->SetName(wsName); - - // Read the docking protocol parameter file - RbtParameterFileSourcePtr spParamSource( - new RbtParameterFileSource(Rbt::GetRbtFileName("data/scripts", strParamFile)) - ); - // Read the receptor parameter file - RbtParameterFileSourcePtr spRecepPrmSource( - new RbtParameterFileSource(Rbt::GetRbtFileName("data/receptors", strReceptorPrmFile)) - ); - cout << endl - << "DOCKING PROTOCOL:" << endl - << spParamSource->GetFileName() << endl - << spParamSource->GetTitle() << endl; - cout << endl - << "RECEPTOR:" << endl - << spRecepPrmSource->GetFileName() << endl - << spRecepPrmSource->GetTitle() << endl; - - // Create the scoring function from the SCORE section of the docking protocol prm file - // Format is: - // SECTION SCORE - // INTER RbtInterSF.prm - // INTRA RbtIntraSF.prm - // END_SECTION - // - // Notes: - // Section name must be SCORE. This is also the name of the root SF aggregate - // An aggregate is created for each parameter in the section. - // Parameter name becomes the name of the subaggregate (e.g. SCORE.INTER) - // Parameter value is the file name for the subaggregate definition - // Default directory is $RBT_ROOT/data/sf - RbtSFFactoryPtr spSFFactory(new RbtSFFactory()); // Factory class for scoring functions - RbtSFAggPtr spSF(new RbtSFAgg(_ROOT_SF)); // Root SF aggregate - spParamSource->SetSection(_ROOT_SF); - RbtStringList sfList(spParamSource->GetParameterList()); - // Loop over all parameters in the SCORE section - for (RbtStringListConstIter sfIter = sfList.begin(); sfIter != sfList.end(); sfIter++) { - // sfFile = file name for scoring function subaggregate - RbtString sfFile(Rbt::GetRbtFileName("data/sf", spParamSource->GetParameterValueAsString(*sfIter))); - RbtParameterFileSourcePtr spSFSource(new RbtParameterFileSource(sfFile)); - // Create and add the subaggregate - spSF->Add(spSFFactory->CreateAggFromFile(spSFSource, *sfIter)); - } - - // Add the RESTRAINT subaggregate scoring function from any SF definitions in the receptor prm file - spSF->Add(spSFFactory->CreateAggFromFile(spRecepPrmSource, _RESTRAINT_SF)); - - // Create the docking transform aggregate from the transform definitions in the docking prm file - RbtTransformFactoryPtr spTransformFactory(new RbtTransformFactory()); - spParamSource->SetSection(); - RbtTransformAggPtr spTransform(spTransformFactory->CreateAggFromFile(spParamSource, _ROOT_TRANSFORM)); - - // Override the TRACE levels for the scoring function and transform - // Dump details to cout - // Register the scoring function and the transform with the workspace - if (bTrace) { - RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", iTrace)); - spSF->HandleRequest(spTraceReq); - spTransform->HandleRequest(spTraceReq); - } - if (iTrace > 0) { - cout << endl << "SCORING FUNCTION DETAILS:" << endl << *spSF << endl; - cout << endl << "SEARCH DETAILS:" << endl << *spTransform << endl; - } - spWS->SetSF(spSF); - spWS->SetTransform(spTransform); - - // DM 18 May 1999 - // Variants describing the library version, exe version, parameter file, and current directory - // Will be stored in the ligand SD files - RbtVariant vLib(Rbt::GetProduct() + " (" + Rbt::GetVersion() + ", Build" + Rbt::GetBuild() + ")"); - RbtVariant vExe(strExeName + " - " + EXEVERSION); - RbtVariant vRecep(spRecepPrmSource->GetFileName()); - RbtVariant vPrm(spParamSource->GetFileName()); - RbtVariant vDir(Rbt::GetCurrentDirectory()); - - spRecepPrmSource->SetSection(); - // Read docking site from file and register with workspace - RbtString strASFile = spWS->GetName() + ".as"; - RbtString strInputFile = Rbt::GetRbtFileName("data/grids", strASFile); - // DM 26 Sep 2000 - ios_base::binary is invalid with IRIX CC -#if defined(__sgi) && !defined(__GNUC__) - ifstream istr(strInputFile.c_str(), ios_base::in); -#else - ifstream istr(strInputFile.c_str(), ios_base::in | ios_base::binary); -#endif - // DM 14 June 2006 - bug fix to one of the longest standing rDock issues - //(the cryptic "Error reading from input stream" message, if cavity file was missing) - if (!istr) { - RbtString message = "Cavity file (" + strASFile + ") not found in current directory or $RBT_HOME"; - message += " - run rbcavity first"; - throw RbtFileReadError(_WHERE_, message); - } - RbtDockingSitePtr spDS(new RbtDockingSite(istr)); - istr.close(); - spWS->SetDockingSite(spDS); - cout << endl << "DOCKING SITE" << endl << (*spDS) << endl; - - // Prepare the SD file sink for saving the docked conformations for each ligand - // DM 3 Dec 1999 - replaced ostringstream with RbtString in determining SD file name - // SRC 2014 moved here this block to allow WRITE_ERROR TRUE - if (bOutput) { - RbtMolecularFileSinkPtr spMdlFileSink(new RbtMdlFileSink(strRunName + ".sd", RbtModelPtr())); - spWS->SetSink(spMdlFileSink); - } - - RbtPRMFactory prmFactory(spRecepPrmSource, spDS); - prmFactory.SetTrace(iTrace); - // Create the receptor model from the file names in the receptor parameter file - RbtModelPtr spReceptor = prmFactory.CreateReceptor(); - spWS->SetReceptor(spReceptor); - - // Register any solvent - RbtModelList solventList = prmFactory.CreateSolvent(); - spWS->SetSolvent(solventList); - if (spWS->hasSolvent()) { - RbtInt nSolvent = spWS->GetSolvent().size(); - cout << endl << nSolvent << " solvent molecules registered" << endl; - } else { - cout << endl << "No solvent" << endl; - } - - // SRC 2014 removed sector bOutput from here to some blocks above, for WRITEERRORS TRUE - - // Seed the random number generator - RbtRand &theRand = Rbt::GetRbtRand(); // ref to random number generator - if (bSeed) { - theRand.Seed(nSeed); - } - - // Create the filter object for controlling early termination of protocol - RbtFilterPtr spfilter; - if (bFilter) { - spfilter = new RbtFilter(strFilterFile); - if (bDockingRuns) { - spfilter->SetMaxNRuns(nDockingRuns); - } - } else { - spfilter = new RbtFilter(strFilter.str(), true); - } - if (bTrace) { - RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", iTrace)); - spfilter->HandleRequest(spTraceReq); - } - - // Register the Filter with the workspace - spWS->SetFilter(spfilter); - - // MAIN LOOP OVER LIGAND RECORDS - // DM 20 Apr 1999 - add explicit bPosIonise and bNegIonise flags to MdlFileSource constructor - RbtMolecularFileSourcePtr spMdlFileSource( - new RbtMdlFileSource(strLigandMdlFile, bPosIonise, bNegIonise, bImplH) - ); - for (RbtInt nRec = 1; spMdlFileSource->FileStatusOK(); spMdlFileSource->NextRecord(), nRec++) { - cout.setf(ios_base::left, ios_base::adjustfield); - cout << endl << "**************************************************" << endl << "RECORD #" << nRec << endl; - RbtError molStatus = spMdlFileSource->Status(); - if (!molStatus.isOK()) { - cout << endl << molStatus << endl << "************************************************" << endl; - continue; - } - - // DM 26 Jul 1999 - only read the largest segment (guaranteed to be called H) - // BGD 07 Oct 2002 - catching errors created by the ligands, - // so rbdock continues with the next one, instead of - // completely stopping - try { - spMdlFileSource->SetSegmentFilterMap(Rbt::ConvertStringToSegmentMap("H")); - - if (spMdlFileSource->isDataFieldPresent("Name")) - cout << "NAME: " << spMdlFileSource->GetDataValue("Name") << endl; - if (spMdlFileSource->isDataFieldPresent("REG_Number")) - cout << "REG_Num:" << spMdlFileSource->GetDataValue("REG_Number") << endl; - cout << setw(30) << "RANDOM_NUMBER_SEED:" << theRand.GetSeed() << endl; - - // Create and register the ligand model - RbtModelPtr spLigand = prmFactory.CreateLigand(spMdlFileSource); - RbtString strMolName = spLigand->GetName(); - spWS->SetLigand(spLigand); - // Update any model coords from embedded chromosomes in the ligand file - spWS->UpdateModelCoordsFromChromRecords(spMdlFileSource, iTrace); - - // DM 18 May 1999 - store run info in model data - // Clear any previous Rbt.* data fields - spLigand->ClearAllDataFields("Rbt."); - spLigand->SetDataValue("Rbt.Library", vLib); - spLigand->SetDataValue("Rbt.Executable", vExe); - spLigand->SetDataValue("Rbt.Receptor", vRecep); - spLigand->SetDataValue("Rbt.Parameter_File", vPrm); - spLigand->SetDataValue("Rbt.Current_Directory", vDir); - - // DM 10 Dec 1999 - if in target mode, loop until target score is reached - RbtBool bTargetMet = false; - - //////////////////////////////////////////////////// - // MAIN LOOP OVER EACH SIMULATED ANNEALING RUN - // Create a history file sink, just in case it's needed by any - // of the transforms - RbtInt iRun = 1; - // need to check this here. The termination - // filter is only run once at least - // one docking run has been done. - if (nDockingRuns < 1) bTargetMet = true; - while (!bTargetMet) { - // Catching errors with this specific run - try { - if (bOutput) { - ostringstream histr; - histr << strRunName << "_" << strMolName << nRec << "_his_" << iRun << ".sd" << ends; - RbtMolecularFileSinkPtr spHistoryFileSink(new RbtMdlFileSink(histr.str(), spLigand)); - spWS->SetHistorySink(spHistoryFileSink); - } - spWS->Run(); // Dock! - RbtBool bterm = spfilter->Terminate(); - RbtBool bwrite = spfilter->Write(); - if (bterm) bTargetMet = true; - if (bOutput && bwrite) { - spWS->Save(); - } - iRun++; - } catch (RbtDockingError &e) { - cout << e << endl; - } - } - // END OF MAIN LOOP OVER EACH SIMULATED ANNEALING RUN - //////////////////////////////////////////////////// - } - // END OF TRY - catch (RbtLigandError &e) { - cout << e << endl; - } - } - // END OF MAIN LOOP OVER LIGAND RECORDS - //////////////////////////////////////////////////// - cout << endl << "END OF RUN" << endl; - // if (bOutput && flexRec) { - // RbtMolecularFileSinkPtr spRecepSink(new RbtCrdFileSink(strRunName+".crd",spReceptor)); - // spRecepSink->Render(); - // } + RBDock(config, strExeName); } catch (RbtError &e) { cout << e << endl; + return 1; } catch (...) { cout << "Unknown exception" << endl; + return 1; } _RBTOBJECTCOUNTER_DUMP_(cout) From 074b6a888f46477ae2b0f2c7bffa29208de1dba9 Mon Sep 17 00:00:00 2001 From: ggutierrez-sunbright Date: Fri, 3 May 2024 20:24:32 +0000 Subject: [PATCH 02/13] remove popt include --- src/exe/rbdock.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/exe/rbdock.cxx b/src/exe/rbdock.cxx index 7c95f40..1609d13 100644 --- a/src/exe/rbdock.cxx +++ b/src/exe/rbdock.cxx @@ -12,7 +12,6 @@ // Main docking application #include -#include // for command-line parsing //#include #include From 1bc2edc6b6925b41f85730fbcb7a02ac63bfd878 Mon Sep 17 00:00:00 2001 From: ggutierrez-sunbright Date: Fri, 3 May 2024 20:24:42 +0000 Subject: [PATCH 03/13] remove popt from makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d93aeaa..847f165 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ endif DEFINES += -DRBT_VERSION=\"$(RBT_VERSION)\" CXX_FLAGS := $(CXX_BASE_FLAGS) $(CXX_CONFIG_FLAGS) $(CXX_WARNING_FLAGS) $(CXX_EXTRA_FLAGS) $(DEFINES) LINK_FLAGS := -shared -LIB_DEPENDENCIES += -lm -lpopt +LIB_DEPENDENCIES += -lm LIBS += $(LIB_DEPENDENCIES) -lRbt INCLUDE := $(addprefix -I./, $(shell find include/ -type d )) $(addprefix -I./, $(shell find import/ -type d )) LIBRARY := ./lib From 3a64282bf7b7aae577f29b8e21fb730241cff27e Mon Sep 17 00:00:00 2001 From: ggutierrez-sunbright Date: Fri, 3 May 2024 20:26:09 +0000 Subject: [PATCH 04/13] remove popt from docker images --- .github/docker/Dockerfile.centos-centos7 | 1 - .github/docker/Dockerfile.centos-stream8 | 2 +- .github/docker/Dockerfile.debian-10 | 2 +- .github/docker/Dockerfile.debian-11 | 2 +- .github/docker/Dockerfile.ubuntu-20.04 | 2 +- .github/docker/Dockerfile.ubuntu-22.04 | 2 +- .github/docker/Dockerfile.ubuntu-22.04-clang | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/docker/Dockerfile.centos-centos7 b/.github/docker/Dockerfile.centos-centos7 index 536f141..0bdcdab 100644 --- a/.github/docker/Dockerfile.centos-centos7 +++ b/.github/docker/Dockerfile.centos-centos7 @@ -2,7 +2,6 @@ FROM centos:centos7 as base # Install dependencies RUN yum install -y centos-release-scl && yum install -y devtoolset-11-gcc devtoolset-11-gcc-c++ devtoolset-11-make devtoolset-11-binutils -RUN yum install -y popt-devel RUN echo "source /opt/rh/devtoolset-11/enable" >> /etc/profile.d/devtoolset-11.sh RUN chmod +x /etc/profile.d/devtoolset-11.sh diff --git a/.github/docker/Dockerfile.centos-stream8 b/.github/docker/Dockerfile.centos-stream8 index 66bc507..d288787 100644 --- a/.github/docker/Dockerfile.centos-stream8 +++ b/.github/docker/Dockerfile.centos-stream8 @@ -1,4 +1,4 @@ FROM tgagor/centos-stream:stream8 as base # Install dependencies -RUN yum install -y popt-devel gcc-c++ make +RUN yum install -y gcc-c++ make diff --git a/.github/docker/Dockerfile.debian-10 b/.github/docker/Dockerfile.debian-10 index fd63aa3..7fdd883 100644 --- a/.github/docker/Dockerfile.debian-10 +++ b/.github/docker/Dockerfile.debian-10 @@ -1,4 +1,4 @@ FROM debian:10 as base # Install dependencies -RUN apt-get update && apt-get install -y --no-install-recommends make g++ libpopt-dev libpopt0 +RUN apt-get update && apt-get install -y --no-install-recommends make g++ diff --git a/.github/docker/Dockerfile.debian-11 b/.github/docker/Dockerfile.debian-11 index b567aef..ef4055c 100644 --- a/.github/docker/Dockerfile.debian-11 +++ b/.github/docker/Dockerfile.debian-11 @@ -1,4 +1,4 @@ FROM debian:11 as base # Install dependencies -RUN apt-get update && apt-get install -y --no-install-recommends make g++ libpopt-dev libpopt0 +RUN apt-get update && apt-get install -y --no-install-recommends make g++ diff --git a/.github/docker/Dockerfile.ubuntu-20.04 b/.github/docker/Dockerfile.ubuntu-20.04 index 680ea04..f402fa7 100644 --- a/.github/docker/Dockerfile.ubuntu-20.04 +++ b/.github/docker/Dockerfile.ubuntu-20.04 @@ -1,4 +1,4 @@ FROM ubuntu:20.04 as base # Install dependencies -RUN apt-get update && apt-get install -y --no-install-recommends make g++ libpopt-dev libpopt0 +RUN apt-get update && apt-get install -y --no-install-recommends make g++ diff --git a/.github/docker/Dockerfile.ubuntu-22.04 b/.github/docker/Dockerfile.ubuntu-22.04 index 1ccba1e..aeaf5e7 100644 --- a/.github/docker/Dockerfile.ubuntu-22.04 +++ b/.github/docker/Dockerfile.ubuntu-22.04 @@ -1,4 +1,4 @@ FROM ubuntu:22.04 as base # Install dependencies -RUN apt-get update && apt-get install -y --no-install-recommends make g++ libpopt-dev libpopt0 +RUN apt-get update && apt-get install -y --no-install-recommends make g++ \ No newline at end of file diff --git a/.github/docker/Dockerfile.ubuntu-22.04-clang b/.github/docker/Dockerfile.ubuntu-22.04-clang index 3a04628..17888a6 100644 --- a/.github/docker/Dockerfile.ubuntu-22.04-clang +++ b/.github/docker/Dockerfile.ubuntu-22.04-clang @@ -1,4 +1,4 @@ FROM ubuntu:22.04 as base # Install dependencies -RUN apt-get update && apt-get install -y --no-install-recommends make clang libpopt-dev libpopt0 +RUN apt-get update && apt-get install -y --no-install-recommends make clang From b0dd1b6ef6ec5b070e3d6669608b70a9df89bdb6 Mon Sep 17 00:00:00 2001 From: ggutierrez-sb Date: Tue, 17 Dec 2024 20:14:56 +0000 Subject: [PATCH 05/13] refactor rbdock --- include/rbdock/rbdock_argparser.h | 16 + include/rbdock/rbdock_config.h | 87 ++++++ include/rbdock/rbdock_main.h | 13 + src/exe/rbdock.cxx | 469 ++-------------------------- src/lib/rbdock/rbdock_argparser.cxx | 73 +++++ src/lib/rbdock/rbdock_main.cxx | 301 ++++++++++++++++++ 6 files changed, 508 insertions(+), 451 deletions(-) create mode 100644 include/rbdock/rbdock_argparser.h create mode 100644 include/rbdock/rbdock_config.h create mode 100644 include/rbdock/rbdock_main.h create mode 100644 src/lib/rbdock/rbdock_argparser.cxx create mode 100644 src/lib/rbdock/rbdock_main.cxx diff --git a/include/rbdock/rbdock_argparser.h b/include/rbdock/rbdock_argparser.h new file mode 100644 index 0000000..5dd23f4 --- /dev/null +++ b/include/rbdock/rbdock_argparser.h @@ -0,0 +1,16 @@ +#ifndef _RBT_RBDOCK_ARGPARSER_H_ +#define _RBT_RBDOCK_ARGPARSER_H_ + +#include "rbdock/rbdock_config.h" + +#include "RbtArgParser.h" + +namespace RBDock { + +RbtArgParser::RbtArgParser get_options_parser(); + +RBDock::RBDockConfig parse_args(int argc, const char *argv[]); + +} // namespace RBDock + +#endif // _RBT_RBDOCK_ARGPARSER_H_ \ No newline at end of file diff --git a/include/rbdock/rbdock_config.h b/include/rbdock/rbdock_config.h new file mode 100644 index 0000000..df0328f --- /dev/null +++ b/include/rbdock/rbdock_config.h @@ -0,0 +1,87 @@ +#ifndef _RBDOCK_CONFIG_H_ +#define _RBDOCK_CONFIG_H_ + +#include +#include + +#include "RbtValidationError.h" + +namespace RBDock { + +struct RBDockConfig { + std::string strLigandMdlFile; + bool bOutput = false; + std::string strRunName; + std::string strReceptorPrmFile; + std::string strParamFile; + std::string strFilterFile; + int nDockingRuns = 1; + bool bTarget = false; + bool bContinue = false; + bool bDockingRuns = false; + double dTargetScore; + bool bFilter = false; + bool bPosIonise = false; + bool bNegIonise = false; + bool bAllH = false; + bool bSeed = false; + int nSeed = 0; + bool bTrace = false; + int iTrace = 0; + + friend std::ostream &operator<<(std::ostream &os, const RBDockConfig &config) { + os << "Command line args:" << std::endl; + os << " -i " << config.strLigandMdlFile << std::endl; + os << " -r " << config.strReceptorPrmFile << std::endl; + os << " -p " << config.strParamFile << std::endl; + if (config.bOutput) { + os << " -o " << config.strRunName << std::endl; + } else { + os << "WARNING: output file name is missing." << std::endl; + } + auto def_aux = config.bDockingRuns ? " (default) " : ""; + os << " -n " << config.nDockingRuns << def_aux << std::endl; + if (config.bSeed) os << " -s " << config.nSeed << std::endl; + if (config.bTrace) os << " -T " << config.iTrace << std::endl; + if (config.bPosIonise) os << " -ap " << std::endl; + if (config.bNegIonise) os << " -an " << std::endl; + if (!config.bAllH) os << " -allH " << std::endl; + if (config.bTarget) os << " -t " << config.dTargetScore << std::endl; + if (config.bContinue) os << " -cont " << std::endl; + if (config.bPosIonise) + os << "Automatically protonating positive ionisable groups (amines, imidazoles, guanidines)" << std::endl; + if (config.bNegIonise) + os << "Automatically deprotonating negative ionisable groups (carboxylic acids, phosphates, sulphates, " + "sulphonates)" + << std::endl; + if (!config.bAllH) + os << "Reading polar hydrogens only from ligand SD file" << std::endl; + else + os << "Reading all hydrogens from ligand SD file" << std::endl; + + if (config.bTarget) { + os << std::endl << "Lower target intermolecular score = " << config.dTargetScore << std::endl; + } + return os; + } + + void validate() { + if (strLigandMdlFile.empty()) throw Rbt::ValidationError("input ligand SD file is mandatory"); + if (strReceptorPrmFile.empty()) throw Rbt::ValidationError("receptor parameter file is mandatory"); + if (nDockingRuns < 1) throw Rbt::ValidationError("number of runs must be greater than 0"); + } + + bool operator==(const RBDockConfig &rhs) const { + return strLigandMdlFile == rhs.strLigandMdlFile && bOutput == rhs.bOutput && strRunName == rhs.strRunName + && strReceptorPrmFile == rhs.strReceptorPrmFile && strParamFile == rhs.strParamFile + && strFilterFile == rhs.strFilterFile && nDockingRuns == rhs.nDockingRuns && bTarget == rhs.bTarget + && bContinue == rhs.bContinue && bDockingRuns == rhs.bDockingRuns && dTargetScore == rhs.dTargetScore + && bFilter == rhs.bFilter && bPosIonise == rhs.bPosIonise && bNegIonise == rhs.bNegIonise + && bAllH == rhs.bAllH && bSeed == rhs.bSeed && nSeed == rhs.nSeed && bTrace == rhs.bTrace + && iTrace == rhs.iTrace; + } +}; + +} // namespace RBDock + +#endif // _RBDOCK_CONFIG_H_ diff --git a/include/rbdock/rbdock_main.h b/include/rbdock/rbdock_main.h new file mode 100644 index 0000000..d0e6b03 --- /dev/null +++ b/include/rbdock/rbdock_main.h @@ -0,0 +1,13 @@ +#ifndef _RBT_RBDOCK_MAIN_H_ +#define _RBT_RBDOCK_MAIN_H_ + +#include + +#include "rbdock/rbdock_config.h" + +namespace RBDock { +std::string get_filter_string(const RBDockConfig &config); +void RBDock(const RBDockConfig &config, const std::string &strExeName); +} // namespace RBDock + +#endif // _RBT_RBDOCK_MAIN_H_ \ No newline at end of file diff --git a/src/exe/rbdock.cxx b/src/exe/rbdock.cxx index 649630c..698d5db 100644 --- a/src/exe/rbdock.cxx +++ b/src/exe/rbdock.cxx @@ -9,474 +9,41 @@ * the University of Barcelona. * http://rdock.sourceforge.net/ ***********************************************************************/ +#include "rbdock/rbdock_argparser.h" +#include "rbdock/rbdock_config.h" +#include "rbdock/rbdock_main.h" -// Main docking application -#include - -//#include -#include - -#include "RbtArgParser.h" -#include "RbtBiMolWorkSpace.h" -#include "RbtCrdFileSink.h" -#include "RbtDockingError.h" -#include "RbtFileError.h" -#include "RbtFilter.h" -#include "RbtLigandError.h" -#include "RbtMdlFileSink.h" -#include "RbtMdlFileSource.h" -#include "RbtModelError.h" -#include "RbtPRMFactory.h" -#include "RbtParameterFileSource.h" -#include "RbtPlatformCompatibility.h" -#include "RbtRand.h" -#include "RbtSFFactory.h" -#include "RbtSFRequest.h" -#include "RbtTransformFactory.h" +#include "Rbt.h" +#include "RbtDebug.h" #include "RbtVersion.h" const RbtString EXEVERSION = RBT_VERSION; -// Section name in docking prm file containing scoring function definition -const RbtString _ROOT_SF = "SCORE"; -const RbtString _RESTRAINT_SF = "RESTR"; -const RbtString _ROOT_TRANSFORM = "DOCK"; - -RbtArgParser::RbtArgParser get_arguments_parser() { - using std::string; - - RbtArgParser::RbtArgParser parser("rbdock", "Docking application"); - parser.add("i,input", "input ligand SD file (mandatory)"); - parser.add("o,output-root", "root name for output file(s)", ""); - parser.add("r,receptor", "receptor parameter file (mandatory)"); - parser.add("p,protocol", "docking protocol parameter file", "dock.prm"); - parser.add("n,runs", "number of runs/ligand", "1"); - parser.add_flag("P,ap", "protonate all neutral amines, guanidines, imidazoles"); - parser.add_flag("D,an", "deprotonate all carboxylic, sulphur and phosphorous acid groups"); - parser.add_flag("H,allH", "read all hydrogens present. If disabled, read polar hydrogens only"); - parser.add("t,target", "score threshold OR filter file name"); - parser.add_flag("C,cont", "if enabled, continue if score threshold is met (use with -t )"); - parser.add("T,trace", "controls output level for debugging (0 = minimal, >0 = more verbose)", "0"); - parser.add("s,seed", "random number seed (default=from sys clock)"); - - return parser; -} - -struct RBDockConfig { - RbtString strLigandMdlFile; - RbtBool bOutput = false; - RbtString strRunName; - RbtString strReceptorPrmFile; - RbtString strParamFile; - RbtString strFilterFile; - RbtInt nDockingRuns = 1; - RbtBool bTarget = false; - RbtBool bContinue = false; - RbtBool bDockingRuns = false; - RbtDouble dTargetScore; - RbtBool bFilter = false; - RbtBool bPosIonise = false; - RbtBool bNegIonise = false; - RbtBool bAllH = false; - RbtBool bSeed = false; - RbtInt nSeed = 0; - RbtBool bTrace = false; - RbtInt iTrace = 0; - - friend std::ostream &operator<<(std::ostream &os, const RBDockConfig &config); - - void validate() { - using RbtArgParser::ValidationError; - if (strLigandMdlFile.empty()) throw ValidationError("input ligand SD file is mandatory"); - if (strReceptorPrmFile.empty()) throw ValidationError("receptor parameter file is mandatory"); - if (nDockingRuns < 1) throw ValidationError("number of runs must be greater than 0"); - } -}; - -std::ostream &operator<<(std::ostream &os, const RBDockConfig &config) { - os << "Command line args:" << std::endl; - os << " -i " << config.strLigandMdlFile << std::endl; - os << " -r " << config.strReceptorPrmFile << std::endl; - os << " -p " << config.strParamFile << std::endl; - if (config.bOutput) { - os << " -o " << config.strRunName << std::endl; - } else { - os << "WARNING: output file name is missing." << std::endl; - } - auto def_aux = config.bDockingRuns ? " (default) " : ""; - os << " -n " << config.nDockingRuns << def_aux << std::endl; - if (config.bSeed) os << " -s " << config.nSeed << std::endl; - if (config.bTrace) os << " -T " << config.iTrace << std::endl; - if (config.bPosIonise) os << " -ap " << std::endl; - if (config.bNegIonise) os << " -an " << std::endl; - if (!config.bAllH) os << " -allH " << std::endl; - if (config.bTarget) os << " -t " << config.dTargetScore << std::endl; - if (config.bContinue) os << " -cont " << std::endl; - - return os; -} - -RBDockConfig parse_args(int argc, const char *argv[]) { - auto parser = get_arguments_parser(); - try { - auto parser_result = RbtArgParser::RbtParseResult(parser.parse(argc, argv)); - RBDockConfig config; - parser_result["input"] >> config.strLigandMdlFile; - parser_result["receptor"] >> config.strReceptorPrmFile; - parser_result["protocol"] >> config.strParamFile; - config.bOutput = parser_result["output-root"].is_present(); - parser_result["output-root"] >> config.strRunName; - parser_result["runs"] >> config.nDockingRuns; - parser_result["ap"] >> config.bPosIonise; - parser_result["an"] >> config.bNegIonise; - parser_result["allH"] >> config.bAllH; - config.bSeed = parser_result["seed"].is_present(); - parser_result["seed"] >> config.nSeed; - config.bTrace = parser_result["trace"].is_present(); - parser_result["trace"] >> config.iTrace; - if (parser_result["target"].is_present()) { - std::string target; - parser_result["target"] >> target; - if (target.find(".prm") != string::npos) { - config.bFilter = true; - config.strFilterFile = target; - } else { - config.bTarget = true; - config.dTargetScore = std::stod(target); - } - } - parser_result["cont"] >> config.bContinue; - - config.validate(); - return config; - } catch (RbtArgParser::ParsingError &e) { - std::cerr << "Error parsing options: " << e.what() << std::endl; - } catch (RbtArgParser::ValidationError &e) { - std::cerr << "Invalid configuration: " << e.what() << std::endl; - } - std::cerr << parser.help() << std::endl; - exit(1); -} ///////////////////////////////////////////////////////////////////// // MAIN PROGRAM STARTS HERE ///////////////////////////////////////////////////////////////////// -std::string get_filter_string(const RBDockConfig &config) { - ostringstream strFilter; - if (!config.bFilter) { - if (config.bTarget) { // -t - if (!config.bDockingRuns) { // -t only - strFilter << "0 1 - SCORE.INTER " << config.dTargetScore << endl; - } else // -t -n need to check if -cont present - // for all other cases it doesn't matter - if (config.bContinue) { // -t -n -cont - strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " - << config.dTargetScore << endl; - } else { // -t -n - strFilter << "1 if - " << config.dTargetScore << " SCORE.INTER 0.0 " - << "if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " - << config.dTargetScore << endl; - } - } // no target score, no filter - else if (config.bDockingRuns) { // -n - strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n0"; - } else { // no -t no -n - strFilter << "0 0\n"; - } - } - return strFilter.str(); -} - -void RBDock(const RBDockConfig &config, const RbtString &strExeName) { - // Create a bimolecular workspace - RbtBiMolWorkSpacePtr spWS(new RbtBiMolWorkSpace()); - // Set the workspace name to the root of the receptor .prm filename - RbtStringList componentList = Rbt::ConvertDelimitedStringToList(config.strReceptorPrmFile, "."); - RbtString wsName = componentList.front(); - spWS->SetName(wsName); - - // Read the docking protocol parameter file - RbtParameterFileSourcePtr spParamSource( - new RbtParameterFileSource(Rbt::GetRbtFileName("data/scripts", config.strParamFile)) - ); - // Read the receptor parameter file - RbtParameterFileSourcePtr spRecepPrmSource( - new RbtParameterFileSource(Rbt::GetRbtFileName("data/receptors", config.strReceptorPrmFile)) - ); - cout << endl - << "DOCKING PROTOCOL:" << endl - << spParamSource->GetFileName() << endl - << spParamSource->GetTitle() << endl; - cout << endl - << "RECEPTOR:" << endl - << spRecepPrmSource->GetFileName() << endl - << spRecepPrmSource->GetTitle() << endl; - - // Create the scoring function from the SCORE section of the docking protocol prm file - // Format is: - // SECTION SCORE - // INTER RbtInterSF.prm - // INTRA RbtIntraSF.prm - // END_SECTION - // - // Notes: - // Section name must be SCORE. This is also the name of the root SF aggregate - // An aggregate is created for each parameter in the section. - // Parameter name becomes the name of the subaggregate (e.g. SCORE.INTER) - // Parameter value is the file name for the subaggregate definition - // Default directory is $RBT_ROOT/data/sf - RbtSFFactoryPtr spSFFactory(new RbtSFFactory()); // Factory class for scoring functions - RbtSFAggPtr spSF(new RbtSFAgg(_ROOT_SF)); // Root SF aggregate - spParamSource->SetSection(_ROOT_SF); - RbtStringList sfList(spParamSource->GetParameterList()); - // Loop over all parameters in the SCORE section - for (RbtStringListConstIter sfIter = sfList.begin(); sfIter != sfList.end(); sfIter++) { - // sfFile = file name for scoring function subaggregate - RbtString sfFile(Rbt::GetRbtFileName("data/sf", spParamSource->GetParameterValueAsString(*sfIter))); - RbtParameterFileSourcePtr spSFSource(new RbtParameterFileSource(sfFile)); - // Create and add the subaggregate - spSF->Add(spSFFactory->CreateAggFromFile(spSFSource, *sfIter)); - } - - // Add the RESTRAINT subaggregate scoring function from any SF definitions in the receptor prm file - spSF->Add(spSFFactory->CreateAggFromFile(spRecepPrmSource, _RESTRAINT_SF)); - - // Create the docking transform aggregate from the transform definitions in the docking prm file - RbtTransformFactoryPtr spTransformFactory(new RbtTransformFactory()); - spParamSource->SetSection(); - RbtTransformAggPtr spTransform(spTransformFactory->CreateAggFromFile(spParamSource, _ROOT_TRANSFORM)); - - // Override the TRACE levels for the scoring function and transform - // Dump details to cout - // Register the scoring function and the transform with the workspace - if (config.bTrace) { - RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace)); - spSF->HandleRequest(spTraceReq); - spTransform->HandleRequest(spTraceReq); - } - if (config.iTrace > 0) { - cout << endl << "SCORING FUNCTION DETAILS:" << endl << *spSF << endl; - cout << endl << "SEARCH DETAILS:" << endl << *spTransform << endl; - } - spWS->SetSF(spSF); - spWS->SetTransform(spTransform); - - // DM 18 May 1999 - // Variants describing the library version, exe version, parameter file, and current directory - // Will be stored in the ligand SD files - RbtVariant vLib(Rbt::GetProduct() + " (" + Rbt::GetVersion() + ", Build" + Rbt::GetBuild() + ")"); - RbtVariant vExe(strExeName + " - " + EXEVERSION); - RbtVariant vRecep(spRecepPrmSource->GetFileName()); - RbtVariant vPrm(spParamSource->GetFileName()); - RbtVariant vDir(Rbt::GetCurrentDirectory()); - - spRecepPrmSource->SetSection(); - // Read docking site from file and register with workspace - RbtString strASFile = spWS->GetName() + ".as"; - RbtString strInputFile = Rbt::GetRbtFileName("data/grids", strASFile); - // DM 26 Sep 2000 - ios_base::binary is invalid with IRIX CC - ifstream istr(strInputFile.c_str(), Rbt::inputMode); - // DM 14 June 2006 - bug fix to one of the longest standing rDock issues - //(the cryptic "Error reading from input stream" message, if cavity file was missing) - if (!istr) { - RbtString message = "Cavity file (" + strASFile + ") not found in current directory or $RBT_HOME"; - message += " - run rbcavity first"; - throw RbtFileReadError(_WHERE_, message); - } - RbtDockingSitePtr spDS(new RbtDockingSite(istr)); - istr.close(); - spWS->SetDockingSite(spDS); - cout << endl << "DOCKING SITE" << endl << (*spDS) << endl; - - // Prepare the SD file sink for saving the docked conformations for each ligand - // DM 3 Dec 1999 - replaced ostringstream with RbtString in determining SD file name - // SRC 2014 moved here this block to allow WRITE_ERROR TRUE - if (config.bOutput) { - RbtMolecularFileSinkPtr spMdlFileSink(new RbtMdlFileSink(config.strRunName + ".sd", RbtModelPtr())); - spWS->SetSink(spMdlFileSink); - } - - RbtPRMFactory prmFactory(spRecepPrmSource, spDS); - prmFactory.SetTrace(config.iTrace); - // Create the receptor model from the file names in the receptor parameter file - RbtModelPtr spReceptor = prmFactory.CreateReceptor(); - spWS->SetReceptor(spReceptor); - - // Register any solvent - RbtModelList solventList = prmFactory.CreateSolvent(); - spWS->SetSolvent(solventList); - if (spWS->hasSolvent()) { - RbtInt nSolvent = spWS->GetSolvent().size(); - cout << endl << nSolvent << " solvent molecules registered" << endl; - } else { - cout << endl << "No solvent" << endl; - } - - // SRC 2014 removed sector bOutput from here to some blocks above, for WRITEERRORS TRUE - - // Seed the random number generator - RbtRand &theRand = Rbt::GetRbtRand(); // ref to random number generator - if (config.bSeed) { - theRand.Seed(config.nSeed); - } - - // Create the filter object for controlling early termination of protocol - RbtFilterPtr spfilter; - if (config.bFilter) { - spfilter = new RbtFilter(config.strFilterFile); - if (config.bDockingRuns) { - spfilter->SetMaxNRuns(config.nDockingRuns); - } - } else { - spfilter = new RbtFilter(get_filter_string(config), true); - } - if (config.bTrace) { - RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace)); - spfilter->HandleRequest(spTraceReq); - } - - // Register the Filter with the workspace - spWS->SetFilter(spfilter); - - // MAIN LOOP OVER LIGAND RECORDS - // DM 20 Apr 1999 - add explicit bPosIonise and bNegIonise flags to MdlFileSource constructor - RbtMolecularFileSourcePtr spMdlFileSource( - new RbtMdlFileSource(config.strLigandMdlFile, config.bPosIonise, config.bNegIonise, !config.bAllH) - ); - for (RbtInt nRec = 1; spMdlFileSource->FileStatusOK(); spMdlFileSource->NextRecord(), nRec++) { - cout.setf(ios_base::left, ios_base::adjustfield); - cout << endl << "**************************************************" << endl << "RECORD #" << nRec << endl; - RbtError molStatus = spMdlFileSource->Status(); - if (!molStatus.isOK()) { - cout << endl << molStatus << endl << "************************************************" << endl; - continue; - } - - // DM 26 Jul 1999 - only read the largest segment (guaranteed to be called H) - // BGD 07 Oct 2002 - catching errors created by the ligands, - // so rbdock continues with the next one, instead of - // completely stopping - try { - spMdlFileSource->SetSegmentFilterMap(Rbt::ConvertStringToSegmentMap("H")); - - if (spMdlFileSource->isDataFieldPresent("Name")) - cout << "NAME: " << spMdlFileSource->GetDataValue("Name") << endl; - if (spMdlFileSource->isDataFieldPresent("REG_Number")) - cout << "REG_Num:" << spMdlFileSource->GetDataValue("REG_Number") << endl; - cout << std::setw(30) << "RANDOM_NUMBER_SEED:" << theRand.GetSeed() << endl; - - // Create and register the ligand model - RbtModelPtr spLigand = prmFactory.CreateLigand(spMdlFileSource); - RbtString strMolName = spLigand->GetName(); - spWS->SetLigand(spLigand); - // Update any model coords from embedded chromosomes in the ligand file - spWS->UpdateModelCoordsFromChromRecords(spMdlFileSource, config.iTrace); - - // DM 18 May 1999 - store run info in model data - // Clear any previous Rbt.* data fields - spLigand->ClearAllDataFields("Rbt."); - spLigand->SetDataValue("Rbt.Library", vLib); - spLigand->SetDataValue("Rbt.Executable", vExe); - spLigand->SetDataValue("Rbt.Receptor", vRecep); - spLigand->SetDataValue("Rbt.Parameter_File", vPrm); - spLigand->SetDataValue("Rbt.Current_Directory", vDir); - - // DM 10 Dec 1999 - if in target mode, loop until target score is reached - RbtBool bTargetMet = false; - - //////////////////////////////////////////////////// - // MAIN LOOP OVER EACH SIMULATED ANNEALING RUN - // Create a history file sink, just in case it's needed by any - // of the transforms - RbtInt iRun = 1; - // need to check this here. The termination - // filter is only run once at least - // one docking run has been done. - if (config.nDockingRuns < 1) bTargetMet = true; - while (!bTargetMet) { - // Catching errors with this specific run - try { - if (config.bOutput) { - ostringstream histr; - histr << config.strRunName << "_" << strMolName << nRec << "_his_" << iRun << ".sd"; - RbtMolecularFileSinkPtr spHistoryFileSink(new RbtMdlFileSink(histr.str(), spLigand)); - spWS->SetHistorySink(spHistoryFileSink); - } - spWS->Run(); // Dock! - RbtBool bterm = spfilter->Terminate(); - RbtBool bwrite = spfilter->Write(); - if (bterm) bTargetMet = true; - if (config.bOutput && bwrite) { - spWS->Save(); - } - iRun++; - } catch (RbtDockingError &e) { - cout << e << endl; - } - } - // END OF MAIN LOOP OVER EACH SIMULATED ANNEALING RUN - //////////////////////////////////////////////////// - } - // END OF TRY - catch (RbtLigandError &e) { - cout << e << endl; - } - } - // END OF MAIN LOOP OVER LIGAND RECORDS - //////////////////////////////////////////////////// - cout << endl << "END OF RUN" << endl; - // if (bOutput && flexRec) { - // RbtMolecularFileSinkPtr spRecepSink(new RbtCrdFileSink(strRunName+".crd",spReceptor)); - // spRecepSink->Render(); - // } -} - int main(int argc, const char *argv[]) { - cout.setf(ios_base::left, ios_base::adjustfield); - // Strip off the path to the executable, leaving just the file name - RbtString strExeName(argv[0]); - RbtString::size_type i = strExeName.rfind("/"); - if (i != RbtString::npos) strExeName.erase(0, i + 1); - - // Print a standard header - Rbt::PrintStdHeader(cout, strExeName + " - " + EXEVERSION); - - // Parse command line arguments - RBDockConfig config = parse_args(argc, argv); - std::cout << "Command line args:\n"; - std::cout << config << std::endl; - - // BGD 26 Feb 2003 - Create filters to simulate old rbdock - // behaviour - - // DM 20 Apr 1999 - set the auto-ionise flags - if (config.bPosIonise) - cout << "Automatically protonating positive ionisable groups (amines, imidazoles, guanidines)" << endl; - if (config.bNegIonise) - cout << "Automatically deprotonating negative ionisable groups (carboxylic acids, phosphates, sulphates, " - "sulphonates)" - << endl; - if (!config.bAllH) - cout << "Reading polar hydrogens only from ligand SD file" << endl; - else - cout << "Reading all hydrogens from ligand SD file" << endl; - - if (config.bTarget) { - cout << endl << "Lower target intermolecular score = " << config.dTargetScore << endl; - } + std::string exeFullPath(argv[0]); + std::string strExeName = exeFullPath.substr(exeFullPath.find_last_of("/\\") + 1); + Rbt::PrintStdHeader(std::cout, strExeName + " - " + EXEVERSION); try { - RBDock(config, strExeName); + RBDock::RBDockConfig config = RBDock::parse_args(argc, argv); + std::cout << config << std::endl; + std::cout.setf(std::ios_base::left, std::ios_base::adjustfield); + RBDock::RBDock(config, strExeName); } catch (RbtError &e) { - cout << e << endl; + std::cerr << e << std::endl; return 1; - } catch (...) { - cout << "Unknown exception" << endl; + } catch (std::exception &e) { + std::cerr << "Unknown exception" << std::endl; + std::cerr << typeid(e).name() << std::endl; + std::cerr << e.what() << std::endl; return 1; } - _RBTOBJECTCOUNTER_DUMP_(cout) - + _RBTOBJECTCOUNTER_DUMP_(std::cout) return 0; } diff --git a/src/lib/rbdock/rbdock_argparser.cxx b/src/lib/rbdock/rbdock_argparser.cxx new file mode 100644 index 0000000..848c0bd --- /dev/null +++ b/src/lib/rbdock/rbdock_argparser.cxx @@ -0,0 +1,73 @@ +#include "rbdock/rbdock_argparser.h" + +#include +#include + +#include "rbdock/rbdock_config.h" + +#include "RbtArgParser.h" +#include "RbtError.h" + +RbtArgParser::RbtArgParser RBDock::get_options_parser() { + using std::string; + + RbtArgParser::RbtArgParser parser("rbdock", "Docking application"); + parser.add("i,input", "input ligand SD file (mandatory)"); + parser.add("o,output-root", "root name for output file(s)", ""); + parser.add("r,receptor", "receptor parameter file (mandatory)"); + parser.add("p,protocol", "docking protocol parameter file", "dock.prm"); + parser.add("n,runs", "number of runs/ligand", "1"); + parser.add_flag("P,ap", "protonate all neutral amines, guanidines, imidazoles"); + parser.add_flag("D,an", "deprotonate all carboxylic, sulphur and phosphorous acid groups"); + parser.add_flag("H,allH", "read all hydrogens present. If disabled, read polar hydrogens only"); + parser.add("t,target", "score threshold OR filter file name"); + parser.add_flag("C,cont", "if enabled, continue if score threshold is met (use with -t )"); + parser.add("T,trace", "controls output level for debugging (0 = minimal, >0 = more verbose)", "0"); + parser.add("s,seed", "random number seed (default=from sys clock)"); + + return parser; +} + +RBDock::RBDockConfig RBDock::parse_args(int argc, const char *argv[]) { + auto parser = get_options_parser(); + try { + auto parser_result = RbtArgParser::RbtParseResult(parser.parse(argc, argv)); + RBDock::RBDockConfig config; + parser_result["input"] >> config.strLigandMdlFile; + parser_result["receptor"] >> config.strReceptorPrmFile; + if (parser_result["protocol"].is_present()) { + parser_result["protocol"] >> config.strParamFile; + } + config.bOutput = parser_result["output-root"].is_present(); + parser_result["output-root"] >> config.strRunName; + parser_result["runs"] >> config.nDockingRuns; + parser_result["ap"] >> config.bPosIonise; + parser_result["an"] >> config.bNegIonise; + parser_result["allH"] >> config.bAllH; + config.bSeed = parser_result["seed"].is_present(); + if (config.bSeed) parser_result["seed"] >> config.nSeed; + config.bTrace = parser_result["trace"].is_present(); + if (config.bTrace) parser_result["trace"] >> config.iTrace; + if (parser_result["target"].is_present()) { + std::string target; + parser_result["target"] >> target; + if (target.find(".prm") != string::npos) { + config.bFilter = true; + config.strFilterFile = target; + } else { + config.bTarget = true; + config.dTargetScore = std::stod(target); + } + } + parser_result["cont"] >> config.bContinue; + + config.validate(); + return config; + } catch (RbtArgParser::ParsingError &e) { + std::cerr << "Error parsing options: " << e.what() << std::endl; + } catch (RbtArgParser::ValidationError &e) { + std::cerr << "Invalid configuration: " << e.what() << std::endl; + } + std::cerr << parser.help() << std::endl; + exit(1); +} \ No newline at end of file diff --git a/src/lib/rbdock/rbdock_main.cxx b/src/lib/rbdock/rbdock_main.cxx new file mode 100644 index 0000000..0045257 --- /dev/null +++ b/src/lib/rbdock/rbdock_main.cxx @@ -0,0 +1,301 @@ +#include "rbdock/rbdock_main.h" + +#include +#include + +#include "rbdock/rbdock_argparser.h" +#include "rbdock/rbdock_config.h" + +#include "RbtArgParser.h" +#include "RbtBiMolWorkSpace.h" +#include "RbtCrdFileSink.h" +#include "RbtDockingError.h" +#include "RbtFileError.h" +#include "RbtFilter.h" +#include "RbtLigandError.h" +#include "RbtMdlFileSink.h" +#include "RbtMdlFileSource.h" +#include "RbtModelError.h" +#include "RbtPRMFactory.h" +#include "RbtParameterFileSource.h" +#include "RbtPlatformCompatibility.h" +#include "RbtRand.h" +#include "RbtSFFactory.h" +#include "RbtSFRequest.h" +#include "RbtTransformFactory.h" +#include "RbtVersion.h" + +// Section name in docking prm file containing scoring function definition +const RbtString _ROOT_SF = "SCORE"; +const RbtString _RESTRAINT_SF = "RESTR"; +const RbtString _ROOT_TRANSFORM = "DOCK"; + +std::string RBDock::get_filter_string(const RBDock::RBDockConfig &config) { + std::ostringstream strFilter; + if (!config.bFilter) { + if (config.bTarget) { // -t + if (!config.bDockingRuns) { // -t only + strFilter << "0 1 - SCORE.INTER " << config.dTargetScore << std::endl; + } else // -t -n need to check if -cont present + // for all other cases it doesn't matter + if (config.bContinue) { // -t -n -cont + strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " + << config.dTargetScore << std::endl; + } else { // -t -n + strFilter << "1 if - " << config.dTargetScore << " SCORE.INTER 0.0 " + << "if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " + << config.dTargetScore << std::endl; + } + } // no target score, no filter + else if (config.bDockingRuns) { // -n + strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n0"; + } else { // no -t no -n + strFilter << "0 0\n"; + } + } + return strFilter.str(); +} + +void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeName) { + // Create a bimolecular workspace + RbtBiMolWorkSpacePtr spWS(new RbtBiMolWorkSpace()); + // Set the workspace name to the root of the receptor .prm filename + RbtStringList componentList = Rbt::ConvertDelimitedStringToList(config.strReceptorPrmFile, "."); + RbtString wsName = componentList.front(); + spWS->SetName(wsName); + + // Read the docking protocol parameter file + RbtParameterFileSourcePtr spParamSource( + new RbtParameterFileSource(Rbt::GetRbtFileName("data/scripts", config.strParamFile)) + ); + // Read the receptor parameter file + RbtParameterFileSourcePtr spRecepPrmSource( + new RbtParameterFileSource(Rbt::GetRbtFileName("data/receptors", config.strReceptorPrmFile)) + ); + cout << endl + << "DOCKING PROTOCOL:" << endl + << spParamSource->GetFileName() << endl + << spParamSource->GetTitle() << endl; + cout << endl + << "RECEPTOR:" << endl + << spRecepPrmSource->GetFileName() << endl + << spRecepPrmSource->GetTitle() << endl; + + // Create the scoring function from the SCORE section of the docking protocol prm file + // Format is: + // SECTION SCORE + // INTER RbtInterSF.prm + // INTRA RbtIntraSF.prm + // END_SECTION + // + // Notes: + // Section name must be SCORE. This is also the name of the root SF aggregate + // An aggregate is created for each parameter in the section. + // Parameter name becomes the name of the subaggregate (e.g. SCORE.INTER) + // Parameter value is the file name for the subaggregate definition + // Default directory is $RBT_ROOT/data/sf + RbtSFFactoryPtr spSFFactory(new RbtSFFactory()); // Factory class for scoring functions + RbtSFAggPtr spSF(new RbtSFAgg(_ROOT_SF)); // Root SF aggregate + spParamSource->SetSection(_ROOT_SF); + RbtStringList sfList(spParamSource->GetParameterList()); + // Loop over all parameters in the SCORE section + for (RbtStringListConstIter sfIter = sfList.begin(); sfIter != sfList.end(); sfIter++) { + // sfFile = file name for scoring function subaggregate + RbtString sfFile(Rbt::GetRbtFileName("data/sf", spParamSource->GetParameterValueAsString(*sfIter))); + RbtParameterFileSourcePtr spSFSource(new RbtParameterFileSource(sfFile)); + // Create and add the subaggregate + spSF->Add(spSFFactory->CreateAggFromFile(spSFSource, *sfIter)); + } + + // Add the RESTRAINT subaggregate scoring function from any SF definitions in the receptor prm file + spSF->Add(spSFFactory->CreateAggFromFile(spRecepPrmSource, _RESTRAINT_SF)); + + // Create the docking transform aggregate from the transform definitions in the docking prm file + RbtTransformFactoryPtr spTransformFactory(new RbtTransformFactory()); + spParamSource->SetSection(); + RbtTransformAggPtr spTransform(spTransformFactory->CreateAggFromFile(spParamSource, _ROOT_TRANSFORM)); + + // Override the TRACE levels for the scoring function and transform + // Dump details to cout + // Register the scoring function and the transform with the workspace + if (config.bTrace) { + RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace)); + spSF->HandleRequest(spTraceReq); + spTransform->HandleRequest(spTraceReq); + } + if (config.iTrace > 0) { + cout << endl << "SCORING FUNCTION DETAILS:" << endl << *spSF << endl; + cout << endl << "SEARCH DETAILS:" << endl << *spTransform << endl; + } + spWS->SetSF(spSF); + spWS->SetTransform(spTransform); + + // DM 18 May 1999 + // Variants describing the library version, exe version, parameter file, and current directory + // Will be stored in the ligand SD files + RbtVariant vLib(Rbt::GetProduct() + " (" + Rbt::GetVersion() + ", Build" + Rbt::GetBuild() + ")"); + RbtVariant vExe(strExeName + " - " + RBT_VERSION); + RbtVariant vRecep(spRecepPrmSource->GetFileName()); + RbtVariant vPrm(spParamSource->GetFileName()); + RbtVariant vDir(Rbt::GetCurrentDirectory()); + + spRecepPrmSource->SetSection(); + // Read docking site from file and register with workspace + RbtString strASFile = spWS->GetName() + ".as"; + RbtString strInputFile = Rbt::GetRbtFileName("data/grids", strASFile); + // DM 26 Sep 2000 - ios_base::binary is invalid with IRIX CC + ifstream istr(strInputFile.c_str(), Rbt::inputMode); + // DM 14 June 2006 - bug fix to one of the longest standing rDock issues + //(the cryptic "Error reading from input stream" message, if cavity file was missing) + if (!istr) { + RbtString message = "Cavity file (" + strASFile + ") not found in current directory or $RBT_HOME"; + message += " - run rbcavity first"; + throw RbtFileReadError(_WHERE_, message); + } + RbtDockingSitePtr spDS(new RbtDockingSite(istr)); + istr.close(); + spWS->SetDockingSite(spDS); + cout << endl << "DOCKING SITE" << endl << (*spDS) << endl; + + // Prepare the SD file sink for saving the docked conformations for each ligand + // DM 3 Dec 1999 - replaced ostringstream with RbtString in determining SD file name + // SRC 2014 moved here this block to allow WRITE_ERROR TRUE + if (config.bOutput) { + RbtMolecularFileSinkPtr spMdlFileSink(new RbtMdlFileSink(config.strRunName + ".sd", RbtModelPtr())); + spWS->SetSink(spMdlFileSink); + } + + RbtPRMFactory prmFactory(spRecepPrmSource, spDS); + prmFactory.SetTrace(config.iTrace); + // Create the receptor model from the file names in the receptor parameter file + RbtModelPtr spReceptor = prmFactory.CreateReceptor(); + spWS->SetReceptor(spReceptor); + + // Register any solvent + RbtModelList solventList = prmFactory.CreateSolvent(); + spWS->SetSolvent(solventList); + if (spWS->hasSolvent()) { + RbtInt nSolvent = spWS->GetSolvent().size(); + cout << endl << nSolvent << " solvent molecules registered" << endl; + } else { + cout << endl << "No solvent" << endl; + } + + // SRC 2014 removed sector bOutput from here to some blocks above, for WRITEERRORS TRUE + + // Seed the random number generator + RbtRand &theRand = Rbt::GetRbtRand(); // ref to random number generator + if (config.bSeed) { + theRand.Seed(config.nSeed); + } + + // Create the filter object for controlling early termination of protocol + RbtFilterPtr spfilter; + if (config.bFilter) { + spfilter = new RbtFilter(config.strFilterFile); + if (config.bDockingRuns) { + spfilter->SetMaxNRuns(config.nDockingRuns); + } + } else { + spfilter = new RbtFilter(get_filter_string(config), true); + } + if (config.bTrace) { + RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace)); + spfilter->HandleRequest(spTraceReq); + } + + // Register the Filter with the workspace + spWS->SetFilter(spfilter); + + // MAIN LOOP OVER LIGAND RECORDS + // DM 20 Apr 1999 - add explicit bPosIonise and bNegIonise flags to MdlFileSource constructor + RbtMolecularFileSourcePtr spMdlFileSource( + new RbtMdlFileSource(config.strLigandMdlFile, config.bPosIonise, config.bNegIonise, !config.bAllH) + ); + for (RbtInt nRec = 1; spMdlFileSource->FileStatusOK(); spMdlFileSource->NextRecord(), nRec++) { + cout.setf(ios_base::left, ios_base::adjustfield); + cout << endl << "**************************************************" << endl << "RECORD #" << nRec << endl; + RbtError molStatus = spMdlFileSource->Status(); + if (!molStatus.isOK()) { + cout << endl << molStatus << endl << "************************************************" << endl; + continue; + } + + // DM 26 Jul 1999 - only read the largest segment (guaranteed to be called H) + // BGD 07 Oct 2002 - catching errors created by the ligands, + // so rbdock continues with the next one, instead of + // completely stopping + try { + spMdlFileSource->SetSegmentFilterMap(Rbt::ConvertStringToSegmentMap("H")); + + if (spMdlFileSource->isDataFieldPresent("Name")) + cout << "NAME: " << spMdlFileSource->GetDataValue("Name") << endl; + if (spMdlFileSource->isDataFieldPresent("REG_Number")) + cout << "REG_Num:" << spMdlFileSource->GetDataValue("REG_Number") << endl; + cout << std::setw(30) << "RANDOM_NUMBER_SEED:" << theRand.GetSeed() << endl; + + // Create and register the ligand model + RbtModelPtr spLigand = prmFactory.CreateLigand(spMdlFileSource); + RbtString strMolName = spLigand->GetName(); + spWS->SetLigand(spLigand); + // Update any model coords from embedded chromosomes in the ligand file + spWS->UpdateModelCoordsFromChromRecords(spMdlFileSource, config.iTrace); + + // DM 18 May 1999 - store run info in model data + // Clear any previous Rbt.* data fields + spLigand->ClearAllDataFields("Rbt."); + spLigand->SetDataValue("Rbt.Library", vLib); + spLigand->SetDataValue("Rbt.Executable", vExe); + spLigand->SetDataValue("Rbt.Receptor", vRecep); + spLigand->SetDataValue("Rbt.Parameter_File", vPrm); + spLigand->SetDataValue("Rbt.Current_Directory", vDir); + + // DM 10 Dec 1999 - if in target mode, loop until target score is reached + RbtBool bTargetMet = false; + + //////////////////////////////////////////////////// + // MAIN LOOP OVER EACH SIMULATED ANNEALING RUN + // Create a history file sink, just in case it's needed by any + // of the transforms + RbtInt iRun = 1; + // need to check this here. The termination + // filter is only run once at least + // one docking run has been done. + if (config.nDockingRuns < 1) bTargetMet = true; + while (!bTargetMet) { + // Catching errors with this specific run + try { + if (config.bOutput) { + ostringstream histr; + histr << config.strRunName << "_" << strMolName << nRec << "_his_" << iRun << ".sd"; + RbtMolecularFileSinkPtr spHistoryFileSink(new RbtMdlFileSink(histr.str(), spLigand)); + spWS->SetHistorySink(spHistoryFileSink); + } + spWS->Run(); // Dock! + RbtBool bterm = spfilter->Terminate(); + RbtBool bwrite = spfilter->Write(); + if (bterm) bTargetMet = true; + if (config.bOutput && bwrite) { + spWS->Save(); + } + iRun++; + } catch (RbtDockingError &e) { + cout << e << endl; + } + } + // END OF MAIN LOOP OVER EACH SIMULATED ANNEALING RUN + //////////////////////////////////////////////////// + } + // END OF TRY + catch (RbtLigandError &e) { + cout << e << endl; + } + } + // END OF MAIN LOOP OVER LIGAND RECORDS + //////////////////////////////////////////////////// + cout << endl << "END OF RUN" << endl; + // if (bOutput && flexRec) { + // RbtMolecularFileSinkPtr spRecepSink(new RbtCrdFileSink(strRunName+".crd",spReceptor)); + // spRecepSink->Render(); + // } +} \ No newline at end of file From c823f88440a8728a7f40cbcabff9c6b16ab741be Mon Sep 17 00:00:00 2001 From: ggutierrez-sb Date: Sat, 4 Jan 2025 19:05:34 +0000 Subject: [PATCH 06/13] prepare argparser for optional values --- include/RbtArgParser.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/RbtArgParser.h b/include/RbtArgParser.h index 285b118..aa5bbe2 100644 --- a/include/RbtArgParser.h +++ b/include/RbtArgParser.h @@ -2,6 +2,7 @@ #define _RBTARGPARSER_H_ #include +#include #include #include @@ -61,6 +62,13 @@ class RbtOptionValue { return *this; } + template + RbtOptionValue &operator>>(std::optional &v) { + v = value.as(); + return *this; + } + + inline bool is_present() { return value.count() > 0; } }; From 948024ca4865a2fa4f7cb85ffc64bb63988124c9 Mon Sep 17 00:00:00 2001 From: ggutierrez-sb Date: Sat, 4 Jan 2025 19:07:41 +0000 Subject: [PATCH 07/13] refactor rbdock config to use std::optional --- include/rbdock/rbdock_config.h | 63 +++++++++++++++-------------- src/lib/rbdock/rbdock_argparser.cxx | 29 +++++++------ src/lib/rbdock/rbdock_main.cxx | 56 ++++++++++++------------- 3 files changed, 77 insertions(+), 71 deletions(-) diff --git a/include/rbdock/rbdock_config.h b/include/rbdock/rbdock_config.h index df0328f..78a2c3c 100644 --- a/include/rbdock/rbdock_config.h +++ b/include/rbdock/rbdock_config.h @@ -2,6 +2,7 @@ #define _RBDOCK_CONFIG_H_ #include +#include #include #include "RbtValidationError.h" @@ -9,45 +10,44 @@ namespace RBDock { struct RBDockConfig { + // mandatory parameters std::string strLigandMdlFile; - bool bOutput = false; - std::string strRunName; std::string strReceptorPrmFile; std::string strParamFile; - std::string strFilterFile; - int nDockingRuns = 1; - bool bTarget = false; + + // optional parameters + std::optional strOutputPrefix; + std::optional strFilterFile; + std::optional nDockingRuns; + std::optional dTargetScore; + std::optional nSeed; + std::optional iTrace; + + // flags bool bContinue = false; - bool bDockingRuns = false; - double dTargetScore; - bool bFilter = false; bool bPosIonise = false; bool bNegIonise = false; bool bAllH = false; - bool bSeed = false; - int nSeed = 0; - bool bTrace = false; - int iTrace = 0; friend std::ostream &operator<<(std::ostream &os, const RBDockConfig &config) { os << "Command line args:" << std::endl; os << " -i " << config.strLigandMdlFile << std::endl; os << " -r " << config.strReceptorPrmFile << std::endl; os << " -p " << config.strParamFile << std::endl; - if (config.bOutput) { - os << " -o " << config.strRunName << std::endl; + if (config.strOutputPrefix.has_value()) { + os << " -o " << config.strOutputPrefix.value() << std::endl; } else { os << "WARNING: output file name is missing." << std::endl; } - auto def_aux = config.bDockingRuns ? " (default) " : ""; - os << " -n " << config.nDockingRuns << def_aux << std::endl; - if (config.bSeed) os << " -s " << config.nSeed << std::endl; - if (config.bTrace) os << " -T " << config.iTrace << std::endl; - if (config.bPosIonise) os << " -ap " << std::endl; - if (config.bNegIonise) os << " -an " << std::endl; - if (!config.bAllH) os << " -allH " << std::endl; - if (config.bTarget) os << " -t " << config.dTargetScore << std::endl; - if (config.bContinue) os << " -cont " << std::endl; + auto def_aux = config.nDockingRuns.has_value() ? " (default) " : ""; + os << " -n " << config.nDockingRuns.value_or(1) << def_aux << std::endl; + if (config.nSeed.has_value()) os << " -s " << config.nSeed.value() << std::endl; + if (config.iTrace.has_value()) os << " -T " << config.iTrace.value() << std::endl; + if (config.bPosIonise) os << " --ap " << std::endl; + if (config.bNegIonise) os << " --an " << std::endl; + if (!config.bAllH) os << " --allH " << std::endl; + if (config.dTargetScore.has_value()) os << " -t " << config.dTargetScore.value() << std::endl; + if (config.bContinue) os << " --cont " << std::endl; if (config.bPosIonise) os << "Automatically protonating positive ionisable groups (amines, imidazoles, guanidines)" << std::endl; if (config.bNegIonise) @@ -59,9 +59,11 @@ struct RBDockConfig { else os << "Reading all hydrogens from ligand SD file" << std::endl; - if (config.bTarget) { - os << std::endl << "Lower target intermolecular score = " << config.dTargetScore << std::endl; + if (config.dTargetScore.has_value()) { + os << std::endl << "Lower target intermolecular score = " << config.dTargetScore.value() << std::endl; } + if (config.strFilterFile.has_value()) os << " -f " << config.strFilterFile.value() << std::endl; + return os; } @@ -72,13 +74,12 @@ struct RBDockConfig { } bool operator==(const RBDockConfig &rhs) const { - return strLigandMdlFile == rhs.strLigandMdlFile && bOutput == rhs.bOutput && strRunName == rhs.strRunName + return strLigandMdlFile == rhs.strLigandMdlFile && strOutputPrefix == rhs.strOutputPrefix && strReceptorPrmFile == rhs.strReceptorPrmFile && strParamFile == rhs.strParamFile - && strFilterFile == rhs.strFilterFile && nDockingRuns == rhs.nDockingRuns && bTarget == rhs.bTarget - && bContinue == rhs.bContinue && bDockingRuns == rhs.bDockingRuns && dTargetScore == rhs.dTargetScore - && bFilter == rhs.bFilter && bPosIonise == rhs.bPosIonise && bNegIonise == rhs.bNegIonise - && bAllH == rhs.bAllH && bSeed == rhs.bSeed && nSeed == rhs.nSeed && bTrace == rhs.bTrace - && iTrace == rhs.iTrace; + && strFilterFile == rhs.strFilterFile && nDockingRuns == rhs.nDockingRuns + && bContinue == rhs.bContinue && dTargetScore == rhs.dTargetScore + && bPosIonise == rhs.bPosIonise && bNegIonise == rhs.bNegIonise + && bAllH == rhs.bAllH && nSeed == rhs.nSeed && iTrace == rhs.iTrace; } }; diff --git a/src/lib/rbdock/rbdock_argparser.cxx b/src/lib/rbdock/rbdock_argparser.cxx index 848c0bd..c6979ef 100644 --- a/src/lib/rbdock/rbdock_argparser.cxx +++ b/src/lib/rbdock/rbdock_argparser.cxx @@ -20,10 +20,11 @@ RbtArgParser::RbtArgParser RBDock::get_options_parser() { parser.add_flag("P,ap", "protonate all neutral amines, guanidines, imidazoles"); parser.add_flag("D,an", "deprotonate all carboxylic, sulphur and phosphorous acid groups"); parser.add_flag("H,allH", "read all hydrogens present. If disabled, read polar hydrogens only"); - parser.add("t,target", "score threshold OR filter file name"); + parser.add("t,target", "score threshold (or filter file name, deprecated)"); parser.add_flag("C,cont", "if enabled, continue if score threshold is met (use with -t )"); parser.add("T,trace", "controls output level for debugging (0 = minimal, >0 = more verbose)", "0"); parser.add("s,seed", "random number seed (default=from sys clock)"); + parser.add("f,filter", "filter file name", ""); return parser; } @@ -38,26 +39,30 @@ RBDock::RBDockConfig RBDock::parse_args(int argc, const char *argv[]) { if (parser_result["protocol"].is_present()) { parser_result["protocol"] >> config.strParamFile; } - config.bOutput = parser_result["output-root"].is_present(); - parser_result["output-root"] >> config.strRunName; + parser_result["output-root"] >> config.strOutputPrefix; parser_result["runs"] >> config.nDockingRuns; parser_result["ap"] >> config.bPosIonise; parser_result["an"] >> config.bNegIonise; parser_result["allH"] >> config.bAllH; - config.bSeed = parser_result["seed"].is_present(); - if (config.bSeed) parser_result["seed"] >> config.nSeed; - config.bTrace = parser_result["trace"].is_present(); - if (config.bTrace) parser_result["trace"] >> config.iTrace; + if (parser_result["seed"].is_present()) parser_result["seed"] >> config.nSeed; + if (parser_result["trace"].is_present()) parser_result["trace"] >> config.iTrace; if (parser_result["target"].is_present()) { std::string target; parser_result["target"] >> target; - if (target.find(".prm") != string::npos) { - config.bFilter = true; - config.strFilterFile = target; - } else { - config.bTarget = true; + // if target is numeric, store as a target score + try { config.dTargetScore = std::stod(target); + } catch (std::invalid_argument &e) { + // if target is not numeric, store as a filter file name + std::cerr << "Warning: -t option is deprecated for filter files. Use -f instead." << std::endl; + config.strFilterFile = target; + } + } + if (parser_result["filter"].is_present()) { + if (config.dTargetScore.has_value()) { + throw Rbt::ValidationError("Cannot specify both -t and -f options"); } + parser_result["filter"] >> config.strFilterFile; } parser_result["cont"] >> config.bContinue; diff --git a/src/lib/rbdock/rbdock_main.cxx b/src/lib/rbdock/rbdock_main.cxx index 0045257..b442d96 100644 --- a/src/lib/rbdock/rbdock_main.cxx +++ b/src/lib/rbdock/rbdock_main.cxx @@ -32,23 +32,23 @@ const RbtString _ROOT_TRANSFORM = "DOCK"; std::string RBDock::get_filter_string(const RBDock::RBDockConfig &config) { std::ostringstream strFilter; - if (!config.bFilter) { - if (config.bTarget) { // -t - if (!config.bDockingRuns) { // -t only - strFilter << "0 1 - SCORE.INTER " << config.dTargetScore << std::endl; + if (!config.strFilterFile.has_value()) { + if (config.dTargetScore.has_value()) { // -t + if (!config.nDockingRuns.has_value()) { // -t only + strFilter << "0 1 - SCORE.INTER " << config.dTargetScore.value() << std::endl; } else // -t -n need to check if -cont present // for all other cases it doesn't matter if (config.bContinue) { // -t -n -cont - strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " - << config.dTargetScore << std::endl; + strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns.value() - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " + << config.dTargetScore.value() << std::endl; } else { // -t -n - strFilter << "1 if - " << config.dTargetScore << " SCORE.INTER 0.0 " - << "if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " - << config.dTargetScore << std::endl; + strFilter << "1 if - " << config.dTargetScore.value() << " SCORE.INTER 0.0 " + << "if - SCORE.NRUNS " << (config.nDockingRuns.value() - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " + << config.dTargetScore.value() << std::endl; } } // no target score, no filter - else if (config.bDockingRuns) { // -n - strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns - 1) << " 0.0 -1.0,\n0"; + else if (config.nDockingRuns.has_value()) { // -n + strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns.value() - 1) << " 0.0 -1.0,\n0"; } else { // no -t no -n strFilter << "0 0\n"; } @@ -118,8 +118,8 @@ void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeN // Override the TRACE levels for the scoring function and transform // Dump details to cout // Register the scoring function and the transform with the workspace - if (config.bTrace) { - RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace)); + if (config.iTrace.has_value()) { + RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace.value())); spSF->HandleRequest(spTraceReq); spTransform->HandleRequest(spTraceReq); } @@ -160,13 +160,13 @@ void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeN // Prepare the SD file sink for saving the docked conformations for each ligand // DM 3 Dec 1999 - replaced ostringstream with RbtString in determining SD file name // SRC 2014 moved here this block to allow WRITE_ERROR TRUE - if (config.bOutput) { - RbtMolecularFileSinkPtr spMdlFileSink(new RbtMdlFileSink(config.strRunName + ".sd", RbtModelPtr())); + if (config.strOutputPrefix.has_value()) { + RbtMolecularFileSinkPtr spMdlFileSink(new RbtMdlFileSink(config.strOutputPrefix.value() + ".sd", RbtModelPtr())); spWS->SetSink(spMdlFileSink); } RbtPRMFactory prmFactory(spRecepPrmSource, spDS); - prmFactory.SetTrace(config.iTrace); + prmFactory.SetTrace(config.iTrace.value_or(0)); // Create the receptor model from the file names in the receptor parameter file RbtModelPtr spReceptor = prmFactory.CreateReceptor(); spWS->SetReceptor(spReceptor); @@ -185,22 +185,22 @@ void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeN // Seed the random number generator RbtRand &theRand = Rbt::GetRbtRand(); // ref to random number generator - if (config.bSeed) { - theRand.Seed(config.nSeed); + if (config.nSeed.has_value()) { + theRand.Seed(config.nSeed.value()); } // Create the filter object for controlling early termination of protocol RbtFilterPtr spfilter; - if (config.bFilter) { - spfilter = new RbtFilter(config.strFilterFile); - if (config.bDockingRuns) { - spfilter->SetMaxNRuns(config.nDockingRuns); + if (config.strFilterFile.has_value()) { + spfilter = new RbtFilter(config.strFilterFile.value()); + if (config.nDockingRuns.has_value()) { + spfilter->SetMaxNRuns(config.nDockingRuns.value()); } } else { spfilter = new RbtFilter(get_filter_string(config), true); } - if (config.bTrace) { - RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace)); + if (config.iTrace.has_value()) { + RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace.value())); spfilter->HandleRequest(spTraceReq); } @@ -239,7 +239,7 @@ void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeN RbtString strMolName = spLigand->GetName(); spWS->SetLigand(spLigand); // Update any model coords from embedded chromosomes in the ligand file - spWS->UpdateModelCoordsFromChromRecords(spMdlFileSource, config.iTrace); + spWS->UpdateModelCoordsFromChromRecords(spMdlFileSource, config.iTrace.value_or(0)); // DM 18 May 1999 - store run info in model data // Clear any previous Rbt.* data fields @@ -265,9 +265,9 @@ void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeN while (!bTargetMet) { // Catching errors with this specific run try { - if (config.bOutput) { + if (config.strOutputPrefix.has_value()) { ostringstream histr; - histr << config.strRunName << "_" << strMolName << nRec << "_his_" << iRun << ".sd"; + histr << config.strOutputPrefix.value() << "_" << strMolName << nRec << "_his_" << iRun << ".sd"; RbtMolecularFileSinkPtr spHistoryFileSink(new RbtMdlFileSink(histr.str(), spLigand)); spWS->SetHistorySink(spHistoryFileSink); } @@ -275,7 +275,7 @@ void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeN RbtBool bterm = spfilter->Terminate(); RbtBool bwrite = spfilter->Write(); if (bterm) bTargetMet = true; - if (config.bOutput && bwrite) { + if (config.strOutputPrefix.has_value() && bwrite) { spWS->Save(); } iRun++; From 257f77459629075487f704f0a24246f640f5b20e Mon Sep 17 00:00:00 2001 From: ggutierrez-sb Date: Sat, 4 Jan 2025 20:23:14 +0000 Subject: [PATCH 08/13] move filter string generation into rbdock config --- include/rbdock/rbdock_config.h | 34 ++++++++++++++++++++++++++++++---- include/rbdock/rbdock_main.h | 1 - src/lib/rbdock/rbdock_main.cxx | 33 +++++---------------------------- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/include/rbdock/rbdock_config.h b/include/rbdock/rbdock_config.h index 78a2c3c..a7a4065 100644 --- a/include/rbdock/rbdock_config.h +++ b/include/rbdock/rbdock_config.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "RbtValidationError.h" @@ -70,17 +71,42 @@ struct RBDockConfig { void validate() { if (strLigandMdlFile.empty()) throw Rbt::ValidationError("input ligand SD file is mandatory"); if (strReceptorPrmFile.empty()) throw Rbt::ValidationError("receptor parameter file is mandatory"); - if (nDockingRuns < 1) throw Rbt::ValidationError("number of runs must be greater than 0"); + if (nDockingRuns.has_value() && nDockingRuns < 1) + throw Rbt::ValidationError("number of runs must be greater than 0"); } bool operator==(const RBDockConfig &rhs) const { return strLigandMdlFile == rhs.strLigandMdlFile && strOutputPrefix == rhs.strOutputPrefix && strReceptorPrmFile == rhs.strReceptorPrmFile && strParamFile == rhs.strParamFile - && strFilterFile == rhs.strFilterFile && nDockingRuns == rhs.nDockingRuns - && bContinue == rhs.bContinue && dTargetScore == rhs.dTargetScore - && bPosIonise == rhs.bPosIonise && bNegIonise == rhs.bNegIonise + && strFilterFile == rhs.strFilterFile && nDockingRuns == rhs.nDockingRuns && bContinue == rhs.bContinue + && dTargetScore == rhs.dTargetScore && bPosIonise == rhs.bPosIonise && bNegIonise == rhs.bNegIonise && bAllH == rhs.bAllH && nSeed == rhs.nSeed && iTrace == rhs.iTrace; } + + std::string get_filter_string() const { + std::ostringstream strAuxFilter; + if (strFilterFile.has_value()) return ""; + if (dTargetScore.has_value()) { // -t + if (!nDockingRuns.has_value()) { // -t only + strAuxFilter << "0 1 - SCORE.INTER " << dTargetScore.value() << std::endl; + } else // -t -n need to check if -cont present + // for all other cases it doesn't matter + if (bContinue) { // -t -n -cont + strAuxFilter << "1 if - SCORE.NRUNS " << (nDockingRuns.value() - 1) + << " 0.0 -1.0,\n1 - SCORE.INTER " << dTargetScore.value() << std::endl; + } else { // -t -n + strAuxFilter << "1 if - " << dTargetScore.value() << " SCORE.INTER 0.0 " + << "if - SCORE.NRUNS " << (nDockingRuns.value() - 1) + << " 0.0 -1.0,\n1 - SCORE.INTER " << dTargetScore.value() << std::endl; + } + } // no target score, no filter + else if (nDockingRuns.has_value()) { // -n + strAuxFilter << "1 if - SCORE.NRUNS " << (nDockingRuns.value() - 1) << " 0.0 -1.0,\n0"; + } else { // no -t no -n + strAuxFilter << "0 0\n"; + } + return strAuxFilter.str(); + } }; } // namespace RBDock diff --git a/include/rbdock/rbdock_main.h b/include/rbdock/rbdock_main.h index d0e6b03..49a3caf 100644 --- a/include/rbdock/rbdock_main.h +++ b/include/rbdock/rbdock_main.h @@ -6,7 +6,6 @@ #include "rbdock/rbdock_config.h" namespace RBDock { -std::string get_filter_string(const RBDockConfig &config); void RBDock(const RBDockConfig &config, const std::string &strExeName); } // namespace RBDock diff --git a/src/lib/rbdock/rbdock_main.cxx b/src/lib/rbdock/rbdock_main.cxx index b442d96..12ec4e2 100644 --- a/src/lib/rbdock/rbdock_main.cxx +++ b/src/lib/rbdock/rbdock_main.cxx @@ -30,31 +30,6 @@ const RbtString _ROOT_SF = "SCORE"; const RbtString _RESTRAINT_SF = "RESTR"; const RbtString _ROOT_TRANSFORM = "DOCK"; -std::string RBDock::get_filter_string(const RBDock::RBDockConfig &config) { - std::ostringstream strFilter; - if (!config.strFilterFile.has_value()) { - if (config.dTargetScore.has_value()) { // -t - if (!config.nDockingRuns.has_value()) { // -t only - strFilter << "0 1 - SCORE.INTER " << config.dTargetScore.value() << std::endl; - } else // -t -n need to check if -cont present - // for all other cases it doesn't matter - if (config.bContinue) { // -t -n -cont - strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns.value() - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " - << config.dTargetScore.value() << std::endl; - } else { // -t -n - strFilter << "1 if - " << config.dTargetScore.value() << " SCORE.INTER 0.0 " - << "if - SCORE.NRUNS " << (config.nDockingRuns.value() - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " - << config.dTargetScore.value() << std::endl; - } - } // no target score, no filter - else if (config.nDockingRuns.has_value()) { // -n - strFilter << "1 if - SCORE.NRUNS " << (config.nDockingRuns.value() - 1) << " 0.0 -1.0,\n0"; - } else { // no -t no -n - strFilter << "0 0\n"; - } - } - return strFilter.str(); -} void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeName) { // Create a bimolecular workspace @@ -161,7 +136,8 @@ void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeN // DM 3 Dec 1999 - replaced ostringstream with RbtString in determining SD file name // SRC 2014 moved here this block to allow WRITE_ERROR TRUE if (config.strOutputPrefix.has_value()) { - RbtMolecularFileSinkPtr spMdlFileSink(new RbtMdlFileSink(config.strOutputPrefix.value() + ".sd", RbtModelPtr())); + RbtMolecularFileSinkPtr spMdlFileSink(new RbtMdlFileSink(config.strOutputPrefix.value() + ".sd", RbtModelPtr()) + ); spWS->SetSink(spMdlFileSink); } @@ -197,7 +173,7 @@ void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeN spfilter->SetMaxNRuns(config.nDockingRuns.value()); } } else { - spfilter = new RbtFilter(get_filter_string(config), true); + spfilter = new RbtFilter(config.get_filter_string(), true); } if (config.iTrace.has_value()) { RbtRequestPtr spTraceReq(new RbtSFSetParamRequest("TRACE", config.iTrace.value())); @@ -267,7 +243,8 @@ void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeN try { if (config.strOutputPrefix.has_value()) { ostringstream histr; - histr << config.strOutputPrefix.value() << "_" << strMolName << nRec << "_his_" << iRun << ".sd"; + histr << config.strOutputPrefix.value() << "_" << strMolName << nRec << "_his_" << iRun + << ".sd"; RbtMolecularFileSinkPtr spHistoryFileSink(new RbtMdlFileSink(histr.str(), spLigand)); spWS->SetHistorySink(spHistoryFileSink); } From e1f28e869081630b593205304fa9ab1df84112f5 Mon Sep 17 00:00:00 2001 From: ggutierrez-sb Date: Sat, 4 Jan 2025 20:24:35 +0000 Subject: [PATCH 09/13] add tests for rbdock arg parsing --- tests/src/test_rbdock_argparser.cpp | 114 ++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tests/src/test_rbdock_argparser.cpp diff --git a/tests/src/test_rbdock_argparser.cpp b/tests/src/test_rbdock_argparser.cpp new file mode 100644 index 0000000..e9edbee --- /dev/null +++ b/tests/src/test_rbdock_argparser.cpp @@ -0,0 +1,114 @@ +#include +#include +#include + +#include "rbdock/rbdock_argparser.h" +#include "rbdock/rbdock_config.h" +#include "test_utils.hpp" + +using RBDock::RBDockConfig; + +typedef std::tuple, RBDockConfig> TestConfig; + +TEST_CASE("rbdock", "[argparser]") { + std::vector configs{ + // base config + {{"-r", "receptor.prm", "-i", "ligand.sdf"}, + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm"}}, + // config with output + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-o", "output"}, + + RBDockConfig{ + .strLigandMdlFile = "ligand.sdf", + .strReceptorPrmFile = "receptor.prm", + .strOutputPrefix = "output", + }}, + // config with protocol + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-p", "protocol.prm"}, + + RBDockConfig{ + .strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .strParamFile = "protocol.prm"}}, + // config with filter + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-t", "filter.txt"}, + + RBDockConfig{ + .strLigandMdlFile = "ligand.sdf", + .strReceptorPrmFile = "receptor.prm", + .strFilterFile = "filter.txt", + }}, + // config with target score + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-t", "0.5"}, + + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .dTargetScore = 0.5}}, + // config with continue + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-C"}, + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .bContinue = true}}, + // config with docking runs + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-n", "5"}, + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .nDockingRuns = 5}}, + // config with protonate + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-P"}, + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .bPosIonise = true}}, + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-ap"}, + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .bPosIonise = true}}, + // config with deprotonate + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-D"}, + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .bNegIonise = true}}, + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-an"}, + + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .bNegIonise = true}}, + // config with all hydrogens + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-H"}, + + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .bAllH = true}}, + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-allH"}, + + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .bAllH = true}}, + // config with seed + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-s", "123"}, + + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .nSeed = 123}}, + // config with trace + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-T", "2"}, + + RBDockConfig{.strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .iTrace = 2}}, + // config with filter + {{"-r", "receptor.prm", "-i", "ligand.sdf", "-f", "filter.txt"}, + RBDockConfig{ + .strLigandMdlFile = "ligand.sdf", .strReceptorPrmFile = "receptor.prm", .strFilterFile = "filter.txt"}}, + + // config with all options + { + {"-r", "receptor.prm", "-i", "ligand.sdf", "-o", "output", "-p", "protocol.prm", "-t", "0.5", + "-C", "-n", "5", "-P", "-D", "-H", "-s", "123", "-T", "2"}, + + RBDockConfig{ + .strLigandMdlFile = "ligand.sdf", + .strReceptorPrmFile = "receptor.prm", + .strParamFile = "protocol.prm", + .strOutputPrefix = "output", + .nDockingRuns = 5, + .dTargetScore = 0.5, + .nSeed = 123, + .iTrace = 2, + .bContinue = true, + .bPosIonise = true, + .bNegIonise = true, + .bAllH = true, + }, + }, + }; + NullBuffer null_buffer; + CoutRedirect redirect_cout(&null_buffer); + CerrRedirect redirect_cerr(&null_buffer); + + auto [test_input, expected_config] = GENERATE_COPY(from_range(configs)); + + auto inputs = std::vector{"rbdock"}; + for (auto &input: test_input) inputs.push_back(input.c_str()); + std::cerr << "inputs: "; + for (auto &input: inputs) std::cerr << input << " "; + std::cerr << std::endl; + auto result = RBDock::parse_args(inputs.size(), inputs.data()); + REQUIRE(result == expected_config); +} From 0a079e233db358a751e411f01d0a9b3bff670296 Mon Sep 17 00:00:00 2001 From: ggutierrez-sb Date: Sat, 4 Jan 2025 20:25:17 +0000 Subject: [PATCH 10/13] lint --- include/RbtArgParser.h | 1 - include/rbdock/rbdock_config.h | 8 ++++---- src/lib/rbdock/rbdock_argparser.cxx | 8 +++----- src/lib/rbdock/rbdock_main.cxx | 1 - 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/include/RbtArgParser.h b/include/RbtArgParser.h index aa5bbe2..d85912b 100644 --- a/include/RbtArgParser.h +++ b/include/RbtArgParser.h @@ -68,7 +68,6 @@ class RbtOptionValue { return *this; } - inline bool is_present() { return value.count() > 0; } }; diff --git a/include/rbdock/rbdock_config.h b/include/rbdock/rbdock_config.h index a7a4065..916827e 100644 --- a/include/rbdock/rbdock_config.h +++ b/include/rbdock/rbdock_config.h @@ -93,11 +93,11 @@ struct RBDockConfig { // for all other cases it doesn't matter if (bContinue) { // -t -n -cont strAuxFilter << "1 if - SCORE.NRUNS " << (nDockingRuns.value() - 1) - << " 0.0 -1.0,\n1 - SCORE.INTER " << dTargetScore.value() << std::endl; + << " 0.0 -1.0,\n1 - SCORE.INTER " << dTargetScore.value() << std::endl; } else { // -t -n strAuxFilter << "1 if - " << dTargetScore.value() << " SCORE.INTER 0.0 " - << "if - SCORE.NRUNS " << (nDockingRuns.value() - 1) - << " 0.0 -1.0,\n1 - SCORE.INTER " << dTargetScore.value() << std::endl; + << "if - SCORE.NRUNS " << (nDockingRuns.value() - 1) << " 0.0 -1.0,\n1 - SCORE.INTER " + << dTargetScore.value() << std::endl; } } // no target score, no filter else if (nDockingRuns.has_value()) { // -n @@ -105,7 +105,7 @@ struct RBDockConfig { } else { // no -t no -n strAuxFilter << "0 0\n"; } - return strAuxFilter.str(); + return strAuxFilter.str(); } }; diff --git a/src/lib/rbdock/rbdock_argparser.cxx b/src/lib/rbdock/rbdock_argparser.cxx index c6979ef..62b6a77 100644 --- a/src/lib/rbdock/rbdock_argparser.cxx +++ b/src/lib/rbdock/rbdock_argparser.cxx @@ -36,11 +36,9 @@ RBDock::RBDockConfig RBDock::parse_args(int argc, const char *argv[]) { RBDock::RBDockConfig config; parser_result["input"] >> config.strLigandMdlFile; parser_result["receptor"] >> config.strReceptorPrmFile; - if (parser_result["protocol"].is_present()) { - parser_result["protocol"] >> config.strParamFile; - } - parser_result["output-root"] >> config.strOutputPrefix; - parser_result["runs"] >> config.nDockingRuns; + if (parser_result["protocol"].is_present()) parser_result["protocol"] >> config.strParamFile; + if (parser_result["output-root"].is_present()) parser_result["output-root"] >> config.strOutputPrefix; + if (parser_result["runs"].is_present()) parser_result["runs"] >> config.nDockingRuns; parser_result["ap"] >> config.bPosIonise; parser_result["an"] >> config.bNegIonise; parser_result["allH"] >> config.bAllH; diff --git a/src/lib/rbdock/rbdock_main.cxx b/src/lib/rbdock/rbdock_main.cxx index 12ec4e2..ac050c5 100644 --- a/src/lib/rbdock/rbdock_main.cxx +++ b/src/lib/rbdock/rbdock_main.cxx @@ -30,7 +30,6 @@ const RbtString _ROOT_SF = "SCORE"; const RbtString _RESTRAINT_SF = "RESTR"; const RbtString _ROOT_TRANSFORM = "DOCK"; - void RBDock::RBDock(const RBDock::RBDockConfig &config, const RbtString &strExeName) { // Create a bimolecular workspace RbtBiMolWorkSpacePtr spWS(new RbtBiMolWorkSpace()); From 61cc722cde4a16f458c0081793fa7a161312bbe4 Mon Sep 17 00:00:00 2001 From: ggutierrez-sb Date: Sat, 4 Jan 2025 20:27:56 +0000 Subject: [PATCH 11/13] remove libpopt from dependencies --- .github/docker/Dockerfile.centos-stream9 | 3 ++- .github/docker/Dockerfile.debian-12 | 2 +- .github/docker/Dockerfile.ubuntu-24.04 | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/docker/Dockerfile.centos-stream9 b/.github/docker/Dockerfile.centos-stream9 index 95b83b9..2389a28 100644 --- a/.github/docker/Dockerfile.centos-stream9 +++ b/.github/docker/Dockerfile.centos-stream9 @@ -1,3 +1,4 @@ FROM quay.io/centos/centos:stream9 AS base -RUN yum install -y popt-devel gcc-c++ make diffutils +# Install dependencies +RUN yum install -y gcc-c++ make diffutils diff --git a/.github/docker/Dockerfile.debian-12 b/.github/docker/Dockerfile.debian-12 index b8b09e5..678e303 100644 --- a/.github/docker/Dockerfile.debian-12 +++ b/.github/docker/Dockerfile.debian-12 @@ -1,4 +1,4 @@ FROM debian:12 AS base # Install dependencies -RUN apt-get update && apt-get install -y --no-install-recommends make g++ libpopt-dev libpopt0 +RUN apt-get update && apt-get install -y --no-install-recommends make g++ diff --git a/.github/docker/Dockerfile.ubuntu-24.04 b/.github/docker/Dockerfile.ubuntu-24.04 index bd411c9..26c215b 100644 --- a/.github/docker/Dockerfile.ubuntu-24.04 +++ b/.github/docker/Dockerfile.ubuntu-24.04 @@ -1,4 +1,4 @@ FROM ubuntu:22.04 AS base # Install dependencies -RUN apt-get update && apt-get install -y --no-install-recommends make g++ libpopt-dev libpopt0 +RUN apt-get update && apt-get install -y --no-install-recommends make g++ From 21e27c5379e32742c7af8ae56bc9880d53a134b7 Mon Sep 17 00:00:00 2001 From: ggutierrez-sb Date: Sat, 4 Jan 2025 20:30:19 +0000 Subject: [PATCH 12/13] update readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 99cad4f..d2e7d9e 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,12 @@ make sure the following requirements are installed and available: * make * a c++ compiler (g++ by default) -* popt and development headers (libpopt0 and libpopt-dev in ubuntu) * git (optional if you download the code directly) if you're running ubuntu, you can get all of them by running ``` -sudo apt update && sudo apt install -y make git libpopt0 libpopt-dev g++ +sudo apt update && sudo apt install -y make git g++ ``` you can also check requirements for other officially supported distributions in the [Dockerfiles](https://github.com/CBDD/rDock/blob/main/.github/docker) used for CI From 424e714a24dfa7f92909449359d47193da311614 Mon Sep 17 00:00:00 2001 From: ggutierrez-sb Date: Mon, 3 Feb 2025 18:28:13 +0000 Subject: [PATCH 13/13] update tests for rbcavity argparser --- tests/src/test_rbcavity_argparser.cpp | 37 ++++++++++++--------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/tests/src/test_rbcavity_argparser.cpp b/tests/src/test_rbcavity_argparser.cpp index 36865f2..9904e69 100644 --- a/tests/src/test_rbcavity_argparser.cpp +++ b/tests/src/test_rbcavity_argparser.cpp @@ -1,24 +1,22 @@ #include +#include +#include #include "rbcavity/rbcavity_argparser.h" #include "rbcavity/rbcavity_config.h" - #include "test_utils.hpp" -#include -#include - - -struct TestConfig{ +struct TestConfig { std::vector input; RBCavity::RBCavityConfig expected_config; }; - TEST_CASE("rbcavity", "[argparser]") { auto config_base = RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm"}; - auto config_with_list = RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm", .bList = true, .dist = 3.0f}; - auto config_with_border = RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm", .bBorder = true, .border = 5.0f}; + auto config_with_list = + RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm", .bList = true, .dist = 3.0f}; + auto config_with_border = + RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm", .bBorder = true, .border = 5.0f}; auto config_with_read_as = RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm", .bReadAS = true}; auto config_with_write_as = RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm", .bWriteAS = true}; auto config_with_dump_insight = RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm", .bDump = true}; @@ -26,7 +24,8 @@ TEST_CASE("rbcavity", "[argparser]") { auto config_with_site = RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm", .bSite = true}; auto config_with_moe_grid = RBCavity::RBCavityConfig{.strReceptorPrmFile = "receptor.prm", .bMOEgrid = true}; - std::vector all_settings{"-r", "receptor.prm", "-l", "3", "-b", "5", "-R", "-W", "-d", "-v", "-s", "-m"}; + std::vector all_settings{ + "-r", "receptor.prm", "-l", "3", "-b", "5", "-R", "-W", "-d", "-v", "-s", "-m"}; auto config_all_settings = RBCavity::RBCavityConfig{ .strReceptorPrmFile = "receptor.prm", .bReadAS = true, @@ -41,7 +40,7 @@ TEST_CASE("rbcavity", "[argparser]") { .dist = 3.0f, }; - std::vector configs { + std::vector configs{ TestConfig{.input = {"-r", "receptor.prm"}, .expected_config = config_base}, TestConfig{.input = {"-rreceptor.prm"}, .expected_config = config_base}, TestConfig{.input = {"-receptor=receptor.prm"}, .expected_config = config_base}, @@ -75,16 +74,14 @@ TEST_CASE("rbcavity", "[argparser]") { TestConfig{.input = {"-r", "receptor.prm", "-m"}, .expected_config = config_with_moe_grid}, TestConfig{.input = {"-r", "receptor.prm", "-dump-moe"}, .expected_config = config_with_moe_grid}, TestConfig{.input = {"-r", "receptor.prm", "--dump-moe"}, .expected_config = config_with_moe_grid}, - TestConfig{.input = all_settings, .expected_config = config_all_settings} - }; + TestConfig{.input = all_settings, .expected_config = config_all_settings}}; NullBuffer null_buffer; CoutRedirect redirect_cout(&null_buffer); CerrRedirect redirect_cerr(&null_buffer); - - for (auto test_config: configs) { - auto inputs = std::vector{"rbcavity"}; - for (auto & input: test_config.input) inputs.push_back(input.c_str()); - auto result = RBCavity::parse_args(inputs.size(), inputs.data()); - REQUIRE(result == test_config.expected_config); - } + + auto test_config = GENERATE_COPY(from_range(configs)); + auto inputs = std::vector{"rbcavity"}; + for (auto &input: test_config.input) inputs.push_back(input.c_str()); + auto result = RBCavity::parse_args(inputs.size(), inputs.data()); + REQUIRE(result == test_config.expected_config); }