Skip to content
Snippets Groups Projects
Commit acb8fd31 authored by BIOPZ-Haas Juergen's avatar BIOPZ-Haas Juergen
Browse files

adding automatic conversion of non-standard amino-acids to standard ones, in...

adding automatic conversion of non-standard amino-acids to standard ones, in case parent residue is not the same only BB will be copied;CB will be inserted where possible if copying from a GLY
parent 0dc37a20
No related branches found
No related tags found
No related merge requests found
......@@ -4,6 +4,7 @@ set(OST_CONOP_PYMOD_SOURCES
export_compound.cc
export_amino_acids.cc
export_conop.cc
export_non_standard.cc
export_ring_finder.cc
)
......
//------------------------------------------------------------------------------
// This file is part of the OpenStructure project <www.openstructure.org>
//
// Copyright (C) 2008-2011 by the OpenStructure authors
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 3.0 of the License, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//------------------------------------------------------------------------------
#include <boost/python.hpp>
#include <ost/mol/mol.hh>
#include <ost/conop/nonstandard.hh>
using namespace boost::python;
using namespace ost::conop;
using namespace ost::mol;
object copy_conserved_handle(ResidueHandle src_res, ResidueHandle dst_res,
XCSEditor edi) {
bool has_cbeta = false;
bool ret = CopyConserved(src_res, dst_res, edi, has_cbeta);
return make_tuple(ret, has_cbeta);
}
object copy_non_conserved_handle(ResidueHandle src_res, ResidueHandle dst_res,
XCSEditor edi) {
bool has_cbeta = false;
bool ret = CopyNonConserved(src_res, dst_res, edi, has_cbeta);
return make_tuple(ret, has_cbeta);
}
void export_NonStandard()
{
def("CopyNonConserved",&copy_non_conserved_handle);
def("CopyConserved", copy_conserved_handle);
def("CopyResidue", &CopyResidue);
}
......@@ -25,6 +25,8 @@ void export_Sanitizer();
void export_Conop();
void export_RingFinder();
void export_AminoAcids();
void export_NonStandard();
BOOST_PYTHON_MODULE(_ost_conop)
{
export_Builder();
......@@ -32,4 +34,5 @@ BOOST_PYTHON_MODULE(_ost_conop)
export_Compound();
export_RingFinder();
export_AminoAcids();
export_NonStandard();
}
......@@ -7,6 +7,7 @@ amino_acids.hh
compound.hh
compound_lib.hh
module_config.hh
nonstandard.hh
rule_based_builder.hh
ring_finder.hh
)
......@@ -18,12 +19,13 @@ conop.cc
heuristic_builder.cc
compound.cc
compound_lib.cc
nonstandard.cc
rule_based_builder.cc
ring_finder.cc
)
module(NAME conop SOURCES ${OST_CONOP_SOURCES}
HEADERS ${OST_CONOP_HEADERS} DEPENDS_ON ost_mol ost_geom ost_db)
HEADERS ${OST_CONOP_HEADERS} DEPENDS_ON ost_mol ost_mol_alg ost_geom ost_db)
executable(NAME chemdict_tool SOURCES chemdict_tool.cc DEPENDS_ON ost_io STATIC)
......
//------------------------------------------------------------------------------
// This file is part of the OpenStructure project <www.openstructure.org>
//
// Copyright (C) 2008-2011 by the OpenStructure authors
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 3.0 of the License, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//------------------------------------------------------------------------------
/*
Author: Marco Biasini, Juergen Haas
*/
#include <ost/log.hh>
#include <ost/dyn_cast.hh>
#include <ost/conop/conop.hh>
#include <ost/mol/mol.hh>
#include <ost/mol/alg/construct_cbeta.hh>
#include <ost/conop/rule_based_builder.hh>
#include <ost/conop/compound_lib.hh>
#include "nonstandard.hh"
using namespace ost::mol;
using namespace ost;
using namespace ost::conop;
namespace ost { namespace conop {
namespace {
bool CheckBackboneAtoms(ResidueHandle res)
{
String atom_names[]={"N", "CA", "C", "O"};
std::vector<String> missing;
for (int i =0; i<4; ++i) {
if (!res.FindAtom(atom_names[i])) {
missing.push_back(atom_names[i]);
}
}
if (!missing.empty()) {
std::stringstream ss;
ss << "residue " << res.GetQualifiedName() << " is missing atoms ";
for (std::vector<String>::const_iterator
i=missing.begin(), e=missing.end(); i!=e; ++i) {
if (i!=missing.begin()) {
ss << ", ";
}
ss << *i;
}
LOG_WARNING(ss.str());
return false;
}
return true;
}
bool CheckCalphaAtom(ResidueHandle res)
{
String atom_names[]={"N", "CA", "C", "O"};
std::vector<String> missing;
for (int i =0; i<4; ++i) {
if (!res.FindAtom(atom_names[i])) {
missing.push_back(atom_names[i]);
}
}
if (!res.FindAtom("CA")) {
LOG_WARNING("residue " << res.GetQualifiedName() << " is missing CA atom");
return false;
}
return true;
}
}
bool CopyResidue(ResidueHandle src_res, ResidueHandle dst_res, XCSEditor& edi)
{
bool has_cbeta = false;
bool ret;
if (src_res.GetName()==dst_res.GetName()) {
ret = CopyConserved(src_res, dst_res, edi, has_cbeta);
} else {
ret = CopyNonConserved(src_res, dst_res, edi, has_cbeta);
}
// insert Cbeta, unless dst residue is glycine.
if (!has_cbeta && dst_res.GetName()!="GLY") {
geom::Vec3 cbeta_pos=mol::alg::CBetaPosition(dst_res);
edi.InsertAtom(dst_res, "CB", cbeta_pos, "C");
}
return ret;
}
bool CopyConserved(ResidueHandle src_res, ResidueHandle dst_res, XCSEditor& edi,
bool& has_cbeta)
{
// check if the residue name of dst and src are the same. In the easy
// case, the two residue names match and we just copy over all atoms.
// If they don't match, we are dealing with modified residues.
//~ return copy_conserved(src_res, dst_res, edi, has_cbeta);
if (dst_res.GetName()==src_res.GetName()) {
return CopyIdentical(src_res, dst_res, edi, has_cbeta);
} else if (src_res.GetName()=="MSE") {
return CopyMSE(src_res, dst_res, edi, has_cbeta);
} else {
return CopyModified(src_res, dst_res, edi, has_cbeta);
}
}
bool CopyIdentical(ResidueHandle src_res, ResidueHandle dst_res, XCSEditor& edi,
bool& has_cbeta)
{
//~ return copy_identical();
AtomHandleList atoms=src_res.GetAtomList();
for (AtomHandleList::const_iterator
a=atoms.begin(), e=atoms.end(); a!=e; ++a) {
if (a->GetName()=="CB") {
has_cbeta=true;
}
if (a->GetElement()=="D" || a->GetElement()=="H") {
continue;
}
edi.InsertAtom(dst_res, a->GetName(), a->GetPos(), a->GetElement(),
a->GetOccupancy(), a->GetBFactor());
}
return true;
}
bool CopyMSE(ResidueHandle src_res, ResidueHandle dst_res, XCSEditor& edi,
bool& has_cbeta)
{
// selenium methionine is easy. We copy all atoms and substitute the SE
// with SD
AtomHandleList atoms=src_res.GetAtomList();
for (AtomHandleList::const_iterator
a=atoms.begin(), e=atoms.end(); a!=e; ++a) {
if (a->GetName()=="CB") {
has_cbeta=true;
}
if (a->GetElement()=="D" || a->GetElement()=="H") {
continue;
}
if (a->GetName()=="SE") {
edi.InsertAtom(dst_res, "SD", a->GetPos(), "S",
a->GetOccupancy(), a->GetBFactor());
} else {
edi.InsertAtom(dst_res, a->GetName(), a->GetPos(), a->GetElement(),
a->GetOccupancy(), a->GetBFactor());
}
}
return true;
}
bool CopyModified(ResidueHandle src_res, ResidueHandle dst_res,
XCSEditor& edi, bool& has_cbeta)
{
// FIXME: for now this functions ignores chirality changes of sidechain
// chiral atoms. To detect those changes, we would need to store the
// chirality of those centers in the compound library.
// For now, this function just handles cases where the src_res contains
// additional atoms, but the dst_atom doesn't contain any atoms the src_res
// doesn't have. It these two requirements are not met, we fall back to
// CopyNonConserved.
// first let's get our hands on the component library
conop::BuilderP builder=conop::Conopology::Instance().GetBuilder("DEFAULT");
conop::RuleBasedBuilderPtr rbb=dyn_cast<conop::RuleBasedBuilder>(builder);
conop::CompoundLibPtr comp_lib=rbb->GetCompoundLib();
CompoundPtr src_compound=comp_lib->FindCompound(src_res.GetName(),
Compound::PDB);
if (!src_compound) {
// OK, that's bad. Let's copy the backbone and be done with it!
return CopyNonConserved(src_res, dst_res, edi, has_cbeta);
}
// since dst_res is one of the 20 amino acids, we don't have to check for
// existence of the compound. We know it is there!
CompoundPtr dst_compound=comp_lib->FindCompound(dst_res.GetName(),
Compound::PDB);
std::set<String> dst_atoms;
std::set<String> src_atoms;
// to compare the atoms of dst_res with those of src_res, let's create two
// sets containing all heavy atoms.
for (AtomSpecList::const_iterator i=dst_compound->GetAtomSpecs().begin(),
e=dst_compound->GetAtomSpecs().end(); i!=e; ++i) {
if (i->element=="H" || i->element=="D") {
continue;
}
dst_atoms.insert(i->name);
}
for (AtomSpecList::const_iterator i=src_compound->GetAtomSpecs().begin(),
e=src_compound->GetAtomSpecs().end(); i!=e; ++i) {
if (i->element=="H" || i->element=="D") {
continue;
}
src_atoms.insert(i->name);
}
for (std::set<String>::const_iterator i=dst_atoms.begin(),
e=dst_atoms.end(); i!=e; ++i) {
if (src_atoms.find(*i)==src_atoms.end()) {
return CopyNonConserved(src_res, dst_res, edi, has_cbeta);
}
}
// Muahaha, all is good. Let's copy the atoms. Muahaha
AtomHandleList atoms=src_res.GetAtomList();
for (AtomHandleList::const_iterator
a=atoms.begin(), e=atoms.end(); a!=e; ++a) {
if (a->GetName()=="CB") {
if (dst_res.GetName()=="GLY") {
continue;
}
has_cbeta=true;
}
if (a->GetElement()=="D" || a->GetElement()=="H") {
continue;
}
if (dst_atoms.find(a->GetName())==dst_atoms.end()) {
continue;
}
edi.InsertAtom(dst_res, a->GetName(), a->GetPos(), a->GetElement(),
a->GetOccupancy(), a->GetBFactor());
}
return true;
}
bool CopyNonConserved(ResidueHandle src_res, ResidueHandle dst_res,
XCSEditor& edi, bool& has_cbeta)
{
AtomHandleList atoms=src_res.GetAtomList();
for (AtomHandleList::const_iterator
a=atoms.begin(), e=atoms.end(); a!=e; ++a) {
String name=a->GetName();
if (name=="CA" || name=="N" || name=="C" || name=="O" || name=="CB") {
if (name=="CB") {
if (dst_res.GetName()=="GLY") {
continue;
}
has_cbeta=true;
}
if (a->GetElement()=="D" || a->GetElement()=="H") {
continue;
}
edi.InsertAtom(dst_res, a->GetName(), a->GetPos(), a->GetElement(),
a->GetOccupancy(), a->GetBFactor());
}
}
return false;
}
}}
//------------------------------------------------------------------------------
// This file is part of the OpenStructure project <www.openstructure.org>
//
// Copyright (C) 2008-2011 by the OpenStructure authors
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 3.0 of the License, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//------------------------------------------------------------------------------
#ifndef OST_CONOP_NONSTANDARD_HH
#define OST_CONOP_NONSTANDARD_HH
/*
Author: Marco Biasini, Juergen Haas
*/
#include "module_config.hh"
namespace ost { namespace conop {
/// \brief copies all atom of src_res to dst_res
/// \param has_cbeta will be set to true if the src_res has a cbeta and the
/// dst_residue is not a glycine, it will be inserted if in the dst should
/// be one and in src it was not present
bool DLLEXPORT_OST_CONOP CopyResidue(ost::mol::ResidueHandle src_res,
ost::mol::ResidueHandle dst_res,
ost::mol::XCSEditor& edi);
/// \brief copies all atom of src_res to dst_res
/// \param has_cbeta will be set to true if the src_res has a cbeta and the
/// dst_residue is not a glycine
bool DLLEXPORT_OST_CONOP CopyIdentical(ost::mol::ResidueHandle src_res,
ost::mol::ResidueHandle dst_res,
ost::mol::XCSEditor& edi,
bool& has_cbeta);
/// \brief copies atoms of src_res to dst_res
///
/// src_res and dst_res are thought to be conserved, e.g. the parent standard
/// amino acid of both residues is the same. This includes cases where e.g. the
/// src_rs is and MSE and the dst_res is a MET. This function automatically
/// tries to do the right thing an keep as many atoms as possible from src_res
bool DLLEXPORT_OST_CONOP CopyConserved(ost::mol::ResidueHandle src_res,
ost::mol::ResidueHandle dst_res,
ost::mol::XCSEditor& edi,
bool& has_cbeta);
/// \brief construct dst_res in case src_res and dst_res are not conserved.
///
/// This essentially copies the backbone of src_res to dst_res. The CB atom is
/// only copied if dst_res is not equal to glycine.
bool DLLEXPORT_OST_CONOP CopyNonConserved(ost::mol::ResidueHandle src_res,
ost::mol::ResidueHandle dst_res,
ost::mol::XCSEditor& edi,
bool& has_cbeta);
/// \brief construct dst_res from src_res when src_res is an MSE
bool DLLEXPORT_OST_CONOP CopyMSE(ost::mol::ResidueHandle src_res,
ost::mol::ResidueHandle dst_res,
ost::mol::XCSEditor& edi,
bool& has_cbeta);
/// \brief construct a dst_res with only atoms matching the standard aminoacid
/// from src_res when src_res is an is modified
bool DLLEXPORT_OST_CONOP CopyModified(ost::mol::ResidueHandle src_res,
ost::mol::ResidueHandle dst_res,
ost::mol::XCSEditor& edi,
bool& has_cbeta);
}}
#endif
......@@ -5,6 +5,7 @@ set(OST_CONOP_UNIT_TESTS
test_builder.cc
test_compound.py
test_cleanup.py
test_nonstandard.py
)
ost_unittest(MODULE conop
......
import unittest
from ost import conop
class TestNonStandard(unittest.TestCase):
def test_fastModified(self):
# phoshoserine: test if we correctly strip off modifications
tpl=io.LoadPDB('testfiles/sep.pdb')
new_hdl=mol.CreateEntity();
ed=new_hdl.EditXCS()
c=ed.InsertChain('A')
ed.AppendResidue(c, 'SER')
err, has_cbeta=conop.CopyConserved(tpl.residues[0], new_hdl.residues[0], ed)
self.assertTrue(err)
self.assertTrue(has_cbeta)
residues=new_hdl.residues
self.assertEqual(len(residues), 1)
self.assertEqual(len(residues[0].atoms), 6)
self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "N").IsValid())
self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "CA").IsValid())
self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "C").IsValid())
self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "O").IsValid())
self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "CB").IsValid())
self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "OG").IsValid())
def test_CBeta(self):
# test if the dst residues contain cbeta, unless they are glycines
tpl=io.LoadPDB('testfiles/cbeta.pdb')
new_hdl=mol.CreateEntity();
ed=new_hdl.EditXCS()
c=ed.InsertChain('A')
ed.AppendResidue(c, 'MET')
ed.AppendResidue(c, 'GLY')
ed.AppendResidue(c, 'GLY')
ed.AppendResidue(c, 'HIS')
err, has_cbeta=conop.CopyConserved(tpl.residues[0], new_hdl.residues[0], ed)
self.assertTrue(has_cbeta)
self.assertTrue(err)
err, has_cbeta=conop.CopyConserved(tpl.residues[1], new_hdl.residues[1], ed)
self.assertFalse(has_cbeta)
self.assertTrue(err)
err, has_cbeta=conop.CopyConserved(tpl.residues[2], new_hdl.residues[2], ed)
self.assertFalse(has_cbeta)
self.assertTrue(err)
err, has_cbeta=conop.CopyConserved(tpl.residues[3], new_hdl.residues[3], ed)
self.assertTrue(has_cbeta)
self.assertTrue(err)
residues=new_hdl.residues
self.assertEqual(len(residues), 4)
self.assertTrue(residues[0].FindAtom("CB").IsValid())
self.assertFalse(residues[1].FindAtom("CB").IsValid())
self.assertFalse(residues[2].FindAtom("CB").IsValid())
self.assertTrue(residues[3].FindAtom("CB").IsValid())
def test_CopyResidue(self):
tpl=io.LoadPDB('testfiles/cbeta.pdb')
new_hdl=mol.CreateEntity();
ed=new_hdl.EditXCS()
c=ed.InsertChain('A')
ed.AppendResidue(c, 'MET')
ed.AppendResidue(c, 'GLY')
ed.AppendResidue(c, 'GLY')
ed.AppendResidue(c, 'HIS')
ed.AppendResidue(c, 'HIS')
ed.AppendResidue(c, 'GLY')
ed.AppendResidue(c, 'HIS')
ed.AppendResidue(c, 'MET')
# MET to MET
err =conop.CopyResidue(tpl.residues[0], new_hdl.residues[0], ed)
self.assertTrue(err)
#GLY to GLY
err =conop.CopyResidue(tpl.residues[1], new_hdl.residues[1], ed)
self.assertTrue(err)
# GLY to GLY
err =conop.CopyResidue(tpl.residues[2], new_hdl.residues[2], ed)
self.assertTrue(err)
#now we copy a HIS to a HIS
err =conop.CopyResidue(tpl.residues[3], new_hdl.residues[3], ed)
self.assertTrue(err)
# copy a GLY to a HIS
err, has_cbeta=conop.CopyNonConserved(tpl.residues[1], new_hdl.residues[4], ed)
self.assertFalse(has_cbeta)
# copy a MET to a GLY
err =conop.CopyResidue(tpl.residues[0], new_hdl.residues[5], ed)
self.assertFalse(err)
# copy a MET to a HIS
err =conop.CopyResidue(tpl.residues[0], new_hdl.residues[6], ed)
self.assertFalse(err)
# copy a GLY to a MET with adding CB
err=conop.CopyResidue(tpl.residues[1], new_hdl.residues[7], ed)
self.assertFalse(err)
residues=new_hdl.residues
self.assertEqual(len(residues), 8)
# MET to MET
self.assertTrue(residues[0].FindAtom("CB").IsValid())
#GLY to GLY
self.assertFalse(residues[1].FindAtom("CB").IsValid())
#now we copy a GLY to a GLY
self.assertFalse(residues[2].FindAtom("CB").IsValid())
#now we copy a HIS to a HIS
self.assertTrue(residues[3].FindAtom("CB").IsValid())
#now we copy a GLY to a HIS without adding CB
self.assertFalse(residues[4].FindAtom("CB").IsValid())
#now we copy a MET to a GLY
self.assertFalse(residues[5].FindAtom("CB").IsValid())
# copy a MET to a HIS
self.assertTrue(residues[6].FindAtom("CB").IsValid())
# copy a GLY to a MET with adding CB
self.assertTrue(residues[7].FindAtom("CB").IsValid())
if __name__ == "__main__":
suite = unittest.TestLoader().loadTestsFromTestCase(TestNonStandard)
unittest.TextTestRunner().run(suite)
ATOM 1 N MET A 55 -11.301 11.863 12.812 1.00 46.35 N
ATOM 2 CA MET A 55 -10.174 12.241 13.713 1.00 45.84 C
ATOM 3 C MET A 55 -9.595 11.051 14.465 1.00 44.35 C
ATOM 4 O MET A 55 -10.219 9.989 14.526 1.00 46.54 O
ATOM 5 CB MET A 55 -10.591 13.367 14.670 1.00 48.03 C
ATOM 6 CG MET A 55 -11.911 13.150 15.404 1.00 49.20 C
ATOM 7 SD MET A 55 -12.173 14.422 16.660 1.00 55.85 S
ATOM 8 CE MET A 55 -10.955 13.907 17.875 1.00 52.51 C
ATOM 9 N GLY A 56 -8.383 11.240 14.995 1.00 42.02 N
ATOM 10 CA GLY A 56 -7.611 10.243 15.755 1.00 39.04 C
ATOM 11 C GLY A 56 -7.093 9.042 14.960 1.00 35.73 C
ATOM 12 O GLY A 56 -7.875 8.322 14.336 1.00 35.25 O
ATOM 18 N GLY A 57 -5.757 8.838 14.934 1.00 32.59 N
ATOM 19 CA GLY A 57 -5.167 7.704 14.210 1.00 30.22 C
ATOM 20 C GLY A 57 -5.475 6.389 14.924 1.00 28.03 C
ATOM 21 O GLY A 57 -5.774 6.389 16.125 1.00 25.91 O
ATOM 25 N HIS A 58 -5.434 5.288 14.176 1.00 26.73 N
ATOM 26 CA HIS A 58 -5.705 3.960 14.726 1.00 26.95 C
ATOM 27 C HIS A 58 -4.622 3.524 15.706 1.00 27.12 C
ATOM 28 O HIS A 58 -3.426 3.545 15.366 1.00 27.18 O
ATOM 29 CB HIS A 58 -5.849 2.928 13.607 1.00 26.98 C
ATOM 30 CG HIS A 58 -7.149 3.014 12.872 1.00 27.32 C
ATOM 31 ND1 HIS A 58 -8.359 3.179 13.510 1.00 28.47 N
ATOM 32 CD2 HIS A 58 -7.428 2.948 11.552 1.00 26.86 C
ATOM 33 CE1 HIS A 58 -9.327 3.211 12.613 1.00 28.81 C
ATOM 34 NE2 HIS A 58 -8.789 3.073 11.416 1.00 28.59 N
END
HETATM 2554 N SEP A 338 22.112 31.452 4.376 1.00 36.83 N
HETATM 2555 CA SEP A 338 21.303 32.489 4.986 1.00 35.62 C
HETATM 2556 CB SEP A 338 20.220 31.868 5.843 1.00 36.98 C
HETATM 2557 OG SEP A 338 19.529 32.909 6.526 1.00 38.75 O
HETATM 2558 C SEP A 338 22.121 33.517 5.710 1.00 36.32 C
HETATM 2559 O SEP A 338 23.245 32.996 6.389 1.00 28.28 O
HETATM 2560 P SEP A 338 18.280 33.605 5.779 1.00 36.73 P
HETATM 2561 O1P SEP A 338 17.256 33.885 6.849 1.00 38.47 O
HETATM 2562 O2P SEP A 338 17.811 32.606 4.750 1.00 39.29 O
HETATM 2563 O3P SEP A 338 18.956 34.824 5.189 1.00 32.24 O
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment