Packing similarity examples

Note

The crystal packing similarity features are available only to CSD-Materials and CSD-Enterprise users.

Comparing similarity measures

This example searches the CSD for structures similar to a given entry, then calculates the molecular-, crystal- and powder pattern simulation similarities, presenting them in an HTML table with a diagram of the structure. For example this which was created from the command line ‘python ccdc/examples/packing_similarity.py ZERLUD –threshold 0.8’.

#!/usr/bin/env python
#
# This script can be used for any purpose without limitation subject to the
# conditions at https://www.ccdc.cam.ac.uk/Community/Pages/Licences/v2.aspx
#
# This permission notice and the following statement of attribution must be
# included in all copies or substantial portions of this script.
#
# 2015-06-17: created by the Cambridge Crystallographic Data Centre
#
######################################################################
'''
packing_similarity.py - find similar molecules and report crystal packing and powder
simulation similarities.

The CSD will be searched for any similar molecules to the given refcode(s).  Their Crystal
Packing similarity and Powder Simulation similarity will be reported in an HTML table.
'''

import argparse

from ccdc.io import EntryReader
from ccdc.search import SimilaritySearch
from ccdc.crystal import PackingSimilarity
from ccdc.descriptors import CrystalDescriptors
from ccdc.diagram import DiagramGenerator

######################################################################

class Runner(argparse.ArgumentParser):
    '''Interprets arguments, and runs the script.'''
    def __init__(self):
        super(self.__class__, self).__init__(description=__doc__)
        self.add_argument(
            'refcodes', nargs='+',
            help='Refcode(s) for which to perform the similarity search and comparison'
        )
        self.add_argument(
            '-t', '--threshold', default=0.9, type=float, help='Similarity search threshold to use.'
        )
        self.parse_args(namespace=self)

    def run(self):
        '''Run all the comparisons.'''
        self.csd = EntryReader('csd')
        self.packing_sim = PackingSimilarity()
        self.packing_sim.settings.allow_molecular_differences = True
        self.diagram_generator = DiagramGenerator()
        self.diagram_generator.settings.return_type = 'SVG'
        print('<H2>Similarity measures</H2>')
        print('<TABLE border="1"><TR>')
        print('<TH>Refcode</TH><TH>Diagram</TH><TH>Molecular</TH><TH>Packing</TH><TH>Powder Sim.</TH>')
        print('</TR>')
        for refcode in self.refcodes:
            self.run_one(refcode)
        print('</TABLE>')

    def run_one(self, refcode):
        '''Single comparison.'''
        crystal = self.csd.crystal(refcode)
        powder_sim = CrystalDescriptors.PowderPattern.from_crystal(crystal)
        mol = crystal.molecule
        diagram = self.diagram_generator.image(self.csd.entry(refcode))
        search = SimilaritySearch(mol, self.threshold)
        hits = search.search()
        print('<TR><TH>%s</TH><TD>%s<TD colspan=3>%d hits</TD></TR>' % (refcode, diagram, len(hits)))
        for h in hits:
            packing_sim = self.packing_sim.compare(crystal, h.crystal)
            other_powder = CrystalDescriptors.PowderPattern.from_crystal(h.crystal)
            powder = powder_sim.similarity(other_powder)
            other_diagram = self.diagram_generator.image(h.entry)
            if packing_sim is None:
                pack = '---'
            else:
                pack = '%.2f (%d)' % (packing_sim.rmsd, packing_sim.nmatched_molecules)
            print('<TR><TD>%s</TD><TD>%s<TD>%.2f</TD><TD>%s</TD><TD>%.2f</TD></TR>' % (
                h.identifier, other_diagram, h.similarity, pack, powder
            ))

######################################################################

if __name__ == '__main__':
    Runner().run()