diff --git a/modules/conop/doc/compoundlib.rst b/modules/conop/doc/compoundlib.rst index fcad2af47fcfeae5784990b42f39d26819a71bad..73514ba01b2c6ad4ca11d2a9b095bc00a8875e6d 100644 --- a/modules/conop/doc/compoundlib.rst +++ b/modules/conop/doc/compoundlib.rst @@ -58,11 +58,17 @@ built with OST 1.5.0 or later can be loaded. Create a new compound library - .. method:: FindCompound(tlc, dialect='PDB') + .. method:: FindCompound(id, dialect='PDB', by="tlc") - Lookup compound by its three-letter-code, e.g ALA. If no compound with that - name exists, the function returns None. Compounds are cached after they have - been loaded with FindCompound. To delete the compound cache, use + Lookup a compound. By default the compound is searched by its + three-letter-code, e.g ALA. This can be changed with the `by` argument. + The following keys are available: "tlc" (three-letter-code or compound ID), + "inchi_code", "inchi_key" and "smiles". + + If no compound with that name exists, the function returns None. + + Compounds are cached after they have been loaded with FindCompound. + To delete the compound cache, use :meth:`ClearCache`. :returns: The found compound diff --git a/modules/conop/pymod/export_compound.cc b/modules/conop/pymod/export_compound.cc index 0051e1f3c54988ca79074821272a63353b2c7293..edd30c2585cad216366377734bf9eb6a43a1fc09 100644 --- a/modules/conop/pymod/export_compound.cc +++ b/modules/conop/pymod/export_compound.cc @@ -70,9 +70,10 @@ char get_chemtype(CompoundPtr compound) } CompoundPtr find_compound(CompoundLibPtr comp_lib, - const String& tlc, const String& dialect) + const String& id, const String& dialect, + const String& by="tlc") { - return comp_lib->FindCompound(tlc, tr_dialect(dialect)); + return comp_lib->FindCompound(id, tr_dialect(dialect), by); } bool is_residue_complete(CompoundLibPtr comp_lib, @@ -151,7 +152,7 @@ void export_Compound() { class_<CompoundLib>("CompoundLib", no_init) .def("Load", &CompoundLib::Load, arg("readonly")=true).staticmethod("Load") .def("FindCompound", &find_compound, - (arg("tlc"), arg("dialect")="PDB")) + (arg("id"), arg("dialect")="PDB", arg("by")="tlc")) .def("IsResidueComplete", &is_residue_complete, (arg("residue"), arg("check_hydrogens")=false, arg("dialect")="PDB")) diff --git a/modules/conop/src/compound_lib.cc b/modules/conop/src/compound_lib.cc index 62b3ed8ccc494c655232213ed50b5f3558814588..1611570bc36bd893a02d60dffecca2deea296ef6 100644 --- a/modules/conop/src/compound_lib.cc +++ b/modules/conop/src/compound_lib.cc @@ -70,8 +70,14 @@ const char* CREATE_CMD[]={ " inchi_key TEXT, " " smiles TEXT " ");", -" CREATE UNIQUE INDEX IF NOT EXISTS commpound_tlc_index ON chem_compounds " +" CREATE UNIQUE INDEX IF NOT EXISTS compound_tlc_index ON chem_compounds " " (tlc, dialect)", +" CREATE INDEX IF NOT EXISTS compound_smiles_index ON chem_compounds " +" (smiles, dialect)", +" CREATE INDEX IF NOT EXISTS compound_inchi_code_index ON chem_compounds " +" (inchi_code, dialect)", +" CREATE INDEX IF NOT EXISTS compound_inchi_key_index ON chem_compounds " +" (inchi_key, dialect)", "CREATE TABLE IF NOT EXISTS atoms ( " " id INTEGER PRIMARY KEY AUTOINCREMENT, " " compound_id INTEGER REFERENCES chem_compounds (id) ON DELETE CASCADE, " @@ -498,18 +504,37 @@ void CompoundLib::LoadBondsFromDB(CompoundPtr comp, int pk) const { } CompoundPtr CompoundLib::FindCompound(const String& id, - Compound::Dialect dialect) const { - CompoundMap::const_iterator i=compound_cache_.find(id); + Compound::Dialect dialect, + const String& by) const { + + // Validate "by" argument + std::set<std::string> allowed_keys{"tlc", "inchi_code", "inchi_key"}; + if(smiles_available_) { + allowed_keys.insert("smiles"); + } + if (allowed_keys.find(by) == allowed_keys.end()) { + std::stringstream msg; + msg << "Invalid 'by' key: " << by; + throw ost::Error(msg.str()); + } + + // Check cache + String cache_key = by + "_" + id; + CompoundMap::const_iterator i=compound_cache_.find(cache_key); if (i!=compound_cache_.end()) { + LOG_DEBUG("Retrieved compound " << cache_key << " from cache"); return i->second; } + + // Build the query String query="SELECT id, tlc, olc, chem_class, dialect, formula, chem_type, name, inchi_code, inchi_key"; if(smiles_available_) { query+=", smiles"; } - query+=" FROM chem_compounds" - " WHERE tlc=? AND dialect='"+String(1, char(dialect))+"'"; + " WHERE " + by + "=? AND dialect='"+String(1, char(dialect))+"'"; + + // Run the query sqlite3_stmt* stmt; int retval=sqlite3_prepare_v2(db_->ptr, query.c_str(), static_cast<int>(query.length()), @@ -553,7 +578,7 @@ CompoundPtr CompoundLib::FindCompound(const String& id, // Load atoms and bonds this->LoadAtomsFromDB(compound, pk); this->LoadBondsFromDB(compound, pk); - compound_cache_.insert(std::make_pair(compound->GetID(), compound)); + compound_cache_.insert(std::make_pair(cache_key, compound)); sqlite3_finalize(stmt); return compound; } diff --git a/modules/conop/src/compound_lib.hh b/modules/conop/src/compound_lib.hh index 8786ce8105ef9c176a7f0c1273d090c1e10d3650..c2e75f6a6981868103f3d2bec8da4745471b751f 100644 --- a/modules/conop/src/compound_lib.hh +++ b/modules/conop/src/compound_lib.hh @@ -39,7 +39,8 @@ public: ~CompoundLib(); virtual CompoundPtr FindCompound(const String& id, - Compound::Dialect dialect) const; + Compound::Dialect dialect, + const String& by="tlc") const; void AddCompound(const CompoundPtr& compound); CompoundLibPtr Copy(const String& filename) const; void ClearCache(); diff --git a/modules/conop/src/compound_lib_base.hh b/modules/conop/src/compound_lib_base.hh index aee5215b944597bc0a4a621af137118a8824da75..d8cdd7e4332f6f193dae8548beace6496e0751cd 100644 --- a/modules/conop/src/compound_lib_base.hh +++ b/modules/conop/src/compound_lib_base.hh @@ -13,7 +13,8 @@ class DLLEXPORT_OST_CONOP CompoundLibBase { public: virtual ~CompoundLibBase() {} virtual CompoundPtr FindCompound(const String& id, - Compound::Dialect dialect) const = 0; + Compound::Dialect dialect, + const String& by="tlc") const = 0; bool IsResidueComplete(const ost::mol::ResidueHandle& res, bool check_hydrogens, diff --git a/modules/conop/src/minimal_compound_lib.cc b/modules/conop/src/minimal_compound_lib.cc index 9eeb107539e70a34bcdfe9f66ec4917d8b2bcc56..3b0d6dc8ce858fac1b96ef76a221023c74f62dcd 100644 --- a/modules/conop/src/minimal_compound_lib.cc +++ b/modules/conop/src/minimal_compound_lib.cc @@ -42,8 +42,15 @@ CompoundMap MinimalCompoundLib::InitCompounds() { CompoundPtr MinimalCompoundLib::FindCompound(const String& id, - Compound::Dialect dialect) const + Compound::Dialect dialect, + const String& by) const { + if (by != "tlc") { + // Only tlc is supported by the minimal compound lib + std::stringstream msg; + msg << "Invalid 'by' key: " << by; + throw ost::Error(msg.str()); + } CompoundMap::const_iterator i = MinimalCompoundLib::compounds_.find(id); if (i != MinimalCompoundLib::compounds_.end()) { return i->second; diff --git a/modules/conop/src/minimal_compound_lib.hh b/modules/conop/src/minimal_compound_lib.hh index b0defbabaae9fafa9ca9f5c49142879c5c32e590..16b58bff4bb6302fa711924733abbac4c301e111 100644 --- a/modules/conop/src/minimal_compound_lib.hh +++ b/modules/conop/src/minimal_compound_lib.hh @@ -17,7 +17,8 @@ public: CompoundLibBase() {} virtual CompoundPtr FindCompound(const String& id, - Compound::Dialect dialect) const; + Compound::Dialect dialect, + const String& by="tlc") const; private: static CompoundMap InitCompounds(); // since this information is never going to change, it is shared