From 440936a8ff3afc1020136425ad4d202606dda0ee Mon Sep 17 00:00:00 2001 From: Gabriel Studer <gabriel.studer@unibas.ch> Date: Thu, 17 Aug 2017 20:54:32 +0200 Subject: [PATCH] Add solvent accessibility calculations - the DSSP style --- modules/mol/alg/doc/molalg.rst | 43 ++- modules/mol/alg/pymod/export_accessibility.cc | 22 +- modules/mol/alg/src/accessibility.cc | 335 ++++++++++++++---- modules/mol/alg/src/accessibility.hh | 54 ++- modules/mol/alg/tests/test_accessibility.py | 52 ++- 5 files changed, 412 insertions(+), 94 deletions(-) diff --git a/modules/mol/alg/doc/molalg.rst b/modules/mol/alg/doc/molalg.rst index 4f0ab63a4..4ef9b3d51 100644 --- a/modules/mol/alg/doc/molalg.rst +++ b/modules/mol/alg/doc/molalg.rst @@ -848,10 +848,12 @@ Algorithms on Structures .. method:: Accessibility(ent, probe_radius=1.4, include_hydrogens=False,\ include_hetatm=False, include_water=False,\ oligo_mode=False, selection="", asa_abs="asaAbs",\ - asa_rel="asaRel", asa_atom="asaAtom") + asa_rel="asaRel", asa_atom="asaAtom", \ + algorithm = NACCESS) - Calculates the accesssible surface area for ever atom in *ent* according to - Lee & Richards by "rolling" a probe with given *probe_radius* over the atoms. + Calculates the accesssible surface area for ever atom in *ent*. The algorithm + mimics the behaviour of the bindings available for the NACCESS and DSSP tools + and has been tested to reproduce the numbers accordingly. :param ent: Entity on which to calculate the surface :type ent: :class:`~ost.mol.EntityView` / @@ -907,18 +909,43 @@ Algorithms on Structures :param asa_rel: Float property name to assign the relative solvent accessibility to a residue. This is the absolute accessibility divided by the maximum solvent - accessibility of that particular residue. Only - residues of the 20 standarad amino acids can be handled. - Every non standard residue gets assigned a value of - -99.9. + accessibility of that particular residue. + This maximum solvent accessibility is dependent on + the chosen :class:`AccessibilityAlgorithm`. + Only residues of the 20 standarad amino acids + can be handled. + + * In case of the **NACCESS** algorithm you can expect + a value in range [0.0, 100.0] and a value of -99.9 + for non standard residues. + + * In case of the **DSSP** algorithm you can expect a + value in range [0.0, 1.0], no float property is assigned + in case of a non standard residue. + :type asa_rel: :class:`str` :param asa_atom: Float property name to assign the solvent accessible area to each atom. - :type asa_atom: :class:`str` + :type asa_atom: :class:`str` + + :param algorithm: Specifies the used algorithm for solvent accessibility + calculations + + :type algorithm: :class:`AccessibilityAlgorithm` + + :return: The summed solvent accessibilty of each atom in *ent*. +.. class:: AccessibilityAlgorithm + + The accessibility algorithm enum specifies the algorithm used by + the respective tools. Available are: + + NACCESS, DSSP + + .. method:: AssignSecStruct(ent) diff --git a/modules/mol/alg/pymod/export_accessibility.cc b/modules/mol/alg/pymod/export_accessibility.cc index 94d2bcabc..789c8f8da 100644 --- a/modules/mol/alg/pymod/export_accessibility.cc +++ b/modules/mol/alg/pymod/export_accessibility.cc @@ -35,11 +35,12 @@ Real WrapAccessibilityHandle(ost::mol::EntityHandle& ent, const String& selection, const String& asa_abs, const String& asa_rel, - const String& asa_atom) { + const String& asa_atom, + ost::mol::alg::AccessibilityAlgorithm algorithm) { return ost::mol::alg::Accessibility(ent, probe_radius, include_hydrogens, include_hetatm, include_water, oligo_mode, - selection, asa_abs, asa_rel, asa_atom); + selection, asa_abs, asa_rel, asa_atom, algorithm); } Real WrapAccessibilityView(ost::mol::EntityView& ent, @@ -50,11 +51,12 @@ Real WrapAccessibilityView(ost::mol::EntityView& ent, bool oligo_mode, const String& selection, const String& asa_abs, const String& asa_rel, - const String& asa_atom) { + const String& asa_atom, + ost::mol::alg::AccessibilityAlgorithm algorithm) { return ost::mol::alg::Accessibility(ent, probe_radius, include_hydrogens, include_hetatm, include_water, oligo_mode, - selection, asa_abs, asa_rel, asa_atom); + selection, asa_abs, asa_rel, asa_atom, algorithm); } } // ns @@ -64,6 +66,12 @@ Real WrapAccessibilityView(ost::mol::EntityView& ent, void export_accessibility() { + enum_<ost::mol::alg::AccessibilityAlgorithm>("AccessibilityAlgorithm") + .value("NACCESS", ost::mol::alg::NACCESS) + .value("DSSP", ost::mol::alg::DSSP) + .export_values() + ; + def("Accessibility", WrapAccessibilityHandle, (arg("ent"), arg("probe_radius")=1.4, arg("include_hydrogens")=false, @@ -73,7 +81,8 @@ void export_accessibility() { arg("selection")="", arg("asa_abs")="asaAbs", arg("asa_rel")="asaRel", - arg("asa_atom")="asaAtom")); + arg("asa_atom")="asaAtom", + arg("algorithm")=ost::mol::alg::NACCESS)); def("Accessibility", WrapAccessibilityView, (arg("ent"), arg("probe_radius")=1.4, @@ -84,6 +93,7 @@ void export_accessibility() { arg("selection")="", arg("asa_abs")="asaAbs", arg("asa_rel")="asaRel", - arg("asa_atom")="asaAtom")); + arg("asa_atom")="asaAtom", + arg("algorithm")=ost::mol::alg::NACCESS)); } diff --git a/modules/mol/alg/src/accessibility.cc b/modules/mol/alg/src/accessibility.cc index bb6eb6ecd..6b3903638 100644 --- a/modules/mol/alg/src/accessibility.cc +++ b/modules/mol/alg/src/accessibility.cc @@ -180,14 +180,13 @@ struct CubeOccupationGrid{ bool* occupied_cubes; }; - -Real GetAtomAccessibility(Real x_pos, Real y_pos, Real z_pos, - Real radius, - const std::vector<Real>& x, - const std::vector<Real>& y, - const std::vector<Real>& z, - const std::vector<Real>& radii) { - +Real GetAtomAccessibilityNACCESS(Real x_pos, Real y_pos, Real z_pos, + Real radius, + const std::vector<Real>& x, + const std::vector<Real>& y, + const std::vector<Real>& z, + const std::vector<Real>& radii) { + int num_close_atoms = x.size(); if(num_close_atoms == 0) { @@ -329,9 +328,119 @@ Real GetAtomAccessibility(Real x_pos, Real y_pos, Real z_pos, } +struct DSSPHelper{ + + DSSPHelper(Real x, Real y, Real z, Real r, Real d): x_pos(x), y_pos(y), + z_pos(z), + squared_radius(r), + squared_distance(d) { } + + Real x_pos; + Real y_pos; + Real z_pos; + Real squared_radius; + Real squared_distance; + + bool operator<(const DSSPHelper& rhs) const { return squared_distance < + rhs.squared_distance; } +}; + + +Real GetAtomAccessibilityDSSP(Real x_pos, Real y_pos, Real z_pos, + Real radius, + const std::vector<Real>& x, + const std::vector<Real>& y, + const std::vector<Real>& z, + const std::vector<Real>& radii) { + + int num_close_atoms = x.size(); + + if(num_close_atoms == 0) { + // return area of full sphere + return Real(4.0) * M_PI * radius * radius; + } + + std::vector<DSSPHelper> helpers; + helpers.reserve(num_close_atoms); + + Real dx, dy, dz, dist_squared, summed_radii; + for(int i = 0; i < num_close_atoms; ++i) { + dx = x_pos - x[i]; + dy = y_pos - y[i]; + dz = z_pos - z[i]; + dist_squared = dx*dx + dy*dy + dz*dz; + summed_radii = radius + radii[i]; + summed_radii *= summed_radii; + if(dist_squared < summed_radii) { + helpers.push_back(DSSPHelper(x[i] - x_pos, y[i] - y_pos, z[i] - z_pos, + radii[i] * radii[i], dist_squared)); + } + } + + std::sort(helpers.begin(), helpers.end()); + + const ost::mol::alg::DSSPAccessibilityParam& param = + ost::mol::alg::DSSPAccessibilityParam::GetInstance(); + const std::vector<Real>& fibonacci_x = param.GetFibonacciX(); + const std::vector<Real>& fibonacci_y = param.GetFibonacciY(); + const std::vector<Real>& fibonacci_z = param.GetFibonacciZ(); + Real fibo_weight = param.GetPointWeight(); + Real summed_fibo_weight = 0.0; + Real fibo_x, fibo_y, fibo_z; + uint num_helpers = helpers.size(); + + for(uint i = 0; i < fibonacci_x.size(); ++i) { + fibo_x = fibonacci_x[i] * radius; + fibo_y = fibonacci_y[i] * radius; + fibo_z = fibonacci_z[i] * radius; + + bool covered = false; + + for(uint j = 0; j < num_helpers; ++j) { + dx = fibo_x - helpers[j].x_pos; + dy = fibo_y - helpers[j].y_pos; + dz = fibo_z - helpers[j].z_pos; + dist_squared = dx*dx + dy*dy + dz*dz; + if(dist_squared < helpers[j].squared_radius) { + covered = true; + break; + } + } + if(!covered) { + summed_fibo_weight += fibo_weight; + } + } + + return summed_fibo_weight * radius * radius; +} + +Real GetAtomAccessibility(Real x_pos, Real y_pos, Real z_pos, + Real radius, + const std::vector<Real>& x, + const std::vector<Real>& y, + const std::vector<Real>& z, + const std::vector<Real>& radii, + ost::mol::alg::AccessibilityAlgorithm algorithm) { + switch(algorithm){ + case ost::mol::alg::NACCESS: return GetAtomAccessibilityNACCESS(x_pos, y_pos, + z_pos, radius, + x, y, z, radii); + + case ost::mol::alg::DSSP: return GetAtomAccessibilityDSSP(x_pos, y_pos, + z_pos, radius, + x, y, z, radii); + + } + + // silence compiler warning... + return Real(0); +} + + void SolveCube(const CubeGrid& cube_grid, int cube_idx, const std::vector<Real>& x, const std::vector<Real>& y, const std::vector<Real>& z, const std::vector<Real>& radii, + ost::mol::alg::AccessibilityAlgorithm algorithm, std::vector<Real>& asa) { //prepare some stuff @@ -395,7 +504,8 @@ void SolveCube(const CubeGrid& cube_grid, int cube_idx, asa[atom_idx] = GetAtomAccessibility(current_x, current_y, current_z, current_radius, close_atom_x, close_atom_y, - close_atom_z, close_atom_radii); + close_atom_z, close_atom_radii, + algorithm); } } @@ -451,8 +561,9 @@ CubeGrid SetupCubeGrid(const std::vector<Real>& x, void CalculateASAOligo(std::vector<Real>& x, std::vector<Real>& y, std::vector<Real>& z, std::vector<Real>& radii, - std::vector<int> chain_indices, - Real probe_radius, std::vector<Real>& asa, + std::vector<int> chain_indices, Real probe_radius, + ost::mol::alg::AccessibilityAlgorithm algorithm, + std::vector<Real>& asa, std::vector<Real>& asa_single_chain) { int num_atoms = x.size(); @@ -472,7 +583,8 @@ void CalculateASAOligo(std::vector<Real>& x, std::vector<Real>& y, if(cube_grid.IsInitialized(cube_idx)) { // there is at least one atom! - SolveCube(cube_grid, cube_idx, x, y, z, full_radii, asa); + SolveCube(cube_grid, cube_idx, x, y, z, full_radii, + algorithm, asa); } } @@ -524,7 +636,7 @@ void CalculateASAOligo(std::vector<Real>& x, std::vector<Real>& y, // there is at least one atom in the cube AND the environment has // changes compared to the previous asa calculation SolveCube(single_chain_cube_grid, cube_idx, x, y, z, full_radii, - asa_single_chain); + algorithm, asa_single_chain); } } } @@ -536,6 +648,7 @@ void CalculateASA(const std::vector<Real>& x, const std::vector<Real>& z, const std::vector<Real>& radii, Real probe_radius, + ost::mol::alg::AccessibilityAlgorithm algorithm, std::vector<Real>& asa) { int num_atoms = x.size(); @@ -555,33 +668,51 @@ void CalculateASA(const std::vector<Real>& x, if(cube_grid.IsInitialized(cube_idx)) { // there is at least one atom! - SolveCube(cube_grid, cube_idx, x, y, z, full_radii, asa); + SolveCube(cube_grid, cube_idx, x, y, z, full_radii, + algorithm, asa); } } } void ASAParamFromAtomList(const ost::mol::AtomViewList& atom_list, + ost::mol::alg::AccessibilityAlgorithm algorithm, std::vector<Real>& x_pos, std::vector<Real>& y_pos, std::vector<Real>& z_pos, std::vector<Real>& radii) { - const ost::mol::alg::AccessibilityParam& param = - ost::mol::alg::AccessibilityParam::GetInstance(); - String rname, aname, ele; - - for(ost::mol::AtomViewList::const_iterator at_it = atom_list.begin(); - at_it != atom_list.end(); ++at_it) { - rname = at_it->GetResidue().GetName(); - aname = at_it->GetName(); - ele = at_it->GetElement(); - geom::Vec3 at_pos = at_it->GetPos(); - x_pos.push_back(at_pos[0]); - y_pos.push_back(at_pos[1]); - z_pos.push_back(at_pos[2]); - radii.push_back(param.GetVdWRadius(rname, aname, ele)); - } + if(algorithm == ost::mol::alg::NACCESS) { + const ost::mol::alg::NACCESSAccessibilityParam& param = + ost::mol::alg::NACCESSAccessibilityParam::GetInstance(); + String rname, aname, ele; + + for(ost::mol::AtomViewList::const_iterator at_it = atom_list.begin(); + at_it != atom_list.end(); ++at_it) { + rname = at_it->GetResidue().GetName(); + aname = at_it->GetName(); + ele = at_it->GetElement(); + geom::Vec3 at_pos = at_it->GetPos(); + x_pos.push_back(at_pos[0]); + y_pos.push_back(at_pos[1]); + z_pos.push_back(at_pos[2]); + radii.push_back(param.GetVdWRadius(rname, aname, ele)); + } + } else if(algorithm == ost::mol::alg::DSSP) { + const ost::mol::alg::DSSPAccessibilityParam& param = + ost::mol::alg::DSSPAccessibilityParam::GetInstance(); + String aname; + + for(ost::mol::AtomViewList::const_iterator at_it = atom_list.begin(); + at_it != atom_list.end(); ++at_it) { + aname = at_it->GetName(); + geom::Vec3 at_pos = at_it->GetPos(); + x_pos.push_back(at_pos[0]); + y_pos.push_back(at_pos[1]); + z_pos.push_back(at_pos[2]); + radii.push_back(param.GetVdWRadius(aname)); + } + } } void ChainIndicesFromAtomList(const ost::mol::AtomViewList& atom_list, @@ -608,7 +739,8 @@ Real SetAccessibilityProps(ost::mol::EntityView& ent, const std::vector<Real>& asa, const String& asa_atom, const String& asa_abs, - const String& asa_rel){ + const String& asa_rel, + ost::mol::alg::AccessibilityAlgorithm algorithm) { // assign absolute accessibilities Real summed_asa = 0.0; @@ -621,22 +753,40 @@ Real SetAccessibilityProps(ost::mol::EntityView& ent, summed_asa += val; } - // go over residue and assign relative accessibilities String rname; ost::mol::ResidueViewList res_list = ent.GetResidueList(); - for(uint idx = 0; idx < res_list.size(); ++idx) { - rname = res_list[idx].GetName(); - Real tot_acc = - ost::mol::alg::AccessibilityParam::GetInstance().GetResidueAccessibility(rname); - if(tot_acc == Real(-1.0)) { - // no accessibility found... - // let's mimic NACCESS behaviour - res_list[idx].SetFloatProp(asa_rel, Real(-99.9)); + if(algorithm == ost::mol::alg::NACCESS) { + // go over residue and assign relative accessibilities + for(uint idx = 0; idx < res_list.size(); ++idx) { + rname = res_list[idx].GetName(); + Real tot_acc = + ost::mol::alg::NACCESSAccessibilityParam::GetInstance().GetResidueAccessibility(rname); + if(tot_acc == Real(-1.0)) { + // no accessibility found... + // let's mimic NACCESS behaviour + res_list[idx].SetFloatProp(asa_rel, Real(-99.9)); + } + else { + // the fraction gets multiplied by 100 (Thats how NACCESS does it...) + Real val = res_list[idx].GetFloatProp(asa_abs, 0.0) / tot_acc * 100.0; + res_list[idx].SetFloatProp(asa_rel, val); + } } - else { - // the fraction gets multiplied by 100 (Thats how NACCESS does it...) - Real val = res_list[idx].GetFloatProp(asa_abs, 0.0) / tot_acc * 100.0; - res_list[idx].SetFloatProp(asa_rel, val); + } else if(algorithm == ost::mol::alg::DSSP) { + // go over residue and assign relative accessibilities + for(uint idx = 0; idx < res_list.size(); ++idx) { + rname = res_list[idx].GetName(); + Real tot_acc = + ost::mol::alg::DSSPAccessibilityParam::GetInstance().GetResidueAccessibility(rname); + if(tot_acc == Real(-1.0)) { + // no accessibility found... + // let's mimic DSSP binding behaviour + // => do nothing + } + else { + Real val = res_list[idx].GetFloatProp(asa_abs, 0.0) / tot_acc; + res_list[idx].SetFloatProp(asa_rel, val); + } } } @@ -650,7 +800,7 @@ Real SetAccessibilityProps(ost::mol::EntityView& ent, namespace ost { namespace mol { namespace alg { -AccessibilityParam::AccessibilityParam() { +NACCESSAccessibilityParam::NACCESSAccessibilityParam() { std::map<String, Real> ala_map; std::map<String, Real> arg_map; @@ -1095,13 +1245,6 @@ AccessibilityParam::AccessibilityParam() { hoh_map["O"] = 1.40; - - - - - - - vdw_radii_["ALA"] = ala_map; vdw_radii_["ARG"] = arg_map; vdw_radii_["ASP"] = asp_map; @@ -1158,7 +1301,7 @@ AccessibilityParam::AccessibilityParam() { } -Real AccessibilityParam::GuessRadius(const String& ele) const{ +Real NACCESSAccessibilityParam::GuessRadius(const String& ele) const{ if(ele == "C") return 1.80; if(ele == "N") return 1.60; if(ele == "S") return 1.85; @@ -1175,8 +1318,9 @@ Real AccessibilityParam::GuessRadius(const String& ele) const{ } -Real AccessibilityParam::GetVdWRadius(const String& rname, const String& aname, - const String& ele) const{ +Real NACCESSAccessibilityParam::GetVdWRadius(const String& rname, + const String& aname, + const String& ele) const{ std::map<String, std::map<String, Real> >::const_iterator res_map_it = vdw_radii_.find(rname); if(res_map_it != vdw_radii_.end()) { @@ -1188,12 +1332,70 @@ Real AccessibilityParam::GetVdWRadius(const String& rname, const String& aname, } -Real AccessibilityParam::GetResidueAccessibility(const String& rname) const{ +Real NACCESSAccessibilityParam::GetResidueAccessibility(const String& rname) const{ std::map<String, Real>::const_iterator it = accessibilities_.find(rname); if(it != accessibilities_.end()) return it->second; else return Real(-1.0); } +DSSPAccessibilityParam::DSSPAccessibilityParam() { + + // these values are from the dssp binding. nobody knows + // the source... + accessibilities_["ALA"] = Real(118.0); + accessibilities_["ARG"] = Real(317.0); + accessibilities_["ASN"] = Real(238.0); + accessibilities_["ASP"] = Real(243.0); + accessibilities_["CYS"] = Real(183.0); + accessibilities_["GLN"] = Real(262.0); + accessibilities_["GLU"] = Real(286.0); + accessibilities_["GLY"] = Real(154.0); + accessibilities_["HIS"] = Real(258.0); + accessibilities_["ILE"] = Real(228.0); + accessibilities_["LEU"] = Real(243.0); + accessibilities_["LYS"] = Real(278.0); + accessibilities_["MET"] = Real(260.0); + accessibilities_["PHE"] = Real(271.0); + accessibilities_["PRO"] = Real(204.0); + accessibilities_["SER"] = Real(234.0); + accessibilities_["THR"] = Real(206.0); + accessibilities_["TRP"] = Real(300.0); + accessibilities_["TYR"] = Real(303.0); + accessibilities_["VAL"] = Real(216.0); + + + // construct evenly distributed points on a sphere. + // same as in DSSP... + fibonacci_x_.reserve(401); + fibonacci_y_.reserve(401); + fibonacci_z_.reserve(401); + + Real golden_ratio = (Real(1.0) + std::sqrt(5.0)) * Real(0.5); + point_weight_ = (Real(4.0) * Real(M_PI)) / Real(401.0); + + for (int i = -200; i <= 200; ++i) { + Real lat = std::asin((Real(2.0) * Real(i)) / Real(401.0)); + Real lon = std::fmod(Real(i), golden_ratio) * + Real(2.0) * Real(M_PI) / golden_ratio; + fibonacci_x_.push_back(std::sin(lon) * std::cos(lat)); + fibonacci_y_.push_back(std::cos(lon) * std::cos(lat)); + fibonacci_z_.push_back(std::sin(lat)); + } +} + +Real DSSPAccessibilityParam::GetVdWRadius(const String& aname) const{ + if(aname == "N") return Real(1.65); + if(aname == "CA") return Real(1.87); + if(aname == "C") return Real(1.76); + if(aname == "O") return Real(1.4); + return Real(1.8); +} + +Real DSSPAccessibilityParam::GetResidueAccessibility(const String& rname) const{ + std::map<String, Real>::const_iterator it = accessibilities_.find(rname); + if(it != accessibilities_.end()) return it->second; + else return Real(-1.0); +} Real Accessibility(ost::mol::EntityView& ent, Real probe_radius, bool include_hydrogens, @@ -1202,7 +1404,8 @@ Real Accessibility(ost::mol::EntityView& ent, const String& selection, const String& asa_abs, const String& asa_rel, - const String& asa_atom) { + const String& asa_atom, + AccessibilityAlgorithm algorithm) { String internal_selection = selection; @@ -1254,7 +1457,7 @@ Real Accessibility(ost::mol::EntityView& ent, // extract data from ent ost::mol::AtomViewList atom_list = selected_ent.GetAtomList(); - ASAParamFromAtomList(atom_list, x_pos, y_pos, z_pos, radii); + ASAParamFromAtomList(atom_list, algorithm, x_pos, y_pos, z_pos, radii); if(atom_list.size() == 0) return 0.0; @@ -1269,10 +1472,11 @@ Real Accessibility(ost::mol::EntityView& ent, std::vector<Real> asa; std::vector<Real> asa_single_chain; CalculateASAOligo(x_pos, y_pos, z_pos, radii, chain_indices, - probe_radius, asa, asa_single_chain); + probe_radius, algorithm, asa, asa_single_chain); Real summed_asa = SetAccessibilityProps(selected_ent, atom_list, asa, - asa_atom, asa_abs, asa_rel); + asa_atom, asa_abs, asa_rel, + algorithm); // in case of the single chain asa, the property names are // moodified!! @@ -1283,7 +1487,7 @@ Real Accessibility(ost::mol::EntityView& ent, SetAccessibilityProps(selected_ent, atom_list, asa_single_chain, single_chain_asa_atom, single_chain_asa_abs, - single_chain_asa_rel); + single_chain_asa_rel, algorithm); return summed_asa; } @@ -1291,14 +1495,14 @@ Real Accessibility(ost::mol::EntityView& ent, // do it! do it! do it! std::vector<Real> asa; - CalculateASA(x_pos, y_pos, z_pos, radii, probe_radius, asa); + CalculateASA(x_pos, y_pos, z_pos, radii, probe_radius, algorithm, asa); Real summed_asa = SetAccessibilityProps(selected_ent, atom_list, asa, - asa_atom, asa_abs, asa_rel); + asa_atom, asa_abs, asa_rel, + algorithm); return summed_asa; } - } @@ -1309,12 +1513,13 @@ Real Accessibility(ost::mol::EntityHandle& ent, const String& selection, const String& asa_abs, const String& asa_rel, - const String& asa_atom) { + const String& asa_atom, + AccessibilityAlgorithm algorithm) { ost::mol::EntityView entity_view = ent.CreateFullView(); return Accessibility(entity_view, probe_radius, include_hydrogens, include_hetatm, include_water, oligo_mode, - selection, asa_abs, asa_rel, asa_atom); + selection, asa_abs, asa_rel, asa_atom, algorithm); } }}} //ns diff --git a/modules/mol/alg/src/accessibility.hh b/modules/mol/alg/src/accessibility.hh index cd0a57638..2ed83cc53 100644 --- a/modules/mol/alg/src/accessibility.hh +++ b/modules/mol/alg/src/accessibility.hh @@ -25,19 +25,19 @@ namespace ost { namespace mol { namespace alg { +typedef enum { +NACCESS, DSSP +} AccessibilityAlgorithm; -class AccessibilityParam { +class NACCESSAccessibilityParam { public: // Singleton access to one constant instance - static const AccessibilityParam& GetInstance() { - static AccessibilityParam instance; + static const NACCESSAccessibilityParam& GetInstance() { + static NACCESSAccessibilityParam instance; return instance; } // Data access - - Real GuessRadius(const String& ele) const; - Real GetVdWRadius(const String& rname, const String& aname, const String& ele) const; @@ -46,12 +46,46 @@ public: private: // construction only inside here - AccessibilityParam(); + NACCESSAccessibilityParam(); + + Real GuessRadius(const String& ele) const; + std::map<String, std::map<String, Real> > vdw_radii_; std::map<String, Real> accessibilities_; }; +class DSSPAccessibilityParam { + + public: + // Singleton access to one constant instance + static const DSSPAccessibilityParam& GetInstance() { + static DSSPAccessibilityParam instance; + return instance; + } + // Data access + Real GetVdWRadius(const String& aname) const; + + Real GetResidueAccessibility(const String& rname) const; + + const std::vector<Real>& GetFibonacciX() const { return fibonacci_x_; } + const std::vector<Real>& GetFibonacciY() const { return fibonacci_y_; } + const std::vector<Real>& GetFibonacciZ() const { return fibonacci_z_; } + Real GetPointWeight() const { return point_weight_; } + + private: + + // construction only inside here + DSSPAccessibilityParam(); + + std::map<String, std::map<String, Real> > vdw_radii_; + std::map<String, Real> accessibilities_; + std::vector<Real> fibonacci_x_; + std::vector<Real> fibonacci_y_; + std::vector<Real> fibonacci_z_; + Real point_weight_; + }; + Real Accessibility(ost::mol::EntityView& ent, Real probe_radius = 1.4, bool include_hydrogens = false, @@ -61,7 +95,8 @@ Real Accessibility(ost::mol::EntityView& ent, const String& selection = "", const String& asa_abs = "asaAbs", const String& asa_rel = "asaRel", - const String& asa_atom = "asaAtom"); + const String& asa_atom = "asaAtom", + AccessibilityAlgorithm algorithm = NACCESS); Real Accessibility(ost::mol::EntityHandle& ent, @@ -73,7 +108,8 @@ Real Accessibility(ost::mol::EntityHandle& ent, const String& selection = "", const String& asa_abs = "asaAbs", const String& asa_rel = "asaRel", - const String& asa_atom = "asaAtom"); + const String& asa_atom = "asaAtom", + AccessibilityAlgorithm algorithm = NACCESS); }}} //ns diff --git a/modules/mol/alg/tests/test_accessibility.py b/modules/mol/alg/tests/test_accessibility.py index 748b4d8c1..3ff4c0fde 100644 --- a/modules/mol/alg/tests/test_accessibility.py +++ b/modules/mol/alg/tests/test_accessibility.py @@ -2,6 +2,7 @@ from ost import io, mol, settings import unittest import os from ost.bindings import naccess +from ost.bindings import dssp class AccessibilityContainer: @@ -80,7 +81,7 @@ def Compare(acc_one, acc_two): class TestAccessibility(unittest.TestCase): - def testAcc(self): + def testAccNACCESS(self): # tests oligo mode by comparing the results from doing the # corresponding calculations manually @@ -100,15 +101,54 @@ class TestAccessibility(unittest.TestCase): # naccess results try: naccess_path = settings.Locate("naccess") + ent_three = io.LoadPDB(os.path.join("testfiles", "1a0s.pdb")) + ent_three = ent_three.Select("peptide=true") + acc_naccess = AccessibilitiesRaw(ent_three, use_naccess=True) + self.assertTrue(Compare(acc_classic, acc_naccess)) except: print "Could not find NACCESS, could not compare Accessiblity function..." - return - ent_three = io.LoadPDB(os.path.join("testfiles", "1a0s.pdb")) - ent_three = ent_three.Select("peptide=true") - acc_naccess = AccessibilitiesRaw(ent_three, use_naccess=True) - self.assertTrue(Compare(acc_classic, acc_naccess)) + def testAccDSSP(self): + + dssp_path = None + + try: + dssp_path = settings.Locate("dssp") + except: + try: + dssp_path = settings.locate("mkdssp") + except: + pass + pass + + if dssp_path == None: + print "Could not find DSSP, could not compare Accessibility function..." + + # we assume oligo mode to be working as it is tested in + # testAccNACCESS. So we only test the single residue + # accessibilitities + ent_one = io.LoadPDB(os.path.join("testfiles", "1a0s.pdb")) + ent_two = io.LoadPDB(os.path.join("testfiles", "1a0s.pdb")) + ent_one = ent_one.Select("peptide=true") + ent_two = ent_two.Select("peptide=true") + + dssp.AssignDSSP(ent_one, extract_burial_status=True, dssp_bin = dssp_path) + mol.alg.Accessibility(ent_two, algorithm=mol.alg.AccessibilityAlgorithm.DSSP) + + for a,b in zip(ent_one.residues, ent_two.residues): + + # overall accessibility + if a.HasProp("solvent_accessibility") and b.HasProp("asaAbs"): + diff = abs(a.GetFloatProp("solvent_accessibility") -\ + round(b.GetFloatProp("asaAbs"))) + self.assertTrue(diff < 0.01) + + # relative accessibility + if a.HasProp("relative_solvent_accessibility") and b.HasProp("asaRel"): + diff = abs(a.GetFloatProp("relative_solvent_accessibility") -\ + b.GetFloatProp("asaRel")) + self.assertTrue(diff < 0.01) if __name__ == "__main__": -- GitLab