diff --git a/modules/conop/doc/compoundlib.rst b/modules/conop/doc/compoundlib.rst index fed70b6379713ceee56ca9273dc3a1541455947c..640ced9e1ee3dfc7f97340dea72282e4baf1444e 100644 --- a/modules/conop/doc/compoundlib.rst +++ b/modules/conop/doc/compoundlib.rst @@ -192,6 +192,10 @@ build the compound library manually. of a leaving atom is the *OXT* atom of amino acids that gets lost when a peptide bond is formed. + .. attribute:: charge + + The charge of the atom. + .. class:: BondSpec Definition of a bond diff --git a/modules/conop/pymod/export_compound.cc b/modules/conop/pymod/export_compound.cc index 98acbb126527f4c274cefb5b6e70377861f8dd77..0051e1f3c54988ca79074821272a63353b2c7293 100644 --- a/modules/conop/pymod/export_compound.cc +++ b/modules/conop/pymod/export_compound.cc @@ -138,6 +138,7 @@ void export_Compound() { .def_readonly("is_leaving", &AtomSpec::is_leaving) .def_readonly("is_aromatic", &AtomSpec::is_aromatic) .def_readonly("ordinal", &AtomSpec::ordinal) + .def_readonly("charge", &AtomSpec::charge) ; class_<BondSpec>("BondSpec", no_init) diff --git a/modules/conop/src/compound.hh b/modules/conop/src/compound.hh index 8d1d7be1d5f569819ec9d919ca6533d1ba304167..0630c1caa5f42b1432c6cf3602df024a48a869bf 100644 --- a/modules/conop/src/compound.hh +++ b/modules/conop/src/compound.hh @@ -76,17 +76,19 @@ struct DLLEXPORT_OST_CONOP AtomSpec { alt_name(), element(), is_leaving(false), - is_aromatic() + is_aromatic(), + charge(0) { } AtomSpec(int o, const String& n, const String& a, const String& e, - bool l, bool r): + bool l, bool r, int c=0): ordinal(o), name(n), alt_name(a), element(e), is_leaving(l), - is_aromatic(r) + is_aromatic(r), + charge(c) {} int ordinal; String name; @@ -94,6 +96,7 @@ struct DLLEXPORT_OST_CONOP AtomSpec { String element; bool is_leaving; bool is_aromatic; + int charge; bool operator==(const AtomSpec& rhs) const { return ordinal==rhs.ordinal && name==rhs.name && alt_name==rhs.alt_name && element==rhs.element && is_leaving==rhs.is_leaving && diff --git a/modules/conop/src/compound_lib.cc b/modules/conop/src/compound_lib.cc index 9529157ef463eaf054611853ca256293a5eae462..5a41d91ec0f5acfe8531850536ce4d5bd16e6e59 100644 --- a/modules/conop/src/compound_lib.cc +++ b/modules/conop/src/compound_lib.cc @@ -74,9 +74,10 @@ const char* CREATE_CMD[]={ " alt_name VARCHAR(4) NOT NULL, " " element VARCHAR(2) NOT NULL, " " is_aromatic VARCHAR(1) NOT NULL, " -" stereo_conf VARCHAR(1) NOT NULL, " +" stereo_conf VARCHAR(1), " " is_leaving VARCHAR(1) NOT NULL, " -" ordinal INT " +" ordinal INT, " +" charge INT " ");", " CREATE INDEX IF NOT EXISTS atom_name_index ON atoms " " (compound_id, name, alt_name)", @@ -86,7 +87,7 @@ const char* CREATE_CMD[]={ " atom_one INTEGER REFERENCES atoms (id) ON DELETE CASCADE, " " atom_two INTEGER REFERENCES atoms (id) ON DELETE CASCADE, " " bond_order INT, " -" stereo_conf VARCHAR(1) NOT NULL " +" stereo_conf VARCHAR(1) " " );", " CREATE INDEX IF NOT EXISTS bond_index ON bonds (compound_id)", " CREATE TRIGGER delete_related_objects " @@ -104,13 +105,13 @@ const char* INSERT_COMPOUND_STATEMENT="INSERT INTO chem_compounds " VALUES (?, ?, ?, ?, ?, ?, DATE(?), DATE(?), ?, ?, ?, ?)"; const char* INSERT_ATOM_STATEMENT="INSERT INTO atoms " -" (compound_id, name, alt_name, element, is_aromatic, stereo_conf, " -" is_leaving, ordinal) " +" (compound_id, name, alt_name, element, is_aromatic, " +" is_leaving, ordinal, charge) " " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; const char* INSERT_BOND_STATEMENT="insert into bonds " -" (compound_id, atom_one, atom_two, bond_order, stereo_conf) " -" VALUES (?, ?, ?, ?, ?)"; +" (compound_id, atom_one, atom_two, bond_order) " +" VALUES (?, ?, ?, ?)"; const char* INSERT_CHEMLIB_INFO_STATEMENT="insert into chemlib_info " " (creation_date, ost_version_used) " @@ -296,11 +297,13 @@ void CompoundLib::AddCompound(const CompoundPtr& compound) a.alt_name.length(), NULL); sqlite3_bind_text(stmt, 4, a.element.c_str(), a.element.length(), NULL); sqlite3_bind_int(stmt, 5, a.is_aromatic); - sqlite3_bind_int(stmt, 6, 0); - sqlite3_bind_int(stmt, 7, a.is_leaving); - sqlite3_bind_int(stmt, 8, a.ordinal); + sqlite3_bind_int(stmt, 6, a.is_leaving); + sqlite3_bind_int(stmt, 7, a.ordinal); + sqlite3_bind_int(stmt, 8, a.charge); retval=sqlite3_step(stmt); - assert(retval==SQLITE_DONE); + if (retval != SQLITE_DONE) { + LOG_ERROR(sqlite3_errmsg(db_->ptr)); + } atom_ids[a.ordinal]=sqlite3_last_insert_rowid(db_->ptr); } else { LOG_ERROR(sqlite3_errmsg(db_->ptr)); @@ -317,9 +320,10 @@ void CompoundLib::AddCompound(const CompoundPtr& compound) sqlite3_bind_int64(stmt, 2, atom_ids[b.atom_one]); sqlite3_bind_int64(stmt, 3, atom_ids[b.atom_two]); sqlite3_bind_int(stmt, 4, b.order); - sqlite3_bind_int(stmt, 5, 0); retval=sqlite3_step(stmt); - assert(retval==SQLITE_DONE); + if (retval != SQLITE_DONE) { + LOG_ERROR(sqlite3_errmsg(db_->ptr)); + }; } else { LOG_ERROR(sqlite3_errmsg(db_->ptr)); } @@ -417,15 +421,27 @@ CompoundLibPtr CompoundLib::Load(const String& database, bool readonly) lib->smiles_available_ = retval==SQLITE_OK; sqlite3_finalize(stmt); + // check if charges are available + aq="SELECT charge FROM atoms LIMIT 1"; + retval=sqlite3_prepare_v2(lib->db_->ptr, aq.c_str(), + static_cast<int>(aq.length()), + &stmt, NULL); + lib->charges_available_ = retval==SQLITE_OK; + sqlite3_finalize(stmt); + lib->creation_date_ = lib->GetCreationDate(); lib->ost_version_used_ = lib->GetOSTVersionUsed(); return lib; } void CompoundLib::LoadAtomsFromDB(CompoundPtr comp, int pk) const { - String aq=str(format("SELECT name, alt_name, element, ordinal, is_leaving " - "FROM atoms WHERE compound_id=%d " - "ORDER BY ordinal ASC") % pk); + String aq="SELECT name, alt_name, element, ordinal, is_leaving"; + if (charges_available_) { + aq+=", charge"; + } + aq = str(format(aq + + " FROM atoms WHERE compound_id=%d" + " ORDER BY ordinal ASC") % pk); sqlite3_stmt* stmt; int retval=sqlite3_prepare_v2(db_->ptr, aq.c_str(), static_cast<int>(aq.length()), @@ -439,6 +455,9 @@ void CompoundLib::LoadAtomsFromDB(CompoundPtr comp, int pk) const { atom_sp.element=String(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2))); atom_sp.ordinal=sqlite3_column_int(stmt, 3); atom_sp.is_leaving=bool(sqlite3_column_int(stmt, 4)!=0); + if (charges_available_) { + atom_sp.charge=sqlite3_column_int(stmt, 5); + } comp->AddAtom(atom_sp); } } else { @@ -574,6 +593,7 @@ CompoundLib::CompoundLib(): name_available_(), inchi_available_(), smiles_available_(), + charges_available_(), creation_date_(), ost_version_used_() { } diff --git a/modules/conop/src/compound_lib.hh b/modules/conop/src/compound_lib.hh index b61355b2021cefd514edfe74d5fe61158373bcf4..ee76aea300bdb2e3012110cf4a174e3e43e32007 100644 --- a/modules/conop/src/compound_lib.hh +++ b/modules/conop/src/compound_lib.hh @@ -59,6 +59,7 @@ private: bool name_available_; // wether name is available in db bool inchi_available_; //whether inchi is available in db bool smiles_available_; //whether smiles are available in db + bool charges_available_; //whether atom charges are available in db Date creation_date_; String ost_version_used_; }; diff --git a/modules/conop/tests/test_complib.py b/modules/conop/tests/test_complib.py index 2419d57eb1517cf0ac94bbdb9a0595bc94ed572a..99ef78d5a1904cdb257c07ac1fd936292917e45e 100644 --- a/modules/conop/tests/test_complib.py +++ b/modules/conop/tests/test_complib.py @@ -37,6 +37,12 @@ class TestCompLib(unittest.TestCase): comp_001 = complib.FindCompound("001") self.assertTrue(comp_001.smiles == "COc1cc(cc(c1OC)OC)C(C(=O)N2CCCC[C@H]2C(=O)O[C@@H](CCCc3ccccc3)CCCc4cccnc4)(F)F") + def test_charges(self): + complib = self.complib + comp_nh4 = complib.FindCompound("NH4") + self.assertTrue(comp_nh4.atom_specs[0].charge == 1) + self.assertTrue(comp_nh4.atom_specs[1].charge == 0) + if __name__ == "__main__": from ost import testutils diff --git a/modules/conop/tests/testfiles/test_compounds.cif b/modules/conop/tests/testfiles/test_compounds.cif index 045010ac8a232fc7cc7589f2cd585533076923af..c961f2cb8baf612fe33876ea13d77b0fb9bb51a3 100644 --- a/modules/conop/tests/testfiles/test_compounds.cif +++ b/modules/conop/tests/testfiles/test_compounds.cif @@ -601,4 +601,101 @@ _pdbx_chem_comp_audit.date _pdbx_chem_comp_audit.processing_site hello "Create component" 2006-02-02 RCSB hello "Modify descriptor" 2011-06-04 RCSB -# +# + +data_NH4 +# +_chem_comp.id NH4 +_chem_comp.name "AMMONIUM ION" +_chem_comp.type NON-POLYMER +_chem_comp.pdbx_type HETAI +_chem_comp.formula "H4 N" +_chem_comp.mon_nstd_parent_comp_id ? +_chem_comp.pdbx_synonyms ? +_chem_comp.pdbx_formal_charge 1 +_chem_comp.pdbx_initial_date 1999-07-08 +_chem_comp.pdbx_modified_date 2011-06-04 +_chem_comp.pdbx_ambiguous_flag N +_chem_comp.pdbx_release_status REL +_chem_comp.pdbx_replaced_by ? +_chem_comp.pdbx_replaces ? +_chem_comp.formula_weight 18.038 +_chem_comp.one_letter_code ? +_chem_comp.three_letter_code NH4 +_chem_comp.pdbx_model_coordinates_details ? +_chem_comp.pdbx_model_coordinates_missing_flag N +_chem_comp.pdbx_ideal_coordinates_details ? +_chem_comp.pdbx_ideal_coordinates_missing_flag N +_chem_comp.pdbx_model_coordinates_db_code 1SY2 +_chem_comp.pdbx_subcomponent_list ? +_chem_comp.pdbx_processing_site RCSB +# +loop_ +_chem_comp_atom.comp_id +_chem_comp_atom.atom_id +_chem_comp_atom.alt_atom_id +_chem_comp_atom.type_symbol +_chem_comp_atom.charge +_chem_comp_atom.pdbx_align +_chem_comp_atom.pdbx_aromatic_flag +_chem_comp_atom.pdbx_leaving_atom_flag +_chem_comp_atom.pdbx_stereo_config +_chem_comp_atom.model_Cartn_x +_chem_comp_atom.model_Cartn_y +_chem_comp_atom.model_Cartn_z +_chem_comp_atom.pdbx_model_Cartn_x_ideal +_chem_comp_atom.pdbx_model_Cartn_y_ideal +_chem_comp_atom.pdbx_model_Cartn_z_ideal +_chem_comp_atom.pdbx_component_atom_id +_chem_comp_atom.pdbx_component_comp_id +_chem_comp_atom.pdbx_ordinal +NH4 N N N 1 1 N N N 11.106 19.171 34.702 0.000 0.000 0.000 N NH4 1 +NH4 HN1 1HN H 0 1 N N N 12.106 19.171 34.702 -0.385 -0.545 -0.771 HN1 NH4 2 +NH4 HN2 2HN H 0 1 N N N 10.772 19.171 35.645 1.020 0.000 0.000 HN2 NH4 3 +NH4 HN3 3HN H 0 1 N N N 10.773 19.988 34.231 -0.340 0.962 0.000 HN3 NH4 4 +NH4 HN4 4HN H 0 1 N N N 10.773 18.354 34.231 -0.385 -0.545 0.771 HN4 NH4 5 +# +loop_ +_chem_comp_bond.comp_id +_chem_comp_bond.atom_id_1 +_chem_comp_bond.atom_id_2 +_chem_comp_bond.value_order +_chem_comp_bond.pdbx_aromatic_flag +_chem_comp_bond.pdbx_stereo_config +_chem_comp_bond.pdbx_ordinal +NH4 N HN1 SING N N 1 +NH4 N HN2 SING N N 2 +NH4 N HN3 SING N N 3 +NH4 N HN4 SING N N 4 +# +loop_ +_pdbx_chem_comp_descriptor.comp_id +_pdbx_chem_comp_descriptor.type +_pdbx_chem_comp_descriptor.program +_pdbx_chem_comp_descriptor.program_version +_pdbx_chem_comp_descriptor.descriptor +NH4 SMILES ACDLabs 10.04 "[NH4+]" +NH4 SMILES_CANONICAL CACTVS 3.341 "[NH4+]" +NH4 SMILES CACTVS 3.341 "[NH4+]" +NH4 SMILES_CANONICAL "OpenEye OEToolkits" 1.5.0 "[NH4+]" +NH4 SMILES "OpenEye OEToolkits" 1.5.0 "[NH4+]" +NH4 InChI InChI 1.03 InChI=1S/H3N/h1H3/p+1 +NH4 InChIKey InChI 1.03 QGZKDVFQNNGYKY-UHFFFAOYSA-O +# +loop_ +_pdbx_chem_comp_identifier.comp_id +_pdbx_chem_comp_identifier.type +_pdbx_chem_comp_identifier.program +_pdbx_chem_comp_identifier.program_version +_pdbx_chem_comp_identifier.identifier +NH4 "SYSTEMATIC NAME" ACDLabs 10.04 ammonium +NH4 "SYSTEMATIC NAME" "OpenEye OEToolkits" 1.5.0 azanium +# +loop_ +_pdbx_chem_comp_audit.comp_id +_pdbx_chem_comp_audit.action_type +_pdbx_chem_comp_audit.date +_pdbx_chem_comp_audit.processing_site +NH4 "Create component" 1999-07-08 RCSB +NH4 "Modify descriptor" 2011-06-04 RCSB +# diff --git a/modules/io/src/mol/chemdict_parser.cc b/modules/io/src/mol/chemdict_parser.cc index e344cd2c7d642ae7227b52c7492c7bf848a44e3d..5e138f03dbd500f88a207321c6fc0ddcac462191 100644 --- a/modules/io/src/mol/chemdict_parser.cc +++ b/modules/io/src/mol/chemdict_parser.cc @@ -30,7 +30,8 @@ bool ChemdictParser::OnBeginLoop(const StarLoopDesc& header) indices_[ELE]=header.GetIndex("type_symbol"); indices_[IS_LEAVING]=header.GetIndex("pdbx_leaving_atom_flag"); indices_[IS_AROMATIC]=header.GetIndex("pdbx_aromatic_flag"); - indices_[ORDINAL]=header.GetIndex("pdbx_ordinal"); + indices_[ORDINAL]=header.GetIndex("pdbx_ordinal"); + indices_[CHARGE]=header.GetIndex("charge"); return true; } else if (header.GetCategory()=="chem_comp_bond") { loop_type_=BOND_SPEC; @@ -42,6 +43,7 @@ bool ChemdictParser::OnBeginLoop(const StarLoopDesc& header) loop_type_=DESC_SPEC; indices_[DESC_TYPE]=header.GetIndex("type"); indices_[DESC]=header.GetIndex("descriptor"); + indices_[PROGRAM]=header.GetIndex("program"); return true; } loop_type_=DONT_KNOW; @@ -59,6 +61,7 @@ void ChemdictParser::OnDataRow(const StarLoopDesc& header, atom.ordinal=columns[indices_[ORDINAL]].to_int().second-1; atom.element=columns[indices_[ELE]].str(); atom.is_aromatic=columns[indices_[IS_AROMATIC]][0]=='Y'; + atom.charge=columns[indices_[CHARGE]].to_int().second; compound_->AddAtom(atom); atom_map_[atom.name]=atom.ordinal; } else if (loop_type_==BOND_SPEC) { diff --git a/modules/io/src/mol/chemdict_parser.hh b/modules/io/src/mol/chemdict_parser.hh index 5c9281bb7e3f776498730148c712bb3ff1a2f024..f33ee72fb69623aa41921cb15d6b9d7378c87ae4 100644 --- a/modules/io/src/mol/chemdict_parser.hh +++ b/modules/io/src/mol/chemdict_parser.hh @@ -75,7 +75,7 @@ private: ORDINAL=3, IS_LEAVING=4, ELE=5, - STEREO_CONF=6, + CHARGE=6, ATOM_ID1=0, ATOM_ID2=1, BOND_ORDER=2,