Commit 0f0d3603 authored by Lukas Pravda's avatar Lukas Pravda
Browse files

Merge branch 'dev'

parents 2acf0ec2 9f609913
#!/usr/bin/env python
# software from PDBe: Protein Data Bank in Europe; http://pdbe.org
#
# Copyright 2018 EMBL - European Bioinformatics Institute
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from pdbeccdutils.scripts.process_components_cif_cli import main
if __name__ == "__main__":
main()
#!/usr/bin/env python
# software from PDBe: Protein Data Bank in Europe; https://pdbe.org
#
# Copyright 2018 EMBL - European Bioinformatics Institute
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from pdbeccdutils.scripts.setup_pubchem_library_cli import main
if __name__ == "__main__":
main()
__version__ = '0.5.3'
__version__ = '0.5.4'
......@@ -31,7 +31,7 @@ from datetime import date
from typing import Dict, List, NamedTuple
import rdkit
from mmCif.mmcifIO import MMCIF2Dict
from pdbecif.mmcif_io import MMCIF2Dict
from pdbeccdutils.core.component import Component
from pdbeccdutils.core.exceptions import CCDUtilsError
......
......@@ -30,7 +30,7 @@ from collections import OrderedDict
from typing import List
from xml.dom import minidom
import mmCif.mmcifIO as mmcif
import pdbecif.mmcif_io as mmcif
import rdkit
import pdbeccdutils
......
......@@ -179,9 +179,15 @@ def convert_svg(svg_string, ccd_id, mol: rdkit.Chem.Mol):
result_bag['bonds'].append(temp)
for label_svg in label_elem:
x = label_svg.attrib.get('x')
y = label_svg.attrib.get('y')
if 'nan' in (x, y):
continue
temp = {
'x': float(label_svg.attrib.get('x')),
'y': float(label_svg.attrib.get('y')),
'x': float(x),
'y': float(y),
'style': label_svg.attrib.get('style'),
'tspans': [{
'value': tspan.text,
......
......@@ -58,13 +58,15 @@ class PDBeChemManager:
Args:
logger (logging.Logger, optional): Defaults to None. Application log
"""
self.compounds: List[ccd_reader.CCDReaderResult] = [] # processed compounds
self.ligands_to_process: int = 0 # no. ligands to process
self.output_dir: str = '' # where the results will be written
self.depictions: DepictionManager = None # helper class to get nice depictions
self.pubchem: PubChemDownloader = None # helper class to download templates if needed
self.fragment_library: FragmentLibrary = None # Fragments library to get substructure matches
self.logger = logger if logger is not None else logging.getLogger(__name__) # log of the application
self.compounds: List[ccd_reader.CCDReaderResult] = [] # processed compounds
self.ligands_to_process: int = 0 # no. ligands to process
self.output_dir: str = "" # where the results will be written
self.depictions: DepictionManager = None # helper class to get nice depictions
self.pubchem: PubChemDownloader = None # helper class to download templates if needed
self.fragment_library: FragmentLibrary = None # Fragments library to get substructure matches
self.logger = (
logger if logger is not None else logging.getLogger(__name__)
) # log of the application
def run_pipeline(self, args):
"""Run PDBeChem pipeline
......@@ -81,18 +83,26 @@ class PDBeChemManager:
Args:
args (argparse.Namespace): Verified application arguments
"""
self.logger.debug('Initializing calculation...')
self.logger.debug("Initializing calculation...")
self.output_dir = args.output_dir
self.depictions = DepictionManager(args.pubchem_templates, args.general_templates)
self.pubchem = PubChemDownloader(args.pubchem_templates) if os.path.isdir(args.pubchem_templates) else None
self.depictions = DepictionManager(
args.pubchem_templates, args.general_templates
)
self.pubchem = (
PubChemDownloader(args.pubchem_templates)
if os.path.isdir(args.pubchem_templates)
else None
)
self.fragment_library = FragmentLibrary(args.library)
self.logger.debug(f'Reading in {args.components_cif} file...')
self.logger.debug(f"Reading in {args.components_cif} file...")
self.compounds = ccd_reader.read_pdb_components_file(args.components_cif)
self.ligands_to_process = len(self.compounds) if args.test_first is None else args.test_first
self.ligands_to_process = (
len(self.compounds) if args.test_first is None else args.test_first
)
self.logger.debug('Initialization finished.')
self.logger.debug("Initialization finished.")
def _process_data(self):
"""Main part of the PDBeChem process. Update all the data.
......@@ -102,13 +112,13 @@ class PDBeChemManager:
try:
self.process_single_component(ccd_reader_result)
except Exception:
self.logger.error(f'{key} | FAILURE {traceback.format_exc()}.')
self.logger.error(f"{key} | FAILURE {traceback.format_exc()}.")
self.ligands_to_process -= 1
self.compounds[key] = None
if self.ligands_to_process == 0:
self.logger.debug('All is done!')
self.logger.debug("All is done!")
break
def process_single_component(self, ccd_reader_result):
......@@ -117,7 +127,7 @@ class PDBeChemManager:
Args:
ccd_reader_result (CCDReaderResult): pdbeccdutils parser output.
"""
self.logger.info(f'{ccd_reader_result.component.id} | processing...')
self.logger.info(f"{ccd_reader_result.component.id} | processing...")
ccd_id = ccd_reader_result.component.id
component = ccd_reader_result.component
......@@ -160,10 +170,10 @@ class PDBeChemManager:
self.logger.debug(f'errors: {";".join(ccd_reader_result.errors)}')
if not ccd_reader_result.component.sanitized:
self.logger.debug('sanitization issue.')
self.logger.debug("sanitization issue.")
if not ccd_reader_result.component.inchikey_from_rdkit_matches_ccd():
self.logger.debug('inchikey mismatch.')
self.logger.debug("inchikey mismatch.")
def _download_template(self, component: Component):
"""Attempts to download a pubchem template for the given component
......@@ -174,7 +184,7 @@ class PDBeChemManager:
logger = logging.getLogger(__name__)
component_downloaded = self.pubchem.process_template(component)
if component_downloaded:
logger.debug('downloaded new pubchem template.')
logger.debug("downloaded new pubchem template.")
def _generate_ideal_structure(self, component: Component):
"""Checks whether or not the component has degenerated ideal
......@@ -190,10 +200,10 @@ class PDBeChemManager:
result = component.compute_3d()
if component.has_degenerated_conformer(ConformerType.Ideal):
self.logger.debug('has degenerated ideal coordinates.')
self.logger.debug("has degenerated ideal coordinates.")
if not result:
self.logger.debug('error in generating 3D conformation.')
self.logger.debug("error in generating 3D conformation.")
return result
......@@ -207,7 +217,9 @@ class PDBeChemManager:
matches = component.library_search(self.fragment_library)
if matches:
self.logger.debug(f'{len(matches)} matches found in the library `{self.fragment_library.name}`.')
self.logger.debug(
f"{len(matches)} matches found in the library `{self.fragment_library.name}`."
)
def _compute_component_scaffolds(self, component: Component):
"""Compute scaffolds for a given component.
......@@ -223,7 +235,7 @@ class PDBeChemManager:
return
self.logger.debug(f'{len(component.scaffolds)} scaffold(s) were found.')
self.logger.debug(f"{len(component.scaffolds)} scaffold(s) were found.")
def _generate_depictions(self, component: Component):
"""Generate nice 2D depictions for the component. Presently depictions
......@@ -241,19 +253,33 @@ class PDBeChemManager:
depiction_result = component.compute_2d(self.depictions)
if depiction_result.source == DepictionSource.Failed:
self.logger.debug('failed to generate 2D image.')
self.logger.debug("failed to generate 2D image.")
else:
if depiction_result.score > 0.99:
self.logger.debug('collision free image could not be generated.')
self.logger.debug(f'2D generated using {depiction_result.source.name} with score {depiction_result.score}.')
self.logger.debug("collision free image could not be generated.")
self.logger.debug(
f"2D generated using {depiction_result.source.name} with score {depiction_result.score}."
)
wedge_bonds = depiction_result.template_name != 'cube'
wedge_bonds = depiction_result.template_name != "cube"
for i in range(100, 600, 100):
component.export_2d_svg(os.path.join(parent_dir, f'{component.id}_{i}.svg'), width=i, wedge_bonds=wedge_bonds)
component.export_2d_svg(os.path.join(parent_dir, f'{component.id}_{i}_names.svg'), width=i, names=True, wedge_bonds=wedge_bonds)
component.export_2d_annotation(os.path.join(parent_dir, f'{component.id}_annotation.json'), wedge_bonds=wedge_bonds)
component.export_2d_svg(
os.path.join(parent_dir, f"{component.id}_{i}.svg"),
width=i,
wedge_bonds=wedge_bonds,
)
component.export_2d_svg(
os.path.join(parent_dir, f"{component.id}_{i}_names.svg"),
width=i,
names=True,
wedge_bonds=wedge_bonds,
)
component.export_2d_annotation(
os.path.join(parent_dir, f"{component.id}_annotation.json"),
wedge_bonds=wedge_bonds,
)
def _export_structure_formats(self, component: Component):
"""Writes out component in a different formats as required for the
......@@ -267,14 +293,54 @@ class PDBeChemManager:
"""
parent_dir = os.path.join(self.output_dir, component.id[0], component.id)
self.__write_molecule(os.path.join(parent_dir, f'{component.id}_model.sdf'), component, False, ConformerType.Model)
self.__write_molecule(os.path.join(parent_dir, f'{component.id}_ideal.sdf'), component, False, ConformerType.Ideal)
self.__write_molecule(os.path.join(parent_dir, f'{component.id}_ideal_alt.pdb'), component, True, ConformerType.Ideal)
self.__write_molecule(os.path.join(parent_dir, f'{component.id}_model_alt.pdb'), component, True, ConformerType.Model)
self.__write_molecule(os.path.join(parent_dir, f'{component.id}_ideal.pdb'), component, False, ConformerType.Ideal)
self.__write_molecule(os.path.join(parent_dir, f'{component.id}_model.pdb'), component, False, ConformerType.Model)
self.__write_molecule(os.path.join(parent_dir, f'{component.id}.cml'), component, False, ConformerType.Model)
self.__write_molecule(os.path.join(parent_dir, f'{component.id}.cif'), component, False, ConformerType.AllConformers)
self.__write_molecule(
os.path.join(parent_dir, f"{component.id}_model.sdf"),
component,
False,
ConformerType.Model,
)
self.__write_molecule(
os.path.join(parent_dir, f"{component.id}_ideal.sdf"),
component,
False,
ConformerType.Ideal,
)
self.__write_molecule(
os.path.join(parent_dir, f"{component.id}_ideal_alt.pdb"),
component,
True,
ConformerType.Ideal,
)
self.__write_molecule(
os.path.join(parent_dir, f"{component.id}_model_alt.pdb"),
component,
True,
ConformerType.Model,
)
self.__write_molecule(
os.path.join(parent_dir, f"{component.id}_ideal.pdb"),
component,
False,
ConformerType.Ideal,
)
self.__write_molecule(
os.path.join(parent_dir, f"{component.id}_model.pdb"),
component,
False,
ConformerType.Model,
)
self.__write_molecule(
os.path.join(parent_dir, f"{component.id}.cml"),
component,
False,
ConformerType.Model,
)
self.__write_molecule(
os.path.join(parent_dir, f"{component.id}.cif"),
component,
False,
ConformerType.AllConformers,
)
def __write_molecule(self, path, component, alt_names, conformer_type):
"""Write out deemed structure.
......@@ -287,13 +353,18 @@ class PDBeChemManager:
conformer_type (Component): Conformer to be written.
"""
try:
ccd_writer.write_molecule(path, component, remove_hs=False, alt_names=alt_names,
conf_type=conformer_type)
ccd_writer.write_molecule(
path,
component,
remove_hs=False,
alt_names=alt_names,
conf_type=conformer_type,
)
except Exception:
self.logger.error(f'error writing {path}.')
self.logger.error(f"error writing {path}.")
with open(path, 'w') as f:
f.write('')
with open(path, "w") as f:
f.write("")
# region pre-light tasks
......@@ -304,20 +375,41 @@ def create_parser():
Returns:
argparse.Namespace parser
"""
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawTextHelpFormatter)
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawTextHelpFormatter
)
add_arg = parser.add_argument
add_arg('components_cif', help='Input PDB-CCD components.cif file (must be specified)')
add_arg('--general_templates', default=config.general_templates, type=str,
help='Path to the directory with general templates in sdf format.')
add_arg('--pubchem_templates', default='',
help='Path to the directory with pubchem templates in sdf format.')
add_arg('--output_dir', '-o', required=True,
help='Create an output directory with files suitable for PDBeChem ftp directory')
add_arg('--test_first', type=int,
help='Only process the first TEST_FIRST chemical component definitions (for testing).')
add_arg('--library', default=config.fragment_library,
help='Use this fragment library in place of the one supplied with the code.')
add_arg('--debug', action='store_true', help='Turn on debug message logging output')
add_arg(
"components_cif", help="Input PDB-CCD components.cif file (must be specified)"
)
add_arg(
"--general_templates",
default=config.general_templates,
type=str,
help="Path to the directory with general templates in sdf format.",
)
add_arg(
"--pubchem_templates",
default="",
help="Path to the directory with pubchem templates in sdf format.",
)
add_arg(
"--output_dir",
"-o",
required=True,
help="Create an output directory with files suitable for PDBeChem ftp directory",
)
add_arg(
"--test_first",
type=int,
help="Only process the first TEST_FIRST chemical component definitions (for testing).",
)
add_arg(
"--library",
default=config.fragment_library,
help="Use this fragment library in place of the one supplied with the code.",
)
add_arg("--debug", action="store_true", help="Turn on debug message logging output")
return parser
......@@ -330,7 +422,7 @@ def check_args(args):
required arguments
"""
if not os.path.isfile(args.components_cif):
print(f'{args.components_cif} does not exist', file=sys.stderr)
print(f"{args.components_cif} does not exist", file=sys.stderr)
sys.exit(os.EX_NOINPUT)
if not os.path.isdir(args.output_dir):
......@@ -338,7 +430,9 @@ def check_args(args):
if args.test_first is not None:
if args.test_first < 1:
print(f'Test_first mode needs to have at least 1 component.', file=sys.stderr)
print(
f"Test_first mode needs to have at least 1 component.", file=sys.stderr
)
sys.exit(os.EX_NOINPUT)
......@@ -354,12 +448,16 @@ def _set_up_logger(args):
logger = logging.getLogger(__name__)
level = logging.DEBUG if args.debug else logging.ERROR
frm = '[%(asctime)-15s] %(message)s'
logging.basicConfig(level=level, format=frm, datefmt='%a, %d %b %Y %H:%M:%S')
logger.info(f'PDBeChem pipeline using:')
logger.info(f'pdbeccdutils core v. {pdbeccdutils.__version__}, RDKit v. {rdkit.__version__}')
frm = "[%(asctime)-15s] %(message)s"
logging.basicConfig(level=level, format=frm, datefmt="%a, %d %b %Y %H:%M:%S")
logger.info(f"PDBeChem pipeline using:")
logger.info(
f"pdbeccdutils core v. {pdbeccdutils.__version__}, RDKit v. {rdkit.__version__}"
)
return logger
# endregion
......@@ -372,9 +470,13 @@ def main():
check_args(args)
log = _set_up_logger(args)
log.info('Settings:')
log.info("Settings:")
for k, v in vars(args).items():
log.info(f'{"":5s}{k:25s}{v}')
pdbechem = PDBeChemManager(log)
pdbechem.run_pipeline(args)
if __name__ == "__main__":
main()
......@@ -12,12 +12,25 @@ from pdbeccdutils.utils import PubChemDownloader
def main():
"""Main method of the whole process.
"""
parser = argparse.ArgumentParser(description='PDBe downloader of pubchem depictions')
parser.add_argument('--components_dir', type=str, default='',
help='Path to the directory with CCD files', required=False)
parser.add_argument('--ccd', type=str, default='', help='Path to the CCD file', required=False)
parser.add_argument('--pubchem_templates', type=str, help='Path to the pubchem templates.',
required=True)
parser = argparse.ArgumentParser(
description="PDBe downloader of pubchem depictions"
)
parser.add_argument(
"--components_dir",
type=str,
default="",
help="Path to the directory with CCD files",
required=False,
)
parser.add_argument(
"--ccd", type=str, default="", help="Path to the CCD file", required=False
)
parser.add_argument(
"--pubchem_templates",
type=str,
help="Path to the pubchem templates.",
required=True,
)
config = parser.parse_args()
......@@ -29,5 +42,12 @@ def main():
pubchem.update_ccd_file(config.ccd)
sys.exit(os.EX_OK)
else:
print('Either components_dir or components.cif file needs to be set as a source of data.', file=sys.stderr)
print(
"Either components_dir or components.cif file needs to be set as a source of data.",
file=sys.stderr,
)
sys.exit(os.EX_USAGE)
if __name__ == "__main__":
main()
......@@ -924,3 +924,243 @@ _pdbx_chem_comp_audit.processing_site
004 "Create component" 2010-04-27 RCSB
004 "Modify descriptor" 2011-06-04 RCSB
#
data_ZPN
#
_chem_comp.id ZPN
_chem_comp.name "(2Z,4E)-N-[(S)-[(1S,2E,5S,8E,10Z,17S)-3,11-dimethyl-19-methylidene-7,13-dioxo-6,21-dioxabicyclo[15.3.1]henicosa-2,8,10-trien-5-yl](hydroxy)methyl]hexa-2,4-dienamide"
_chem_comp.type NON-POLYMER
_chem_comp.pdbx_type HETAIN
_chem_comp.formula "C29 H39 N O6"
_chem_comp.mon_nstd_parent_comp_id ?
_chem_comp.pdbx_synonyms "(-)-ZAMPANOLIDE (Bound form)"
_chem_comp.pdbx_formal_charge 0
_chem_comp.pdbx_initial_date 2012-12-20
_chem_comp.pdbx_modified_date 2013-01-18
_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 497.623
_chem_comp.one_letter_code ?
_chem_comp.three_letter_code ZPN
_chem_comp.pdbx_model_coordinates_details ?
_chem_comp.pdbx_model_coordinates_missing_flag N
_chem_comp.pdbx_ideal_coordinates_details Corina
_chem_comp.pdbx_ideal_coordinates_missing_flag N
_chem_comp.pdbx_model_coordinates_db_code 4I4T
_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
ZPN C1 C1 C 0 1 N N N -0.054 -2.210 -39.137 -1.086 1.273 -0.057 C1 ZPN 1
ZPN O1 O1 O 0 1 N N N 0.754 -3.142 -39.137 -1.184 1.359 -1.267 O1 ZPN 2
ZPN C2 C2 C 0 1 N N N -0.593 -1.579 -40.331 -0.438 2.305 0.667 C2 ZPN 3
ZPN C3 C3 C 0 1 N N N -0.072 -1.774 -41.555 0.347 3.179 -0.003 C3 ZPN 4
ZPN C4 C4 C 0 1 N N N -0.591 -1.001 -42.668 1.046 4.256 0.695 C4 ZPN 5
ZPN C5 C5 C 0 1 N N N -0.049 -1.062 -43.887 2.321 4.510 0.376 C5 ZPN 6
ZPN C21 C21 C 0 1 N N N -0.404 -0.045 -44.934 3.055 5.627 1.067 C21 ZPN 7
ZPN C6 C6 C 0 1 N N N 1.190 -1.877 -44.116 3.019 3.669 -0.660 C6 ZPN 8
ZPN C7 C7 C 0 1 N N N 2.332 -0.915 -44.227 4.313 3.143 -0.096 C7 ZPN 9
ZPN O7 O7 O 0 1 N N N 2.993 -0.862 -45.260 5.282 3.862 -0.042 O7 ZPN 10
ZPN C8 C8 C 0 1 N N N 2.270 0.260 -43.298 4.402 1.724 0.402 C8 ZPN 11
ZPN C9 C9 C 0 1 N N N 3.569 0.360 -42.495 4.562 0.774 -0.785 C9 ZPN 12
ZPN C10 C10 C 0 1 N N N 3.480 1.616 -41.608 5.555 -0.334 -0.431 C10 ZPN 13
ZPN C11 C11 C 0 1 N N S 3.800 1.468 -40.117 4.896 -1.697 -0.654 C11 ZPN 14
ZPN C12 C12 C 0 1 N N N 4.170 2.871 -39.626 5.812 -2.798 -0.117 C12 ZPN 15
ZPN C13 C13 C 0 1 N N N 4.236 2.904 -38.123 5.004 -3.738 0.742 C13 ZPN 16
ZPN C22 C22 C 0 1 N N N 5.302 3.384 -37.487 5.502 -4.201 1.861 C22 ZPN 17
ZPN C14 C14 C 0 1 N N N 3.097 2.247 -37.403 3.619 -4.141 0.304 C14 ZPN 18
ZPN C15 C15 C 0 1 N N S 2.883 0.851 -38.012 2.874 -2.912 -0.222 C15 ZPN 19
ZPN O11 O11 O 0 1 N N N 2.651 0.994 -39.419 3.648 -1.739 0.041 O11 ZPN 20
ZPN C16 C16 C 0 1 N N N 1.688 0.203 -37.363 1.537 -2.787 0.462 C16 ZPN 21
ZPN C17 C17 C 0 1 N N N 1.678 -1.038 -36.850 0.528 -2.214 -0.154 C17 ZPN 22
ZPN C23 C23 C 0 1 N N N 2.904 -1.881 -36.635 0.707 -1.696 -1.558 C23 ZPN 23
ZPN C18 C18 C 0 1 N N N 0.547 -1.481 -35.994 -0.806 -2.085 0.536 C18 ZPN 24
ZPN C19 C19 C 0 1 N N S -0.469 -2.350 -36.766 -1.658 -1.021 -0.159 C19 ZPN 25
ZPN O19 O19 O 0 1 N N N -0.870 -2.042 -38.104 -1.597 0.203 0.576 O19 ZPN 26
ZPN C20 C20 C 0 1 N N S -1.492 -3.098 -35.916 -3.109 -1.499 -0.232 C20 ZPN 27
ZPN O20 O20 O 0 1 N N N -2.004 -4.268 -36.540 -3.172 -2.719 -0.973 O20 ZPN 28
ZPN N20 N20 N 0 1 N N N -2.533 -2.077 -35.747 -3.926 -0.481 -0.897 N20 ZPN 29
ZPN "C1'" "C1'" C 0 1 N N N -3.376 -2.125 -34.693 -5.165 -0.207 -0.441 "C1'" ZPN 30
ZPN "O1'" "O1'" O 0 1 N N N -3.223 -3.023 -33.847 -5.604 -0.805 0.523 "O1'" ZPN 31
ZPN "C2'" "C2'" C 0 1 N N N -4.368 -1.047 -34.693 -5.980 0.809 -1.106 "C2'" ZPN 32
ZPN "C3'" "C3'" C 0 1 N N N -5.409 -0.980 -33.827 -7.259 1.010 -0.717 "C3'" ZPN 33
ZPN "C4'" "C4'" C 0 1 N N N -5.513 -1.770 -32.607 -7.882 0.101 0.246 "C4'" ZPN 34
ZPN "C5'" "C5'" C 0 1 N N N -6.593 -1.668 -31.814 -9.097 0.370 0.728 "C5'" ZPN 35
ZPN "C6'" "C6'" C 0 1 N N N -6.821 -2.507 -30.589 -9.738 -0.566 1.719 "C6'" ZPN 36
ZPN H21 H21 H 0 1 N N N -1.448 -0.926 -40.230 -0.541 2.374 1.737 H21 ZPN 37
ZPN H31 H31 H 0 1 N N N 0.719 -2.493 -41.707 0.453 3.082 -1.074 H31 ZPN 38
ZPN H41 H41 H 0 1 N N N -1.442 -0.356 -42.505 0.573 4.807 1.482 H41 ZPN 39
ZPN H211 H211 H 0 0 N N N -1.327 0.476 -44.641 2.391 6.108 1.786 H211 ZPN 40
ZPN H212 H212 H 0 0 N N N 0.414 0.684 -45.029 3.923 5.224 1.588 H212 ZPN 41