1import sys
2import os
3import argparse
4
5import CDPL.Chem as Chem
6import CDPL.Pharm as Pharm
7
8
9# generates the pharmacophore of the argument molecule using
10# atom coordinates of the specified conformation
11def genPharmacophore(mol: Chem.Molecule, conf_idx: int) -> Pharm.Pharmacophore:
12 if conf_idx < 1: # for a new molecule
13 Pharm.prepareForPharmacophoreGeneration(mol) # first call utility function preparing the molecule for pharmacophore generation
14
15 ph4_gen = Pharm.DefaultPharmacophoreGenerator() # create an instance of the pharmacophore generator default implementation
16 ph4 = Pharm.BasicPharmacophore() # create an instance of the default implementation of the Pharm.Pharmacophore interface
17 ph4_name = Chem.getName(mol) # use the name of the input molecule as pharmacophore name
18
19 if conf_idx >= 0: # if mol is a multi-conf. molecule use atom 3D coordinates of the specified conf.
20 ph4_gen.setAtom3DCoordinatesFunction(Chem.AtomConformer3DCoordinatesFunctor(conf_idx))
21 ph4_name += '#' + str(conf_idx) # and append conformer index to the pharmacophore name
22
23 ph4_gen.generate(mol, ph4) # generate the pharmacophore
24 Pharm.setName(ph4, ph4_name) # set the pharmacophore name
25
26 return ph4
27
28def parseArgs() -> argparse.Namespace:
29 parser = argparse.ArgumentParser(description='Generates pharmacophores of the given input molecules.')
30
31 parser.add_argument('-i',
32 dest='in_file',
33 required=True,
34 metavar='<file>',
35 help='Molecule input file')
36 parser.add_argument('-o',
37 dest='out_file',
38 required=True,
39 metavar='<file>',
40 help='Pharmacophore output file')
41 parser.add_argument('-q',
42 dest='quiet',
43 required=False,
44 action='store_true',
45 default=False,
46 help='Disable progress output (default: false)')
47
48 return parser.parse_args()
49
50def main() -> None:
51 args = parseArgs()
52
53 # create reader for input molecules (format specified by file extension)
54 reader = Chem.MoleculeReader(args.in_file)
55
56 # create writer for the generated pharmacophores (format specified by file extension)
57 writer = Pharm.FeatureContainerWriter(args.out_file)
58
59 # create an instance of the default implementation of the Chem.Molecule interface
60 mol = Chem.BasicMolecule()
61 i = 1
62
63 # read and process molecules one after the other until the end of input has been reached
64 try:
65 while reader.read(mol):
66 # compose a simple molecule identifier
67 mol_id = Chem.getName(mol).strip()
68
69 if mol_id == '':
70 mol_id = '#' + str(i) # fallback if name is empty
71 else:
72 mol_id = '\'%s\' (#%s)' % (mol_id, str(i))
73
74 if not args.quiet:
75 print('- Generating pharmacophore of molecule %s...' % mol_id)
76
77 num_confs = Chem.getNumConformations(mol)
78 start_conf_idx = 0
79
80 if num_confs == 0: # test if molecule has conformations
81 start_conf_idx = -1 # if not, make sure conformer loop body gets executed
82
83 try:
84 for conf_idx in range(start_conf_idx, num_confs): # for each conformer
85 ph4 = genPharmacophore(mol, conf_idx) # generate pharmacophore
86
87 if not args.quiet:
88 print(' -> Generated %s features: %s' % (str(ph4.numFeatures), Pharm.generateFeatureTypeHistogramString(ph4)))
89
90 if not writer.write(ph4): # output pharmacophore
91 sys.exit('Error: writing generated pharmacophore %s failed' % mol_id)
92
93 except Exception as e:
94 sys.exit('Error: pharmacophore generation or output for molecule %s failed: %s' % (mol_id, str(e)))
95
96 i += 1
97
98 except Exception as e: # handle exception raised in case of severe read errors
99 sys.exit('Error: reading molecule failed: ' + str(e))
100
101 writer.close()
102 sys.exit(0)
103
104if __name__ == '__main__':
105 main()